From 5cc3a9c00a42ca6b533247daa8e5d6a06b13e182 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 19 Jul 2019 15:39:44 -0500 Subject: [PATCH 001/584] Fix compilation warning --- src/Files/VolumeDynamicConnectivityFile.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Files/VolumeDynamicConnectivityFile.cxx b/src/Files/VolumeDynamicConnectivityFile.cxx index de12c3727..ad2c4f0a7 100644 --- a/src/Files/VolumeDynamicConnectivityFile.cxx +++ b/src/Files/VolumeDynamicConnectivityFile.cxx @@ -489,7 +489,7 @@ VolumeDynamicConnectivityFile::getConnectivityForVoxelIndex(const int64_t ijk[3] const int64_t myTimePointOffset = getVoxelOffset(ijk[0], ijk[1], ijk[2], 0); connCorrelation->getCorrelationForBrainordinate(myTimePointOffset, voxelsOut); - CaretAssert(m_dimI * m_dimJ * m_dimK == static_cast(voxelsOut.size())); + CaretAssert((m_dimI * m_dimJ * m_dimK) == static_cast(voxelsOut.size())); validFlag = true; } } -- GitLab From 9aeeda25a76188415ad78565ba2301bcd9b79f0d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 19 Jul 2019 16:01:00 -0500 Subject: [PATCH 002/584] WB-859 Manual Tile Tabs Layout System: Continuing development of new classes for new and updated tile tab layout configurations including manual layout configuration. --- src/Common/CMakeLists.txt | 18 +- src/Common/CaretPreferences.cxx | 54 ++ .../TileTabsLayoutBackgroundTypeEnum.cxx | 373 ++++++++++++++ ...m.h => TileTabsLayoutBackgroundTypeEnum.h} | 30 +- ...xx => TileTabsLayoutBaseConfiguration.cxx} | 110 +++-- ...on.h => TileTabsLayoutBaseConfiguration.h} | 46 +- ...> TileTabsLayoutConfigurationTypeEnum.cxx} | 127 ++--- .../TileTabsLayoutConfigurationTypeEnum.h | 106 ++++ ...xx => TileTabsLayoutGridConfiguration.cxx} | 107 ++-- ...on.h => TileTabsLayoutGridConfiguration.h} | 79 ++- .../TileTabsLayoutManualConfiguration.cxx | 462 ++++++++++++++++++ .../TileTabsLayoutManualConfiguration.h | 117 +++++ src/Common/TileTabsLayoutTabInfo.cxx | 364 ++++++++++++++ src/Common/TileTabsLayoutTabInfo.h | 128 +++++ 14 files changed, 1880 insertions(+), 241 deletions(-) create mode 100644 src/Common/TileTabsLayoutBackgroundTypeEnum.cxx rename src/Common/{TileTabsConfigurationLayoutTypeEnum.h => TileTabsLayoutBackgroundTypeEnum.h} (74%) rename src/Common/{TileTabsBaseConfiguration.cxx => TileTabsLayoutBaseConfiguration.cxx} (62%) rename src/Common/{TileTabsBaseConfiguration.h => TileTabsLayoutBaseConfiguration.h} (60%) rename src/Common/{TileTabsConfigurationLayoutTypeEnum.cxx => TileTabsLayoutConfigurationTypeEnum.cxx} (63%) create mode 100644 src/Common/TileTabsLayoutConfigurationTypeEnum.h rename src/Common/{TileTabsGridLayoutConfiguration.cxx => TileTabsLayoutGridConfiguration.cxx} (90%) rename src/Common/{TileTabsGridLayoutConfiguration.h => TileTabsLayoutGridConfiguration.h} (70%) create mode 100644 src/Common/TileTabsLayoutManualConfiguration.cxx create mode 100644 src/Common/TileTabsLayoutManualConfiguration.h create mode 100644 src/Common/TileTabsLayoutTabInfo.cxx create mode 100644 src/Common/TileTabsLayoutTabInfo.h diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index f8d6d2db5..c19fbee31 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -153,9 +153,12 @@ StringTableModel.h StructureEnum.h SystemUtilities.h TileTabsConfiguration.h -TileTabsConfigurationLayoutTypeEnum.h -TileTabsBaseConfiguration.h -TileTabsGridLayoutConfiguration.h +TileTabsLayoutBackgroundTypeEnum.h +TileTabsLayoutBaseConfiguration.h +TileTabsLayoutConfigurationTypeEnum.h +TileTabsLayoutGridConfiguration.h +TileTabsLayoutManualConfiguration.h +TileTabsLayoutTabInfo.h TileTabsGridModeEnum.h TileTabsGridRowColumnContentTypeEnum.h TileTabsGridRowColumnElement.h @@ -278,9 +281,12 @@ StringTableModel.cxx StructureEnum.cxx SystemUtilities.cxx TileTabsConfiguration.cxx -TileTabsConfigurationLayoutTypeEnum.cxx -TileTabsBaseConfiguration.cxx -TileTabsGridLayoutConfiguration.cxx +TileTabsLayoutBackgroundTypeEnum.cxx +TileTabsLayoutBaseConfiguration.cxx +TileTabsLayoutConfigurationTypeEnum.cxx +TileTabsLayoutGridConfiguration.cxx +TileTabsLayoutManualConfiguration.cxx +TileTabsLayoutTabInfo.cxx TileTabsGridModeEnum.cxx TileTabsGridRowColumnContentTypeEnum.cxx TileTabsGridRowColumnElement.cxx diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 791e93d85..8908a7545 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -34,6 +34,8 @@ #include "CaretPreferenceDataValue.h" #include "ModelTransform.h" #include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" #include "WuQMacroGroup.h" using namespace caret; @@ -506,6 +508,58 @@ CaretPreferences::readTileTabsConfigurations(const bool performSync) CaretLogWarning(errorMessage); delete ttc; } + + const bool testFlag(true); + if (testFlag) { + AString errorMessage; + TileTabsLayoutBaseConfiguration* config = TileTabsLayoutBaseConfiguration::decodeFromXML(configString, + errorMessage); + if (config != NULL) { + std::cout << "Read config: " << config->toString() << std::endl; + + TileTabsLayoutGridConfiguration* gridConfig = dynamic_cast(config); + if (gridConfig != NULL) { + const int32_t rowCount = gridConfig->getNumberOfRows(); + const int32_t colCount = gridConfig->getNumberOfColumns(); + const int32_t numTabs = rowCount * colCount; + std::vector tabIndices; + for (int32_t i = 0; i < numTabs; i++) { + tabIndices.push_back(i); + } + TileTabsLayoutManualConfiguration* manualLayout + = TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(gridConfig, + TileTabsGridModeEnum::CUSTOM, + tabIndices); + if (manualLayout != NULL) { + std::cout << "MANUAL VERSION OF GRID LAYOUT: " << std::endl; + std::cout << manualLayout->toString() << std::endl; + + AString xmlText = manualLayout->encodeInXML(); + std::cout << "XML: " << std::endl; + std::cout << xmlText << std::endl << std::endl; + + delete manualLayout; + + TileTabsLayoutBaseConfiguration* configMan = + TileTabsLayoutBaseConfiguration::decodeFromXML(xmlText, + errorMessage); + if (configMan != NULL) { + std::cout << "After reading manual configuration and writing it: " << std::endl; + std::cout << configMan->toString() << std::endl << std::endl; + } + else { + std::cout << "ERROR decoding from manual layout: " + << errorMessage << std::endl; + } + } + } + } + else { + std::cout << "Error reading config: " << errorMessage << std::endl; + std::cout << "FROM: " << configString << std::endl; + } + std::cout << std::endl; + } } this->qSettings->endArray(); } diff --git a/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx new file mode 100644 index 000000000..4d75ca484 --- /dev/null +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx @@ -0,0 +1,373 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include +#define __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_DECLARE__ +#include "TileTabsLayoutBackgroundTypeEnum.h" +#undef __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_DECLARE__ + +#include "CaretAssert.h" + +using namespace caret; + + +/** + * \class caret::TileTabsLayoutBackgroundTypeEnum + * \brief Background type (opaque, transparent) for tabs in a tile tabs layout + * + * Using this enumerated type in the GUI with an EnumComboBoxTemplate + * + * Header File (.h) + * Forward declare the data type: + * class EnumComboBoxTemplate; + * + * Declare the member: + * EnumComboBoxTemplate* m_TileTabsLayoutBackgroundTypeEnumComboBox; + * + * Declare a slot that is called when user changes selection + * private slots: + * void TileTabsLayoutBackgroundTypeEnumComboBoxItemActivated(); + * + * Implementation File (.cxx) + * Include the header files + * #include "EnumComboBoxTemplate.h" + * #include "TileTabsLayoutBackgroundTypeEnum.h" + * + * Instatiate: + * m_TileTabsLayoutBackgroundTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_TileTabsLayoutBackgroundTypeEnumComboBox->setup(); + * + * Get notified when the user changes the selection: + * QObject::connect(m_TileTabsLayoutBackgroundTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(TileTabsLayoutBackgroundTypeEnumComboBoxItemActivated())); + * + * Update the selection: + * m_TileTabsLayoutBackgroundTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * + * Read the selection: + * const TileTabsLayoutBackgroundTypeEnum::Enum VARIABLE = m_TileTabsLayoutBackgroundTypeEnumComboBox->getSelectedItem(); + * + */ + +/** + * Constructor. + * + * @param enumValue + * An enumerated value. + * @param name + * Name of enumerated value. + * + * @param guiName + * User-friendly name for use in user-interface. + */ +TileTabsLayoutBackgroundTypeEnum::TileTabsLayoutBackgroundTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName) +{ + this->enumValue = enumValue; + this->integerCode = integerCodeCounter++; + this->name = name; + this->guiName = guiName; +} + +/** + * Destructor. + */ +TileTabsLayoutBackgroundTypeEnum::~TileTabsLayoutBackgroundTypeEnum() +{ +} + +/** + * Initialize the enumerated metadata. + */ +void +TileTabsLayoutBackgroundTypeEnum::initialize() +{ + if (initializedFlag) { + return; + } + initializedFlag = true; + + enumData.push_back(TileTabsLayoutBackgroundTypeEnum(OPAQUE, + "OPAQUE", + "Opaque")); + + enumData.push_back(TileTabsLayoutBackgroundTypeEnum(TRANSPARENT, + "TRANSPARENT", + "Transparent")); + +} + +/** + * Find the data for and enumerated value. + * @param enumValue + * The enumerated value. + * @return Pointer to data for this enumerated type + * or NULL if no data for type or if type is invalid. + */ +const TileTabsLayoutBackgroundTypeEnum* +TileTabsLayoutBackgroundTypeEnum::findData(const Enum enumValue) +{ + if (initializedFlag == false) initialize(); + + size_t num = enumData.size(); + for (size_t i = 0; i < num; i++) { + const TileTabsLayoutBackgroundTypeEnum* d = &enumData[i]; + if (d->enumValue == enumValue) { + return d; + } + } + + return NULL; +} + +/** + * Get a string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsLayoutBackgroundTypeEnum::toName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsLayoutBackgroundTypeEnum* enumInstance = findData(enumValue); + return enumInstance->name; +} + +/** + * Get an enumerated value corresponding to its name. + * @param name + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsLayoutBackgroundTypeEnum::Enum +TileTabsLayoutBackgroundTypeEnum::fromName(const AString& name, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsLayoutBackgroundTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsLayoutBackgroundTypeEnum& d = *iter; + if (d.name == name) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsLayoutBackgroundTypeEnum")); + } + return enumValue; +} + +/** + * Get a GUI string representation of the enumerated type. + * @param enumValue + * Enumerated value. + * @return + * String representing enumerated value. + */ +AString +TileTabsLayoutBackgroundTypeEnum::toGuiName(Enum enumValue) { + if (initializedFlag == false) initialize(); + + const TileTabsLayoutBackgroundTypeEnum* enumInstance = findData(enumValue); + return enumInstance->guiName; +} + +/** + * Get an enumerated value corresponding to its GUI name. + * @param s + * Name of enumerated value. + * @param isValidOut + * If not NULL, it is set indicating that a + * enum value exists for the input name. + * @return + * Enumerated value. + */ +TileTabsLayoutBackgroundTypeEnum::Enum +TileTabsLayoutBackgroundTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsLayoutBackgroundTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsLayoutBackgroundTypeEnum& d = *iter; + if (d.guiName == guiName) { + enumValue = d.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsLayoutBackgroundTypeEnum")); + } + return enumValue; +} + +/** + * Get the integer code for a data type. + * + * @return + * Integer code for data type. + */ +int32_t +TileTabsLayoutBackgroundTypeEnum::toIntegerCode(Enum enumValue) +{ + if (initializedFlag == false) initialize(); + const TileTabsLayoutBackgroundTypeEnum* enumInstance = findData(enumValue); + return enumInstance->integerCode; +} + +/** + * Find the data type corresponding to an integer code. + * + * @param integerCode + * Integer code for enum. + * @param isValidOut + * If not NULL, on exit isValidOut will indicate if + * integer code is valid. + * @return + * Enum for integer code. + */ +TileTabsLayoutBackgroundTypeEnum::Enum +TileTabsLayoutBackgroundTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +{ + if (initializedFlag == false) initialize(); + + bool validFlag = false; + Enum enumValue = TileTabsLayoutBackgroundTypeEnum::enumData[0].enumValue; + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + const TileTabsLayoutBackgroundTypeEnum& enumInstance = *iter; + if (enumInstance.integerCode == integerCode) { + enumValue = enumInstance.enumValue; + validFlag = true; + break; + } + } + + if (isValidOut != 0) { + *isValidOut = validFlag; + } + else if (validFlag == false) { + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsLayoutBackgroundTypeEnum")); + } + return enumValue; +} + +/** + * Get all of the enumerated type values. The values can be used + * as parameters to toXXX() methods to get associated metadata. + * + * @param allEnums + * A vector that is OUTPUT containing all of the enumerated values. + */ +void +TileTabsLayoutBackgroundTypeEnum::getAllEnums(std::vector& allEnums) +{ + if (initializedFlag == false) initialize(); + + allEnums.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allEnums.push_back(iter->enumValue); + } +} + +/** + * Get all of the names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsLayoutBackgroundTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allNames.push_back(TileTabsLayoutBackgroundTypeEnum::toName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allNames.begin(), allNames.end()); + } +} + +/** + * Get all of the GUI names of the enumerated type values. + * + * @param allNames + * A vector that is OUTPUT containing all of the GUI names of the enumerated values. + * @param isSorted + * If true, the names are sorted in alphabetical order. + */ +void +TileTabsLayoutBackgroundTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +{ + if (initializedFlag == false) initialize(); + + allGuiNames.clear(); + + for (std::vector::iterator iter = enumData.begin(); + iter != enumData.end(); + iter++) { + allGuiNames.push_back(TileTabsLayoutBackgroundTypeEnum::toGuiName(iter->enumValue)); + } + + if (isSorted) { + std::sort(allGuiNames.begin(), allGuiNames.end()); + } +} + diff --git a/src/Common/TileTabsConfigurationLayoutTypeEnum.h b/src/Common/TileTabsLayoutBackgroundTypeEnum.h similarity index 74% rename from src/Common/TileTabsConfigurationLayoutTypeEnum.h rename to src/Common/TileTabsLayoutBackgroundTypeEnum.h index 8a57604bd..91a243737 100644 --- a/src/Common/TileTabsConfigurationLayoutTypeEnum.h +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ -#define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ +#ifndef __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_H__ +#define __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_H__ /*LICENSE_START*/ /* @@ -28,7 +28,7 @@ namespace caret { -class TileTabsConfigurationLayoutTypeEnum { +class TileTabsLayoutBackgroundTypeEnum { public: /** @@ -36,13 +36,13 @@ public: */ enum Enum { /** */ - GRID, + OPAQUE, /** */ - MANUAL + TRANSPARENT }; - ~TileTabsConfigurationLayoutTypeEnum(); + ~TileTabsLayoutBackgroundTypeEnum(); static AString toName(Enum enumValue); @@ -63,14 +63,14 @@ public: static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); private: - TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, + TileTabsLayoutBackgroundTypeEnum(const Enum enumValue, const AString& name, const AString& guiName); - static const TileTabsConfigurationLayoutTypeEnum* findData(const Enum enumValue); + static const TileTabsLayoutBackgroundTypeEnum* findData(const Enum enumValue); /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; + static std::vector enumData; /** Initialize instances that contain the enum values and metadata */ static void initialize(); @@ -94,11 +94,11 @@ private: AString guiName; }; -#ifdef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ -std::vector TileTabsConfigurationLayoutTypeEnum::enumData; -bool TileTabsConfigurationLayoutTypeEnum::initializedFlag = false; -int32_t TileTabsConfigurationLayoutTypeEnum::integerCodeCounter = 0; -#endif // __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ +#ifdef __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_DECLARE__ +std::vector TileTabsLayoutBackgroundTypeEnum::enumData; +bool TileTabsLayoutBackgroundTypeEnum::initializedFlag = false; +int32_t TileTabsLayoutBackgroundTypeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_DECLARE__ } // namespace -#endif //__TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ +#endif //__TILE_TABS_LAYOUT_BACKGROUND_TYPE_ENUM_H__ diff --git a/src/Common/TileTabsBaseConfiguration.cxx b/src/Common/TileTabsLayoutBaseConfiguration.cxx similarity index 62% rename from src/Common/TileTabsBaseConfiguration.cxx rename to src/Common/TileTabsLayoutBaseConfiguration.cxx index e22e23a4b..0514f1532 100644 --- a/src/Common/TileTabsBaseConfiguration.cxx +++ b/src/Common/TileTabsLayoutBaseConfiguration.cxx @@ -22,24 +22,26 @@ #include #include -#define __TILE_TABS_BASE_CONFIGURATION_DECLARE__ -#include "TileTabsBaseConfiguration.h" -#undef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ +#define __TILE_TABS_LAYOUT_BASE_CONFIGURATION_DECLARE__ +#include "TileTabsLayoutBaseConfiguration.h" +#undef __TILE_TABS_LAYOUT_BASE_CONFIGURATION_DECLARE__ +#include #include #include #include "CaretAssert.h" #include "CaretLogger.h" #include "SystemUtilities.h" -#include "TileTabsGridLayoutConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" using namespace caret; /** - * \class caret::TileTabsBaseConfiguration + * \class caret::TileTabsLayoutBaseConfiguration * \brief Defines a tile tabs configuration * \ingroup Common */ @@ -47,17 +49,17 @@ using namespace caret; /** * Constructor that creates a 2 by 2 configuration. */ -TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType) +TileTabsLayoutBaseConfiguration::TileTabsLayoutBaseConfiguration(const TileTabsLayoutConfigurationTypeEnum::Enum layoutType) : CaretObject(), m_layoutType(layoutType) { - initializeTileTabsBaseConfiguration(); + initializeTileTabsLayoutBaseConfiguration(); } /** * Destructor. */ -TileTabsBaseConfiguration::~TileTabsBaseConfiguration() +TileTabsLayoutBaseConfiguration::~TileTabsLayoutBaseConfiguration() { } @@ -69,14 +71,14 @@ TileTabsBaseConfiguration::~TileTabsBaseConfiguration() * @param obj * Object that is copied. */ -TileTabsBaseConfiguration::TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) +TileTabsLayoutBaseConfiguration::TileTabsLayoutBaseConfiguration(const TileTabsLayoutBaseConfiguration& obj) : CaretObject(obj), m_layoutType(obj.m_layoutType) { const AString savedUniqueID = m_uniqueIdentifier; - initializeTileTabsBaseConfiguration(); + initializeTileTabsLayoutBaseConfiguration(); m_uniqueIdentifier = savedUniqueID; - this->copyHelperTileTabsBaseConfiguration(obj); + this->copyHelperTileTabsLayoutBaseConfiguration(obj); } /** @@ -89,12 +91,12 @@ m_layoutType(obj.m_layoutType) * @return * Reference to this object. */ -TileTabsBaseConfiguration& -TileTabsBaseConfiguration::operator=(const TileTabsBaseConfiguration& obj) +TileTabsLayoutBaseConfiguration& +TileTabsLayoutBaseConfiguration::operator=(const TileTabsLayoutBaseConfiguration& obj) { if (this != &obj) { CaretObject::operator=(obj); - this->copyHelperTileTabsBaseConfiguration(obj); + this->copyHelperTileTabsLayoutBaseConfiguration(obj); } return *this; } @@ -103,7 +105,7 @@ TileTabsBaseConfiguration::operator=(const TileTabsBaseConfiguration& obj) * Initialize an instance of a tile tabs configuration. */ void -TileTabsBaseConfiguration::initializeTileTabsBaseConfiguration() +TileTabsLayoutBaseConfiguration::initializeTileTabsLayoutBaseConfiguration() { m_name.clear(); m_uniqueIdentifier = SystemUtilities::createUniqueID(); @@ -115,7 +117,7 @@ TileTabsBaseConfiguration::initializeTileTabsBaseConfiguration() * Object that is copied. */ void -TileTabsBaseConfiguration::copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj) +TileTabsLayoutBaseConfiguration::copyHelperTileTabsLayoutBaseConfiguration(const TileTabsLayoutBaseConfiguration& obj) { if (this == &obj) { return; @@ -130,19 +132,19 @@ TileTabsBaseConfiguration::copyHelperTileTabsBaseConfiguration(const TileTabsBas * stretch factors. Name is NOT copied. */ void -TileTabsBaseConfiguration::copy(const TileTabsBaseConfiguration& rhs) +TileTabsLayoutBaseConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs) { CaretAssertToDoFatal(); // need to do this a different way AString savedName = m_name; - copyHelperTileTabsBaseConfiguration(rhs); + copyHelperTileTabsLayoutBaseConfiguration(rhs); m_name = savedName; } /** * @return Type of layout for the configuration */ -TileTabsConfigurationLayoutTypeEnum::Enum -TileTabsBaseConfiguration::getLayoutType() const +TileTabsLayoutConfigurationTypeEnum::Enum +TileTabsLayoutBaseConfiguration::getLayoutType() const { return m_layoutType; } @@ -151,7 +153,7 @@ TileTabsBaseConfiguration::getLayoutType() const * @return the name of the tile tabs configuration. */ AString -TileTabsBaseConfiguration::getName() const +TileTabsLayoutBaseConfiguration::getName() const { return m_name; } @@ -160,7 +162,7 @@ TileTabsBaseConfiguration::getName() const * @return Get the unique identifier that uniquely identifies each configuration. */ AString -TileTabsBaseConfiguration::getUniqueIdentifier() const +TileTabsLayoutBaseConfiguration::getUniqueIdentifier() const { return m_uniqueIdentifier; } @@ -172,7 +174,7 @@ TileTabsBaseConfiguration::getUniqueIdentifier() const * New name for configuration. */ void -TileTabsBaseConfiguration::setName(const AString& name) +TileTabsLayoutBaseConfiguration::setName(const AString& name) { m_name = name; } @@ -184,7 +186,7 @@ TileTabsBaseConfiguration::setName(const AString& name) * New unique identifier for configuration. */ void -TileTabsBaseConfiguration::setUniqueIdentifierProtected(const AString& uniqueID) +TileTabsLayoutBaseConfiguration::setUniqueIdentifierProtected(const AString& uniqueID) { m_uniqueIdentifier = uniqueID; } @@ -194,10 +196,10 @@ TileTabsBaseConfiguration::setUniqueIdentifierProtected(const AString& uniqueID) * @return Encoded tile tabs configuration in XML */ AString -TileTabsBaseConfiguration::encodeInXML() const +TileTabsLayoutBaseConfiguration::encodeInXML() const { AString s; - encodeInXML(s); + encodeInXMLString(s); return s; } @@ -211,40 +213,46 @@ TileTabsBaseConfiguration::encodeInXML() const * @return * Pointer to the configuration or NULL if there was an error. */ -TileTabsBaseConfiguration* -TileTabsBaseConfiguration::decodeFromXML(const AString& xmlString, +TileTabsLayoutBaseConfiguration* +TileTabsLayoutBaseConfiguration::decodeFromXML(const AString& xmlString, AString& errorMessageOut) { errorMessageOut.clear(); - TileTabsBaseConfiguration* configurationOut(NULL); + TileTabsLayoutBaseConfiguration* configurationOut(NULL); QXmlStreamReader xml(xmlString); if (xml.readNextStartElement()) { const QStringRef tagName(xml.name()); - if (tagName == TileTabsGridLayoutConfiguration::s_v1_rootTagName) { - TileTabsGridLayoutConfiguration* v1 = new TileTabsGridLayoutConfiguration(); - v1->decodeFromXML(xml, - tagName.toString()); + if (tagName == TileTabsLayoutGridConfiguration::s_v1_rootTagName) { + TileTabsLayoutGridConfiguration* v1 = new TileTabsLayoutGridConfiguration(); + v1->decodeFromXMLString(xml, + tagName.toString()); configurationOut = v1; } - else if (tagName == TileTabsGridLayoutConfiguration::s_v2_rootTagName) { - TileTabsGridLayoutConfiguration* v2 = new TileTabsGridLayoutConfiguration(); - v2->decodeFromXML(xml, - tagName.toString()); + else if (tagName == TileTabsLayoutGridConfiguration::s_v2_rootTagName) { + TileTabsLayoutGridConfiguration* v2 = new TileTabsLayoutGridConfiguration(); + v2->decodeFromXMLString(xml, + tagName.toString()); configurationOut = v2; } + else if (tagName == TileTabsLayoutManualConfiguration::s_rootElementName) { + TileTabsLayoutManualConfiguration* manConfig = new TileTabsLayoutManualConfiguration(); + manConfig->decodeFromXMLString(xml, + tagName.toString()); + configurationOut = manConfig; + } else { - xml.raiseError("TileTabsBaseConfiguration first element is " + xml.raiseError("TileTabsLayoutBaseConfiguration first element is " + xml.name().toString() + " but should be " - + TileTabsGridLayoutConfiguration::s_v1_rootTagName + + TileTabsLayoutGridConfiguration::s_v1_rootTagName + " or " - + TileTabsGridLayoutConfiguration::s_v2_rootTagName); + + TileTabsLayoutGridConfiguration::s_v2_rootTagName); } } else { - xml.raiseError("TileTabsBaseConfiguration failed to find start elemnent."); + xml.raiseError("TileTabsLayoutBaseConfiguration failed to find start elemnent."); } if (xml.hasError()) { @@ -266,7 +274,7 @@ TileTabsBaseConfiguration::decodeFromXML(const AString& xmlString, // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; // AString em; -// TileTabsBaseConfiguration temp; +// TileTabsLayoutBaseConfiguration temp; // QXmlStreamReader tempReader(xmlText); // tempReader.readNextStartElement(); // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); @@ -287,10 +295,16 @@ TileTabsBaseConfiguration::decodeFromXML(const AString& xmlString, * @return String version of an instance. */ AString -TileTabsBaseConfiguration::toString() const +TileTabsLayoutBaseConfiguration::toString() const { - AString s("Name: %1, Unique ID: %2\n"); - s = s.arg(m_name).arg(m_uniqueIdentifier); + QString str; + QTextStream ts(&str); + ts << "TileTabsLayoutBaseConfiguration: " + << " m_name=" << m_name + << " m_uniqueIdentifier=" << m_uniqueIdentifier + << " m_layoutType=" << TileTabsLayoutConfigurationTypeEnum::toName(m_layoutType); +// AString s("Name: %1, Unique ID: %2\n"); +// s = s.arg(m_name).arg(m_uniqueIdentifier); // // int32_t indx(0); // for (const auto item : m_columns) { @@ -303,7 +317,7 @@ TileTabsBaseConfiguration::toString() const // indx++; // } - return s; + return str; } /** @@ -317,8 +331,8 @@ TileTabsBaseConfiguration::toString() const * True if ttc1 is "less than" when compared by name, else false. */ bool -TileTabsBaseConfiguration::lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, - const TileTabsBaseConfiguration* ttc2) +TileTabsLayoutBaseConfiguration::lessThanComparisonByName(const TileTabsLayoutBaseConfiguration* ttc1, + const TileTabsLayoutBaseConfiguration* ttc2) { if (ttc1->getName() < ttc2->getName()) { return true; diff --git a/src/Common/TileTabsBaseConfiguration.h b/src/Common/TileTabsLayoutBaseConfiguration.h similarity index 60% rename from src/Common/TileTabsBaseConfiguration.h rename to src/Common/TileTabsLayoutBaseConfiguration.h index 8e5ed2571..c01e3a44a 100644 --- a/src/Common/TileTabsBaseConfiguration.h +++ b/src/Common/TileTabsLayoutBaseConfiguration.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_BASE_CONFIGURATION_H__ -#define __TILE_TABS_BASE_CONFIGURATION_H__ +#ifndef __TILE_TABS_LAYOUT_BASE_CONFIGURATION_H__ +#define __TILE_TABS_LAYOUT_BASE_CONFIGURATION_H__ /*LICENSE_START*/ /* @@ -23,7 +23,7 @@ #include "CaretException.h" #include "CaretObject.h" -#include "TileTabsConfigurationLayoutTypeEnum.h" +#include "TileTabsLayoutConfigurationTypeEnum.h" #include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" @@ -32,23 +32,23 @@ class QXmlStreamWriter; namespace caret { - class TileTabsBaseConfiguration : public CaretObject { + class TileTabsLayoutBaseConfiguration : public CaretObject { protected: - TileTabsBaseConfiguration(const TileTabsConfigurationLayoutTypeEnum::Enum layoutType); + TileTabsLayoutBaseConfiguration(const TileTabsLayoutConfigurationTypeEnum::Enum layoutType); public: - virtual ~TileTabsBaseConfiguration(); + virtual ~TileTabsLayoutBaseConfiguration(); - TileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); + TileTabsLayoutBaseConfiguration(const TileTabsLayoutBaseConfiguration& obj); - TileTabsBaseConfiguration& operator=(const TileTabsBaseConfiguration& obj); + TileTabsLayoutBaseConfiguration& operator=(const TileTabsLayoutBaseConfiguration& obj); - void copy(const TileTabsBaseConfiguration& rhs); + void copy(const TileTabsLayoutBaseConfiguration& rhs); - virtual TileTabsBaseConfiguration* newCopyWithNewUniqueIdentifier() const = 0; + virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const = 0; - TileTabsConfigurationLayoutTypeEnum::Enum getLayoutType() const; + TileTabsLayoutConfigurationTypeEnum::Enum getLayoutType() const; AString getName() const; @@ -59,13 +59,13 @@ namespace caret { AString encodeInXML() const; - static TileTabsBaseConfiguration* decodeFromXML(const AString& xmlString, + static TileTabsLayoutBaseConfiguration* decodeFromXML(const AString& xmlString, AString& errorMessageOut); AString toString() const override; - static bool lessThanComparisonByName(const TileTabsBaseConfiguration* ttc1, - const TileTabsBaseConfiguration* ttc2); + static bool lessThanComparisonByName(const TileTabsLayoutBaseConfiguration* ttc1, + const TileTabsLayoutBaseConfiguration* ttc2); // ADD_NEW_METHODS_HERE @@ -81,8 +81,8 @@ namespace caret { * @param rootElement * The root element. */ - virtual void decodeFromXML(QXmlStreamReader& xml, - const QString& rootElementText) = 0; + virtual void decodeFromXMLString(QXmlStreamReader& xml, + const AString& rootElementText) = 0; /** * Encode the configuration in XML. @@ -90,19 +90,19 @@ namespace caret { * @param xmlTextOut * Contains XML representation of configuration. */ - virtual void encodeInXML(AString& xmlTextOut) const = 0; + virtual void encodeInXMLString(AString& xmlTextOut) const = 0; void setUniqueIdentifierProtected(const AString& uniqueID); - void copyHelperTileTabsBaseConfiguration(const TileTabsBaseConfiguration& obj); + void copyHelperTileTabsLayoutBaseConfiguration(const TileTabsLayoutBaseConfiguration& obj); private: - void initializeTileTabsBaseConfiguration(); + void initializeTileTabsLayoutBaseConfiguration(); // ADD_NEW_MEMBERS_HERE - const TileTabsConfigurationLayoutTypeEnum::Enum m_layoutType; + const TileTabsLayoutConfigurationTypeEnum::Enum m_layoutType; AString m_name; @@ -112,9 +112,9 @@ namespace caret { }; -#ifdef __TILE_TABS_BASE_CONFIGURATION_DECLARE__ +#ifdef __TILE_TABS_LAYOUT_BASE_CONFIGURATION_H__ -#endif // __TILE_TABS_BASE_CONFIGURATION_DECLARE__ +#endif // __TILE_TABS_LAYOUT_BASE_CONFIGURATION_DECLARE__ } // namespace -#endif //__TILE_TABS_BASE_CONFIGURATION_H__ +#endif //__TILE_TABS_LAYOUT_BASE_CONFIGURATION_DECLARE__ diff --git a/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx b/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx similarity index 63% rename from src/Common/TileTabsConfigurationLayoutTypeEnum.cxx rename to src/Common/TileTabsLayoutConfigurationTypeEnum.cxx index fe45e41cb..eb0eec546 100644 --- a/src/Common/TileTabsConfigurationLayoutTypeEnum.cxx +++ b/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx @@ -20,9 +20,9 @@ /*LICENSE_END*/ #include -#define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ -#include "TileTabsConfigurationLayoutTypeEnum.h" -#undef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_DECLARE__ +#define __TILE_TABS_LAYOUT_CONFIGURATION_TYPE_ENUM_DECLARE__ +#include "TileTabsLayoutConfigurationTypeEnum.h" +#undef __TILE_TABS_LAYOUT_CONFIGURATION_TYPE_ENUM_DECLARE__ #include "CaretAssert.h" @@ -30,7 +30,7 @@ using namespace caret; /** - * \class caret::TileTabsConfigurationLayoutTypeEnum + * \class caret::TileTabsLayoutConfigurationTypeEnum * \brief Types of tile tabs layouts * * Using this enumerated type in the GUI with an EnumComboBoxTemplate @@ -40,30 +40,30 @@ using namespace caret; * class EnumComboBoxTemplate; * * Declare the member: - * EnumComboBoxTemplate* m_tileTabsConfigurationLayoutTypeEnumComboBox; + * EnumComboBoxTemplate* m_TileTabsLayoutConfigurationTypeEnumComboBox; * * Declare a slot that is called when user changes selection * private slots: - * void tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated(); + * void TileTabsLayoutConfigurationTypeEnumComboBoxItemActivated(); * * Implementation File (.cxx) * Include the header files * #include "EnumComboBoxTemplate.h" - * #include "TileTabsConfigurationLayoutTypeEnum.h" + * #include "TileTabsLayoutConfigurationTypeEnum.h" * * Instatiate: - * m_tileTabsConfigurationLayoutTypeEnumComboBox = new EnumComboBoxTemplate(this); - * m_tileTabsConfigurationLayoutTypeEnumComboBox->setup(); + * m_TileTabsLayoutConfigurationTypeEnumComboBox = new EnumComboBoxTemplate(this); + * m_TileTabsLayoutConfigurationTypeEnumComboBox->setup(); * * Get notified when the user changes the selection: - * QObject::connect(m_tileTabsConfigurationLayoutTypeEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(tileTabsConfigurationLayoutTypeEnumComboBoxItemActivated())); + * QObject::connect(m_TileTabsLayoutConfigurationTypeEnumComboBox, SIGNAL(itemActivated()), + * this, SLOT(TileTabsLayoutConfigurationTypeEnumComboBoxItemActivated())); * * Update the selection: - * m_tileTabsConfigurationLayoutTypeEnumComboBox->setSelectedItem(NEW_VALUE); + * m_TileTabsLayoutConfigurationTypeEnumComboBox->setSelectedItem(NEW_VALUE); * * Read the selection: - * const TileTabsConfigurationLayoutTypeEnum::Enum VARIABLE = m_tileTabsConfigurationLayoutTypeEnumComboBox->getSelectedItem(); + * const TileTabsLayoutConfigurationTypeEnum::Enum VARIABLE = m_TileTabsLayoutConfigurationTypeEnumComboBox->getSelectedItem(); * */ @@ -78,7 +78,7 @@ using namespace caret; * @param guiName * User-friendly name for use in user-interface. */ -TileTabsConfigurationLayoutTypeEnum::TileTabsConfigurationLayoutTypeEnum(const Enum enumValue, +TileTabsLayoutConfigurationTypeEnum::TileTabsLayoutConfigurationTypeEnum(const Enum enumValue, const AString& name, const AString& guiName) { @@ -91,7 +91,7 @@ TileTabsConfigurationLayoutTypeEnum::TileTabsConfigurationLayoutTypeEnum(const E /** * Destructor. */ -TileTabsConfigurationLayoutTypeEnum::~TileTabsConfigurationLayoutTypeEnum() +TileTabsLayoutConfigurationTypeEnum::~TileTabsLayoutConfigurationTypeEnum() { } @@ -99,21 +99,21 @@ TileTabsConfigurationLayoutTypeEnum::~TileTabsConfigurationLayoutTypeEnum() * Initialize the enumerated metadata. */ void -TileTabsConfigurationLayoutTypeEnum::initialize() +TileTabsLayoutConfigurationTypeEnum::initialize() { if (initializedFlag) { return; } initializedFlag = true; - enumData.push_back(TileTabsConfigurationLayoutTypeEnum(GRID, - "GRID", - "Grid")); - - enumData.push_back(TileTabsConfigurationLayoutTypeEnum(MANUAL, - "MANUAL", - "Manual")); + enumData.push_back(TileTabsLayoutConfigurationTypeEnum(CUSTOM_GRID, + "CUSTOM_GRID", + "Custom Grid")); + enumData.push_back(TileTabsLayoutConfigurationTypeEnum(MANUAL, + "MANUAL", + "Manual")); + } /** @@ -123,14 +123,14 @@ TileTabsConfigurationLayoutTypeEnum::initialize() * @return Pointer to data for this enumerated type * or NULL if no data for type or if type is invalid. */ -const TileTabsConfigurationLayoutTypeEnum* -TileTabsConfigurationLayoutTypeEnum::findData(const Enum enumValue) +const TileTabsLayoutConfigurationTypeEnum* +TileTabsLayoutConfigurationTypeEnum::findData(const Enum enumValue) { if (initializedFlag == false) initialize(); size_t num = enumData.size(); for (size_t i = 0; i < num; i++) { - const TileTabsConfigurationLayoutTypeEnum* d = &enumData[i]; + const TileTabsLayoutConfigurationTypeEnum* d = &enumData[i]; if (d->enumValue == enumValue) { return d; } @@ -147,10 +147,10 @@ TileTabsConfigurationLayoutTypeEnum::findData(const Enum enumValue) * String representing enumerated value. */ AString -TileTabsConfigurationLayoutTypeEnum::toName(Enum enumValue) { +TileTabsLayoutConfigurationTypeEnum::toName(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + const TileTabsLayoutConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->name; } @@ -164,18 +164,29 @@ TileTabsConfigurationLayoutTypeEnum::toName(Enum enumValue) { * @return * Enumerated value. */ -TileTabsConfigurationLayoutTypeEnum::Enum -TileTabsConfigurationLayoutTypeEnum::fromName(const AString& name, bool* isValidOut) +TileTabsLayoutConfigurationTypeEnum::Enum +TileTabsLayoutConfigurationTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); + + /* + * Convert names from older versions of tile tab layouts + */ + QString name(nameIn); + if (name == "AUTOMATIC") { + name = TileTabsLayoutConfigurationTypeEnum::toName(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID); + } + else if (name == "CUSTOM") { + name = TileTabsLayoutConfigurationTypeEnum::toName(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); + } bool validFlag = false; - Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsLayoutConfigurationTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationLayoutTypeEnum& d = *iter; + const TileTabsLayoutConfigurationTypeEnum& d = *iter; if (d.name == name) { enumValue = d.enumValue; validFlag = true; @@ -187,7 +198,7 @@ TileTabsConfigurationLayoutTypeEnum::fromName(const AString& name, bool* isValid *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsLayoutConfigurationTypeEnum")); } return enumValue; } @@ -200,10 +211,10 @@ TileTabsConfigurationLayoutTypeEnum::fromName(const AString& name, bool* isValid * String representing enumerated value. */ AString -TileTabsConfigurationLayoutTypeEnum::toGuiName(Enum enumValue) { +TileTabsLayoutConfigurationTypeEnum::toGuiName(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + const TileTabsLayoutConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->guiName; } @@ -217,18 +228,18 @@ TileTabsConfigurationLayoutTypeEnum::toGuiName(Enum enumValue) { * @return * Enumerated value. */ -TileTabsConfigurationLayoutTypeEnum::Enum -TileTabsConfigurationLayoutTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) +TileTabsLayoutConfigurationTypeEnum::Enum +TileTabsLayoutConfigurationTypeEnum::fromGuiName(const AString& guiName, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsLayoutConfigurationTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationLayoutTypeEnum& d = *iter; + const TileTabsLayoutConfigurationTypeEnum& d = *iter; if (d.guiName == guiName) { enumValue = d.enumValue; validFlag = true; @@ -240,7 +251,7 @@ TileTabsConfigurationLayoutTypeEnum::fromGuiName(const AString& guiName, bool* i *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsLayoutConfigurationTypeEnum")); } return enumValue; } @@ -252,10 +263,10 @@ TileTabsConfigurationLayoutTypeEnum::fromGuiName(const AString& guiName, bool* i * Integer code for data type. */ int32_t -TileTabsConfigurationLayoutTypeEnum::toIntegerCode(Enum enumValue) +TileTabsLayoutConfigurationTypeEnum::toIntegerCode(Enum enumValue) { if (initializedFlag == false) initialize(); - const TileTabsConfigurationLayoutTypeEnum* enumInstance = findData(enumValue); + const TileTabsLayoutConfigurationTypeEnum* enumInstance = findData(enumValue); return enumInstance->integerCode; } @@ -270,18 +281,18 @@ TileTabsConfigurationLayoutTypeEnum::toIntegerCode(Enum enumValue) * @return * Enum for integer code. */ -TileTabsConfigurationLayoutTypeEnum::Enum -TileTabsConfigurationLayoutTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) +TileTabsLayoutConfigurationTypeEnum::Enum +TileTabsLayoutConfigurationTypeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) { if (initializedFlag == false) initialize(); bool validFlag = false; - Enum enumValue = TileTabsConfigurationLayoutTypeEnum::enumData[0].enumValue; + Enum enumValue = TileTabsLayoutConfigurationTypeEnum::enumData[0].enumValue; - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - const TileTabsConfigurationLayoutTypeEnum& enumInstance = *iter; + const TileTabsLayoutConfigurationTypeEnum& enumInstance = *iter; if (enumInstance.integerCode == integerCode) { enumValue = enumInstance.enumValue; validFlag = true; @@ -293,7 +304,7 @@ TileTabsConfigurationLayoutTypeEnum::fromIntegerCode(const int32_t integerCode, *isValidOut = validFlag; } else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsConfigurationLayoutTypeEnum")); + CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsLayoutConfigurationTypeEnum")); } return enumValue; } @@ -306,13 +317,13 @@ TileTabsConfigurationLayoutTypeEnum::fromIntegerCode(const int32_t integerCode, * A vector that is OUTPUT containing all of the enumerated values. */ void -TileTabsConfigurationLayoutTypeEnum::getAllEnums(std::vector& allEnums) +TileTabsLayoutConfigurationTypeEnum::getAllEnums(std::vector& allEnums) { if (initializedFlag == false) initialize(); allEnums.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { allEnums.push_back(iter->enumValue); @@ -328,16 +339,16 @@ TileTabsConfigurationLayoutTypeEnum::getAllEnums(std::vector& allNames, const bool isSorted) +TileTabsLayoutConfigurationTypeEnum::getAllNames(std::vector& allNames, const bool isSorted) { if (initializedFlag == false) initialize(); allNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allNames.push_back(TileTabsConfigurationLayoutTypeEnum::toName(iter->enumValue)); + allNames.push_back(TileTabsLayoutConfigurationTypeEnum::toName(iter->enumValue)); } if (isSorted) { @@ -354,16 +365,16 @@ TileTabsConfigurationLayoutTypeEnum::getAllNames(std::vector& allNames, * If true, the names are sorted in alphabetical order. */ void -TileTabsConfigurationLayoutTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) +TileTabsLayoutConfigurationTypeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) { if (initializedFlag == false) initialize(); allGuiNames.clear(); - for (std::vector::iterator iter = enumData.begin(); + for (std::vector::iterator iter = enumData.begin(); iter != enumData.end(); iter++) { - allGuiNames.push_back(TileTabsConfigurationLayoutTypeEnum::toGuiName(iter->enumValue)); + allGuiNames.push_back(TileTabsLayoutConfigurationTypeEnum::toGuiName(iter->enumValue)); } if (isSorted) { diff --git a/src/Common/TileTabsLayoutConfigurationTypeEnum.h b/src/Common/TileTabsLayoutConfigurationTypeEnum.h new file mode 100644 index 000000000..318ea3d51 --- /dev/null +++ b/src/Common/TileTabsLayoutConfigurationTypeEnum.h @@ -0,0 +1,106 @@ +#ifndef __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ +#define __TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include +#include +#include "AString.h" + +namespace caret { + +class TileTabsLayoutConfigurationTypeEnum { + +public: + /** + * Enumerated values. + */ + enum Enum { + /** Automatic grid with rows/columns sufficient to show all tabs */ + AUTOMATIC_GRID, + /** Grid with rows/columns customized by user */ + CUSTOM_GRID, + /** Use sets bounds of layout */ + MANUAL + }; + + + ~TileTabsLayoutConfigurationTypeEnum(); + + static AString toName(Enum enumValue); + + static Enum fromName(const AString& name, bool* isValidOut); + + static AString toGuiName(Enum enumValue); + + static Enum fromGuiName(const AString& guiName, bool* isValidOut); + + static int32_t toIntegerCode(Enum enumValue); + + static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); + + static void getAllEnums(std::vector& allEnums); + + static void getAllNames(std::vector& allNames, const bool isSorted); + + static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); + +private: + TileTabsLayoutConfigurationTypeEnum(const Enum enumValue, + const AString& name, + const AString& guiName); + + static const TileTabsLayoutConfigurationTypeEnum* findData(const Enum enumValue); + + /** Holds all instance of enum values and associated metadata */ + static std::vector enumData; + + /** Initialize instances that contain the enum values and metadata */ + static void initialize(); + + /** Indicates instance of enum values and metadata have been initialized */ + static bool initializedFlag; + + /** Auto generated integer codes */ + static int32_t integerCodeCounter; + + /** The enumerated type value for an instance */ + Enum enumValue; + + /** The integer code associated with an enumerated value */ + int32_t integerCode; + + /** The name, a text string that is identical to the enumerated value */ + AString name; + + /** A user-friendly name that is displayed in the GUI */ + AString guiName; +}; + +#ifdef __TILE_TABS_LAYOUT_CONFIGURATION_TYPE_ENUM_DECLARE__ +std::vector TileTabsLayoutConfigurationTypeEnum::enumData; +bool TileTabsLayoutConfigurationTypeEnum::initializedFlag = false; +int32_t TileTabsLayoutConfigurationTypeEnum::integerCodeCounter = 0; +#endif // __TILE_TABS_LAYOUT_CONFIGURATION_TYPE_ENUM_DECLARE__ + +} // namespace +#endif //__TILE_TABS_CONFIGURATION_LAYOUT_TYPE_ENUM_H__ diff --git a/src/Common/TileTabsGridLayoutConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx similarity index 90% rename from src/Common/TileTabsGridLayoutConfiguration.cxx rename to src/Common/TileTabsLayoutGridConfiguration.cxx index dbe571bf6..e07b58fd5 100644 --- a/src/Common/TileTabsGridLayoutConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -22,9 +22,9 @@ #include #include -#define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ -#include "TileTabsGridLayoutConfiguration.h" -#undef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ +#define __TILE_TABS_LAYOUT_GRID_CONFIGURATION_DECLARE__ +#include "TileTabsLayoutGridConfiguration.h" +#undef __TILE_TABS_LAYOUT_GRID_CONFIGURATION_DECLARE__ #include #include @@ -38,7 +38,7 @@ using namespace caret; /** - * \class caret::TileTabsGridLayoutConfiguration + * \class caret::TileTabsLayoutGridConfiguration * \brief Defines a tile tabs configuration * \ingroup Common */ @@ -46,8 +46,8 @@ using namespace caret; /** * Constructor that creates a 2 by 2 configuration. */ -TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration() -: TileTabsBaseConfiguration(TileTabsConfigurationLayoutTypeEnum::GRID) +TileTabsLayoutGridConfiguration::TileTabsLayoutGridConfiguration() +: TileTabsLayoutBaseConfiguration(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID) { initialize(); } @@ -55,7 +55,7 @@ TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration() /** * Destructor. */ -TileTabsGridLayoutConfiguration::~TileTabsGridLayoutConfiguration() +TileTabsLayoutGridConfiguration::~TileTabsLayoutGridConfiguration() { } @@ -67,11 +67,11 @@ TileTabsGridLayoutConfiguration::~TileTabsGridLayoutConfiguration() * @param obj * Object that is copied. */ -TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) -: TileTabsBaseConfiguration(obj) +TileTabsLayoutGridConfiguration::TileTabsLayoutGridConfiguration(const TileTabsLayoutGridConfiguration& obj) +: TileTabsLayoutBaseConfiguration(obj) { initialize(); - this->copyHelperTileTabsGridLayoutConfiguration(obj); + this->copyHelperTileTabsLayoutGridConfiguration(obj); } /** @@ -84,12 +84,12 @@ TileTabsGridLayoutConfiguration::TileTabsGridLayoutConfiguration(const TileTabsG * @return * Reference to this object. */ -TileTabsGridLayoutConfiguration& -TileTabsGridLayoutConfiguration::operator=(const TileTabsGridLayoutConfiguration& obj) +TileTabsLayoutGridConfiguration& +TileTabsLayoutGridConfiguration::operator=(const TileTabsLayoutGridConfiguration& obj) { if (this != &obj) { - TileTabsBaseConfiguration::operator=(obj); - this->copyHelperTileTabsGridLayoutConfiguration(obj); + TileTabsLayoutBaseConfiguration::operator=(obj); + this->copyHelperTileTabsLayoutGridConfiguration(obj); } return *this; } @@ -100,10 +100,10 @@ TileTabsGridLayoutConfiguration::operator=(const TileTabsGridLayoutConfiguration * * @return The new Copy. */ -TileTabsGridLayoutConfiguration* -TileTabsGridLayoutConfiguration::newCopyWithNewUniqueIdentifier() const +TileTabsLayoutBaseConfiguration* +TileTabsLayoutGridConfiguration::newCopyWithNewUniqueIdentifier() const { - TileTabsGridLayoutConfiguration* newCopy = new TileTabsGridLayoutConfiguration(*this); + TileTabsLayoutGridConfiguration* newCopy = new TileTabsLayoutGridConfiguration(*this); CaretAssert(newCopy); return newCopy; } @@ -113,7 +113,7 @@ TileTabsGridLayoutConfiguration::newCopyWithNewUniqueIdentifier() const * Initialize an instance of a tile tabs configuration. */ void -TileTabsGridLayoutConfiguration::initialize() +TileTabsLayoutGridConfiguration::initialize() { setNumberOfRows(2); setNumberOfColumns(2); @@ -127,13 +127,13 @@ TileTabsGridLayoutConfiguration::initialize() * Object that is copied. */ void -TileTabsGridLayoutConfiguration::copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj) +TileTabsLayoutGridConfiguration::copyHelperTileTabsLayoutGridConfiguration(const TileTabsLayoutGridConfiguration& obj) { if (this == &obj) { return; } - copyHelperTileTabsBaseConfiguration(obj); + copyHelperTileTabsLayoutBaseConfiguration(obj); m_columns = obj.m_columns; m_rows = obj.m_rows; m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; @@ -144,10 +144,10 @@ TileTabsGridLayoutConfiguration::copyHelperTileTabsGridLayoutConfiguration(const * stretch factors. Name is NOT copied. */ void -TileTabsGridLayoutConfiguration::copy(const TileTabsGridLayoutConfiguration& rhs) +TileTabsLayoutGridConfiguration::copy(const TileTabsLayoutGridConfiguration& rhs) { AString savedName = getName(); - copyHelperTileTabsGridLayoutConfiguration(rhs); + copyHelperTileTabsLayoutGridConfiguration(rhs); setName(savedName); } @@ -157,7 +157,7 @@ TileTabsGridLayoutConfiguration::copy(const TileTabsGridLayoutConfiguration& rhs * @param Information for element. */ TileTabsGridRowColumnElement* -TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) +TileTabsLayoutGridConfiguration::getColumn(const int32_t columnIndex) { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; @@ -169,7 +169,7 @@ TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) * @param Information for element. */ const TileTabsGridRowColumnElement* -TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) const +TileTabsLayoutGridConfiguration::getColumn(const int32_t columnIndex) const { CaretAssertVectorIndex(m_columns, columnIndex); return &m_columns[columnIndex]; @@ -181,7 +181,7 @@ TileTabsGridLayoutConfiguration::getColumn(const int32_t columnIndex) const * @param Information for element. */ TileTabsGridRowColumnElement* -TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) +TileTabsLayoutGridConfiguration::getRow(const int32_t rowIndex) { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; @@ -193,7 +193,7 @@ TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) * @param Information for element. */ const TileTabsGridRowColumnElement* -TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) const +TileTabsLayoutGridConfiguration::getRow(const int32_t rowIndex) const { CaretAssertVectorIndex(m_rows, rowIndex); return &m_rows[rowIndex]; @@ -219,7 +219,7 @@ TileTabsGridLayoutConfiguration::getRow(const int32_t rowIndex) const * True if the ouput is valid, else false. */ bool -TileTabsGridLayoutConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, +TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, const TileTabsGridModeEnum::Enum configurationMode, @@ -407,7 +407,7 @@ TileTabsGridLayoutConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const * @return Number of rows. */ int32_t -TileTabsGridLayoutConfiguration::getNumberOfRows() const +TileTabsLayoutGridConfiguration::getNumberOfRows() const { return m_rows.size(); } @@ -419,7 +419,7 @@ TileTabsGridLayoutConfiguration::getNumberOfRows() const * New number of rows. */ void -TileTabsGridLayoutConfiguration::setNumberOfRows(const int32_t numberOfRows) +TileTabsLayoutGridConfiguration::setNumberOfRows(const int32_t numberOfRows) { m_rows.resize(numberOfRows); } @@ -428,7 +428,7 @@ TileTabsGridLayoutConfiguration::setNumberOfRows(const int32_t numberOfRows) * @return Number of columns. */ int32_t -TileTabsGridLayoutConfiguration::getNumberOfColumns() const +TileTabsLayoutGridConfiguration::getNumberOfColumns() const { return m_columns.size(); } @@ -440,7 +440,7 @@ TileTabsGridLayoutConfiguration::getNumberOfColumns() const * New number of rows. */ void -TileTabsGridLayoutConfiguration::setNumberOfColumns(const int32_t numberOfColumns) +TileTabsLayoutGridConfiguration::setNumberOfColumns(const int32_t numberOfColumns) { m_columns.resize(numberOfColumns); } @@ -456,7 +456,7 @@ TileTabsGridLayoutConfiguration::setNumberOfColumns(const int32_t numberOfColumn * Output with number of columns. */ void -TileTabsGridLayoutConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, +TileTabsLayoutGridConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut) { @@ -477,7 +477,7 @@ TileTabsGridLayoutConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t * @return True if the centering correction is enabled. */ bool -TileTabsGridLayoutConfiguration::isCenteringCorrectionEnabled() const +TileTabsLayoutGridConfiguration::isCenteringCorrectionEnabled() const { return m_centeringCorrectionEnabled; } @@ -489,7 +489,7 @@ TileTabsGridLayoutConfiguration::isCenteringCorrectionEnabled() const * New status for enabling the centering correction */ void -TileTabsGridLayoutConfiguration::setCenteringCorrectionEnabled(const bool status) +TileTabsLayoutGridConfiguration::setCenteringCorrectionEnabled(const bool status) { m_centeringCorrectionEnabled = status; } @@ -503,7 +503,7 @@ TileTabsGridLayoutConfiguration::setCenteringCorrectionEnabled(const bool status * columns is always greater than the number of rows. */ void -TileTabsGridLayoutConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) +TileTabsLayoutGridConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) { int32_t numRows(0), numCols(0); getRowsAndColumnsForNumberOfTabs(numberOfTabs, @@ -521,17 +521,17 @@ TileTabsGridLayoutConfiguration::updateAutomaticConfigurationRowsAndColumns(cons * Contains XML representation of configuration. */ void -TileTabsGridLayoutConfiguration::encodeInXML(AString& xmlTextOut) const +TileTabsLayoutGridConfiguration::encodeInXMLString(AString& xmlTextOut) const { xmlTextOut = encodeVersionInXML(2); } /** * @return Encoded tile tabs configuration in XML - * using the give XML version of TileTabsGridLayoutConfiguration. + * using the give XML version of TileTabsLayoutGridConfiguration. */ AString -TileTabsGridLayoutConfiguration::encodeVersionInXML(const int32_t versionNumber) const +TileTabsLayoutGridConfiguration::encodeVersionInXML(const int32_t versionNumber) const { AString s; @@ -555,7 +555,7 @@ TileTabsGridLayoutConfiguration::encodeVersionInXML(const int32_t versionNumber) * @return Encoded tile tabs configuration in XML with Stream Writer */ AString -TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionOne() const +TileTabsLayoutGridConfiguration::encodeInXMLWithStreamWriterVersionOne() const { AString xmlString; QXmlStreamWriter writer(&xmlString); @@ -601,7 +601,7 @@ TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionOne() const * @return Encoded tile tabs configuration in XML with Stream Writer */ AString -TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionTwo() const +TileTabsLayoutGridConfiguration::encodeInXMLWithStreamWriterVersionTwo() const { AString xmlString; QXmlStreamWriter writer(&xmlString); @@ -633,7 +633,7 @@ TileTabsGridLayoutConfiguration::encodeInXMLWithStreamWriterVersionTwo() const * Vector of elements added to XML. */ void -TileTabsGridLayoutConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, +TileTabsLayoutGridConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, const AString tagName, const std::vector& elements) const { @@ -662,8 +662,8 @@ TileTabsGridLayoutConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer * The root element. */ void -TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, - const QString& rootElementText) +TileTabsLayoutGridConfiguration::decodeFromXMLString(QXmlStreamReader& xml, + const AString& rootElementText) { CaretAssert( ! rootElementText.isEmpty()); @@ -689,12 +689,12 @@ TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, decodeFromXMLWithStreamReaderVersionTwo(xml); } else { - xml.raiseError("TileTabsGridLayoutConfiguration invalid version=" + xml.raiseError("TileTabsLayoutGridConfiguration invalid version=" + versionNumberText); } } else { - xml.raiseError("TileTabsGridLayoutConfiguration first element is " + xml.raiseError("TileTabsLayoutGridConfiguration first element is " + xml.name().toString() + " but should be " + s_v1_rootTagName @@ -707,7 +707,7 @@ TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; // AString em; -// TileTabsGridLayoutConfiguration temp; +// TileTabsLayoutGridConfiguration temp; // QXmlStreamReader tempReader(xmlText); // tempReader.readNextStartElement(); // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); @@ -730,7 +730,7 @@ TileTabsGridLayoutConfiguration::decodeFromXML(QXmlStreamReader& xml, * Stream XML parser. */ void -TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) +TileTabsLayoutGridConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) { std::set invalidElements; @@ -860,7 +860,7 @@ TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStr * Stream XML parser. */ void -TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) +TileTabsLayoutGridConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) { m_rows.clear(); m_columns.clear(); @@ -1004,7 +1004,7 @@ TileTabsGridLayoutConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStr * True if read successfully, else false. */ bool -TileTabsGridLayoutConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, +TileTabsLayoutGridConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, TileTabsGridRowColumnElement& element, AString& errorMessageOut) { @@ -1072,9 +1072,14 @@ TileTabsGridLayoutConfiguration::decodeRowColumnElement(QXmlStreamReader& reader * @return String version of an instance. */ AString -TileTabsGridLayoutConfiguration::toString() const +TileTabsLayoutGridConfiguration::toString() const { - AString s = TileTabsBaseConfiguration::toString(); + AString s = TileTabsLayoutBaseConfiguration::toString(); + if ( ! s.isEmpty()) { + s.append("\n"); + } + s.append("TileTabsLayoutGridConfiguration:"); + s.append("\n"); int32_t indx(0); for (const auto item : m_columns) { diff --git a/src/Common/TileTabsGridLayoutConfiguration.h b/src/Common/TileTabsLayoutGridConfiguration.h similarity index 70% rename from src/Common/TileTabsGridLayoutConfiguration.h rename to src/Common/TileTabsLayoutGridConfiguration.h index 35eeb543b..82a931d58 100644 --- a/src/Common/TileTabsGridLayoutConfiguration.h +++ b/src/Common/TileTabsLayoutGridConfiguration.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ -#define __TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ +#ifndef __TILE_TABS_LAYOUT_GRID_CONFIGURATION_H__ +#define __TILE_TABS_LAYOUT_GRID_CONFIGURATION_H__ /*LICENSE_START*/ /* @@ -22,7 +22,7 @@ /*LICENSE_END*/ #include "CaretException.h" -#include "TileTabsBaseConfiguration.h" +#include "TileTabsLayoutBaseConfiguration.h" #include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" @@ -31,20 +31,20 @@ class QXmlStreamWriter; namespace caret { - class TileTabsGridLayoutConfiguration : public TileTabsBaseConfiguration { + class TileTabsLayoutGridConfiguration : public TileTabsLayoutBaseConfiguration { public: - TileTabsGridLayoutConfiguration(); + TileTabsLayoutGridConfiguration(); - virtual ~TileTabsGridLayoutConfiguration(); + virtual ~TileTabsLayoutGridConfiguration(); - TileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); + TileTabsLayoutGridConfiguration(const TileTabsLayoutGridConfiguration& obj); - TileTabsGridLayoutConfiguration& operator=(const TileTabsGridLayoutConfiguration& obj); + TileTabsLayoutGridConfiguration& operator=(const TileTabsLayoutGridConfiguration& obj); - void copy(const TileTabsGridLayoutConfiguration& rhs); + void copy(const TileTabsLayoutGridConfiguration& rhs); - virtual TileTabsGridLayoutConfiguration* newCopyWithNewUniqueIdentifier() const override; + virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const override; bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, @@ -83,14 +83,13 @@ namespace caret { // ADD_NEW_METHODS_HERE protected: - public: - virtual void decodeFromXML(QXmlStreamReader& xml, - const QString& rootElement) override; + virtual void decodeFromXMLString(QXmlStreamReader& xml, + const AString& rootElement) override; - virtual void encodeInXML(AString& xmlTextOut) const override; + virtual void encodeInXMLString(AString& xmlTextOut) const override; private: - void copyHelperTileTabsGridLayoutConfiguration(const TileTabsGridLayoutConfiguration& obj); + void copyHelperTileTabsLayoutGridConfiguration(const TileTabsLayoutGridConfiguration& obj); void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); @@ -145,34 +144,34 @@ namespace caret { static const AString s_v2_centeringCorrectionName; - friend class TileTabsBaseConfiguration; + friend class TileTabsLayoutBaseConfiguration; }; -#ifdef __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ - const AString TileTabsGridLayoutConfiguration::s_nameTagName = "Name"; - const AString TileTabsGridLayoutConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; +#ifdef __TILE_TABS_LAYOUT_GRID_CONFIGURATION_DECLARE__ + const AString TileTabsLayoutGridConfiguration::s_nameTagName = "Name"; + const AString TileTabsLayoutGridConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; - const AString TileTabsGridLayoutConfiguration::s_v1_rootTagName = "TileTabsGridLayoutConfiguration"; - const AString TileTabsGridLayoutConfiguration::s_v1_versionTagName = "Version"; - const AString TileTabsGridLayoutConfiguration::s_v1_versionNumberAttributeName = "Number"; - const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; - const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; - const AString TileTabsGridLayoutConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; - const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; - const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; - const AString TileTabsGridLayoutConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; + const AString TileTabsLayoutGridConfiguration::s_v1_rootTagName = "TileTabsConfiguration"; + const AString TileTabsLayoutGridConfiguration::s_v1_versionTagName = "Version"; + const AString TileTabsLayoutGridConfiguration::s_v1_versionNumberAttributeName = "Number"; + const AString TileTabsLayoutGridConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; + const AString TileTabsLayoutGridConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; + const AString TileTabsLayoutGridConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; + const AString TileTabsLayoutGridConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; + const AString TileTabsLayoutGridConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; + const AString TileTabsLayoutGridConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; - const AString TileTabsGridLayoutConfiguration::s_v2_rootTagName = "TileTabsGridLayoutConfigurationTwo"; - const AString TileTabsGridLayoutConfiguration::s_v2_versionAttributeName = "Version"; - const AString TileTabsGridLayoutConfiguration::s_v2_columnsTagName = "Columns"; - const AString TileTabsGridLayoutConfiguration::s_v2_contentTypeAttributeName = "ContentType"; - const AString TileTabsGridLayoutConfiguration::s_v2_elementTagName = "Element"; - const AString TileTabsGridLayoutConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; - const AString TileTabsGridLayoutConfiguration::s_v2_rowsTagName = "Rows"; - const AString TileTabsGridLayoutConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; - const AString TileTabsGridLayoutConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; - const AString TileTabsGridLayoutConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; -#endif // __TILE_TABS_GRID_LAYOUT_CONFIGURATION_DECLARE__ + const AString TileTabsLayoutGridConfiguration::s_v2_rootTagName = "TileTabsConfigurationTwo"; + const AString TileTabsLayoutGridConfiguration::s_v2_versionAttributeName = "Version"; + const AString TileTabsLayoutGridConfiguration::s_v2_columnsTagName = "Columns"; + const AString TileTabsLayoutGridConfiguration::s_v2_contentTypeAttributeName = "ContentType"; + const AString TileTabsLayoutGridConfiguration::s_v2_elementTagName = "Element"; + const AString TileTabsLayoutGridConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; + const AString TileTabsLayoutGridConfiguration::s_v2_rowsTagName = "Rows"; + const AString TileTabsLayoutGridConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; + const AString TileTabsLayoutGridConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; + const AString TileTabsLayoutGridConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; +#endif // __TILE_TABS_LAYOUT_GRID_CONFIGURATION_DECLARE__ } // namespace -#endif //__TILE_TABS_GRID_LAYOUT_CONFIGURATION_H__ +#endif //__TILE_TABS_LAYOUT_GRID_CONFIGURATION_H__ diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx new file mode 100644 index 000000000..555d6c348 --- /dev/null +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -0,0 +1,462 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#define __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_DECLARE__ +#include "TileTabsLayoutManualConfiguration.h" +#undef __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_DECLARE__ + +#include +#include +#include + +#include "CaretAssert.h" +#include "CaretLogger.h" +#include "SystemUtilities.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutTabInfo.h" + +using namespace caret; + +/** + * \class caret::TileTabsLayoutManualConfiguration + * \brief Contains a manual layout for tabs + * \ingroup Common + */ + +/** + * Constructor. + */ +TileTabsLayoutManualConfiguration::TileTabsLayoutManualConfiguration() +: TileTabsLayoutBaseConfiguration(TileTabsLayoutConfigurationTypeEnum::MANUAL) +{ + +} + +/** + * Destructor. + */ +TileTabsLayoutManualConfiguration::~TileTabsLayoutManualConfiguration() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +TileTabsLayoutManualConfiguration::TileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj) +: TileTabsLayoutBaseConfiguration(obj) +{ + this->copyHelperTileTabsLayoutManualConfiguration(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +TileTabsLayoutManualConfiguration& +TileTabsLayoutManualConfiguration::operator=(const TileTabsLayoutManualConfiguration& obj) +{ + if (this != &obj) { + TileTabsLayoutBaseConfiguration::operator=(obj); + this->copyHelperTileTabsLayoutManualConfiguration(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +TileTabsLayoutManualConfiguration::copyHelperTileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj) +{ + m_tabInfo.clear(); + + for (const auto& ti : obj.m_tabInfo) { + TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(*ti); + addTabInfo(tabInfo); + } +} + +/** + * Copy this instance and give it a new unique identifier. + * Note that copy constructor does not create a new unique identifier. + * + * @return The new Copy. + */ +TileTabsLayoutBaseConfiguration* +TileTabsLayoutManualConfiguration::newCopyWithNewUniqueIdentifier() const +{ + TileTabsLayoutBaseConfiguration* newCopy = new TileTabsLayoutManualConfiguration(*this); + CaretAssert(newCopy); + return newCopy; +} + +/** + * Create a manual layout from the given grid layout using the given tab indices + * + * @param gridLayout + * The grid layout + * @param gridMode + * The grid mode + * @param tabIndices + * Indices of tabs + */ +TileTabsLayoutManualConfiguration* +TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(TileTabsLayoutGridConfiguration* gridLayout, + const TileTabsGridModeEnum::Enum gridMode, + const std::vector& tabIndices) +{ + CaretAssert(gridLayout); + + const int32_t numTabs = static_cast(tabIndices.size()); + if (numTabs <= 0) { + return NULL; + } + + const int32_t windowWidth(10000); + const int32_t windowHeight(10000); + std::vector rowHeights; + std::vector columnWidths; + + if (gridLayout->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numTabs, + gridMode, + rowHeights, + columnWidths)) { + const int32_t numRows = static_cast(rowHeights.size()); + const int32_t numCols = static_cast(columnWidths.size()); + + TileTabsLayoutManualConfiguration* manualLayout = new TileTabsLayoutManualConfiguration(); + manualLayout->setName("From row:" + + AString::number(rowHeights.size()) + + " col:" + + AString::number(columnWidths.size())); + + int32_t tabCounter(0); + float yBottom(windowHeight); + for (int32_t i = 0; i < numRows; i++) { + CaretAssertVectorIndex(rowHeights, i); + const float height = rowHeights[i]; + yBottom -= height; + + float xLeft(0.0); + for (int32_t j = 0; j < numCols; j++) { + CaretAssertVectorIndex(columnWidths, j); + const float width = columnWidths[j]; + + CaretAssertVectorIndex(tabIndices, tabCounter); + const int32_t tabIndex(tabIndices[tabCounter]); + + const float centerX = xLeft + (width / 2.0); + const float centerY = yBottom + (height / 2.0); + TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(tabIndex); + tabInfo->setCenterX((centerX / windowWidth) * 100.0f); + tabInfo->setCenterY((centerY / windowHeight) * 100.0f); + tabInfo->setWidth((width / windowWidth) * 100.0f); + tabInfo->setHeight((height / windowHeight) * 100.0f); + tabInfo->setStackingOrder(tabCounter); + tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); + + manualLayout->addTabInfo(tabInfo); + + xLeft += width; + + tabCounter++; + } + } + + return manualLayout; + } + + return NULL; +} + + +/** + * Add the tab info to this configuration. This configuration will take + * ownership of the tab including destruction of it. + * + * @param tabInfo + * Tab info to add. + */ +void +TileTabsLayoutManualConfiguration::addTabInfo(TileTabsLayoutTabInfo* tabInfo) +{ + std::unique_ptr ptr(tabInfo); + m_tabInfo.push_back(std::move(ptr)); +} + +/** + * @return Number of tab info in this configuration + */ +int32_t +TileTabsLayoutManualConfiguration::getNumberOfTabs() const +{ + return m_tabInfo.size(); +} + +/** + * @return The tab info at the given index + * + * @param index + * Index of the tab info + */ +TileTabsLayoutTabInfo* +TileTabsLayoutManualConfiguration::getTabInfo(const int32_t index) +{ + CaretAssertVectorIndex(m_tabInfo, index); + return m_tabInfo[index].get(); +} + +/** + * @return The tab info at the given index + * + * @param index + * Index of the tab info + */ +const TileTabsLayoutTabInfo* +TileTabsLayoutManualConfiguration::getTabInfo(const int32_t index) const +{ + CaretAssertVectorIndex(m_tabInfo, index); + return m_tabInfo[index].get(); +} + +/** + * @return String version of an instance. + */ +AString +TileTabsLayoutManualConfiguration::toString() const +{ + QString str(TileTabsLayoutBaseConfiguration::toString()); + + QTextStream ts(&str); + ts << "\n" << "TileTabsLayoutManualConfiguration: " << "\n"; + + for (const auto& ti : m_tabInfo) { + ts << ti->toString() << "\n"; + } + + return str; +} + + +/** + * Encode the configuration in XML. + * + * @param xmlTextOut + * Contains XML representation of configuration. + */ +void +TileTabsLayoutManualConfiguration::encodeInXMLString(AString& xmlTextOut) const +{ + xmlTextOut.clear(); + + QXmlStreamWriter writer(&xmlTextOut); + writer.setAutoFormatting(true); + + writer.writeStartElement(s_rootElementName); + writer.writeAttribute(s_rootElementAttributeName, + getName()); + writer.writeAttribute(s_rootElementAttributeVersion, + s_rootElementAttributeValueVersionOne); + writer.writeAttribute(s_rootElementAttributeUniqueID, + getUniqueIdentifier()); + + for (const auto& tabInfo : m_tabInfo) { + writer.writeStartElement(s_tabInfoElementName); + writer.writeAttribute(s_tabInfoAttributeTabIndex, + AString::number(tabInfo->getTabIndex())); + writer.writeAttribute(s_tabInfoAttributeCenterX, + AString::number(tabInfo->getCenterX(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeCenterY, + AString::number(tabInfo->getCenterY(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeWidth, + AString::number(tabInfo->getWidth(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeHeight, + AString::number(tabInfo->getHeight(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeStackingOrder, + AString::number(tabInfo->getStackingOrder())); + writer.writeAttribute(s_tabInfoAttributeBackground, + TileTabsLayoutBackgroundTypeEnum::toName(tabInfo->getBackgroundType())); + writer.writeEndElement(); + } + + writer.writeEndElement(); +} + +/** + * Decode the configuration using the given XML stream reader and root element + * If there is an error, xml.raiseError() should be used to specify the error + * and caller of this method can test for the error using xml.isError(). + * + * @param xml + * The XML stream reader. + * @param rootElement + * The root element. + */ +void +TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, + const AString& rootElementText) +{ + static int32_t invalidNameCounter(1); + + CaretAssert( ! rootElementText.isEmpty()); + + if (rootElementText != s_rootElementName) { + xml.raiseError("TileTabsLayoutManualConfiguration first element is " + + rootElementText + + " but should be " + + s_rootElementName); + return; + } + + AString errorString; + const QXmlStreamAttributes rootAttributes = xml.attributes(); + + const AString version = rootAttributes.value(s_rootElementAttributeVersion).toString(); + if (version != s_rootElementAttributeValueVersionOne) { + errorString.appendWithNewLine("Invalid version \"" + version + "\""); + } + + AString name = rootAttributes.value(s_rootElementAttributeName).toString(); + if (name.isEmpty()) { + name = ("Tabs_" + AString::number(invalidNameCounter)); + invalidNameCounter++; + CaretLogWarning("Tile Tabs Manual Configuration is missing name and has been assigned name \"" + + name + + "\""); + setName(name); + } + + AString uniqueID = rootAttributes.value(s_rootElementAttributeUniqueID).toString(); + if (uniqueID.isEmpty()) { + uniqueID = SystemUtilities::createUniqueID(); + CaretLogWarning("Tile Tabs Manual Configuration is missing uniqueID and has been assigned uniqueID \"" + + uniqueID + + "\""); + + } + setUniqueIdentifierProtected(uniqueID); + + if (! errorString.isEmpty()) { + xml.skipCurrentElement(); + xml.raiseError(errorString); + return; + } + + std::set invalidElementNames; + + while ( ! xml.atEnd()) { + xml.readNext(); + + if (xml.isStartElement()) { + const QString elementName(xml.name().toString()); + + if (elementName == s_tabInfoElementName) { + const QXmlStreamAttributes atts = xml.attributes(); + const int32_t tabIndex = atts.value(s_tabInfoAttributeTabIndex).toInt(); + const float xCenter = atts.value(s_tabInfoAttributeCenterX).toFloat(); + const float yCenter = atts.value(s_tabInfoAttributeCenterY).toFloat(); + const float width = atts.value(s_tabInfoAttributeWidth).toFloat(); + const float height = atts.value(s_tabInfoAttributeHeight).toFloat(); + const int32_t stacking = atts.value(s_tabInfoAttributeStackingOrder).toInt(); + const QString backStr = atts.value(s_tabInfoAttributeBackground).toString(); + const TileTabsLayoutBackgroundTypeEnum::Enum backType = TileTabsLayoutBackgroundTypeEnum::fromName(backStr, NULL); + + TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(tabIndex); + tabInfo->setCenterX(xCenter); + tabInfo->setCenterY(yCenter); + tabInfo->setWidth(width); + tabInfo->setHeight(height); + tabInfo->setStackingOrder(stacking); + tabInfo->setBackgroundType(backType); + + addTabInfo(tabInfo); + } + else { + invalidElementNames.insert(elementName); + } + } + } +// m_centeringCorrectionEnabled = false; +// +// if (rootElementText == s_v1_rootTagName) { +// decodeFromXMLWithStreamReaderVersionOne(xml); +// } +// else if (rootElementText == s_v2_rootTagName) { +// /* +// * Version 2 uses a different root tag than version 1. The reason is that +// * the older code for decoding from XML will throw an exception if it +// * encounters invalid elements or the version number is invalid. The problem +// * is that the exception is not caught and wb_view will terminate. +// */ +// QString versionNumberText("Unknown"); +// const QXmlStreamAttributes atts = xml.attributes(); +// if (atts.hasAttribute(s_v2_versionAttributeName)) { +// versionNumberText = atts.value(s_v2_versionAttributeName).toString(); +// } +// +// if (versionNumberText == "2") { +// decodeFromXMLWithStreamReaderVersionTwo(xml); +// } +// else { +// xml.raiseError("TileTabsLayoutGridConfiguration invalid version=" +// + versionNumberText); +// } +// } +// else { +// xml.raiseError("TileTabsLayoutGridConfiguration first element is " +// + xml.name().toString() +// + " but should be " +// + s_v1_rootTagName +// + " or " +// + s_v2_rootTagName); +// } +// +// // const bool debugFlag(false); +// // if (debugFlag) { +// // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); +// // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; +// // AString em; +// // TileTabsLayoutGridConfiguration temp; +// // QXmlStreamReader tempReader(xmlText); +// // tempReader.readNextStartElement(); +// // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); +// // if (tempReader.hasError()) { +// // std::cout << "Decode error: " << tempReader.errorString() << std::endl; +// // } +// // else { +// // std::cout << "Decoded: " << temp.toString() << std::endl; +// // } +// // +// // std::cout << std::endl; +// // } +// // return true; +} diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h new file mode 100644 index 000000000..18ca37aee --- /dev/null +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -0,0 +1,117 @@ +#ifndef __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_H__ +#define __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "TileTabsLayoutBaseConfiguration.h" +#include "TileTabsGridModeEnum.h" + +namespace caret { + + class TileTabsLayoutGridConfiguration; + class TileTabsLayoutTabInfo; + + class TileTabsLayoutManualConfiguration : public TileTabsLayoutBaseConfiguration { + + public: + static TileTabsLayoutManualConfiguration* newInstanceFromGridLayout(TileTabsLayoutGridConfiguration* gridLayout, + const TileTabsGridModeEnum::Enum gridMode, + const std::vector& tabIndices); + + TileTabsLayoutManualConfiguration(); + + virtual ~TileTabsLayoutManualConfiguration(); + + TileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj); + + TileTabsLayoutManualConfiguration& operator=(const TileTabsLayoutManualConfiguration& obj); + + virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const override; + + virtual AString toString() const override; + + void addTabInfo(TileTabsLayoutTabInfo* tabInfo); + + int32_t getNumberOfTabs() const; + + TileTabsLayoutTabInfo* getTabInfo(const int32_t index); + + const TileTabsLayoutTabInfo* getTabInfo(const int32_t index) const; + + // ADD_NEW_METHODS_HERE + + protected: + virtual void decodeFromXMLString(QXmlStreamReader& xml, + const AString& rootElementText) override; + + virtual void encodeInXMLString(AString& xmlTextOut) const override; + + private: + void copyHelperTileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj); + + std::vector> m_tabInfo; + + // ADD_NEW_MEMBERS_HERE + + + static const AString s_rootElementName; + static const AString s_rootElementAttributeVersion; + static const AString s_rootElementAttributeName; + static const AString s_rootElementAttributeUniqueID; + + static const AString s_rootElementAttributeValueVersionOne; + + static const AString s_tabInfoElementName; + static const AString s_tabInfoAttributeTabIndex; + static const AString s_tabInfoAttributeCenterX; + static const AString s_tabInfoAttributeCenterY; + static const AString s_tabInfoAttributeWidth; + static const AString s_tabInfoAttributeHeight; + static const AString s_tabInfoAttributeStackingOrder; + static const AString s_tabInfoAttributeBackground; + + friend class TileTabsLayoutBaseConfiguration; + }; + +#ifdef __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_DECLARE__ + const AString TileTabsLayoutManualConfiguration::s_rootElementName = "TileTabsManualLayout"; + const AString TileTabsLayoutManualConfiguration::s_rootElementAttributeVersion = "Version"; + const AString TileTabsLayoutManualConfiguration::s_rootElementAttributeName = "Name"; + const AString TileTabsLayoutManualConfiguration::s_rootElementAttributeUniqueID = "UniqueID"; + + const AString TileTabsLayoutManualConfiguration::s_rootElementAttributeValueVersionOne = "1"; + + const AString TileTabsLayoutManualConfiguration::s_tabInfoElementName = "TabInfo"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeTabIndex = "TabIndex"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeCenterX = "CenterX"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeCenterY = "CenterY"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeWidth = "Width"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeHeight = "Height"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeStackingOrder = "StackingOrder"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeBackground = "Background"; +#endif // __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_DECLARE__ + +} // namespace +#endif //__TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_H__ diff --git a/src/Common/TileTabsLayoutTabInfo.cxx b/src/Common/TileTabsLayoutTabInfo.cxx new file mode 100644 index 000000000..52b02449a --- /dev/null +++ b/src/Common/TileTabsLayoutTabInfo.cxx @@ -0,0 +1,364 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TABS_TAB_INFO_DECLARE__ +#include "TileTabsLayoutTabInfo.h" +#undef __TILE_TABS_TAB_INFO_DECLARE__ + +#include + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::TileTabsLayoutTabInfo + * \brief Information about a tab's position in the window using percentage coordinates + * \ingroup Common + * + * + * + */ + +/** + * Constructor. + */ +TileTabsLayoutTabInfo::TileTabsLayoutTabInfo(const int32_t tabIndex) +: CaretObject(), +m_tabIndex(tabIndex) +{ + +} + +/** + * Destructor. + */ +TileTabsLayoutTabInfo::~TileTabsLayoutTabInfo() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +TileTabsLayoutTabInfo::TileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj) +: CaretObject(obj) +{ + this->copyHelperTileTabsLayoutTabInfo(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +TileTabsLayoutTabInfo& +TileTabsLayoutTabInfo::operator=(const TileTabsLayoutTabInfo& obj) +{ + if (this != &obj) { + CaretObject::operator=(obj); + this->copyHelperTileTabsLayoutTabInfo(obj); + } + return *this; +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +TileTabsLayoutTabInfo::copyHelperTileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj) +{ + m_tabIndex = obj.m_tabIndex; + m_xCenter = obj.m_xCenter; + m_yCenter = obj.m_yCenter; + m_width = obj.m_width; + m_height = obj.m_height; + m_stackingOrder = obj.m_stackingOrder; + m_backgroundType = obj.m_backgroundType; +} + +/** + * @return Index of the tab + */ +int32_t +TileTabsLayoutTabInfo::getTabIndex() const +{ + return m_tabIndex; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TileTabsLayoutTabInfo::toString() const +{ + AString str; + QTextStream ts(&str); + + ts << "TileTabsLayoutTabInfo: " + << "m_tabIndex=" << m_tabIndex + << " m_xCenter=" << m_xCenter + << " m_yCenter=" << m_yCenter + << " m_width=" << m_width + << " m_height=" << m_height + << " m_stackingOrder=" << m_stackingOrder + << " m_backgroundType=" << TileTabsLayoutBackgroundTypeEnum::toName(m_backgroundType); + + return str; +} + +/** + * @return center x-coordinate as percentage 0% to 100% + */ +float +TileTabsLayoutTabInfo::getCenterX() const +{ + return m_xCenter; +} + +/** + * Set center x-coordinate as percentage 0% to 100% + * + * @param x + * New value for center x-coordinate as percentage 0% to 100% + */ +void +TileTabsLayoutTabInfo::setCenterX(const float x) +{ + m_xCenter = x; +} + +/** + * @return center y-coordinate as percentage 0% to 100% + */ +float +TileTabsLayoutTabInfo::getCenterY() const +{ + return m_yCenter; +} + +/** + * Set center y-coordinate as percentage 0% to 100% + * + * @param y + * New value for center y-coordinate as percentage 0% to 100% + */ +void +TileTabsLayoutTabInfo::setCenterY(const float y) +{ + m_yCenter = y; +} + +/** + * @return width as percentage 0% to 100% + */ +float +TileTabsLayoutTabInfo::getWidth() const +{ + return m_width; +} + +/** + * Set width as percentage 0% to 100% + * + * @param width + * New value for width as percentage 0% to 100% + */ +void +TileTabsLayoutTabInfo::setWidth(const float width) +{ + m_width = width; +} + +/** + * @return height as percentage 0% to 100% + */ +float +TileTabsLayoutTabInfo::getHeight() const +{ + return m_height; +} + +/** + * Set height as percentage 0% to 100% + * + * @param height + * New value for height as percentage 0% to 100% + */ +void +TileTabsLayoutTabInfo::setHeight(const float height) +{ + m_height = height; +} + +/** + * @return minimum x percentage 0% to 100% at left + */ +float +TileTabsLayoutTabInfo::getMinX() const +{ + return (m_xCenter - (m_width / 2.0)); +} + +/** + * Set minimum x percentage 0% to 100% at left + * + * @param minX + * New value for minimum x percentage 0% to 100% at left + */ +void +TileTabsLayoutTabInfo::setMinX(const float minX) +{ + m_xCenter = minX + (m_width / 2.0); +} + +/** + * @return maximum x percentage 0% to 100% at rigth + */ +float +TileTabsLayoutTabInfo::getMaxX() const +{ + return (m_xCenter + (m_width / 2.0)); +} + +/** + * Set maximum x percentage 0% to 100% at right + * + * @param maxX + * New value for maximum x percentage 0% to 100% at right + */ +void +TileTabsLayoutTabInfo::setMaxX(const float maxX) +{ + m_xCenter = maxX - (m_width / 2.0); +} + +/** + * @return minimum y percentage 0% to 100% at bottom + */ +float +TileTabsLayoutTabInfo::getMinY() const +{ + return (m_yCenter - (m_height / 2.0)); +} + +/** + * Set minimum y percentage 0% to 100% at bottom + * + * @param minY + * New value for minimum y percentage 0% to 100% at bottom + */ +void +TileTabsLayoutTabInfo::setMinY(const float minY) +{ + m_yCenter = minY + (m_height / 2.0); +} + +/** + * @return maximum y percentage 0% to 100% at top + */ +float +TileTabsLayoutTabInfo::getMaxY() const +{ + return (m_xCenter + (m_height / 2.0)); +} + +/** + * Set maximum y percentage 0% to 100% at top + * + * @param maxY + * New value for maximum y percentage 0% to 100% at top + */ +void +TileTabsLayoutTabInfo::setMaxY(const float maxY) +{ + m_xCenter = maxY - (m_height / 2.0); +} + +/** + * Get the window viewport + * + * @param windowWidth + * Width of window in pixels + * @param windowHeight + * Height of window in pixels + * @param viewportOut + * Output containing lower-left X, Y, Width, and Height in window coordinates + */ +void +TileTabsLayoutTabInfo::getWindowViewport(const int32_t windowWidth, + const int32_t windowHeight, + int32_t viewportOut[4]) const +{ + viewportOut[0] = static_cast((getMinX() / 100.0) * windowWidth); + viewportOut[1] = static_cast((getMinY() / 100.0) * windowHeight); + viewportOut[2] = static_cast((getWidth() / 100.0) * windowWidth); + viewportOut[3] = static_cast((getHeight() / 100.0) * windowHeight); +} + +/** + * @return Stacking order (depth in screen) of tab, greater value is 'in front' + */ +int32_t +TileTabsLayoutTabInfo::getStackingOrder() const +{ + return m_stackingOrder; +} + +/** + * Set Stacking order (depth in screen) of tab, greater value is 'in front' + * + * @param stackingOrder + * New value for Stacking order (depth in screen) of tab, greater value is 'in front' + */ +void +TileTabsLayoutTabInfo::setStackingOrder(const int32_t stackingOrder) +{ + m_stackingOrder = stackingOrder; +} + +/** + * @return Type of background (opaque / transparent) for tab + */ +TileTabsLayoutBackgroundTypeEnum::Enum +TileTabsLayoutTabInfo::getBackgroundType() const +{ + return m_backgroundType; +} + +/** + * Set Type of background (opaque / transparent) for tab + * + * @param backgroundType + * New value for Type of background (opaque / transparent) for tab + */ +void +TileTabsLayoutTabInfo::setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType) +{ + m_backgroundType = backgroundType; +} diff --git a/src/Common/TileTabsLayoutTabInfo.h b/src/Common/TileTabsLayoutTabInfo.h new file mode 100644 index 000000000..b124204d0 --- /dev/null +++ b/src/Common/TileTabsLayoutTabInfo.h @@ -0,0 +1,128 @@ +#ifndef __TILE_TABS_LAYOUT_TAB_INFO_H__ +#define __TILE_TABS_LAYOUT_TAB_INFO_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" +#include "TileTabsLayoutBackgroundTypeEnum.h" + + +namespace caret { + + class TileTabsLayoutTabInfo : public CaretObject { + + public: + TileTabsLayoutTabInfo(const int32_t tabIndex); + + virtual ~TileTabsLayoutTabInfo(); + + TileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj); + + TileTabsLayoutTabInfo& operator=(const TileTabsLayoutTabInfo& obj); + + int32_t getTabIndex() const; + + float getCenterX() const; + + void setCenterX(const float x); + + float getCenterY() const; + + void setCenterY(const float y); + + float getWidth() const; + + void setWidth(const float width); + + float getHeight() const; + + void setHeight(const float height); + + float getMinX() const; + + void setMinX(const float minX); + + float getMaxX() const; + + void setMaxX(const float maxX); + + float getMinY() const; + + void setMinY(const float minY); + + float getMaxY() const; + + void setMaxY(const float maxY); + + void getWindowViewport(const int32_t windowWidth, + const int32_t windowHeight, + int32_t viewportOut[4]) const; + + int32_t getStackingOrder() const; + + void setStackingOrder(const int32_t stackingOrder); + + TileTabsLayoutBackgroundTypeEnum::Enum getBackgroundType() const; + + void setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType); + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + void copyHelperTileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj); + + /** index of tab */ + int32_t m_tabIndex; + + /** center x-coordinate as percentage*/ + float m_xCenter = 50.0; + + /** center y-coordinate as percentage*/ + float m_yCenter = 50.0; + + /** width of window as percentage*/ + float m_width = 20.0; + + /** height of window as percentage*/ + float m_height = 20.0; + + /** Stacking order (depth in screen) of tab, greater value is 'in front'*/ + int32_t m_stackingOrder = 1; + + /** Type of background (opaque / transparent) for tab*/ + TileTabsLayoutBackgroundTypeEnum::Enum m_backgroundType = TileTabsLayoutBackgroundTypeEnum::OPAQUE; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_TAB_INFO_DECLARE__ + // +#endif // __TILE_TABS_TAB_INFO_DECLARE__ + +} // namespace +#endif //__TILE_TABS_LAYOUT_TAB_INFO_H__ -- GitLab From 1a735b7000f1d550399516698de8238b25d095b1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 24 Jul 2019 16:11:35 -0500 Subject: [PATCH 003/584] WB-859 Manual Tile Tabs Layout System: Revised existing implementation so that a manual layout system can be added. Also, corrected usage of user tile-tab configurations to prevent problems caused by unexpected synchronization of preferences. --- src/Brain/BrainOpenGLViewportContent.cxx | 114 +- src/Brain/BrainOpenGLViewportContent.h | 19 +- src/Brain/BrowserWindowContent.cxx | 144 +- src/Brain/BrowserWindowContent.h | 19 +- src/Common/CMakeLists.txt | 6 +- src/Common/CaretPreferences.cxx | 236 ++-- src/Common/CaretPreferences.h | 27 +- ...TileTabsGridConfigurationModification.cxx} | 34 +- ...ntTileTabsGridConfigurationModification.h} | 26 +- src/Common/TileTabsConfiguration.cxx | 1182 ----------------- src/Common/TileTabsConfiguration.h | 192 --- .../TileTabsLayoutBaseConfiguration.cxx | 97 +- src/Common/TileTabsLayoutBaseConfiguration.h | 23 +- .../TileTabsLayoutGridConfiguration.cxx | 127 +- src/Common/TileTabsLayoutGridConfiguration.h | 10 +- .../TileTabsLayoutManualConfiguration.cxx | 102 +- .../TileTabsLayoutManualConfiguration.h | 6 + src/Files/AnnotationFile.cxx | 61 +- src/Files/AnnotationFile.h | 4 +- src/GuiQt/BrainBrowserWindow.cxx | 70 +- src/GuiQt/BrainBrowserWindow.h | 8 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 20 +- src/GuiQt/BrainOpenGLWidget.cxx | 56 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 468 ++++--- src/GuiQt/TileTabsConfigurationDialog.h | 35 +- src/GuiQt/TileTabsConfigurationModifier.cxx | 38 +- src/GuiQt/TileTabsConfigurationModifier.h | 12 +- src/Operations/OperationShowScene.cxx | 28 +- 28 files changed, 1066 insertions(+), 2098 deletions(-) rename src/Common/{EventTileTabsConfigurationModification.cxx => EventTileTabsGridConfigurationModification.cxx} (67%) rename src/Common/{EventTileTabsConfigurationModification.h => EventTileTabsGridConfigurationModification.h} (70%) delete mode 100644 src/Common/TileTabsConfiguration.cxx delete mode 100644 src/Common/TileTabsConfiguration.h diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 48f376820..4866836f1 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -40,7 +40,8 @@ #include "ModelSurfaceMontage.h" #include "SpacerTabContent.h" #include "SurfaceMontageConfigurationAbstract.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" using namespace caret; @@ -611,6 +612,69 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetSelectedTileTabsConfiguration(); + CaretAssert(tileTabsConfiguration); + switch (tileTabsConfiguration->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + viewportContentsOut = createViewportContentForGridTileTabs(tabContents, + browserWindowContent, + tileTabsConfiguration->castToGridConfiguration(), + gapsAndMargins, + windowViewport, + windowIndex, + highlightTabIndex); + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + viewportContentsOut = createViewportContentForManualTileTabs(tabContents, + browserWindowContent, + tileTabsConfiguration->castToManualConfiguration(), + gapsAndMargins, + windowViewport, + windowIndex, + highlightTabIndex); + break; + } + + return viewportContentsOut; +} + +/** + * Create Viewport Contents for the given tab contents, window sizes, and tile sizes + * for a grid configuration. + * + * @param tabContents + * Content of each tab. + * @param browserWindowContent + * Content of window. + * @param gridConfiguration + * The grid configuration + * @param gapsAndMargins + * Contains margins around edges of tabs + * @param windowViewport + * The window's viewport. + * @param windowIndex + * Index of the window. + * @param hightlightTabIndex + * Index of tab that is highlighted when selected by user. + * @return + * Vector containing data for drawing each model. + */ +std::vector +BrainOpenGLViewportContent::createViewportContentForGridTileTabs(std::vector& tabContents, + BrowserWindowContent* browserWindowContent, + TileTabsLayoutGridConfiguration* gridConfiguration, + const GapsAndMargins* gapsAndMargins, + const int32_t windowViewport[4], + const int32_t windowIndex, + const int32_t highlightTabIndex) +{ + std::vector viewportContentsOut; + + CaretAssert(browserWindowContent); + CaretAssert(gapsAndMargins); + CaretAssert(gridConfiguration); + int32_t windowX = windowViewport[0]; int32_t windowY = windowViewport[1]; const int32_t windowWidth = windowViewport[2]; @@ -623,8 +687,9 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector rowHeights; std::vector columnWidths; - TileTabsConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); - tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + + const int32_t numberOfTabs = static_cast(tabContents.size()); + gridConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, windowHeight, numberOfTabs, browserWindowContent->getTileTabsConfigurationMode(), @@ -654,7 +719,7 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetRow(iRowFromTop)->getContentType(); + const TileTabsGridRowColumnContentTypeEnum::Enum rowContentType = gridConfiguration->getRow(iRowFromTop)->getContentType(); switch (rowContentType) { case TileTabsGridRowColumnContentTypeEnum::SPACE: spacerTabFlag = true; @@ -663,7 +728,7 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetColumn(jCol)->getContentType(); + const TileTabsGridRowColumnContentTypeEnum::Enum tabContentType = gridConfiguration->getColumn(jCol)->getContentType(); switch (tabContentType) { case TileTabsGridRowColumnContentTypeEnum::SPACE: spacerTabFlag = true; @@ -740,7 +805,7 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorisCenteringCorrectionEnabled()) { + if (gridConfiguration->isCenteringCorrectionEnabled()) { /* * Kludge that fixes old scenes * NEED TO ADJUST FOR X too ? @@ -900,6 +965,43 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vector + BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vector& tabContents, + BrowserWindowContent* browserWindowContent, + TileTabsLayoutManualConfiguration* manualConfiguration, + const GapsAndMargins* gapsAndMargins, + const int32_t windowViewport[4], + const int32_t windowIndex, + const int32_t highlightTabIndex) + { + std::vector viewportContentsOut; + + CaretAssertToDoFatal(); + + return viewportContentsOut; + } + /** * Create viewport from the model using the tab's viewport and the tabs margins. * diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index c8def2508..2d3db3feb 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -32,7 +32,8 @@ namespace caret { class BrowserWindowContent; class GapsAndMargins; class SpacerTabContent; - class TileTabsConfiguration; + class TileTabsLayoutGridConfiguration; + class TileTabsLayoutManualConfiguration; class BrainOpenGLViewportContent : public CaretObject { @@ -153,6 +154,22 @@ namespace caret { void updateTabLockedAspectRatios(const int32_t windowIndex, const int32_t windowViewport[4]); + static std::vector createViewportContentForGridTileTabs(std::vector& tabContents, + BrowserWindowContent* browserWindowContent, + TileTabsLayoutGridConfiguration* gridConfiguration, + const GapsAndMargins* gapsAndMargins, + const int32_t windowViewport[4], + const int32_t windowIndex, + const int32_t highlightTabIndex); + + static std::vector createViewportContentForManualTileTabs(std::vector& tabContents, + BrowserWindowContent* browserWindowContent, + TileTabsLayoutManualConfiguration* manualConfiguration, + const GapsAndMargins* gapsAndMargins, + const int32_t windowViewport[4], + const int32_t windowIndex, + const int32_t highlightTabIndex); + const int m_windowIndex; const bool m_highlightTab; diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index 8c097401f..837e5e072 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -28,7 +28,7 @@ #include "SceneClassAssistant.h" #include "SceneIntegerArray.h" #include "ScenePrimitive.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" using namespace caret; @@ -47,8 +47,8 @@ BrowserWindowContent::BrowserWindowContent(const int32_t windowIndex) : CaretObject(), m_windowIndex(windowIndex) { - m_automaticTileTabsConfiguration.reset(new TileTabsConfiguration()); - m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); + m_automaticGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); + m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); m_validFlag = false; reset(); @@ -109,9 +109,9 @@ BrowserWindowContent::reset() m_sceneGraphicsHeight = 0; m_sceneGraphicsWidth = 0; m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; - m_automaticTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); + m_automaticGridTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); /* sets rows/columns/factors to defaults */ - m_customTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); + m_customGridTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); m_sceneSelectedTabIndex = 0; m_sceneTabIndices.clear(); } @@ -216,17 +216,17 @@ BrowserWindowContent::setTileTabsEnabled(const bool tileTabsEnabled) * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. */ -TileTabsConfiguration* +TileTabsLayoutBaseConfiguration* BrowserWindowContent::getSelectedTileTabsConfiguration() { - TileTabsConfiguration* configMode = NULL; + TileTabsLayoutBaseConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { case TileTabsGridModeEnum::AUTOMATIC: - configMode = m_automaticTileTabsConfiguration.get(); + configMode = m_automaticGridTileTabsConfiguration.get(); break; case TileTabsGridModeEnum::CUSTOM: - configMode = m_customTileTabsConfiguration.get(); + configMode = m_customGridTileTabsConfiguration.get(); break; } CaretAssert(configMode); @@ -239,17 +239,17 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. */ -const TileTabsConfiguration* +const TileTabsLayoutBaseConfiguration* BrowserWindowContent::getSelectedTileTabsConfiguration() const { - TileTabsConfiguration* configMode = NULL; + TileTabsLayoutBaseConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { case TileTabsGridModeEnum::AUTOMATIC: - configMode = m_automaticTileTabsConfiguration.get(); + configMode = m_automaticGridTileTabsConfiguration.get(); break; case TileTabsGridModeEnum::CUSTOM: - configMode = m_customTileTabsConfiguration.get(); + configMode = m_customGridTileTabsConfiguration.get(); break; } CaretAssert(configMode); @@ -258,39 +258,47 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() const } /** - * @return The automatic tile tabs configuration. + * @return The automatic grid tile tabs configuration (const method) */ -TileTabsConfiguration* -BrowserWindowContent::getAutomaticTileTabsConfiguration() +const TileTabsLayoutGridConfiguration* +BrowserWindowContent::getAutomaticGridTileTabsConfiguration() const { - return m_automaticTileTabsConfiguration.get(); + return m_automaticGridTileTabsConfiguration.get(); } /** - * @return The automatic tile tabs configuration (const method) + * @return The custom grid tile tabs configuration */ -const TileTabsConfiguration* -BrowserWindowContent::getAutomaticTileTabsConfiguration() const +TileTabsLayoutGridConfiguration* +BrowserWindowContent::getCustomGridTileTabsConfiguration() { - return m_automaticTileTabsConfiguration.get(); + return m_customGridTileTabsConfiguration.get(); } /** - * @return The custom tile tabs configuration + * @return The custom grid tile tabs configuration (const method) */ -TileTabsConfiguration* -BrowserWindowContent::getCustomTileTabsConfiguration() +const TileTabsLayoutGridConfiguration* +BrowserWindowContent::getCustomGridTileTabsConfiguration() const { - return m_customTileTabsConfiguration.get(); + return m_customGridTileTabsConfiguration.get(); } /** - * @return The custom tile tabs configuration (const method) + * Set the custom grid tile tabs configuration + * + * @param gridConfiguration + * Grid configuration that is copied to the custom grid */ -const TileTabsConfiguration* -BrowserWindowContent::getCustomTileTabsConfiguration() const +void +BrowserWindowContent::setCustomGridTileTabsConfiguration(const TileTabsLayoutGridConfiguration* gridConfiguration) { - return m_customTileTabsConfiguration.get(); + CaretAssert(gridConfiguration); + if (gridConfiguration == NULL) { + return; + } + + m_customGridTileTabsConfiguration->copy(*gridConfiguration); } /** @@ -427,14 +435,14 @@ BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, sceneClass); sceneClass->addString("m_customTileTabsConfigurationLatest", - m_customTileTabsConfiguration->encodeInXML()); + m_customGridTileTabsConfiguration->encodeInXML()); /* * Add a tile tabs version one so older versions of wb_view * may still load the scene correctly */ sceneClass->addString("m_customTileTabsConfiguration", - m_customTileTabsConfiguration->encodeVersionInXML(1)); + m_customGridTileTabsConfiguration->encodeVersionInXML(1)); /* * Write the tile tabs configuration a second time using @@ -443,7 +451,7 @@ BrowserWindowContent::saveToScene(const SceneAttributes* sceneAttributes, * tile tabs correctly. */ sceneClass->addString("m_sceneTileTabsConfiguration", - m_customTileTabsConfiguration->encodeVersionInXML(1)); + m_customGridTileTabsConfiguration->encodeVersionInXML(1)); sceneClass->addChild(new SceneIntegerArray("m_sceneTabIndices", m_sceneTabIndices)); @@ -502,17 +510,36 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, /* Restore an old name for custom configuration */ tileTabsConfig = sceneClass->getStringValue("m_tileTabsConfiguration"); } + if (tileTabsConfig.isEmpty()) { + /* + * "m_sceneTileTabsConfiguration" is from scenes before "m_customTileTabsConfiguration" was added + */ + tileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); + } if ( ! tileTabsConfig.isEmpty()) { AString errorMessage; - const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfig, - errorMessage); - if ( ! valid) { + TileTabsLayoutBaseConfiguration* config = TileTabsLayoutBaseConfiguration::decodeFromXML(tileTabsConfig, + errorMessage); + if (config != NULL) { + switch (config->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + m_customGridTileTabsConfiguration.reset(config->castToGridConfiguration()); + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssert(0); + break; + } + } + else { sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + errorMessage + "\" from BrowserWindowContent: \"" + tileTabsConfig + "\""); - m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); + m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); } /* @@ -522,27 +549,7 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, * versions before before WB-735. */ (void)sceneClass->getStringValue("m_sceneTileTabsConfiguration"); - } - else { - /* - * "m_sceneTileTabsConfiguration" is from scenes before "m_customTileTabsConfiguration" was added - */ - const AString stringTileTabsConfig = sceneClass->getStringValue("m_sceneTileTabsConfiguration"); - if ( ! stringTileTabsConfig.isEmpty()) { - AString errorMessage; - const bool valid = m_customTileTabsConfiguration->decodeFromXML(stringTileTabsConfig, - errorMessage); - if ( ! valid) { - sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" - + errorMessage - + "\" from BrowserWindowContent: \"" - + stringTileTabsConfig - + "\""); - m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); - } - } - } - + } const ScenePrimitive* oldTileTabsAutoPrimitive = sceneClass->getPrimitive("m_tileTabsAutomaticConfigurationEnabled"); if (oldTileTabsAutoPrimitive != NULL) { @@ -620,15 +627,28 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute const AString tileTabsConfigString = browserClass->getStringValue("m_sceneTileTabsConfiguration"); if ( ! tileTabsConfigString.isEmpty()) { AString errorMessage; - const bool valid = m_customTileTabsConfiguration->decodeFromXML(tileTabsConfigString, - errorMessage); - if ( ! valid) { + TileTabsLayoutBaseConfiguration* config = TileTabsLayoutBaseConfiguration::decodeFromXML(tileTabsConfigString, + errorMessage); + if (config != NULL) { + switch (config->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + m_customGridTileTabsConfiguration.reset(config->castToGridConfiguration()); + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssert(0); + break; + } + } + else { sceneAttributes->addToErrorMessage("Failed to decode custom tile tabs configuration with error \"" + errorMessage - + "\" from OLD BrowserWindowContent: \"" + + "\" from BrowserWindowContent: \"" + tileTabsConfigString + "\""); - m_customTileTabsConfiguration.reset(new TileTabsConfiguration()); + m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); } } diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index 06567a3a7..b0e33cbdc 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -32,7 +32,8 @@ namespace caret { class SceneClassAssistant; - class TileTabsConfiguration; + class TileTabsLayoutBaseConfiguration; + class TileTabsLayoutGridConfiguration; class BrowserWindowContent : public CaretObject, public SceneableInterface { @@ -65,17 +66,17 @@ namespace caret { void setTileTabsEnabled(const bool tileTabsEnabled); - TileTabsConfiguration* getSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* getSelectedTileTabsConfiguration(); - const TileTabsConfiguration* getSelectedTileTabsConfiguration() const; + const TileTabsLayoutBaseConfiguration* getSelectedTileTabsConfiguration() const; - TileTabsConfiguration* getAutomaticTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* getAutomaticGridTileTabsConfiguration() const; - const TileTabsConfiguration* getAutomaticTileTabsConfiguration() const; + TileTabsLayoutGridConfiguration* getCustomGridTileTabsConfiguration(); - TileTabsConfiguration* getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* getCustomGridTileTabsConfiguration() const; - const TileTabsConfiguration* getCustomTileTabsConfiguration() const; + void setCustomGridTileTabsConfiguration(const TileTabsLayoutGridConfiguration* gridConfiguration); TileTabsGridModeEnum::Enum getTileTabsConfigurationMode() const; @@ -148,9 +149,9 @@ namespace caret { int32_t m_sceneGraphicsHeight = 0; - std::unique_ptr m_automaticTileTabsConfiguration; + std::unique_ptr m_automaticGridTileTabsConfiguration; - std::unique_ptr m_customTileTabsConfiguration; + std::unique_ptr m_customGridTileTabsConfiguration; int32_t m_sceneSelectedTabIndex = 0; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index c19fbee31..d106fb766 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -110,7 +110,7 @@ EventListenerInterface.h EventManager.h EventPaletteGetByName.h EventProgressUpdate.h -EventTileTabsConfigurationModification.h +EventTileTabsGridConfigurationModification.h EventTypeEnum.h FastStatistics.h FileAdapter.h @@ -152,7 +152,6 @@ StereotaxicSpaceEnum.h StringTableModel.h StructureEnum.h SystemUtilities.h -TileTabsConfiguration.h TileTabsLayoutBackgroundTypeEnum.h TileTabsLayoutBaseConfiguration.h TileTabsLayoutConfigurationTypeEnum.h @@ -243,7 +242,7 @@ EventListenerInterface.cxx EventManager.cxx EventPaletteGetByName.cxx EventProgressUpdate.cxx -EventTileTabsConfigurationModification.cxx +EventTileTabsGridConfigurationModification.cxx EventTypeEnum.cxx FastStatistics.cxx FileAdapter.cxx @@ -280,7 +279,6 @@ StereotaxicSpaceEnum.cxx StringTableModel.cxx StructureEnum.cxx SystemUtilities.cxx -TileTabsConfiguration.cxx TileTabsLayoutBackgroundTypeEnum.cxx TileTabsLayoutBaseConfiguration.cxx TileTabsLayoutConfigurationTypeEnum.cxx diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 8908a7545..de2675659 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -33,7 +33,6 @@ #include "CaretLogger.h" #include "CaretPreferenceDataValue.h" #include "ModelTransform.h" -#include "TileTabsConfiguration.h" #include "TileTabsLayoutGridConfiguration.h" #include "TileTabsLayoutManualConfiguration.h" #include "WuQMacroGroup.h" @@ -448,10 +447,8 @@ CaretPreferences::writeMacros() void CaretPreferences::removeAllTileTabsConfigurations() { - for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); - iter != this->tileTabsConfigurations.end(); - iter++) { - delete *iter; + for (auto ttc : this->tileTabsConfigurations) { + delete ttc; } this->tileTabsConfigurations.clear(); } @@ -460,7 +457,7 @@ CaretPreferences::removeAllTileTabsConfigurations() * Write the tile tabs configurations. */ void -CaretPreferences::writeTileTabsConfigurations() +CaretPreferences::writeTileTabsUserConfigurations() { this->qSettings->beginWriteArray(NAME_TILE_TABS_CONFIGURATIONS); const int32_t numViews = static_cast(this->tileTabsConfigurations.size()); @@ -483,7 +480,7 @@ CaretPreferences::writeTileTabsConfigurations() * by a concurrently running workbench. */ void -CaretPreferences::readTileTabsConfigurations(const bool performSync) +CaretPreferences::readTileTabsUserConfigurations(const bool performSync) { if (performSync) { this->qSettings->sync(); @@ -498,18 +495,17 @@ CaretPreferences::readTileTabsConfigurations(const bool performSync) for (int i = 0; i < numConfigurations; i++) { this->qSettings->setArrayIndex(i); const AString configString = this->qSettings->value(AString::number(i)).toString(); - TileTabsConfiguration* ttc = new TileTabsConfiguration(); AString errorMessage; - if (ttc->decodeFromXML(configString, - errorMessage)) { + TileTabsLayoutBaseConfiguration* ttc = TileTabsLayoutBaseConfiguration::decodeFromXML(configString, + errorMessage); + if (ttc != NULL) { this->tileTabsConfigurations.push_back(ttc); } else { CaretLogWarning(errorMessage); - delete ttc; } - const bool testFlag(true); + const bool testFlag(false); if (testFlag) { AString errorMessage; TileTabsLayoutBaseConfiguration* config = TileTabsLayoutBaseConfiguration::decodeFromXML(configString, @@ -565,71 +561,52 @@ CaretPreferences::readTileTabsConfigurations(const bool performSync) } /** - * @return The Tile tabs configurations sorted by name. + * @return A vector containing pairs of Name and Unique Identifier for each + * Tile Tabs configuration. The items are sorted by name with 'first' being + * the name, and 'second' being the unique identifier. */ -std::vector -CaretPreferences::getTileTabsConfigurationsSortedByName() const +std::vector> +CaretPreferences::getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const { - /* - * Copy the configurations and sort them by name. - */ - std::vector configurations; - configurations.insert(configurations.end(), - this->tileTabsConfigurations.begin(), - this->tileTabsConfigurations.end()); - std::sort(configurations.begin(), - configurations.end(), - TileTabsConfiguration::lessThanComparisonByName); + std::vector> nameIDs; - return configurations; -} - -/** - * Get the tile tabs configuration with the given unique identifier. - * - * @param uniqueIdentifier - * Unique identifier of the requested tile tabs configuration. - * @return - * Pointer to tile tabs configuration with the given unique identifier - * or NULL is it does not exist. - */ -TileTabsConfiguration* -CaretPreferences::getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) -{ - for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); - iter != this->tileTabsConfigurations.end(); - iter++) { - TileTabsConfiguration* ttc = *iter; - if (ttc->getUniqueIdentifier() == uniqueIdentifier) { - return ttc; - } + for (const auto ttc : this->tileTabsConfigurations) { + nameIDs.push_back(std::make_pair(ttc->getName(), + ttc->getUniqueIdentifier())); } - return NULL; + std::sort(nameIDs.begin(), + nameIDs.end(), + [](std::pair& a, std::pair& b) { return a.first < b.first; }); + + return nameIDs; } /** - * Get the tile tabs configuration with the given unique identifier. - * + * @return A copy of the tile tabs configuration with the given unique identifier. A copy is returned + * since preferenes may get updated which causes reloading of the user configurations and if the caller + * had a pointer to a user configuration, that pointer would be invalid (point to destroyed configuration) + * when preferences are updated (synced). Pointer will be NULL if there is no user configuration with + * the given unique identifier. + * * @param uniqueIdentifier * Unique identifier of the requested tile tabs configuration. - * @return - * Pointer to tile tabs configuration with the given unique identifier - * or NULL is it does not exist. */ -const TileTabsConfiguration* -CaretPreferences::getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const +std::unique_ptr +CaretPreferences::getCopyOfTileTabsUserConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const { - for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); + std::unique_ptr pointer; + + for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { - const TileTabsConfiguration* ttc = *iter; + const TileTabsLayoutBaseConfiguration* ttc = *iter; if (ttc->getUniqueIdentifier() == uniqueIdentifier) { - return ttc; + pointer.reset(ttc->newCopyWithNewUniqueIdentifier()); } } - - return NULL; + + return pointer; } /** @@ -641,13 +618,13 @@ CaretPreferences::getTileTabsConfigurationByUniqueIdentifier(const AString& uniq * Pointer to tile tabs configuration with the given name * or NULL is it does not exist. */ -TileTabsConfiguration* -CaretPreferences::getTileTabsConfigurationByName(const AString& name) const +TileTabsLayoutBaseConfiguration* +CaretPreferences::getTileTabsUserConfigurationByName(const AString& name) const { - for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); + for (std::vector::const_iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { - TileTabsConfiguration* ttc = *iter; + TileTabsLayoutBaseConfiguration* ttc = *iter; if (name == ttc->getName()) { return ttc; @@ -658,39 +635,148 @@ CaretPreferences::getTileTabsConfigurationByName(const AString& name) const } /** - * Add a new tile tabs configuration. + * Add a new tile tabs user configuration. * * @param tileTabsConfiguration * New tile tabs configuration that is added. */ void -CaretPreferences::addTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration) +CaretPreferences::addTileTabsUserConfiguration(TileTabsLayoutBaseConfiguration* tileTabsConfiguration) { this->tileTabsConfigurations.push_back(tileTabsConfiguration); - this->writeTileTabsConfigurations(); + this->writeTileTabsUserConfigurations(); +} + +/** + * Replace a tile tabs configuration with another tile tabs configuration + * + * @param replaceUserTileTabsUniqueIdentifier + * Unique identifier of configuration that is to be replaced + * This user configuration will be replaced and this pointer will be INVALID after + * this method is called. + * @param replaceWithConfiguration + * This configuration is copied and replaces the other configuration. + * @param errorMessageOut + * Contains error information if fails to replace configuration + * @return + * True if successful, else false + */ +bool +CaretPreferences::replaceTileTabsUserConfiguration(const AString& replaceUserTileTabsUniqueIdentifier, + const TileTabsLayoutBaseConfiguration* replaceWithConfiguration, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + CaretAssert(replaceWithConfiguration); + + int32_t replaceIndex = -1; + const int32_t numConfigs = static_cast(this->tileTabsConfigurations.size()); + for (int32_t i = 0; i < numConfigs; i++) { + CaretAssertVectorIndex(this->tileTabsConfigurations, i); + if (this->tileTabsConfigurations[i]->getUniqueIdentifier() == replaceUserTileTabsUniqueIdentifier) { + replaceIndex = i; + break; + } + } + + if (replaceIndex < 0) { + errorMessageOut = "Failed to find configuration for replacement."; + return false; + } + + /* + * Delete configuration since it may be a different subclass than other configuration + */ + CaretAssertVectorIndex(this->tileTabsConfigurations, replaceIndex); + const AString uuid = this->tileTabsConfigurations[replaceIndex]->getUniqueIdentifier(); + delete this->tileTabsConfigurations[replaceIndex]; + + TileTabsLayoutBaseConfiguration* newConfig = replaceWithConfiguration->newCopyWithUniqueIdentifier(uuid); + CaretAssert(newConfig); + this->tileTabsConfigurations[replaceIndex] = newConfig; + + this->writeTileTabsUserConfigurations(); + + return true; } /** - * Remove the tile tabs configuration with the given name. + * Rename the tile tabs configuration with the given name. + * + * @param tileTabsUniqueIdentifier + * Unique identifier of configuration that will be renamed. + * @param name + * New name for configuration + * @param errorMessageOut + * Will contain error information if command fails + * @return + * True if configuration was removed, else false. + */ +bool +CaretPreferences::renameTileTabsUserConfiguration(const QString& tileTabsUniqueIdentifier, + const AString& name, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + if (tileTabsUniqueIdentifier.isEmpty()) { + errorMessageOut = "Tile Tabs Unique Identifier is empty."; + return false; + } + + for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); + iter != this->tileTabsConfigurations.end(); + iter++) { + TileTabsLayoutBaseConfiguration* ttc = *iter; + if (ttc->getUniqueIdentifier() == tileTabsUniqueIdentifier) { + ttc->setName(name); + this->writeTileTabsUserConfigurations(); + return true; + } + } + + errorMessageOut = ("Did not find a Tile Tabs Configuration with UniqueID=" + + tileTabsUniqueIdentifier); + return false; +} + +/** + * Remove the tile tabs configuration with the given unique identifier. * * @param tileTabsUniqueIdentifier * Unique identifier of configuration that will be removed. + * @param errorMessageOut + * Will contain error information if command fails + * @return + * True if configuration was removed, else false. */ -void -CaretPreferences::removeTileTabsConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier) +bool +CaretPreferences::removeTileTabsUserConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier, + AString& errorMessageOut) { - for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); + errorMessageOut.clear(); + + if (tileTabsUniqueIdentifier.isEmpty()) { + errorMessageOut = "Tile Tabs Unique Identifier is empty."; + return false; + } + + for (std::vector::iterator iter = this->tileTabsConfigurations.begin(); iter != this->tileTabsConfigurations.end(); iter++) { - TileTabsConfiguration* ttc = *iter; + TileTabsLayoutBaseConfiguration* ttc = *iter; if (ttc->getUniqueIdentifier() == tileTabsUniqueIdentifier) { this->tileTabsConfigurations.erase(iter); delete ttc; - break; + this->writeTileTabsUserConfigurations(); + return true; } } - this->writeTileTabsConfigurations(); + errorMessageOut = ("Did not find a Tile Tabs Configuration with UniqueID=" + + tileTabsUniqueIdentifier); + return false; } @@ -1795,7 +1881,7 @@ CaretPreferences::readPreferences() this->readCustomViews(false); - this->readTileTabsConfigurations(false); + this->readTileTabsUserConfigurations(false); this->readMacros(false); diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index b839d160b..0fa6b8ddb 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -40,7 +40,7 @@ namespace caret { class CaretPreferenceDataValue; class ModelTransform; - class TileTabsConfiguration; + class TileTabsLayoutBaseConfiguration; class WuQMacroGroup; class CaretPreferences : public CaretObject { @@ -136,21 +136,28 @@ namespace caret { void setShowDataToolTipsEnabled(const bool enabled); - void readTileTabsConfigurations(const bool performSync = true); + void readTileTabsUserConfigurations(const bool performSync = true); - std::vector getTileTabsConfigurationsSortedByName() const; + std::vector> getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const; - TileTabsConfiguration* getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier); + std::unique_ptr getCopyOfTileTabsUserConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const; - const TileTabsConfiguration* getTileTabsConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const; + TileTabsLayoutBaseConfiguration* getTileTabsUserConfigurationByName(const AString& name) const; - TileTabsConfiguration* getTileTabsConfigurationByName(const AString& name) const; + void addTileTabsUserConfiguration(TileTabsLayoutBaseConfiguration* tileTabsConfiguration); - void addTileTabsConfiguration(TileTabsConfiguration* tileTabsConfiguration); + bool replaceTileTabsUserConfiguration(const AString& replaceUserTileTabsUniqueIdentifier, + const TileTabsLayoutBaseConfiguration* replaceWithConfiguration, + AString& errorMessageOut); - void removeTileTabsConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier); + bool renameTileTabsUserConfiguration(const QString& tileTabsUniqueIdentifier, + const AString& name, + AString& errorMessageOut); - void writeTileTabsConfigurations(); + bool removeTileTabsUserConfigurationByUniqueIdentifier(const AString& tileTabsUniqueIdentifier, + AString& errorMessageOut); + + void writeTileTabsUserConfigurations(); void readCustomViews(const bool performSync = true); @@ -287,7 +294,7 @@ namespace caret { std::vector customViews; - std::vector tileTabsConfigurations; + std::vector tileTabsConfigurations; bool displayVolumeAxesCrosshairs; diff --git a/src/Common/EventTileTabsConfigurationModification.cxx b/src/Common/EventTileTabsGridConfigurationModification.cxx similarity index 67% rename from src/Common/EventTileTabsConfigurationModification.cxx rename to src/Common/EventTileTabsGridConfigurationModification.cxx index 4f4a12d68..74c3a4ff8 100644 --- a/src/Common/EventTileTabsConfigurationModification.cxx +++ b/src/Common/EventTileTabsGridConfigurationModification.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ -#include "EventTileTabsConfigurationModification.h" -#undef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ +#define __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_DECLARE__ +#include "EventTileTabsGridConfigurationModification.h" +#undef __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_DECLARE__ #include "CaretAssert.h" #include "EventTypeEnum.h" @@ -31,8 +31,8 @@ using namespace caret; /** - * \class caret::EventTileTabsConfigurationModification - * \brief Event for modifying a tile tabs configuration. + * \class caret::EventTileTabsGridConfigurationModification + * \brief Event for modifying a grid tile tabs configuration. * \ingroup Common */ @@ -48,7 +48,7 @@ using namespace caret; * @param operation * Enumerated type with type of modification. */ -EventTileTabsConfigurationModification::EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, +EventTileTabsGridConfigurationModification::EventTileTabsGridConfigurationModification(TileTabsLayoutGridConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const RowColumnType rowColumnType, const Operation operation) @@ -59,21 +59,21 @@ m_rowColumnType(rowColumnType), m_operation(operation), m_windowIndex(-1) { - + CaretAssert(m_tileTabsConfiguration); } /** * Destructor. */ -EventTileTabsConfigurationModification::~EventTileTabsConfigurationModification() +EventTileTabsGridConfigurationModification::~EventTileTabsGridConfigurationModification() { } /** * @return Tile tabs configuration that is modified. */ -TileTabsConfiguration* -EventTileTabsConfigurationModification::getTileTabsConfiguration() +TileTabsLayoutGridConfiguration* +EventTileTabsGridConfigurationModification::getTileTabsConfiguration() { return m_tileTabsConfiguration; } @@ -83,7 +83,7 @@ EventTileTabsConfigurationModification::getTileTabsConfiguration() * @return Index of the window. */ int32_t -EventTileTabsConfigurationModification::getWindowIndex() const +EventTileTabsGridConfigurationModification::getWindowIndex() const { return m_windowIndex; } @@ -95,7 +95,7 @@ EventTileTabsConfigurationModification::getWindowIndex() const * Index of the window. */ void -EventTileTabsConfigurationModification::setWindowIndex(const int32_t windowIndex) +EventTileTabsGridConfigurationModification::setWindowIndex(const int32_t windowIndex) { m_windowIndex = windowIndex; } @@ -104,7 +104,7 @@ EventTileTabsConfigurationModification::setWindowIndex(const int32_t windowIndex * @return The index of the row or column. */ int32_t -EventTileTabsConfigurationModification::getRowColumnIndex() const +EventTileTabsGridConfigurationModification::getRowColumnIndex() const { return m_rowColumnIndex; } @@ -112,8 +112,8 @@ EventTileTabsConfigurationModification::getRowColumnIndex() const /** * @return The type ROW or COLUMN */ -EventTileTabsConfigurationModification::RowColumnType -EventTileTabsConfigurationModification::getRowColumnType() const +EventTileTabsGridConfigurationModification::RowColumnType +EventTileTabsGridConfigurationModification::getRowColumnType() const { return m_rowColumnType; } @@ -121,8 +121,8 @@ EventTileTabsConfigurationModification::getRowColumnType() const /** * @return The operation. */ -EventTileTabsConfigurationModification::Operation -EventTileTabsConfigurationModification::getOperation() const +EventTileTabsGridConfigurationModification::Operation +EventTileTabsGridConfigurationModification::getOperation() const { return m_operation; } diff --git a/src/Common/EventTileTabsConfigurationModification.h b/src/Common/EventTileTabsGridConfigurationModification.h similarity index 70% rename from src/Common/EventTileTabsConfigurationModification.h rename to src/Common/EventTileTabsGridConfigurationModification.h index 202fa67c9..3cf97dbf8 100644 --- a/src/Common/EventTileTabsConfigurationModification.h +++ b/src/Common/EventTileTabsGridConfigurationModification.h @@ -1,5 +1,5 @@ -#ifndef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ -#define __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ +#ifndef __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_H__ +#define __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_H__ /*LICENSE_START*/ /* @@ -31,9 +31,9 @@ namespace caret { - class TileTabsConfiguration; + class TileTabsLayoutGridConfiguration; - class EventTileTabsConfigurationModification : public Event { + class EventTileTabsGridConfigurationModification : public Event { public: /** @@ -57,18 +57,18 @@ namespace caret { MOVE_BEFORE }; - EventTileTabsConfigurationModification(TileTabsConfiguration* tileTabsConfiguration, + EventTileTabsGridConfigurationModification(TileTabsLayoutGridConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const RowColumnType rowColumnType, const Operation operation); - virtual ~EventTileTabsConfigurationModification(); + virtual ~EventTileTabsGridConfigurationModification(); - EventTileTabsConfigurationModification(const EventTileTabsConfigurationModification&) = delete; + EventTileTabsGridConfigurationModification(const EventTileTabsGridConfigurationModification&) = delete; - EventTileTabsConfigurationModification& operator=(const EventTileTabsConfigurationModification&) = delete; + EventTileTabsGridConfigurationModification& operator=(const EventTileTabsGridConfigurationModification&) = delete; - TileTabsConfiguration* getTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* getTileTabsConfiguration(); int32_t getRowColumnIndex() const; @@ -83,7 +83,7 @@ namespace caret { // ADD_NEW_METHODS_HERE private: - TileTabsConfiguration* m_tileTabsConfiguration; + TileTabsLayoutGridConfiguration* m_tileTabsConfiguration; const int32_t m_rowColumnIndex; @@ -97,9 +97,9 @@ namespace caret { }; -#ifdef __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ +#ifdef __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_DECLARE__ // -#endif // __EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_DECLARE__ +#endif // __EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_DECLARE__ } // namespace -#endif //__EVENT_TILE_TABS_CONFIGURATION_MODIFICATION_H__ +#endif //__EVENT_TILE_TABS_GRID_CONFIGURATION_MODIFICATION_H__ diff --git a/src/Common/TileTabsConfiguration.cxx b/src/Common/TileTabsConfiguration.cxx deleted file mode 100644 index 01db9f5cb..000000000 --- a/src/Common/TileTabsConfiguration.cxx +++ /dev/null @@ -1,1182 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include -#include - -#define __TILE_TABS_CONFIGURATION_DECLARE__ -#include "TileTabsConfiguration.h" -#undef __TILE_TABS_CONFIGURATION_DECLARE__ - -#include -#include - -#include "CaretAssert.h" -#include "CaretLogger.h" -#include "SystemUtilities.h" - -using namespace caret; - - - -/** - * \class caret::TileTabsConfiguration - * \brief Defines a tile tabs configuration - * \ingroup Common - */ - -/** - * Constructor that creates a 2 by 2 configuration. - */ -TileTabsConfiguration::TileTabsConfiguration() -: CaretObject() -{ - initialize(); -} - -/** - * Destructor. - */ -TileTabsConfiguration::~TileTabsConfiguration() -{ -} - -/** - * Copy constructor. - * - * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() - * - * @param obj - * Object that is copied. - */ -TileTabsConfiguration::TileTabsConfiguration(const TileTabsConfiguration& obj) -: CaretObject(obj) -{ - const AString savedUniqueID = m_uniqueIdentifier; - initialize(); - m_uniqueIdentifier = savedUniqueID; - this->copyHelperTileTabsConfiguration(obj); -} - -/** - * Assignment operator. - * - * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() - * - * @param obj - * Data copied from obj to this. - * @return - * Reference to this object. - */ -TileTabsConfiguration& -TileTabsConfiguration::operator=(const TileTabsConfiguration& obj) -{ - if (this != &obj) { - CaretObject::operator=(obj); - this->copyHelperTileTabsConfiguration(obj); - } - return *this; -} - -/** - * Copy this instance and give it a new unique identifier. - * Note that copy constructor does not create a new unique identifier. - * - * @return The new Copy. - */ -TileTabsConfiguration* -TileTabsConfiguration::newCopyWithNewUniqueIdentifier() const -{ - TileTabsConfiguration* newCopy = new TileTabsConfiguration(*this); - CaretAssert(newCopy); - newCopy->m_uniqueIdentifier = SystemUtilities::createUniqueID(); - return newCopy; -} - - -/** - * Initialize an instance of a tile tabs configuration. - */ -void -TileTabsConfiguration::initialize() -{ - setNumberOfRows(2); - setNumberOfColumns(2); - - m_name.clear(); - m_uniqueIdentifier = SystemUtilities::createUniqueID(); - m_centeringCorrectionEnabled = false; -} - -/** - * Helps with copying an object of this type. - * @param obj - * Object that is copied. - */ -void -TileTabsConfiguration::copyHelperTileTabsConfiguration(const TileTabsConfiguration& obj) -{ - if (this == &obj) { - return; - } - - m_name = obj.m_name; - m_columns = obj.m_columns; - m_rows = obj.m_rows; - m_centeringCorrectionEnabled = obj.m_centeringCorrectionEnabled; - //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier -} - -/** - * Copies the tile tabs configuration rows, columns, and - * stretch factors. Name is NOT copied. - */ -void -TileTabsConfiguration::copy(const TileTabsConfiguration& rhs) -{ - AString savedName = m_name; - copyHelperTileTabsConfiguration(rhs); - m_name = savedName; -} - -/** - * Get infoformation for the given elemnent in the columns. - * - * @param Information for element. - */ -TileTabsGridRowColumnElement* -TileTabsConfiguration::getColumn(const int32_t columnIndex) -{ - CaretAssertVectorIndex(m_columns, columnIndex); - return &m_columns[columnIndex]; -} - -/** - * Get infoformation for the given elemnent in the columns. - * - * @param Information for element. - */ -const TileTabsGridRowColumnElement* -TileTabsConfiguration::getColumn(const int32_t columnIndex) const -{ - CaretAssertVectorIndex(m_columns, columnIndex); - return &m_columns[columnIndex]; -} - -/** - * Get infoformation for the given elemnent in the rows. - * - * @param Information for element. - */ -TileTabsGridRowColumnElement* -TileTabsConfiguration::getRow(const int32_t rowIndex) -{ - CaretAssertVectorIndex(m_rows, rowIndex); - return &m_rows[rowIndex]; -} - -/** - * Get infoformation for the given elemnent in the rows. - * - * @param Information for element. - */ -const TileTabsGridRowColumnElement* -TileTabsConfiguration::getRow(const int32_t rowIndex) const -{ - CaretAssertVectorIndex(m_rows, rowIndex); - return &m_rows[rowIndex]; -} - -/** - * Get the row heights and column widths for this tile tabs configuration using the - * given window width and height. - * - * @param windowWidth - * Width of window. - * @param windowHeight - * Height of window. - * @param numberOfModelsToDraw - * Number of models to draw. - * @param configurationMode - * The tile tabs configuration mode - * @param rowHeightsOut - * Output containing height of each row. - * @param columnWidthsOut - * Output containing width of each column. - * @return - * True if the ouput is valid, else false. - */ -bool -TileTabsConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, - const int32_t windowHeight, - const int32_t numberOfModelsToDraw, - const TileTabsGridModeEnum::Enum configurationMode, - std::vector& rowHeightsOut, - std::vector& columnWidthsOut) -{ - /* - * NOTE: When computing widths and heights, do not round. - * Rounding may cause the bottom most row or column to extend - * outside the graphics region. Shrinking the last row or - * column is not desired since it might cause the last model - * to be drawn slightly smaller than the others. - */ - - int32_t numRows = 0; - int32_t numCols = 0; - - rowHeightsOut.clear(); - columnWidthsOut.clear(); - - switch (configurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: - { - /* - * Update number of rows/columns in the default configuration - * so that if a scene is saved, the correct number of rows - * and columns are saved to the scene. - */ - updateAutomaticConfigurationRowsAndColumns(numberOfModelsToDraw); - numRows = getNumberOfRows(); - numCols = getNumberOfColumns(); - - for (int32_t i = 0; i < numRows; i++) { - rowHeightsOut.push_back(windowHeight / numRows); - } - for (int32_t i = 0; i < numCols; i++) { - columnWidthsOut.push_back(windowWidth / numCols); - } - } break; - case TileTabsGridModeEnum::CUSTOM: - { - /* - * Rows/columns from user configuration - */ - numRows = getNumberOfRows(); - numCols = getNumberOfColumns(); - - /* - * Determine height of each row - */ - float rowPercentTotal = 0.0; - float rowStretchTotal = 0.0; - for (int32_t i = 0; i < numRows; i++) { - const TileTabsGridRowColumnElement* e = getRow(i); - switch (e->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - rowPercentTotal += (e->getPercentStretch() / 100.0); - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - rowStretchTotal += e->getWeightStretch(); - break; - } - } - - float windowWeightHeight = windowHeight; - if (rowPercentTotal > 0.0) { - if (rowPercentTotal >= 1.0) { - windowWeightHeight = 0.0; - } - else { - windowWeightHeight = (1.0 - rowPercentTotal) * windowHeight; - } - } - for (int32_t i = 0; i < numRows; i++) { - int32_t h = 0; - const TileTabsGridRowColumnElement* e = getRow(i); - switch (e->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - h = (e->getPercentStretch() / 100.0) * windowHeight; - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - if (rowStretchTotal > 0.0) { - h = static_cast((e->getWeightStretch() / rowStretchTotal) - * windowWeightHeight); - } - break; - } - - rowHeightsOut.push_back(h); - } - - /* - * Determine width of each column - */ - float columnPercentTotal = 0.0; - float columnStretchTotal = 0.0; - for (int32_t i = 0; i < numCols; i++) { - const TileTabsGridRowColumnElement* e = getColumn(i); - switch (e->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - columnPercentTotal += (e->getPercentStretch() / 100.0); - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - columnStretchTotal += e->getWeightStretch(); - break; - } - } - - float windowWeightWidth = windowWidth; - if (columnPercentTotal > 0.0) { - if (columnPercentTotal >= 1.0) { - windowWeightWidth = 0.0; - } - else { - windowWeightWidth = (1.0 - columnPercentTotal) * windowWidth; - } - } - - for (int32_t i = 0; i < numCols; i++) { - int32_t w = 0; - const TileTabsGridRowColumnElement* e = getColumn(i); - switch (e->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - w = (e->getPercentStretch() / 100.0) * windowWidth; - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - if (columnStretchTotal > 0.0) { - w = static_cast((e->getWeightStretch() / columnStretchTotal) - * windowWeightWidth); - } - break; - } - columnWidthsOut.push_back(w); - } - } break; - } - - if ((numRows == static_cast(rowHeightsOut.size())) - && (numCols == static_cast(columnWidthsOut.size()))) { -// /* -// * Verify all rows fit within the window -// */ -// int32_t rowHeightsSum = 0; -// for (int32_t i = 0; i < numRows; i++) { -// rowHeightsSum += rowHeightsOut[i]; -// } -// if (rowHeightsSum > windowHeight) { -// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); -//// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); -// } -// -// /* -// * Adjust width of last column so that it does not extend beyond viewport -// */ -// int32_t columnWidthsSum = 0; -// for (int32_t i = 0; i < numCols; i++) { -// columnWidthsSum += columnWidthsOut[i]; -// } -// if (columnWidthsSum > windowWidth) { -// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); -//// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; -// } -// -// CaretLogFiner("Tile Tabs Row Heights: " -// + AString::fromNumbers(rowHeightsOut, ", ")); -// CaretLogFiner("Tile Tabs Column Widths: " -// + AString::fromNumbers(columnWidthsOut, ", ")); - return true; - } - - const QString msg("Row and heights failed rows=" - + AString::number(numRows) - + " rowHeights=" - + AString::number(rowHeightsOut.size()) - + " cols=" - + AString::number(numCols) - + " rowHeights=" - + AString::number(columnWidthsOut.size())); - CaretAssertMessage(0, msg); - CaretLogSevere(msg); - return false; -} - - -/** - * @return the name of the tile tabs configuration. - */ -AString -TileTabsConfiguration::getName() const -{ - return m_name; -} - -/** - * @return Get the unique identifier that uniquely identifies each configuration. - */ -AString -TileTabsConfiguration::getUniqueIdentifier() const -{ - return m_uniqueIdentifier; -} - -/** - * Set the name of the tile tabs configuration. - * - * @param name - * New name for configuration. - */ -void -TileTabsConfiguration::setName(const AString& name) -{ - m_name = name; -} - -/** - * @return Number of rows. - */ -int32_t -TileTabsConfiguration::getNumberOfRows() const -{ - return m_rows.size(); -} - -/** - * Set number of rows. - * - * @param numberOfRows - * New number of rows. - */ -void -TileTabsConfiguration::setNumberOfRows(const int32_t numberOfRows) -{ - m_rows.resize(numberOfRows); -} - -/** - * @return Number of columns. - */ -int32_t -TileTabsConfiguration::getNumberOfColumns() const -{ - return m_columns.size(); -} - -/** - * Set number of rows. - * - * @param numberOfColumns - * New number of rows. - */ -void -TileTabsConfiguration::setNumberOfColumns(const int32_t numberOfColumns) -{ - m_columns.resize(numberOfColumns); -} - -/** - * Get the number of rows and columns for an automatic layout with the - * given number of tabs. - * @param numberOfTabs - * Number of tabs. - * @param numberOfRowsOut - * Output with number of rows. - * @param numberOfColumnsOut - * Output with number of columns. - */ -void -TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, - int32_t& numberOfRowsOut, - int32_t& numberOfColumnsOut) -{ - CaretAssert(numberOfTabs >= 0); - - numberOfRowsOut = (int)std::sqrt((double)numberOfTabs); - numberOfColumnsOut = numberOfRowsOut; - int32_t row2 = numberOfRowsOut * numberOfRowsOut; - if (row2 < numberOfTabs) { - numberOfColumnsOut++; - } - if ((numberOfRowsOut * numberOfColumnsOut) < numberOfTabs) { - numberOfRowsOut++; - } -} - -/** - * @return True if the centering correction is enabled. - */ -bool -TileTabsConfiguration::isCenteringCorrectionEnabled() const -{ - return m_centeringCorrectionEnabled; -} - -/** - * Set the enabled status of the centering correction - * - * @param status - * New status for enabling the centering correction - */ -void -TileTabsConfiguration::setCenteringCorrectionEnabled(const bool status) -{ - m_centeringCorrectionEnabled = status; -} - - -/** - * Updates the number of rows and columns for the automatic configuration - * based upon the number of tabs. - * - * Since screen width typically exceeds height, ensure the number of - * columns is always greater than the number of rows. - */ -void -TileTabsConfiguration::updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs) -{ - int32_t numRows(0), numCols(0); - getRowsAndColumnsForNumberOfTabs(numberOfTabs, - numRows, - numCols); - - setNumberOfRows(numRows); - setNumberOfColumns(numCols); -} - -/** - * @return Encoded tile tabs configuration in XML - */ -AString -TileTabsConfiguration::encodeInXML() const -{ - return encodeVersionInXML(2); -} - -/** - * @return Encoded tile tabs configuration in XML - * using the give XML version of TileTabsConfiguration. - */ -AString -TileTabsConfiguration::encodeVersionInXML(const int32_t versionNumber) const -{ - AString s; - - switch (versionNumber) { - case 1: - s = encodeInXMLWithStreamWriterVersionOne(); - break; - case 2: - s = encodeInXMLWithStreamWriterVersionTwo(); - break; - default: - CaretAssertMessage(0, "Requested invalid version=" + AString::number(versionNumber)); - break; - } - - return s; -} - - -/** - * @return Encoded tile tabs configuration in XML with Stream Writer - */ -AString -TileTabsConfiguration::encodeInXMLWithStreamWriterVersionOne() const -{ - AString xmlString; - QXmlStreamWriter writer(&xmlString); - writer.setAutoFormatting(true); - - writer.writeStartElement(s_v1_rootTagName); - - writer.writeStartElement(s_v1_versionTagName); - writer.writeAttribute(s_v1_versionNumberAttributeName, "1"); - writer.writeEndElement(); - - writer.writeTextElement(s_nameTagName, m_name); - writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); - - const int32_t numberOfRows = getNumberOfRows(); - writer.writeStartElement(s_v1_rowStretchFactorsTagName); - writer.writeAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName, AString::number(numberOfRows)); - writer.writeAttribute(s_v1_rowStretchFactorsTotalCountAttributeName, AString::number(numberOfRows)); - std::vector rowStretchFactors; - for (const auto e : m_rows) { - rowStretchFactors.push_back(e.getWeightStretch()); - } - writer.writeCharacters(AString::fromNumbers(rowStretchFactors, " ")); - writer.writeEndElement(); - - const int32_t numberOfColumns = getNumberOfColumns(); - writer.writeStartElement(s_v1_columnStretchFactorsTagName); - writer.writeAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName, AString::number(numberOfColumns)); - writer.writeAttribute(s_v1_columnStretchFactorsTotalCountAttributeName, AString::number(numberOfColumns)); - std::vector columnStretchFactors; - for (const auto e : m_columns) { - columnStretchFactors.push_back(e.getWeightStretch()); - } - writer.writeCharacters(AString::fromNumbers(columnStretchFactors, " ")); - writer.writeEndElement(); - - writer.writeEndElement(); - - return xmlString; -} - -/** - * @return Encoded tile tabs configuration in XML with Stream Writer - */ -AString -TileTabsConfiguration::encodeInXMLWithStreamWriterVersionTwo() const -{ - AString xmlString; - QXmlStreamWriter writer(&xmlString); - writer.setAutoFormatting(true); - - writer.writeStartElement(s_v2_rootTagName); - writer.writeAttribute(s_v2_versionAttributeName, "2"); - - writer.writeTextElement(s_nameTagName, m_name); - writer.writeTextElement(s_uniqueIdentifierTagName, m_uniqueIdentifier); - writer.writeTextElement(s_v2_centeringCorrectionName, AString::fromBool(m_centeringCorrectionEnabled)); - - encodeRowColumnElement(writer, s_v2_columnsTagName, m_columns); - encodeRowColumnElement(writer, s_v2_rowsTagName, m_rows); - - writer.writeEndElement(); - - return xmlString; -} - -/** - * Encode a vector of elements into xml. - * - * @param writer - * The XML stream writer. - * @param tagName - * Tag name for enclosing the elements. - * @param elements - * Vector of elements added to XML. - */ -void -TileTabsConfiguration::encodeRowColumnElement(QXmlStreamWriter& writer, - const AString tagName, - const std::vector& elements) const -{ - writer.writeStartElement(tagName); - - for (const auto e : elements) { - writer.writeStartElement(s_v2_elementTagName); - writer.writeAttribute(s_v2_contentTypeAttributeName, TileTabsGridRowColumnContentTypeEnum::toName(e.getContentType())); - writer.writeAttribute(s_v2_stretchTypeAttributeName, TileTabsGridRowColumnStretchTypeEnum::toName(e.getStretchType())); - writer.writeAttribute(s_v2_percentStretchAttributeName, AString::number(e.getPercentStretch(), 'f', 2)); - writer.writeAttribute(s_v2_weightStretchAttributeName, AString::number(e.getWeightStretch(), 'f', 2)); - writer.writeEndElement(); - } - - writer.writeEndElement(); -} - -/** - * Decode the tile tabs configuration from XML with stream reader. - * - * @param xmlString - * String containing XML. - * @param errorMessageOut - * Will contain error information. - * @return - * True if decoding is successful, else false. - */ -bool -TileTabsConfiguration::decodeFromXMLWithStreamReader(const AString& xmlString, - AString& errorMessageOut) -{ - m_centeringCorrectionEnabled = false; - - QXmlStreamReader xml(xmlString); - - if (xml.readNextStartElement()) { - const QStringRef tagName(xml.name()); - if (tagName == s_v1_rootTagName) { - decodeFromXMLWithStreamReaderVersionOne(xml); - } - else if (tagName == s_v2_rootTagName) { - /* - * Version 2 uses a different root tag than version 1. The reason is that - * the older code for decoding from XML will throw an exception if it - * encounters invalid elements or the version number is invalid. The problem - * is that the exception is not caught and wb_view will terminate. - */ - QString versionNumberText("Unknown"); - const QXmlStreamAttributes atts = xml.attributes(); - if (atts.hasAttribute(s_v2_versionAttributeName)) { - versionNumberText = atts.value(s_v2_versionAttributeName).toString(); - } - - if (versionNumberText == "2") { - decodeFromXMLWithStreamReaderVersionTwo(xml); - } - else { - xml.raiseError("TileTabsConfiguration invalid version=" - + versionNumberText); - } - } - else { - xml.raiseError("TileTabsConfiguration first element is " - + xml.name().toString() - + " but should be " - + s_v1_rootTagName - + " or " - + s_v2_rootTagName); - } - } - else { - xml.raiseError("TileTabsConfiguration failed to find start elemnent."); - } - - if (xml.hasError()) { - errorMessageOut = ("Tile Tabs Configuration Read Error at line number=" - + AString::number(xml.lineNumber()) - + " column number=" - + AString::number(xml.columnNumber()) - + " description=" - + xml.errorString()); - return false; - } - - const bool debugFlag(false); - if (debugFlag) { - AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); - std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; - AString em; - TileTabsConfiguration temp; - QXmlStreamReader tempReader(xmlText); - tempReader.readNextStartElement(); - temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); - if (tempReader.hasError()) { - std::cout << "Decode error: " << tempReader.errorString() << std::endl; - } - else { - std::cout << "Decoded: " << temp.toString() << std::endl; - } - - std::cout << std::endl; - } - return true; -} - -/** - * Decode Version One of the tile tabs configuration from XML with stream reader. - * - * @param xml - * Stream XML parser. - */ -void -TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml) -{ - std::set invalidElements; - - AString name; - AString uniqueID; - std::vector rowStretchFactors; - std::vector columnStretchFactors; - int32_t numberOfRows(0); - int32_t numberOfColumns(0); - - QString message; - - while ( ! xml.atEnd()) { - xml.readNext(); - - if (xml.isStartElement()) { - const QStringRef tagName(xml.name()); - - if (tagName == s_v1_versionTagName) { - /* ignore */ - } - else if (tagName == s_nameTagName) { - name = xml.readElementText(); - } - else if (tagName == s_uniqueIdentifierTagName) { - uniqueID = xml.readElementText(); - } - else if (tagName == s_v1_rowStretchFactorsTagName) { - QXmlStreamAttributes atts = xml.attributes(); - if (atts.hasAttribute(s_v1_rowStretchFactorsSelectedCountAttributeName)) { - numberOfRows = atts.value(s_v1_rowStretchFactorsSelectedCountAttributeName).toInt(); - } - - AString::toNumbers(xml.readElementText(), rowStretchFactors); - } - else if (tagName == s_v1_columnStretchFactorsTagName) { - QXmlStreamAttributes atts = xml.attributes(); - if (atts.hasAttribute(s_v1_columnStretchFactorsSelectedCountAttributeName)) { - numberOfColumns = atts.value(s_v1_columnStretchFactorsSelectedCountAttributeName).toInt(); - } - AString::toNumbers(xml.readElementText(), columnStretchFactors); - } - else { - invalidElements.insert(tagName.toString()); - xml.skipCurrentElement(); - } - } - } - - static int32_t missingNameCounter = 1; - if (name.isEmpty()) { - name = ("Config_V1_" - + AString::number(missingNameCounter)); - missingNameCounter++; - } - if (uniqueID.isEmpty()) { - uniqueID = SystemUtilities::createUniqueID(); - } - if (rowStretchFactors.empty()) { - message.append(s_v1_rowStretchFactorsTagName - + " not found or invalid. "); - } - if (columnStretchFactors.empty()) { - message.append(s_v1_columnStretchFactorsTagName - + " not found or invalid. "); - } - if (numberOfRows <= 0) { - message.append(s_v1_rowStretchFactorsTagName - + " attribute " - + s_v1_rowStretchFactorsSelectedCountAttributeName - + " is missing or invalid." ); - } - if (numberOfRows <= 0) { - message.append(s_v1_columnStretchFactorsTagName - + " attribute " - + s_v1_columnStretchFactorsSelectedCountAttributeName - + " is missing or invalid." ); - } - - if ( ! invalidElements.empty()) { - /* - * If invalid elements were encountered, don't throw - */ - AString msg("Invalid element(s) ignored: "); - for (const auto s : invalidElements) { - msg.append(s + " "); - } - CaretLogWarning(msg); - } - - if (message.isEmpty()) { - m_name = name; - m_uniqueIdentifier = uniqueID; - - m_rows.clear(); - m_columns.clear(); - - for (int32_t i = 0; i < numberOfRows; i++) { - TileTabsGridRowColumnElement element; - CaretAssertVectorIndex(rowStretchFactors, i); - element.setWeightStretch(rowStretchFactors[i]); - element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); - element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); - m_rows.push_back(element); - } - CaretAssert(numberOfRows == static_cast(m_rows.size())); - - for (int32_t i = 0; i < numberOfColumns; i++) { - TileTabsGridRowColumnElement element; - CaretAssertVectorIndex(columnStretchFactors, i); - element.setWeightStretch(columnStretchFactors[i]); - element.setContentType(TileTabsGridRowColumnContentTypeEnum::TAB); - element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::WEIGHT); - m_columns.push_back(element); - } - CaretAssert(numberOfColumns == static_cast(m_columns.size())); - } - else { - xml.raiseError(message); - } -} - -/** - * Decode Version Two of the tile tabs configuration from XML with stream reader. - * - * @param xml - * Stream XML parser. - */ -void -TileTabsConfiguration::decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml) -{ - m_rows.clear(); - m_columns.clear(); - m_uniqueIdentifier.clear(); - - std::set invalidElements; - - AString name; - AString uniqueID; - - QString message; - - enum class ReadMode { - OTHER, - COLUMNS, - ROWS - }; - ReadMode readMode = ReadMode::OTHER; - - AString centeringCorrectionTextString; - - while ( ! xml.atEnd()) { - xml.readNext(); - - if (xml.isStartElement()) { - const QStringRef tagName(xml.name()); - - if (tagName == s_nameTagName) { - name = xml.readElementText(); - } - else if (tagName == s_uniqueIdentifierTagName) { - uniqueID = xml.readElementText(); - } - else if (tagName == s_v2_columnsTagName) { - readMode = ReadMode::COLUMNS; - } - else if (tagName == s_v2_rowsTagName) { - readMode = ReadMode::ROWS; - } - else if (tagName == s_v2_centeringCorrectionName) { - centeringCorrectionTextString = xml.readElementText(); - } - else if (tagName == s_v2_elementTagName) { - switch (readMode) { - case ReadMode::OTHER: - CaretAssert(0); - break; - case ReadMode::COLUMNS: - { - AString errorMessage; - TileTabsGridRowColumnElement e; - if (decodeRowColumnElement(xml, e, errorMessage)) { - m_columns.push_back(e); - } - else { - message.append(errorMessage); - } - } - break; - case ReadMode::ROWS: - { - AString errorMessage; - TileTabsGridRowColumnElement e; - if (decodeRowColumnElement(xml, e, errorMessage)) { - m_rows.push_back(e); - } - else { - message.append(errorMessage); - } - } - break; - } - } - else { - invalidElements.insert(tagName.toString()); - xml.skipCurrentElement(); - } - } - else if (xml.isEndElement()) { - const QStringRef tagName(xml.name()); - - if (tagName == s_v2_columnsTagName) { - readMode = ReadMode::OTHER; - } - else if (tagName == s_v2_rowsTagName) { - readMode = ReadMode::OTHER; - } - } - } - - static int32_t missingNameCounter = 1; - if (name.isEmpty()) { - name = ("Config_" - + AString::number(missingNameCounter)); - missingNameCounter++; - } - if (uniqueID.isEmpty()) { - uniqueID = SystemUtilities::createUniqueID(); - } - - if ( ! invalidElements.empty()) { - /* - * If invalid elements were encountered, don't throw - */ - AString msg("Invalid element(s) ignored: "); - for (const auto s : invalidElements) { - msg.append(s + " "); - } - CaretLogWarning(msg); - } - - if (message.isEmpty()) { - m_name = name; - m_uniqueIdentifier = uniqueID; - - /* - * Only set centering correction if it is found. This allows usage - * of the default value in the event this is not found in the XML. - */ - if ( ! centeringCorrectionTextString.isEmpty()) { - m_centeringCorrectionEnabled = centeringCorrectionTextString.toBool(); - } - - } - else { - xml.raiseError(message); - } -} - -/** - * Decode elements in a row or column. - * - * @param reader - * The XML stream reader. - * @param element - * row/column element that is read - * @param errorMessageOut - * Contains error information. - * @return - * True if read successfully, else false. - */ -bool -TileTabsConfiguration::decodeRowColumnElement(QXmlStreamReader& reader, - TileTabsGridRowColumnElement& element, - AString& errorMessageOut) -{ - const QXmlStreamAttributes atts = reader.attributes(); - - errorMessageOut.clear(); - - if (atts.hasAttribute(s_v2_contentTypeAttributeName)) { - bool validFlag(false); - const AString s = atts.value(s_v2_contentTypeAttributeName).toString(); - element.setContentType(TileTabsGridRowColumnContentTypeEnum::fromName(s, &validFlag)); - if ( ! validFlag) { - errorMessageOut.append("Content type \"" + s + "\" is not valid. "); - } - } - else { - errorMessageOut.append("Content type is missing. "); - } - - if (atts.hasAttribute(s_v2_stretchTypeAttributeName)) { - bool validFlag(false); - const AString s = atts.value(s_v2_stretchTypeAttributeName).toString(); - element.setStretchType(TileTabsGridRowColumnStretchTypeEnum::fromName(s, &validFlag)); - if ( ! validFlag) { - errorMessageOut.append("Stretch type \"" + s + "\" is not valid. "); - } - } - else { - errorMessageOut.append("Stretch type is missing. "); - } - - if (atts.hasAttribute(s_v2_percentStretchAttributeName)) { - const float f = atts.value(s_v2_percentStretchAttributeName).toFloat(); - if ((f >= 0.0) && (f < 100.0)) { - element.setPercentStretch(f); - } - else { - errorMessageOut.append("Stretch percentage=" + AString::number(f) + " is invalid."); - } - } - else { - errorMessageOut.append("Stretch percentage is missing. "); - } - - if (atts.hasAttribute(s_v2_weightStretchAttributeName)) { - const float f = atts.value(s_v2_weightStretchAttributeName).toFloat(); - if ((f >= 0.0) && (f < 100.0)) { - element.setWeightStretch(f); - } - else { - errorMessageOut.append("Stretch weight=" + AString::number(f) + " is invalid."); - } - } - else { - errorMessageOut.append("Stretch weight is missing. "); - } - - if (errorMessageOut.isEmpty()) { - return true; - } - return false; -} - -/** - * Decode the tile tabs configuration from XML using DOM - * - * @param xmlString - * String containing XML. - * @param errorMessageOut - * Contains error information if decoding fails. - * @return - * True if configuration was successfully read from the XML, else false. - */ -bool -TileTabsConfiguration::decodeFromXML(const AString& xmlString, - AString& errorMessageOut) -{ - errorMessageOut.clear(); - - return decodeFromXMLWithStreamReader(xmlString, - errorMessageOut); -} - -/** - * @return String version of an instance. - */ -AString -TileTabsConfiguration::toString() const -{ - AString s("Name: %1, Unique ID: %2\n"); - s = s.arg(m_name).arg(m_uniqueIdentifier); - - int32_t indx(0); - for (const auto item : m_columns) { - s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); - indx++; - } - indx = 0; - for (const auto item : m_rows) { - s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); - indx++; - } - - return s; -} - -/** - * Compare two tile tabs configurations by name. - * - * @param ttc1 - * First tile tab configuration. - * @param ttc2 - * Second tile tab configuration. - * @return - * True if ttc1 is "less than" when compared by name, else false. - */ -bool -TileTabsConfiguration::lessThanComparisonByName(const TileTabsConfiguration* ttc1, - const TileTabsConfiguration* ttc2) -{ - if (ttc1->getName() < ttc2->getName()) { - return true; - } - return false; -} - diff --git a/src/Common/TileTabsConfiguration.h b/src/Common/TileTabsConfiguration.h deleted file mode 100644 index 87661333f..000000000 --- a/src/Common/TileTabsConfiguration.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef __TILE_TABS_CONFIGURATION_H__ -#define __TILE_TABS_CONFIGURATION_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2014 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include "CaretException.h" -#include "CaretObject.h" -#include "TileTabsGridModeEnum.h" -#include "TileTabsGridRowColumnElement.h" - -class QXmlStreamReader; -class QXmlStreamWriter; - -namespace caret { - - class TileTabsConfiguration : public CaretObject { - - public: - TileTabsConfiguration(); - - virtual ~TileTabsConfiguration(); - - TileTabsConfiguration(const TileTabsConfiguration& obj); - - TileTabsConfiguration& operator=(const TileTabsConfiguration& obj); - - void copy(const TileTabsConfiguration& rhs); - - TileTabsConfiguration* newCopyWithNewUniqueIdentifier() const; - - bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, - const int32_t windowHeight, - const int32_t numberOfModelsToDraw, - const TileTabsGridModeEnum::Enum configurationMode, - std::vector& rowHeightsOut, - std::vector& columnWidthsOut); - - AString getName() const; - - void setName(const AString& name); - - AString getUniqueIdentifier() const; - - int32_t getNumberOfRows() const; - - void setNumberOfRows(const int32_t numberOfRows); - - int32_t getNumberOfColumns() const; - - void setNumberOfColumns(const int32_t numberOfColumns); - - TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex); - - const TileTabsGridRowColumnElement* getColumn(const int32_t columnIndex) const; - - TileTabsGridRowColumnElement* getRow(const int32_t rowIndex); - - const TileTabsGridRowColumnElement* getRow(const int32_t rowIndex) const; - - AString encodeInXML() const; - - AString encodeVersionInXML(const int32_t versionNumber) const; - - bool decodeFromXML(const AString& xmlString, - AString& errorMessageOut); - - void updateAutomaticConfigurationRowsAndColumns(const int32_t numberOfTabs); - - bool isCenteringCorrectionEnabled() const; - - void setCenteringCorrectionEnabled(const bool status); - - AString toString() const override; - - static bool lessThanComparisonByName(const TileTabsConfiguration* ttc1, - const TileTabsConfiguration* ttc2); - - static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, - int32_t& numberOfRowsOut, - int32_t& numberOfColumnsOut); - // ADD_NEW_METHODS_HERE - - - private: - void copyHelperTileTabsConfiguration(const TileTabsConfiguration& obj); - - bool decodeFromXMLWithStreamReader(const AString& xmlString, - AString& errorMessageOut); - - void decodeFromXMLWithStreamReaderVersionOne(QXmlStreamReader& xml); - - void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); - - AString encodeInXMLWithStreamWriterVersionOne() const; - - AString encodeInXMLWithStreamWriterVersionTwo() const; - - void encodeRowColumnElement(QXmlStreamWriter& writer, - const AString tagName, - const std::vector& elements) const; - - bool decodeRowColumnElement(QXmlStreamReader& reader, - TileTabsGridRowColumnElement& element, - AString& errorMessageOut); - - void initialize(); - - // ADD_NEW_MEMBERS_HERE - - AString m_name; - - /** Unique identifier does not get copied */ - AString m_uniqueIdentifier; - - std::vector m_columns; - - std::vector m_rows; - - bool m_centeringCorrectionEnabled = false; - - static const AString s_nameTagName; - static const AString s_uniqueIdentifierTagName; - - static const AString s_v1_rootTagName; - static const AString s_v1_versionTagName; - static const AString s_v1_versionNumberAttributeName; - static const AString s_v1_columnStretchFactorsTagName; - static const AString s_v1_columnStretchFactorsSelectedCountAttributeName; - static const AString s_v1_columnStretchFactorsTotalCountAttributeName; - static const AString s_v1_rowStretchFactorsTagName; - static const AString s_v1_rowStretchFactorsSelectedCountAttributeName; - static const AString s_v1_rowStretchFactorsTotalCountAttributeName; - - static const AString s_v2_rootTagName; - static const AString s_v2_versionAttributeName; - static const AString s_v2_columnsTagName; - static const AString s_v2_contentTypeAttributeName; - static const AString s_v2_elementTagName; - static const AString s_v2_percentStretchAttributeName; - static const AString s_v2_rowsTagName; - static const AString s_v2_stretchTypeAttributeName; - static const AString s_v2_weightStretchAttributeName; - static const AString s_v2_centeringCorrectionName; - - }; - -#ifdef __TILE_TABS_CONFIGURATION_DECLARE__ - const AString TileTabsConfiguration::s_nameTagName = "Name"; - const AString TileTabsConfiguration::s_uniqueIdentifierTagName = "UniqueIdentifier"; - - const AString TileTabsConfiguration::s_v1_rootTagName = "TileTabsConfiguration"; - const AString TileTabsConfiguration::s_v1_versionTagName = "Version"; - const AString TileTabsConfiguration::s_v1_versionNumberAttributeName = "Number"; - const AString TileTabsConfiguration::s_v1_columnStretchFactorsTagName = "ColumnStretchFactors"; - const AString TileTabsConfiguration::s_v1_columnStretchFactorsSelectedCountAttributeName = "SelectedRowCount"; - const AString TileTabsConfiguration::s_v1_columnStretchFactorsTotalCountAttributeName = "TotalRowCount"; - const AString TileTabsConfiguration::s_v1_rowStretchFactorsTagName = "RowStretchFactors"; - const AString TileTabsConfiguration::s_v1_rowStretchFactorsSelectedCountAttributeName = "SelectedColumnCount"; - const AString TileTabsConfiguration::s_v1_rowStretchFactorsTotalCountAttributeName = "TotalColumnCount"; - - const AString TileTabsConfiguration::s_v2_rootTagName = "TileTabsConfigurationTwo"; - const AString TileTabsConfiguration::s_v2_versionAttributeName = "Version"; - const AString TileTabsConfiguration::s_v2_columnsTagName = "Columns"; - const AString TileTabsConfiguration::s_v2_contentTypeAttributeName = "ContentType"; - const AString TileTabsConfiguration::s_v2_elementTagName = "Element"; - const AString TileTabsConfiguration::s_v2_percentStretchAttributeName = "PercentStretch"; - const AString TileTabsConfiguration::s_v2_rowsTagName = "Rows"; - const AString TileTabsConfiguration::s_v2_stretchTypeAttributeName = "StretchType"; - const AString TileTabsConfiguration::s_v2_weightStretchAttributeName = "WeightStretch"; - const AString TileTabsConfiguration::s_v2_centeringCorrectionName = "CenteringCorrection"; -#endif // __TILE_TABS_CONFIGURATION_DECLARE__ - -} // namespace -#endif //__TILE_TABS_CONFIGURATION_H__ diff --git a/src/Common/TileTabsLayoutBaseConfiguration.cxx b/src/Common/TileTabsLayoutBaseConfiguration.cxx index 0514f1532..d00d5f771 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.cxx +++ b/src/Common/TileTabsLayoutBaseConfiguration.cxx @@ -128,16 +128,22 @@ TileTabsLayoutBaseConfiguration::copyHelperTileTabsLayoutBaseConfiguration(const } /** - * Copies the tile tabs configuration rows, columns, and - * stretch factors. Name is NOT copied. + * Create a copy of this configuration and set its unique identifier to + * the given unique identifier. + * + * @param uniqueIdentifier + * The unique identifier (if empty a valid ID will be in the new configuration) + * @return + * Pointer to the new configuration. */ -void -TileTabsLayoutBaseConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs) +TileTabsLayoutBaseConfiguration* +TileTabsLayoutBaseConfiguration::newCopyWithUniqueIdentifier(const AString& uniqueIdentifier) const { - CaretAssertToDoFatal(); // need to do this a different way - AString savedName = m_name; - copyHelperTileTabsLayoutBaseConfiguration(rhs); - m_name = savedName; + TileTabsLayoutBaseConfiguration* config = newCopyWithNewUniqueIdentifier(); + if ( ! uniqueIdentifier.isEmpty()) { + config->setUniqueIdentifierProtected(uniqueIdentifier); + } + return config; } /** @@ -269,24 +275,6 @@ TileTabsLayoutBaseConfiguration::decodeFromXML(const AString& xmlString, return configurationOut; } - const bool debugFlag(false); - if (debugFlag) { -// AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); -// std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; -// AString em; -// TileTabsLayoutBaseConfiguration temp; -// QXmlStreamReader tempReader(xmlText); -// tempReader.readNextStartElement(); -// temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); -// if (tempReader.hasError()) { -// std::cout << "Decode error: " << tempReader.errorString() << std::endl; -// } -// else { -// std::cout << "Decoded: " << temp.toString() << std::endl; -// } -// -// std::cout << std::endl; - } return configurationOut; } @@ -303,23 +291,54 @@ TileTabsLayoutBaseConfiguration::toString() const << " m_name=" << m_name << " m_uniqueIdentifier=" << m_uniqueIdentifier << " m_layoutType=" << TileTabsLayoutConfigurationTypeEnum::toName(m_layoutType); -// AString s("Name: %1, Unique ID: %2\n"); -// s = s.arg(m_name).arg(m_uniqueIdentifier); -// -// int32_t indx(0); -// for (const auto item : m_columns) { -// s.append(" Column " + AString::number(indx) + ": " + item.toString() + "\n"); -// indx++; -// } -// indx = 0; -// for (const auto item : m_rows) { -// s.append(" Row " + AString::number(indx) + ": " + item.toString() + "\n"); -// indx++; -// } return str; } +/** + * Cast to a grid configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to grid configuration or NULL if not a grid configuration. + */ +TileTabsLayoutGridConfiguration* +TileTabsLayoutBaseConfiguration::castToGridConfiguration() +{ + return NULL; +} + +/** + * Cast to a grid configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to grid configuration or NULL if not a grid configuration. + */ +const TileTabsLayoutGridConfiguration* +TileTabsLayoutBaseConfiguration::castToGridConfiguration() const +{ + return NULL; +} + +/** + * Cast to a manual configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to manual configuration or NULL if not a manual configuration. + */ +TileTabsLayoutManualConfiguration* +TileTabsLayoutBaseConfiguration::castToManualConfiguration() +{ + return NULL; +} + +/** + * Cast to a manual configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to manual configuration or NULL if not a manual configuration. + */ +const TileTabsLayoutManualConfiguration* +TileTabsLayoutBaseConfiguration::castToManualConfiguration() const +{ + return NULL; +} + /** * Compare two tile tabs configurations by name. * diff --git a/src/Common/TileTabsLayoutBaseConfiguration.h b/src/Common/TileTabsLayoutBaseConfiguration.h index c01e3a44a..2769d1084 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.h +++ b/src/Common/TileTabsLayoutBaseConfiguration.h @@ -31,6 +31,9 @@ class QXmlStreamReader; class QXmlStreamWriter; namespace caret { + + class TileTabsLayoutGridConfiguration; + class TileTabsLayoutManualConfiguration; class TileTabsLayoutBaseConfiguration : public CaretObject { @@ -44,10 +47,20 @@ namespace caret { TileTabsLayoutBaseConfiguration& operator=(const TileTabsLayoutBaseConfiguration& obj); - void copy(const TileTabsLayoutBaseConfiguration& rhs); + /** + * Copy the given configuration to "this" configuration. If given configuration + * does not cast to "this class type" log a warning and do not copy. + * Name property is not copied. + * + * @param rhs + * Configuration to copy. + */ + virtual void copy(const TileTabsLayoutBaseConfiguration& rhs) = 0; virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const = 0; + TileTabsLayoutBaseConfiguration* newCopyWithUniqueIdentifier(const AString& uniqueIdentifier) const; + TileTabsLayoutConfigurationTypeEnum::Enum getLayoutType() const; AString getName() const; @@ -64,6 +77,14 @@ namespace caret { AString toString() const override; + virtual TileTabsLayoutGridConfiguration* castToGridConfiguration(); + + virtual const TileTabsLayoutGridConfiguration* castToGridConfiguration() const; + + virtual TileTabsLayoutManualConfiguration* castToManualConfiguration(); + + virtual const TileTabsLayoutManualConfiguration* castToManualConfiguration() const; + static bool lessThanComparisonByName(const TileTabsLayoutBaseConfiguration* ttc1, const TileTabsLayoutBaseConfiguration* ttc2); diff --git a/src/Common/TileTabsLayoutGridConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx index e07b58fd5..71194afaf 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -140,15 +140,28 @@ TileTabsLayoutGridConfiguration::copyHelperTileTabsLayoutGridConfiguration(const } /** - * Copies the tile tabs configuration rows, columns, and - * stretch factors. Name is NOT copied. + * Copy the given configuration to "this" configuration. If given configuration + * does not cast to "this class type" log a warning and do not copy. + * Name property is not copied. + * + * @param rhs + * Configuration to copy. */ void -TileTabsLayoutGridConfiguration::copy(const TileTabsLayoutGridConfiguration& rhs) +TileTabsLayoutGridConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs) { - AString savedName = getName(); - copyHelperTileTabsLayoutGridConfiguration(rhs); - setName(savedName); + const TileTabsLayoutGridConfiguration* gridConfig = rhs.castToGridConfiguration(); + if (gridConfig != NULL) { + AString savedName = getName(); + copyHelperTileTabsLayoutGridConfiguration(*gridConfig); + setName(savedName); + } + else { + CaretLogSevere("Attempt to copy layout configuration " + + rhs.toString() + + " to " + + toString()); + } } /** @@ -359,34 +372,35 @@ TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const if ((numRows == static_cast(rowHeightsOut.size())) && (numCols == static_cast(columnWidthsOut.size()))) { -// /* -// * Verify all rows fit within the window -// */ -// int32_t rowHeightsSum = 0; -// for (int32_t i = 0; i < numRows; i++) { -// rowHeightsSum += rowHeightsOut[i]; -// } -// if (rowHeightsSum > windowHeight) { -// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); -//// rowHeightsOut[numRows - 1] -= (rowHeightsSum - windowHeight); -// } -// -// /* -// * Adjust width of last column so that it does not extend beyond viewport -// */ -// int32_t columnWidthsSum = 0; -// for (int32_t i = 0; i < numCols; i++) { -// columnWidthsSum += columnWidthsOut[i]; -// } -// if (columnWidthsSum > windowWidth) { -// CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); -//// columnWidthsOut[numCols - 1] = columnWidthsSum - windowWidth; -// } -// -// CaretLogFiner("Tile Tabs Row Heights: " -// + AString::fromNumbers(rowHeightsOut, ", ")); -// CaretLogFiner("Tile Tabs Column Widths: " -// + AString::fromNumbers(columnWidthsOut, ", ")); + const bool debugFlag(false); + if (debugFlag) { + /* + * Verify all rows fit within the window + */ + int32_t rowHeightsSum = 0; + for (int32_t i = 0; i < numRows; i++) { + rowHeightsSum += rowHeightsOut[i]; + } + if (rowHeightsSum > windowHeight) { + CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); + } + + /* + * Adjust width of last column so that it does not extend beyond viewport + */ + int32_t columnWidthsSum = 0; + for (int32_t i = 0; i < numCols; i++) { + columnWidthsSum += columnWidthsOut[i]; + } + if (columnWidthsSum > windowWidth) { + CaretLogSevere("PROGRAM ERROR: Tile Tabs total row heights exceed window height"); + } + + CaretLogFiner("Tile Tabs Row Heights: " + + AString::fromNumbers(rowHeightsOut, ", ")); + CaretLogFiner("Tile Tabs Column Widths: " + + AString::fromNumbers(columnWidthsOut, ", ")); + } return true; } @@ -509,7 +523,6 @@ TileTabsLayoutGridConfiguration::updateAutomaticConfigurationRowsAndColumns(cons getRowsAndColumnsForNumberOfTabs(numberOfTabs, numRows, numCols); - setNumberOfRows(numRows); setNumberOfColumns(numCols); } @@ -700,27 +713,7 @@ TileTabsLayoutGridConfiguration::decodeFromXMLString(QXmlStreamReader& xml, + s_v1_rootTagName + " or " + s_v2_rootTagName); - } - -// const bool debugFlag(false); -// if (debugFlag) { -// AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); -// std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; -// AString em; -// TileTabsLayoutGridConfiguration temp; -// QXmlStreamReader tempReader(xmlText); -// tempReader.readNextStartElement(); -// temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); -// if (tempReader.hasError()) { -// std::cout << "Decode error: " << tempReader.errorString() << std::endl; -// } -// else { -// std::cout << "Decoded: " << temp.toString() << std::endl; -// } -// -// std::cout << std::endl; -// } -// return true; + } } /** @@ -1095,3 +1088,25 @@ TileTabsLayoutGridConfiguration::toString() const return s; } +/** + * Cast to a grid configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to grid configuration or NULL if not a grid configuration. + */ +TileTabsLayoutGridConfiguration* +TileTabsLayoutGridConfiguration::castToGridConfiguration() +{ + return this; +} + +/** + * Cast to a grid configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to grid configuration or NULL if not a grid configuration. + */ +const TileTabsLayoutGridConfiguration* +TileTabsLayoutGridConfiguration::castToGridConfiguration() const +{ + return this; +} + diff --git a/src/Common/TileTabsLayoutGridConfiguration.h b/src/Common/TileTabsLayoutGridConfiguration.h index 82a931d58..031f52554 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.h +++ b/src/Common/TileTabsLayoutGridConfiguration.h @@ -42,7 +42,7 @@ namespace caret { TileTabsLayoutGridConfiguration& operator=(const TileTabsLayoutGridConfiguration& obj); - void copy(const TileTabsLayoutGridConfiguration& rhs); + virtual void copy(const TileTabsLayoutBaseConfiguration& rhs) override; virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const override; @@ -80,6 +80,12 @@ namespace caret { static void getRowsAndColumnsForNumberOfTabs(const int32_t numberOfTabs, int32_t& numberOfRowsOut, int32_t& numberOfColumnsOut); + AString encodeVersionInXML(const int32_t versionNumber) const; + + virtual TileTabsLayoutGridConfiguration* castToGridConfiguration() override; + + virtual const TileTabsLayoutGridConfiguration* castToGridConfiguration() const override; + // ADD_NEW_METHODS_HERE protected: @@ -95,8 +101,6 @@ namespace caret { void decodeFromXMLWithStreamReaderVersionTwo(QXmlStreamReader& xml); - AString encodeVersionInXML(const int32_t versionNumber) const; - AString encodeInXMLWithStreamWriterVersionOne() const; AString encodeInXMLWithStreamWriterVersionTwo() const; diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx index 555d6c348..54e367918 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.cxx +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -103,6 +103,31 @@ TileTabsLayoutManualConfiguration::copyHelperTileTabsLayoutManualConfiguration(c } } +/** + * Copy the given configuration to "this" configuration. If given configuration + * does not cast to "this class type" log a warning and do not copy. + * Name property is not copied. + * + * @param rhs + * Configuration to copy. + */ +void +TileTabsLayoutManualConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs) +{ + const TileTabsLayoutManualConfiguration* manualConfig = rhs.castToManualConfiguration(); + if (manualConfig != NULL) { + AString savedName = getName(); + copyHelperTileTabsLayoutManualConfiguration(*manualConfig); + setName(savedName); + } + else { + CaretLogSevere("Attempt to copy layout configuration " + + rhs.toString() + + " to " + + toString()); + } +} + /** * Copy this instance and give it a new unique identifier. * Note that copy constructor does not create a new unique identifier. @@ -405,58 +430,27 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, } } } -// m_centeringCorrectionEnabled = false; -// -// if (rootElementText == s_v1_rootTagName) { -// decodeFromXMLWithStreamReaderVersionOne(xml); -// } -// else if (rootElementText == s_v2_rootTagName) { -// /* -// * Version 2 uses a different root tag than version 1. The reason is that -// * the older code for decoding from XML will throw an exception if it -// * encounters invalid elements or the version number is invalid. The problem -// * is that the exception is not caught and wb_view will terminate. -// */ -// QString versionNumberText("Unknown"); -// const QXmlStreamAttributes atts = xml.attributes(); -// if (atts.hasAttribute(s_v2_versionAttributeName)) { -// versionNumberText = atts.value(s_v2_versionAttributeName).toString(); -// } -// -// if (versionNumberText == "2") { -// decodeFromXMLWithStreamReaderVersionTwo(xml); -// } -// else { -// xml.raiseError("TileTabsLayoutGridConfiguration invalid version=" -// + versionNumberText); -// } -// } -// else { -// xml.raiseError("TileTabsLayoutGridConfiguration first element is " -// + xml.name().toString() -// + " but should be " -// + s_v1_rootTagName -// + " or " -// + s_v2_rootTagName); -// } -// -// // const bool debugFlag(false); -// // if (debugFlag) { -// // AString xmlText = encodeInXMLWithStreamWriterVersionTwo(); -// // std::cout << std::endl << "NEW: " << xmlText << std::endl << std::endl; -// // AString em; -// // TileTabsLayoutGridConfiguration temp; -// // QXmlStreamReader tempReader(xmlText); -// // tempReader.readNextStartElement(); -// // temp.decodeFromXMLWithStreamReaderVersionTwo(tempReader); -// // if (tempReader.hasError()) { -// // std::cout << "Decode error: " << tempReader.errorString() << std::endl; -// // } -// // else { -// // std::cout << "Decoded: " << temp.toString() << std::endl; -// // } -// // -// // std::cout << std::endl; -// // } -// // return true; } + +/** + * Cast to a manual configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to manual configuration or NULL if not a manual configuration. + */ +TileTabsLayoutManualConfiguration* +TileTabsLayoutManualConfiguration::castToManualConfiguration() +{ + return this; +} + +/** + * Cast to a manual configuration (avoids dynamic_cast that can be slow) + * + * @return Pointer to manual configuration or NULL if not a manual configuration. + */ +const TileTabsLayoutManualConfiguration* +TileTabsLayoutManualConfiguration::castToManualConfiguration() const +{ + return this; +} + diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h index 18ca37aee..82528d9bd 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.h +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -48,6 +48,8 @@ namespace caret { TileTabsLayoutManualConfiguration& operator=(const TileTabsLayoutManualConfiguration& obj); + virtual void copy(const TileTabsLayoutBaseConfiguration& rhs) override; + virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const override; virtual AString toString() const override; @@ -60,6 +62,10 @@ namespace caret { const TileTabsLayoutTabInfo* getTabInfo(const int32_t index) const; + virtual TileTabsLayoutManualConfiguration* castToManualConfiguration() override; + + virtual const TileTabsLayoutManualConfiguration* castToManualConfiguration() const override; + // ADD_NEW_METHODS_HERE protected: diff --git a/src/Files/AnnotationFile.cxx b/src/Files/AnnotationFile.cxx index 5962690d5..ea4e48007 100644 --- a/src/Files/AnnotationFile.cxx +++ b/src/Files/AnnotationFile.cxx @@ -46,7 +46,7 @@ #include "EventBrowserTabDelete.h" #include "EventBrowserTabNewClone.h" #include "EventManager.h" -#include "EventTileTabsConfigurationModification.h" +#include "EventTileTabsGridConfigurationModification.h" #include "GiftiMetaData.h" #include "SceneClass.h" #include "SceneClassAssistant.h" @@ -493,7 +493,7 @@ AnnotationFile::receiveEvent(Event* event) textSubEvent->setEventProcessed(); } else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { - EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); + EventTileTabsGridConfigurationModification* modEvent = dynamic_cast(event); CaretAssert(modEvent); updateSpacerAnnotationsAfterTileTabsModification(modEvent); } @@ -1142,30 +1142,6 @@ AnnotationFile::processGroupingAnnotations(EventAnnotationGrouping* groupingEven AnnotationGroup* spaceGroup = (*spaceGroupIter).data(); CaretAssert(spaceGroup); - - - - - -// AnnotationGroupKey spaceGroupKey = groupingEvent->getAnnotationGroupKey(); -// -// AnnotationGroup* spaceGroup = NULL; -// AnnotationGroupIterator spaceGroupIter = m_annotationGroups.end(); -// for (spaceGroupIter = m_annotationGroups.begin(); -// spaceGroupIter != m_annotationGroups.end(); -// spaceGroupIter++) { -// QSharedPointer groupPointer = *spaceGroupIter; -// if (spaceGroupKey == groupPointer->getAnnotationGroupKey()) { -// spaceGroup = groupPointer.data(); -// break; -// } -// } -// -// if (spaceGroup == NULL) { -// groupingEvent->setErrorMessage("PROGRAM ERROR: Did not find space group for source of grouping annotations"); -// return; -// } - groupingEvent->setEventProcessed(); @@ -1318,7 +1294,6 @@ AnnotationFile::processRegroupingAnnotations(EventAnnotationGrouping* groupingEv * Find annotations in ONE space group that were * previously assigned to the previous user group. */ - //AnnotationGroupIterator spaceGroupIter = m_annotationGroups.end(); for (AnnotationGroupIterator spaceGroupIter = m_annotationGroups.begin(); spaceGroupIter != m_annotationGroups.end(); spaceGroupIter++) { @@ -2173,10 +2148,10 @@ AnnotationFile::isItemSelectedForEditingInWindow(const int32_t /*windowIndex*/) * The tile tabs modify event. */ void -AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent) +AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsGridConfigurationModification* modEvent) { const int32_t rowColumnIndex = modEvent->getRowColumnIndex(); - const bool rowFlag = (modEvent->getRowColumnType() == EventTileTabsConfigurationModification::RowColumnType::ROW); + const bool rowFlag = (modEvent->getRowColumnType() == EventTileTabsGridConfigurationModification::RowColumnType::ROW); int32_t deleteIndex(-1); int32_t shiftStartIndex(-1); @@ -2186,35 +2161,35 @@ AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTile int32_t moveTwoIndex(-1); switch (modEvent->getOperation()) { - case EventTileTabsConfigurationModification::Operation::DELETE_IT: + case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: deleteIndex = rowColumnIndex; shiftStartIndex = rowColumnIndex + 1; break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: { shiftStartIndex = rowColumnIndex + 1; duplicateFromIndex = rowColumnIndex; duplicateToIndex = rowColumnIndex + 1; } break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: { shiftStartIndex = rowColumnIndex; duplicateFromIndex = rowColumnIndex + 1; duplicateToIndex = rowColumnIndex; } break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: shiftStartIndex = rowColumnIndex; break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: shiftStartIndex = rowColumnIndex + 1; break; - case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: moveOneIndex = rowColumnIndex; moveTwoIndex = rowColumnIndex + 1; break; - case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: moveOneIndex = rowColumnIndex; moveTwoIndex = rowColumnIndex - 1; break; @@ -2242,7 +2217,7 @@ AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTile int32_t columnIndex = spacerTabIndex.getColumnIndex(); switch (modEvent->getOperation()) { - case EventTileTabsConfigurationModification::Operation::DELETE_IT: + case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); if (rcIndex == deleteIndex) { @@ -2264,8 +2239,8 @@ AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTile } } break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: - case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); /* @@ -2302,8 +2277,8 @@ AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTile } } break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); if (rcIndex >= shiftStartIndex) { @@ -2317,8 +2292,8 @@ AnnotationFile::updateSpacerAnnotationsAfterTileTabsModification(const EventTile } } break; - case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: - case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: { int32_t rcIndex = (rowFlag ? rowIndex : columnIndex); int32_t newIndex(-1); diff --git a/src/Files/AnnotationFile.h b/src/Files/AnnotationFile.h index be344a600..5f2ca1493 100644 --- a/src/Files/AnnotationFile.h +++ b/src/Files/AnnotationFile.h @@ -33,7 +33,7 @@ #include "DisplayGroupAndTabItemInterface.h" #include "EventAnnotationGrouping.h" #include "EventListenerInterface.h" -#include "EventTileTabsConfigurationModification.h" +#include "EventTileTabsGridConfigurationModification.h" namespace caret { @@ -218,7 +218,7 @@ namespace caret { AnnotationGroup* getSpaceAnnotationGroup(const Annotation* annotation); - void updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsConfigurationModification* modEvent); + void updateSpacerAnnotationsAfterTileTabsModification(const EventTileTabsGridConfigurationModification* modEvent); const AnnotationFileSubType m_fileSubType; diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 2544151a8..7dc39102e 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -81,7 +81,7 @@ #include "EventGraphicsUpdateOneWindow.h" #include "EventSpecFileReadDataFiles.h" #include "EventSurfaceColoringInvalidate.h" -#include "EventTileTabsConfigurationModification.h" +#include "EventTileTabsGridConfigurationModification.h" #include "EventUserInterfaceUpdate.h" #include "FileInformation.h" #include "FociProjectionDialog.h" @@ -109,7 +109,8 @@ #include "Surface.h" #include "SurfaceMontageConfigurationAbstract.h" #include "SurfaceSelectionViewController.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" #include "TileTabsConfigurationModifier.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" @@ -538,7 +539,7 @@ BrainBrowserWindow::receiveEvent(Event* event) } } else if (event->getEventType() == EventTypeEnum::EVENT_TILE_TABS_MODIFICATION) { - EventTileTabsConfigurationModification* modEvent = dynamic_cast(event); + EventTileTabsGridConfigurationModification* modEvent = dynamic_cast(event); CaretAssert(modEvent); if (modEvent->getWindowIndex() == this->m_browserWindowIndex) { @@ -2483,10 +2484,10 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum AString modeLabel; switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: - modeLabel = "Automatic"; + modeLabel = "Automatic Grid"; break; case TileTabsGridModeEnum::CUSTOM: - modeLabel = "Custom"; + modeLabel = "Custom Grid"; break; } @@ -2498,13 +2499,13 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum AString errorText; switch (configurationMode) { case TileTabsGridModeEnum::AUTOMATIC: - TileTabsConfiguration::getRowsAndColumnsForNumberOfTabs(windowTabCount, + TileTabsLayoutGridConfiguration::getRowsAndColumnsForNumberOfTabs(windowTabCount, configRowCount, configColCount); break; case TileTabsGridModeEnum::CUSTOM: { - const TileTabsConfiguration* customConfig = getBrowerWindowContent()->getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* customConfig = getBrowerWindowContent()->getCustomGridTileTabsConfiguration(); configRowCount = customConfig->getNumberOfRows(); configColCount = customConfig->getNumberOfColumns(); const int32_t customTabCount = (configRowCount @@ -2541,7 +2542,7 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum * Event with modification information. */ void -BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent) +BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsGridConfigurationModification* modEvent) { CaretAssert(modEvent); @@ -2586,11 +2587,17 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow() m_viewCustomTileTabsConfigurationActions.clear(); const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - std::vector tileTabsConfigs = prefs->getTileTabsConfigurationsSortedByName(); - for (auto config : tileTabsConfigs) { - QAction* action = m_viewTileTabsLoadUserConfigurationMenu->addAction(config->getName()); + + std::vector> nameUniqueIDs = + prefs->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(); + + for (const auto nameID : nameUniqueIDs) { + /* + * Second element is user data which contains the Unique ID + */ + QAction* action = m_viewTileTabsLoadUserConfigurationMenu->addAction(nameID.first); m_viewCustomTileTabsConfigurationActions.push_back(std::make_pair(action, - const_cast(config))); + nameID.second)); } } @@ -2626,24 +2633,45 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QA { CaretAssert(action); + const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + BrowserWindowContent* bwc = getBrowerWindowContent(); bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); - TileTabsConfiguration* tileTabsConfig = NULL; + AString tileTabsConfigID; for (auto& config : m_viewCustomTileTabsConfigurationActions) { if (config.first == action) { - tileTabsConfig = config.second; - CaretAssert(tileTabsConfig); + tileTabsConfigID = config.second; break; } } - CaretAssert(tileTabsConfig); - - bwc->getCustomTileTabsConfiguration()->copy(*tileTabsConfig); - - EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + std::unique_ptr tileTabsConfig = prefs->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(tileTabsConfigID); + if (tileTabsConfig) { + switch (tileTabsConfig->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + const TileTabsLayoutGridConfiguration* gridConfig = tileTabsConfig->castToGridConfiguration(); + CaretAssert(gridConfig); + + bwc->getCustomGridTileTabsConfiguration()->copy(*gridConfig); + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssertToDoFatal(); + break; + } + + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); + } + else { + WuQMessageBox::errorOk(this, "Unable to find User Configuration with UniqueID: " + + tileTabsConfigID); + } } /** diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 67dfd4ece..a285377ca 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -46,10 +46,10 @@ namespace caret { class BrainOpenGLWidget; class BrowserWindowContent; class BrowserTabContent; - class EventTileTabsConfigurationModification; + class EventTileTabsGridConfigurationModification; class PlainTextStringBuilder; class SceneClassAssistant; - class TileTabsConfiguration; + class TileTabsLayoutBaseConfiguration; /** @@ -335,7 +335,7 @@ namespace caret { void saveBrowserWindowContentForScene(); - void modifyTileTabsConfiguration(EventTileTabsConfigurationModification* modEvent); + void modifyTileTabsConfiguration(EventTileTabsGridConfigurationModification* modEvent); /** Index of this window */ const int32_t m_browserWindowIndex; @@ -391,7 +391,7 @@ namespace caret { QAction* m_viewTileTabsConfigurationDialogAction; QAction* m_viewAutomaticTileTabsConfigurationAction; QAction* m_viewCustomTileTabsConfigurationAction; - std::vector> m_viewCustomTileTabsConfigurationActions; + std::vector> m_viewCustomTileTabsConfigurationActions; QAction* m_gapsAndMarginsAction; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f1fffa402..f223183d2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -120,7 +120,7 @@ #include "SurfaceSelectionModel.h" #include "SurfaceSelectionViewController.h" #include "StructureSurfaceSelectionControl.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" #include "UserInputModeAbstract.h" #include "VolumeFile.h" #include "VolumeSliceViewPlaneEnum.h" @@ -969,7 +969,7 @@ BrainBrowserWindowToolBar::allowAddingNewTab() /* * Is there space in the current configuration? */ - const TileTabsConfiguration* tileTabs = browserWindowContent->getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* tileTabs = browserWindowContent->getCustomGridTileTabsConfiguration(); CaretAssert(tileTabs); const int32_t tileTabsCount = tileTabs->getNumberOfColumns() * tileTabs->getNumberOfRows(); if (getNumberOfTabs() < tileTabsCount) { @@ -2636,10 +2636,6 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() SLOT(wholeBrainSurfaceLeftToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainLeftSurfaceToolButton); wholeBrainLeftSurfaceToolButton->setDefaultAction(leftSurfaceAction); -// leftSurfaceAction->setObjectName(objectNamePrefix -// + "SelectLeft"); -// macroManager->addMacroSupportToObject(leftSurfaceAction, -// "Select all view left surface"); /* * Left menu is displayed when tool button is clicked @@ -2674,10 +2670,6 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() SLOT(wholeBrainSurfaceRightToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainRightSurfaceToolButton); wholeBrainRightSurfaceToolButton->setDefaultAction(rightSurfaceAction); -// rightSurfaceAction->setObjectName(objectNamePrefix -// + "SelectRight"); -// macroManager->addMacroSupportToObject(rightSurfaceAction, -// "Select all view right surface"); /* * Right menu is displayed when tool button is clicked @@ -2712,10 +2704,6 @@ BrainBrowserWindowToolBar::createWholeBrainSurfaceOptionsWidget() SLOT(wholeBrainSurfaceCerebellumToolButtonTriggered(bool))); WuQtUtilities::setToolButtonStyleForQt5Mac(wholeBrainCerebellumSurfaceToolButton); wholeBrainCerebellumSurfaceToolButton->setDefaultAction(cerebellumSurfaceAction); -// cerebellumSurfaceAction->setObjectName(objectNamePrefix -// + "SurfaceCerebellum"); -// macroManager->addMacroSupportToObject(cerebellumSurfaceAction, -// "Select all view cerebellum surface"); /* * Cerebellum menu is displayed when tool button is clicked @@ -3076,10 +3064,6 @@ BrainBrowserWindowToolBar::createModeWidget() "Select view mode"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputVolumeEditAction, "Select volume mode"); -// this->modeInputModeActionGroup->setObjectName(m_objectNamePrefix -// + ":Mode_Action_Group"); -// WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeActionGroup, -// "Selects Mode for Mouse Operations"); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 71c19edce..24bfb3ab0 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -83,7 +83,8 @@ #include "SelectionItemVoxelEditing.h" #include "SessionManager.h" #include "Surface.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" #include "UserInputModeAnnotations.h" #include "UserInputModeBorders.h" #include "UserInputModeFoci.h" @@ -582,35 +583,44 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], /* * Determine if default configuration for tiles */ - TileTabsConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); CaretAssert(tileTabsConfiguration); - /* - * Get the sizes of the tab tiles from the tile tabs configuration - */ - if (tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numberOfTabs, - browserWindowContent->getTileTabsConfigurationMode(), - rowHeights, - columnsWidths)) { - + TileTabsLayoutGridConfiguration* gridConfiguration = tileTabsConfiguration->castToGridConfiguration(); + TileTabsLayoutManualConfiguration* manualConfiguration = tileTabsConfiguration->castToManualConfiguration(); + if (gridConfiguration != NULL) { /* - * Create the viewport drawing contents for all tabs + * Get the sizes of the tab tiles from the tile tabs configuration */ - - std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, - browserWindowContent, - gapsAndMargins, - windowViewport, - this->windowIndex, - getModelEvent.getTabIndexForTileTabsHighlighting()); - for (auto tabvp : tabViewportContent) { - windowContent.addTabViewport(tabvp); + if (gridConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numberOfTabs, + browserWindowContent->getTileTabsConfigurationMode(), + rowHeights, + columnsWidths)) { + + /* + * Create the viewport drawing contents for all tabs + */ + std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, + browserWindowContent, + gapsAndMargins, + windowViewport, + this->windowIndex, + getModelEvent.getTabIndexForTileTabsHighlighting()); + for (auto tabvp : tabViewportContent) { + windowContent.addTabViewport(tabvp); + } + } + else { + CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); } } + else if (manualConfiguration != NULL) { + CaretAssertToDoFatal(); + } else { - CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); + CaretAssert(0); } } else if (numberOfTabs >= 1) { diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index cc2bc54ee..33a12d946 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -53,7 +53,8 @@ #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "SessionManager.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" #include "TileTabsGridRowColumnElement.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" @@ -160,6 +161,14 @@ TileTabsConfigurationDialog::focusGained() QWidget* TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() { + m_addPushButton = new QPushButton("Add -->"); + m_addPushButton->setAutoDefault(false); + WuQtUtilities::setWordWrappedToolTip(m_addPushButton, + "Add a new User Configuration containing the Rows, Columns, and Stretch Factors " + "with those from the Custom Configuration"); + QObject::connect(m_addPushButton, SIGNAL(clicked()), + this, SLOT(addUserConfigurationPushButtonClicked())); + m_replacePushButton = new QPushButton("Replace -->"); m_replacePushButton->setAutoDefault(false); WuQtUtilities::setWordWrappedToolTip(m_replacePushButton, @@ -179,6 +188,8 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->addSpacing(50); + layout->addWidget(m_addPushButton); + layout->addSpacing(10); layout->addWidget(m_replacePushButton); layout->addSpacing(50); layout->addWidget(m_loadPushButton); @@ -187,32 +198,107 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() return widget; } +/** + * @return Name for new tile tabs configuration + * If empty, user cancelled. + */ +AString +TileTabsConfigurationDialog::getNewConfigurationName(QWidget* dialogParent) +{ + AString newTileTabsName; + + bool exitLoop = false; + while (exitLoop == false) { + /* + * Popup dialog to get name for new configuration + */ + WuQDataEntryDialog ded("New Tile Tabs Configuration", + dialogParent); + + QLineEdit* nameLineEdit = ded.addLineEditWidget("Configuration Name"); + nameLineEdit->setText(newTileTabsName); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + /* + * Make sure name is not empty + */ + newTileTabsName = nameLineEdit->text().trimmed(); + if (newTileTabsName.isEmpty()) { + WuQMessageBox::errorOk(dialogParent, + "Empty name is invalid."); + } + else { + /* + * See if a configuration with the user entered name already exists + */ + const TileTabsLayoutBaseConfiguration* configuration = m_caretPreferences->getTileTabsUserConfigurationByName(newTileTabsName); + if (configuration != NULL) { + const QString msg = ("Configuration named \"" + + newTileTabsName + + "\" already exits. Choose a different name."); + WuQMessageBox::errorOk(dialogParent, msg); + } + else { + /* + * Have new name + */ + exitLoop = true; + } + } + } + else { + /* + * User pressed cancel button. + */ + exitLoop = true; + newTileTabsName = ""; + } + } + + return newTileTabsName; +} + /** * Called when Replace to user configuration pushbutton is clicked. */ void -TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() +TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() { + const AString newConfigName = getNewConfigurationName(m_addPushButton); + if (newConfigName.isEmpty()) { + return; + } + m_blockReadConfigurationsFromPreferences = true; + + const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(activeConfiguration); - const TileTabsConfiguration* activeConfiguration = getCustomTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* configCopy = new TileTabsLayoutGridConfiguration(*activeConfiguration); + CaretAssert(configCopy); + configCopy->setName(newConfigName); + m_caretPreferences->addTileTabsUserConfiguration(configCopy); + + m_blockReadConfigurationsFromPreferences = false; + updateDialog(); +} + +/** + * Called when Replace to user configuration pushbutton is clicked. + */ +void +TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() +{ + const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); CaretAssert(activeConfiguration); - TileTabsConfiguration* userConfiguration = getSelectedUserTileTabsConfiguration(); - if (userConfiguration == NULL) { - newUserConfigurationButtonClicked(); - userConfiguration = getSelectedUserTileTabsConfiguration(); - if (userConfiguration == NULL) { + const AString tileTabsUniqueID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + if (tileTabsUniqueID.isEmpty()) { WuQMessageBox::errorOk(this, - "There are no user configurations"); - m_blockReadConfigurationsFromPreferences = false; + "There are no user configurations, use Add button."); return; - } } else { - const AString msg("Do you want to replace " - + userConfiguration->getName() - + "?"); + const AString msg("Do you want to replace the configuration?"); if ( ! WuQMessageBox::warningOkCancel(m_replacePushButton, msg)) { m_blockReadConfigurationsFromPreferences = false; @@ -220,10 +306,16 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() } } - userConfiguration->copy(*activeConfiguration); - - m_caretPreferences->writeTileTabsConfigurations(); + m_blockReadConfigurationsFromPreferences = true; + AString errorMessage; + if ( ! m_caretPreferences->replaceTileTabsUserConfiguration(tileTabsUniqueID, + activeConfiguration, + errorMessage)) { + WuQMessageBox::errorOk(m_replacePushButton, + errorMessage); + } + m_blockReadConfigurationsFromPreferences = false; updateDialog(); } @@ -238,17 +330,38 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() return; } - TileTabsConfiguration* activeConfiguration = getCustomTileTabsConfiguration(); - CaretAssert(activeConfiguration); + const AString userConfigID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + if (userConfigID.isEmpty()) { + WuQMessageBox::errorOk(this, "No user configuration is selected."); + return; + } - const TileTabsConfiguration* userConfiguration = getSelectedUserTileTabsConfiguration(); - if (userConfiguration == NULL) { + std::unique_ptr userConfiguration = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(userConfigID); + if ( ! userConfiguration) { WuQMessageBox::errorOk(this, - "There are no user configurations"); + ("User configuration with UniqueID=" + + userConfigID + + " was not found")); return; } - activeConfiguration->copy(*userConfiguration); + switch (userConfiguration->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + TileTabsLayoutGridConfiguration* activeGridConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(activeGridConfiguration); + + const TileTabsLayoutGridConfiguration* copyConfig = userConfiguration->castToGridConfiguration(); + CaretAssert(copyConfig); + + activeGridConfiguration->copy(*copyConfig); + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssertToDoFatal(); + break; + } updateStretchFactors(); updateGraphicsWindow(); @@ -257,7 +370,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() /** * @return The browser window selected window index. */ - BrainBrowserWindow* TileTabsConfigurationDialog::getBrowserWindow() { @@ -269,8 +381,6 @@ TileTabsConfigurationDialog::getBrowserWindow() return bbw; } - - /** * @return The browser window content for the selected window index. * May be NULL when no tabs are open. @@ -304,12 +414,7 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() const AString newToolTip = WuQtUtilities::createWordWrappedToolTipText("Create new User Configuration by entering a name.\n" "It will contain rows/columns/factors from the Custom Configuration"); - m_newConfigurationPushButton = new QPushButton("New..."); - m_newConfigurationPushButton->setAutoDefault(false); - m_newConfigurationPushButton->setToolTip(newToolTip); - QObject::connect(m_newConfigurationPushButton, SIGNAL(clicked()), - this, SLOT(newUserConfigurationButtonClicked())); - + m_renameConfigurationPushButton = new QPushButton("Rename..."); m_renameConfigurationPushButton->setToolTip("Rename the selected User Configuration"); m_renameConfigurationPushButton->setAutoDefault(false); @@ -324,9 +429,8 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() QGridLayout* buttonsLayout = new QGridLayout(); buttonsLayout->setContentsMargins(0, 0, 0, 0); - buttonsLayout->addWidget(m_newConfigurationPushButton, 0, 0, Qt::AlignRight); - buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 1, Qt::AlignLeft); - buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 0, 1, 2, Qt::AlignHCenter); + buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 1, Qt::AlignHCenter); + buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 1, Qt::AlignHCenter); QGroupBox* configurationWidget = new QGroupBox("User Configurations"); QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); @@ -398,7 +502,7 @@ TileTabsConfigurationDialog::createCustomOptionsWidget() void TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked(bool checked) { - TileTabsConfiguration* config = getCustomTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* config = getCustomTileTabsGridConfiguration(); if (config != NULL) { config->setCenteringCorrectionEnabled(checked); updateGraphicsWindow(); @@ -411,7 +515,7 @@ TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked(bool checked) void TileTabsConfigurationDialog::updateCustomOptionsWidget() { - TileTabsConfiguration* config = getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* config = getCustomTileTabsGridConfiguration(); if (config != NULL) { m_centeringCorrectionCheckBox->setChecked(config->isCenteringCorrectionEnabled()); } @@ -450,7 +554,7 @@ TileTabsConfigurationDialog::createRowColumnStretchWidget() * Current custom configuration. */ void -TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration* configuration) +TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridConfiguration* configuration) { /* * Update rows @@ -464,7 +568,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration */ const int32_t numToAdd = numRows - numRowElements; for (int32_t iRow = 0; iRow < numToAdd; iRow++) { - addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::ROW, + addRowColumnStretchWidget(EventTileTabsGridConfigurationModification::RowColumnType::ROW, m_rowElementsGridLayout, m_rowElements); } @@ -498,7 +602,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration */ const int32_t numToAdd = numColumns - numColumnElements; for (int32_t iColumn = 0; iColumn < numToAdd; iColumn++) { - addRowColumnStretchWidget(EventTileTabsConfigurationModification::RowColumnType::COLUMN, + addRowColumnStretchWidget(EventTileTabsGridConfigurationModification::RowColumnType::COLUMN, m_columnElementsGridLayout, m_columnElements); } @@ -521,8 +625,6 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration } updateCustomOptionsWidget(); - -// m_customConfigurationWidget->adjustSize(); } /** @@ -536,7 +638,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsConfiguration * Container for row/column elements. */ void -TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, +TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, std::vector& elementVector) { @@ -615,7 +717,6 @@ TileTabsConfigurationDialog::createActiveConfigurationWidget() QScrollArea* stretchFactorScrollArea = new QScrollArea(); stretchFactorScrollArea->setWidget(m_customConfigurationWidget); stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); -// stretchFactorScrollArea->setSizeAdjustPolicy(QScrollArea::AdjustToContents); stretchFactorScrollArea->setWidgetResizable(true); QGroupBox* widget = new QGroupBox("Tile Tabs Configuration in Workbench Window"); @@ -724,7 +825,7 @@ TileTabsConfigurationDialog::readConfigurationsFromPreferences() return; } - m_caretPreferences->readTileTabsConfigurations(); + m_caretPreferences->readTileTabsUserConfigurations(); } /** @@ -754,28 +855,19 @@ TileTabsConfigurationDialog::updateDialog() QSignalBlocker blocker(m_userConfigurationSelectionListWidget); m_userConfigurationSelectionListWidget->clear(); - std::vector configurations = m_caretPreferences->getTileTabsConfigurationsSortedByName(); - const int32_t numConfig = static_cast(configurations.size()); - for (int32_t i = 0; i < numConfig; i++) { - const TileTabsConfiguration* configuration = configurations[i]; - - AString configName = configuration->getName(); - - configName.append(" (" - + AString::number(configuration->getNumberOfRows()) - + ", " - + AString::number(configuration->getNumberOfColumns()) - + ")"); - + std::vector> nameUniqueIDs = + m_caretPreferences->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(); + + for (const auto nameID : nameUniqueIDs) { /* * Second element is user data which contains the Unique ID */ - QListWidgetItem* item = new QListWidgetItem(configName); + QListWidgetItem* item = new QListWidgetItem(nameID.first); item->setData(Qt::UserRole, - QVariant(configuration->getUniqueIdentifier())); + QVariant(nameID.second)); m_userConfigurationSelectionListWidget->addItem(item); } - + const int32_t numItemsInComboBox = m_userConfigurationSelectionListWidget->count(); if (defaultIndex >= numItemsInComboBox) { defaultIndex = numItemsInComboBox - 1; @@ -801,9 +893,9 @@ TileTabsConfigurationDialog::updateStretchFactors() true)); m_customConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, false)); - const TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration != NULL) { - updateRowColumnStretchWidgets(const_cast(configuration)); + updateRowColumnStretchWidgets(const_cast(configuration)); QSignalBlocker rowBlocker(m_numberOfRowsSpinBox); m_numberOfRowsSpinBox->setValue(configuration->getNumberOfRows()); QSignalBlocker columnBlocker(m_numberOfColumnsSpinBox); @@ -812,9 +904,6 @@ TileTabsConfigurationDialog::updateStretchFactors() const bool editableFlag = ( ! m_automaticConfigurationRadioButton->isChecked()); - // This does not re-enable the construction menu - //m_customConfigurationWidget->setEnabled(editableFlag); - m_loadPushButton->setEnabled(editableFlag); } @@ -836,79 +925,6 @@ TileTabsConfigurationDialog::selectTileTabConfigurationByUniqueID(const AString& } } -/** - * Called when new user configuration button is clicked. - */ -void -TileTabsConfigurationDialog::newUserConfigurationButtonClicked() -{ - AString newTileTabsName; - - AString configurationUniqueID; - - bool exitLoop = false; - while (exitLoop == false) { - /* - * Popup dialog to get name for new configuration - */ - WuQDataEntryDialog ded("New Tile Tabs Configuration", - m_newConfigurationPushButton); - - QLineEdit* nameLineEdit = ded.addLineEditWidget("Configuration Name"); - nameLineEdit->setText(newTileTabsName); - if (ded.exec() == WuQDataEntryDialog::Accepted) { - /* - * Make sure name is not empty - */ - newTileTabsName = nameLineEdit->text().trimmed(); - if (newTileTabsName.isEmpty()) { - WuQMessageBox::errorOk(m_newConfigurationPushButton, - "Enter a name"); - } - else { - /* - * See if a configuration with the user entered name already exists - */ - TileTabsConfiguration* configuration = m_caretPreferences->getTileTabsConfigurationByName(newTileTabsName); - if (configuration != NULL) { - const QString msg = ("Configuration named \"" - + newTileTabsName - + "\" already exits. Rename it?"); - if (WuQMessageBox::warningYesNo(m_newConfigurationPushButton, - msg)) { - configuration->setName(newTileTabsName); - configurationUniqueID = configuration->getUniqueIdentifier(); - exitLoop = true; - } - } - else { - /* - * New configuration is copy of selected configuration (if available) - */ - const TileTabsConfiguration* selectedConfiguration = getCustomTileTabsConfiguration(); - TileTabsConfiguration* configuration = ((selectedConfiguration != NULL) - ? selectedConfiguration->newCopyWithNewUniqueIdentifier() - : new TileTabsConfiguration()); - configuration->setName(newTileTabsName); - configurationUniqueID = configuration->getUniqueIdentifier(); - m_caretPreferences->addTileTabsConfiguration(configuration); - exitLoop = true; - } - } - } - else { - /* - * User pressed cancel button. - */ - exitLoop = true; - } - } - - if ( ! configurationUniqueID.isEmpty()) { - updateDialog(); - selectTileTabConfigurationByUniqueID(configurationUniqueID); - } -} /** * Called when delete user configuration button is clicked. @@ -916,17 +932,17 @@ TileTabsConfigurationDialog::newUserConfigurationButtonClicked() void TileTabsConfigurationDialog::deleteUserConfigurationButtonClicked() { - TileTabsConfiguration* configuration = getSelectedUserTileTabsConfiguration(); - if (configuration != NULL) { - const AString uniqueID = configuration->getUniqueIdentifier(); - const QString msg = ("Delete configuration named \"" - + configuration->getName() - + "\" ?"); - if (WuQMessageBox::warningYesNo(m_newConfigurationPushButton, - msg)) { - m_caretPreferences->removeTileTabsConfigurationByUniqueIdentifier(uniqueID); - updateDialog(); + const QString uniqueID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + const QString msg = ("Delete selected configuration ?"); + if (WuQMessageBox::warningYesNo(m_deleteConfigurationPushButton, + msg)) { + AString errorMessage; + if ( ! m_caretPreferences->removeTileTabsUserConfigurationByUniqueIdentifier(uniqueID, + errorMessage)) { + WuQMessageBox::errorOk(m_deleteConfigurationPushButton, + errorMessage); } + updateDialog(); } } @@ -936,12 +952,11 @@ TileTabsConfigurationDialog::deleteUserConfigurationButtonClicked() void TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() { - TileTabsConfiguration* configuration = getSelectedUserTileTabsConfiguration(); - if (configuration != NULL) { - m_blockReadConfigurationsFromPreferences = true; - + AString oldName; + AString uniqueID; + if (getSelectedUserConfigurationNameAndUniqueID(oldName, + uniqueID)) { bool ok = false; - const AString oldName = configuration->getName(); const AString newName = QInputDialog::getText(m_deleteConfigurationPushButton, "Rename Configuration", "Name", @@ -949,60 +964,83 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() oldName, &ok); if (ok - && (newName.isEmpty() == false)) { - configuration->setName(newName); - m_caretPreferences->writeTileTabsConfigurations(); + && ( ! newName.isEmpty())) { + m_blockReadConfigurationsFromPreferences = true; + AString errorMessage; + if (m_caretPreferences->renameTileTabsUserConfiguration(uniqueID, + newName, + errorMessage)) { + } + else { + WuQMessageBox::errorOk(m_renameConfigurationPushButton, + errorMessage); + } m_blockReadConfigurationsFromPreferences = false; updateDialog(); } - else { - m_blockReadConfigurationsFromPreferences = false; - } + } } /** - * @return A pointer to the automatic tile tabs configuration. + * @return A pointer to the custom tile tabs configuration. */ -TileTabsConfiguration* -TileTabsConfigurationDialog::getAutomaticTileTabsConfiguration() +TileTabsLayoutGridConfiguration* +TileTabsConfigurationDialog::getCustomTileTabsGridConfiguration() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); - TileTabsConfiguration* configuration = browserWindowContent->getAutomaticTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* configuration = browserWindowContent->getCustomGridTileTabsConfiguration(); CaretAssert(configuration); return configuration; } /** - * @return A pointer to the custom tile tabs configuration. + * Get the name and unique identifier for the selected user configuration + * + * @param nameOut + * Output with name + * @param uniqueIDOut + * Output with Unique ID + * @return + * True if the output data is valid or false if no configuration is selected */ -TileTabsConfiguration* -TileTabsConfigurationDialog::getCustomTileTabsConfiguration() +bool +TileTabsConfigurationDialog::getSelectedUserConfigurationNameAndUniqueID(AString& nameOut, + AString& uniqueIDOut) const { - BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); - TileTabsConfiguration* configuration = browserWindowContent->getCustomTileTabsConfiguration(); - CaretAssert(configuration); - return configuration; + const int32_t indx = m_userConfigurationSelectionListWidget->currentRow(); + if ((indx >= 0) + && (indx < m_userConfigurationSelectionListWidget->count())) { + QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(indx); + nameOut = item->text(); + uniqueIDOut = item->data(Qt::UserRole).toString(); + + return true; + } + + nameOut.clear(); + uniqueIDOut.clear(); + + return false; } /** - * @return The selected user tile tabs configuration (will be - * NULL if there are no user configurations). + * @return The Unique Identifier of the selected user tile tabs configuration. + * Empty if no configuration is selected. */ -TileTabsConfiguration* -TileTabsConfigurationDialog::getSelectedUserTileTabsConfiguration() +AString +TileTabsConfigurationDialog::getSelectedUserTileTabsConfigurationUniqueIdentifier() { - TileTabsConfiguration* configuration = NULL; + AString uniqueID; const int32_t indx = m_userConfigurationSelectionListWidget->currentRow(); if ((indx >= 0) && (indx < m_userConfigurationSelectionListWidget->count())) { QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(indx); - const AString itemID = item->data(Qt::UserRole).toString(); - configuration = m_caretPreferences->getTileTabsConfigurationByUniqueIdentifier(itemID); + uniqueID = item->data(Qt::UserRole).toString(); } - return configuration; + return uniqueID; } /** @@ -1011,7 +1049,7 @@ TileTabsConfigurationDialog::getSelectedUserTileTabsConfiguration() void TileTabsConfigurationDialog::configurationNumberOfRowsOrColumnsChanged() { - TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration != NULL) { configuration->setNumberOfRows(m_numberOfRowsSpinBox->value()); configuration->setNumberOfColumns(m_numberOfColumnsSpinBox->value()); @@ -1028,7 +1066,7 @@ TileTabsConfigurationDialog::configurationNumberOfRowsOrColumnsChanged() void TileTabsConfigurationDialog::configurationStretchFactorWasChanged() { - TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration == NULL) { return; } @@ -1044,9 +1082,9 @@ TileTabsConfigurationDialog::configurationStretchFactorWasChanged() * Modification that is requested. */ void -TileTabsConfigurationDialog::tileTabsModificationRequested(EventTileTabsConfigurationModification& modification) +TileTabsConfigurationDialog::tileTabsModificationRequested(EventTileTabsGridConfigurationModification& modification) { - TileTabsConfiguration* configuration = getCustomTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration != NULL) { modification.setWindowIndex(m_browserWindowComboBox->getSelectedBrowserWindowIndex()); @@ -1100,7 +1138,7 @@ TileTabsConfigurationDialog::helpButtonClicked() * Parent QObject */ TileTabElementWidgets::TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, - const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, const int32_t index, QGridLayout* gridLayout, QObject* parent) @@ -1113,7 +1151,7 @@ m_element(NULL) m_indexLabel = new QLabel(QString::number(m_index + 1)); m_indexLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - const AString rowColText((rowColumnType == EventTileTabsConfigurationModification::RowColumnType::ROW) + const AString rowColText((rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::ROW) ? "Row" : "Column"); const AString contructionToolTip(WuQtUtilities::createWordWrappedToolTipText("Delete, Duplicate, or Move " @@ -1209,52 +1247,52 @@ TileTabElementWidgets::~TileTabElementWidgets() QMenu* TileTabElementWidgets::createConstructionMenu(QToolButton* toolButton) { - const AString deleteText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString deleteText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Delete this Column" : "Delete this Row"); - const AString duplicateAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString duplicateAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Duplicate this Column to Right" : "Duplicate this Row Below"); - const AString duplicateBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString duplicateBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Duplicate this Column to Left" : "Duplicate this Row Above"); - const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Insert Spacer Column to Right" : "Insert Spacer Row Below"); - const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Insert Spacer Column to Left" : "Insert Spacer Row Above"); - const AString moveAfterText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString moveAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Move this Column to Right" : "Move this Row Down"); - const AString moveBeforeText((m_rowColumnType == EventTileTabsConfigurationModification::RowColumnType::COLUMN) + const AString moveBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) ? "Move this Column to Left" : "Move this Row Up"); m_menuDeleteAction = new QAction(deleteText); - m_menuDeleteAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DELETE_IT)); + m_menuDeleteAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DELETE_IT)); m_menuDuplicateAfterAction = new QAction(duplicateAfterText); - m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER)); + m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER)); m_menuDuplicateBeforeAction = new QAction(duplicateBeforeText); - m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE)); + m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE)); m_insertSpacerAfterAction = new QAction(insertSpacerAfterText); - m_insertSpacerAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER)); + m_insertSpacerAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER)); m_insertSpacerBeforeAction = new QAction(insertSpacerBeforeText); - m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE)); + m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE)); m_menuMoveAfterAction = new QAction(moveAfterText); - m_menuMoveAfterAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_AFTER)); + m_menuMoveAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER)); m_menuMoveBeforeAction = new QAction(moveBeforeText); - m_menuMoveBeforeAction->setData(static_cast(EventTileTabsConfigurationModification::Operation::MOVE_BEFORE)); + m_menuMoveBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE)); QMenu* menu = new QMenu(toolButton); menu->addAction(m_menuDuplicateBeforeAction); @@ -1313,34 +1351,34 @@ void TileTabElementWidgets::constructionMenuTriggered(QAction* action) { if (action != NULL) { - const EventTileTabsConfigurationModification::Operation operation - = static_cast(action->data().toInt()); + const EventTileTabsGridConfigurationModification::Operation operation + = static_cast(action->data().toInt()); /* * This switch is here so that it will cause a compilation error * if the operations are changed. */ switch (operation) { - case EventTileTabsConfigurationModification::Operation::DELETE_IT: + case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: break; - case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: break; - case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: break; } - EventTileTabsConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(), - m_index, - m_rowColumnType, - operation); + EventTileTabsGridConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(), + m_index, + m_rowColumnType, + operation); emit modificationRequested(modification); } @@ -1352,14 +1390,14 @@ TileTabElementWidgets::constructionMenuTriggered(QAction* action) void TileTabElementWidgets::constructionMenuAboutToShow() { - const TileTabsConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(); if (config != NULL) { int32_t numItems(-1); switch (m_rowColumnType) { - case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: numItems = config->getNumberOfColumns(); break; - case EventTileTabsConfigurationModification::RowColumnType::ROW: + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: numItems = config->getNumberOfRows(); break; } diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index 29e31cff2..a229c72ad 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -22,7 +22,7 @@ /*LICENSE_END*/ #include "EventListenerInterface.h" -#include "EventTileTabsConfigurationModification.h" +#include "EventTileTabsGridConfigurationModification.h" #include "TileTabsGridRowColumnContentTypeEnum.h" #include "TileTabsGridRowColumnStretchTypeEnum.h" #include "WuQDialogNonModal.h" @@ -44,7 +44,9 @@ namespace caret { class BrowserWindowContent; class CaretPreferences; class EnumComboBoxTemplate; - class TileTabsConfiguration; + class TileTabsLayoutBaseConfiguration; + class TileTabsLayoutGridConfiguration; + class TileTabsLayoutManualConfiguration; class TileTabElementWidgets; class TileTabsGridRowColumnElement; class WuQGridLayoutGroup; @@ -77,8 +79,6 @@ namespace caret { private slots: void browserWindowComboBoxValueChanged(BrainBrowserWindow* browserWindow); - void newUserConfigurationButtonClicked(); - void deleteUserConfigurationButtonClicked(); void renameUserConfigurationButtonClicked(); @@ -87,13 +87,15 @@ namespace caret { void configurationStretchFactorWasChanged(); + void addUserConfigurationPushButtonClicked(); + void replaceUserConfigurationPushButtonClicked(); void loadIntoActiveConfigurationPushButtonClicked(); void automaticCustomButtonClicked(QAbstractButton*); - void tileTabsModificationRequested(EventTileTabsConfigurationModification& modification); + void tileTabsModificationRequested(EventTileTabsGridConfigurationModification& modification); void centeringCorrectionCheckBoxClicked(bool checked); @@ -111,11 +113,12 @@ namespace caret { void selectTileTabConfigurationByUniqueID(const AString& uniqueID); - TileTabsConfiguration* getAutomaticTileTabsConfiguration(); + TileTabsLayoutGridConfiguration* getCustomTileTabsGridConfiguration(); - TileTabsConfiguration* getCustomTileTabsConfiguration(); + AString getSelectedUserTileTabsConfigurationUniqueIdentifier(); - TileTabsConfiguration* getSelectedUserTileTabsConfiguration(); + bool getSelectedUserConfigurationNameAndUniqueID(AString& nameOut, + AString& uniqueIDOut) const; QWidget* createUserConfigurationSelectionWidget(); @@ -125,9 +128,9 @@ namespace caret { QWidget* createCustomOptionsWidget(); - void updateRowColumnStretchWidgets(TileTabsConfiguration* configuration); + void updateRowColumnStretchWidgets(TileTabsLayoutGridConfiguration* configuration); - void addRowColumnStretchWidget(const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + void addRowColumnStretchWidget(const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, std::vector& elementVector); @@ -143,6 +146,8 @@ namespace caret { BrowserWindowContent* getBrowserWindowContent(); + AString getNewConfigurationName(QWidget* dialogParent); + BrainBrowserWindowComboBox* m_browserWindowComboBox; QWidget* m_customConfigurationWidget; @@ -153,12 +158,12 @@ namespace caret { QRadioButton* m_customConfigurationRadioButton; - QPushButton* m_newConfigurationPushButton; - QPushButton* m_deleteConfigurationPushButton; QPushButton* m_renameConfigurationPushButton; + QPushButton* m_addPushButton; + QPushButton* m_replacePushButton; QPushButton* m_loadPushButton; @@ -203,7 +208,7 @@ namespace caret { public: TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, - const EventTileTabsConfigurationModification::RowColumnType rowColumnType, + const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, const int32_t index, QGridLayout* gridLayout, QObject* parent); @@ -215,7 +220,7 @@ namespace caret { signals: void itemChanged(); - void modificationRequested(EventTileTabsConfigurationModification& modification); + void modificationRequested(EventTileTabsGridConfigurationModification& modification); private slots: void constructionMenuAboutToShow(); @@ -232,7 +237,7 @@ namespace caret { QMenu* createConstructionMenu(QToolButton* toolButton); TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; - const EventTileTabsConfigurationModification::RowColumnType m_rowColumnType; + const EventTileTabsGridConfigurationModification::RowColumnType m_rowColumnType; const int32_t m_index; TileTabsGridRowColumnElement* m_element; diff --git a/src/GuiQt/TileTabsConfigurationModifier.cxx b/src/GuiQt/TileTabsConfigurationModifier.cxx index 3b04e14c4..914647de9 100644 --- a/src/GuiQt/TileTabsConfigurationModifier.cxx +++ b/src/GuiQt/TileTabsConfigurationModifier.cxx @@ -34,10 +34,10 @@ #include "EventBrowserTabNew.h" #include "EventBrowserWindowTileTabOperation.h" #include "EventManager.h" -#include "EventTileTabsConfigurationModification.h" +#include "EventTileTabsGridConfigurationModification.h" #include "GuiManager.h" #include "SpacerTabContent.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" using namespace caret; @@ -58,7 +58,7 @@ static bool debugFlag = false; * Event describing modification. */ TileTabsConfigurationModifier::TileTabsConfigurationModifier(const std::vector& existingTabs, - EventTileTabsConfigurationModification* modifyEvent) + EventTileTabsGridConfigurationModification* modifyEvent) : CaretObject(), m_existingTabs(existingTabs), m_modifyEvent(modifyEvent) @@ -135,7 +135,7 @@ TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() const int32_t numColumns = m_currentTileTabsConfiguration->getNumberOfColumns(); switch (m_modifyEvent->getRowColumnType()) { - case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: for (int32_t jCol = 0; jCol < numColumns; jCol++) { m_rowColumns.push_back(new RowColumnContent(m_existingTabs, m_modifyEvent->getTileTabsConfiguration(), @@ -143,7 +143,7 @@ TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() false)); } break; - case EventTileTabsConfigurationModification::RowColumnType::ROW: + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: for (int32_t iRow = 0; iRow < numRows; iRow++) { m_rowColumns.push_back(new RowColumnContent(m_existingTabs, m_modifyEvent->getTileTabsConfiguration(), @@ -170,7 +170,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) const int32_t numRowColumns = static_cast(m_rowColumns.size()); switch (m_modifyEvent->getOperation()) { - case EventTileTabsConfigurationModification::Operation::DELETE_IT: + case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: if (numRowColumns <= 1) { errorMessageOut = "Cannot delete ROWCOL when there is only one ROWCOL"; } @@ -195,7 +195,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) errorMessageOut = "Invalid ROWCOL index=RCINDEX when deleting"; } break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); @@ -210,7 +210,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; } break; - case EventTileTabsConfigurationModification::Operation::DUPLICATE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { RowColumnContent* rowColumnCopy = m_rowColumns[rowColumnIndex]->clone(errorMessageOut); @@ -225,8 +225,8 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) errorMessageOut = "Invalid ROWCOL index=RCINDEX when duplicating"; } break; - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER: - case EventTileTabsConfigurationModification::Operation::INSERT_SPACER_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: if ((rowColumnIndex >= 0) && (rowColumnIndex < numRowColumns)) { CaretAssertVectorIndex(m_rowColumns, 0); @@ -234,7 +234,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) RowColumnContent* rowColumnSpacer = RowColumnContent::newInstanceContainingSpacers(numberOfElements); if (rowColumnSpacer != NULL) { int32_t insertOffset = rowColumnIndex; - if (m_modifyEvent->getOperation() == EventTileTabsConfigurationModification::Operation::INSERT_SPACER_AFTER) { + if (m_modifyEvent->getOperation() == EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER) { insertOffset++; } m_rowColumns.insert(m_rowColumns.begin() + @@ -246,7 +246,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) errorMessageOut = "Invalid ROWCOL index=RCINDEX when insert spacer"; } break; - case EventTileTabsConfigurationModification::Operation::MOVE_AFTER: + case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: if (numRowColumns <= 1) { errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; } @@ -264,7 +264,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) errorMessageOut = "Invalid ROWCOL index=RCINDEX when moving"; } break; - case EventTileTabsConfigurationModification::Operation::MOVE_BEFORE: + case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: if (numRowColumns <= 1) { errorMessageOut = "Cannot move ROWCOL when there is only one ROWCOL"; } @@ -287,10 +287,10 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) if ( ! errorMessageOut.isEmpty()) { AString nameText; switch (m_modifyEvent->getRowColumnType()) { - case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: nameText = " Column "; break; - case EventTileTabsConfigurationModification::RowColumnType::ROW: + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: nameText = " Row "; break; } @@ -317,11 +317,11 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) bool TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut) { - TileTabsConfiguration newConfiguration(*m_currentTileTabsConfiguration); + TileTabsLayoutGridConfiguration newConfiguration(*m_currentTileTabsConfiguration); std::vector browserTabs; switch (m_modifyEvent->getRowColumnType()) { - case EventTileTabsConfigurationModification::RowColumnType::COLUMN: + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: { const int32_t numRows = static_cast(m_rowColumns[0]->m_tabElements.size()); CaretAssert(numRows == m_currentTileTabsConfiguration->getNumberOfRows()); @@ -349,7 +349,7 @@ TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& } } break; - case EventTileTabsConfigurationModification::RowColumnType::ROW: + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: { const int32_t numRows = static_cast(m_rowColumns.size()); const int32_t numColumns = static_cast(m_rowColumns[0]->m_tabElements.size()); @@ -469,7 +469,7 @@ TileTabsConfigurationModifier::Element::toString() const * True if rows are being operated upon, false if operating on columns */ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const std::vector& existingTabs, - TileTabsConfiguration* tileTabsConfiguration, + TileTabsLayoutGridConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const bool rowFlag) { diff --git a/src/GuiQt/TileTabsConfigurationModifier.h b/src/GuiQt/TileTabsConfigurationModifier.h index c0b57e106..9f9be37b2 100644 --- a/src/GuiQt/TileTabsConfigurationModifier.h +++ b/src/GuiQt/TileTabsConfigurationModifier.h @@ -33,16 +33,16 @@ namespace caret { class BrainOpenGLViewportContent; class BrowserTabContent; - class EventTileTabsConfigurationModification; + class EventTileTabsGridConfigurationModification; class SpacerTabContent; - class TileTabsConfiguration; + class TileTabsLayoutGridConfiguration; class TileTabsGridRowColumnElement; class TileTabsConfigurationModifier : public CaretObject { public: TileTabsConfigurationModifier(const std::vector& existingTabs, - EventTileTabsConfigurationModification* modifyEvent); + EventTileTabsGridConfigurationModification* modifyEvent); virtual ~TileTabsConfigurationModifier(); @@ -83,7 +83,7 @@ namespace caret { class RowColumnContent : public CaretObject { public: RowColumnContent(const std::vector& existingTabs, - TileTabsConfiguration* tileTabsConfiguration, + TileTabsLayoutGridConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const bool rowFlag); @@ -115,7 +115,7 @@ namespace caret { const std::vector& m_existingTabs; - EventTileTabsConfigurationModification* m_modifyEvent; + EventTileTabsGridConfigurationModification* m_modifyEvent; std::vector m_rowColumns; @@ -124,7 +124,7 @@ namespace caret { /** * This is the current tile tabs configuration in the window so DO NOT delete it */ - TileTabsConfiguration* m_currentTileTabsConfiguration = NULL; + TileTabsLayoutGridConfiguration* m_currentTileTabsConfiguration = NULL; // ADD_NEW_MEMBERS_HERE diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 19b9e4990..62ba3fafe 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -61,7 +61,8 @@ #include "SceneFile.h" #include "ScenePrimitiveArray.h" #include "SessionManager.h" -#include "TileTabsConfiguration.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsLayoutManualConfiguration.h" #include "VolumeFile.h" //#include "workbench_png.h" @@ -463,9 +464,13 @@ OperationShowScene::useParameters(OperationParameters* myParams, if (restoreToTabTiles) { CaretPointer brainOpenGL(createBrainOpenGL()); - TileTabsConfiguration* tileTabsConfiguration = bwc->getSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = bwc->getSelectedTileTabsConfiguration(); CaretAssert(tileTabsConfiguration); + TileTabsLayoutGridConfiguration* gridConfig = tileTabsConfiguration->castToGridConfiguration(); + TileTabsLayoutManualConfiguration* manualConfig = tileTabsConfiguration->castToManualConfiguration(); + + if (gridConfig != NULL) { const std::vector tabIndices = bwc->getSceneTabIndices(); if ( ! tabIndices.empty()) { std::vector allTabContent; @@ -491,12 +496,12 @@ OperationShowScene::useParameters(OperationParameters* myParams, } std::vector rowHeights; std::vector columnWidths; - if ( ! tileTabsConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numTabContent, - bwc->getTileTabsConfigurationMode(), - rowHeights, - columnWidths)) { + if ( ! gridConfig->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numTabContent, + bwc->getTileTabsConfigurationMode(), + rowHeights, + columnWidths)) { throw OperationException("Tile Tabs Row/Column sizing failed !!!"); } @@ -534,6 +539,13 @@ OperationShowScene::useParameters(OperationParameters* myParams, } viewports.clear(); } + } + else if (manualConfig != NULL) { + CaretAssertToDoFatal(); + } + else { + throw OperationException("Tile tabs configuration is neither Grid nor Manual"); + } } else { CaretPointer brainOpenGL(createBrainOpenGL()); -- GitLab From 96c3a470dc9f9006bcb71c5f8cab5b9d8895b17e Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 26 Jul 2019 15:26:09 -0500 Subject: [PATCH 004/584] In tile tabs dialog, move the class containing the widgets for grid row/columns into its own file. --- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/TileTabGridRowColumnWidgets.cxx | 383 ++++++++++++++++++++++ src/GuiQt/TileTabGridRowColumnWidgets.h | 112 +++++++ src/GuiQt/TileTabsConfigurationDialog.cxx | 342 +------------------ src/GuiQt/TileTabsConfigurationDialog.h | 71 +--- 5 files changed, 509 insertions(+), 402 deletions(-) create mode 100644 src/GuiQt/TileTabGridRowColumnWidgets.cxx create mode 100644 src/GuiQt/TileTabGridRowColumnWidgets.h diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index a1fbd8033..9e2bd576c 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -185,6 +185,7 @@ ELSE() SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h + TileTabGridRowColumnWidgets.h TileTabsConfigurationDialog.h UserInputModeAnnotationsContextMenu.h UserInputModeAnnotationsWidget.h @@ -444,6 +445,7 @@ StructureSurfaceSelectionControl.h SurfacePropertiesEditorDialog.h SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h +TileTabGridRowColumnWidgets.h TileTabsConfigurationDialog.h TileTabsConfigurationModifier.h UserInputModeAbstract.h @@ -716,6 +718,7 @@ StructureSurfaceSelectionControl.cxx SurfacePropertiesEditorDialog.cxx SurfaceSelectionViewController.cxx ThresholdingSetMapsDialog.cxx +TileTabGridRowColumnWidgets.cxx TileTabsConfigurationDialog.cxx TileTabsConfigurationModifier.cxx UserInputModeAbstract.cxx diff --git a/src/GuiQt/TileTabGridRowColumnWidgets.cxx b/src/GuiQt/TileTabGridRowColumnWidgets.cxx new file mode 100644 index 000000000..eb3bf2d09 --- /dev/null +++ b/src/GuiQt/TileTabGridRowColumnWidgets.cxx @@ -0,0 +1,383 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_DECLARE__ +#include "TileTabGridRowColumnWidgets.h" +#undef __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_DECLARE__ + +#include +#include +#include +#include +#include + +#include "CaretAssert.h" +#include "EnumComboBoxTemplate.h" +#include "TileTabsConfigurationDialog.h" +#include "TileTabsGridRowColumnElement.h" +#include "TileTabsLayoutGridConfiguration.h" +#include "WuQGridLayoutGroup.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::TileTabGridRowColumnWidgets + * \brief Contains info about a tile tabs grid row or column + * \ingroup GuiQt + */ + + +/** + * Constructor. + * + * @param tileTabsConfigurationDialog + * The tile tabs configuration dialog. + * @param rowColumnType + * 'Row' or 'Column' + * @param index + * Index of the row/column + * @param gridLayout + * Gridlayout for widgets + * @param parent + * Parent QObject + */ +TileTabGridRowColumnWidgets::TileTabGridRowColumnWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent) +: QObject(parent), +m_tileTabsConfigurationDialog(tileTabsConfigurationDialog), +m_rowColumnType(rowColumnType), +m_index(index), +m_element(NULL) +{ + m_indexLabel = new QLabel(QString::number(m_index + 1)); + m_indexLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + const AString rowColText((rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::ROW) + ? "Row" + : "Column"); + const AString contructionToolTip(WuQtUtilities::createWordWrappedToolTipText("Delete, Duplicate, or Move " + + rowColText)); + const AString contentToolTip(WuQtUtilities::createWordWrappedToolTipText("Content of the " + + rowColText + + ": Spacer (empty space for Annotations) " + "or Tabs (Browser Tabs)")); + const AString typeToolTip(WuQtUtilities::createWordWrappedToolTipText("Type of Stretching: Percent or Weight")); + const AString stretchToolTip(WuQtUtilities::createWordWrappedToolTipText("Value of Stretching Percentage [0, 100] or Stretching Weight")); + + /* + * Construction Tool Button + */ + QIcon constructionIcon; + const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", + constructionIcon); + m_constructionAction = WuQtUtilities::createAction("M", + "Add/Move/Remove", + this); + if (constructionIconValid) { + m_constructionAction->setIcon(constructionIcon); + } + m_constructionToolButton = new QToolButton(); + QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); + QObject::connect(constructionMenu, &QMenu::aboutToShow, + this, &TileTabGridRowColumnWidgets::constructionMenuAboutToShow); + QObject::connect(constructionMenu, &QMenu::triggered, + this, &TileTabGridRowColumnWidgets::constructionMenuTriggered); + m_constructionAction->setMenu(constructionMenu); + m_constructionToolButton->setDefaultAction(m_constructionAction); + m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); + m_constructionToolButton->setFixedWidth(m_constructionToolButton->sizeHint().width()); + m_constructionToolButton->setToolTip(contructionToolTip); + + /* + * Content type combo box + */ + m_contentTypeComboBox = new EnumComboBoxTemplate(this); + m_contentTypeComboBox->setup(); + QObject::connect(m_contentTypeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &TileTabGridRowColumnWidgets::contentTypeActivated); + m_contentTypeComboBox->getComboBox()->setFixedWidth(m_contentTypeComboBox->getComboBox()->sizeHint().width()); + m_contentTypeComboBox->getComboBox()->setToolTip(contentToolTip); + + /* + * Stretch type combo box + */ + m_stretchTypeComboBox = new EnumComboBoxTemplate(this); + m_stretchTypeComboBox->setup(); + QObject::connect(m_stretchTypeComboBox, &EnumComboBoxTemplate::itemActivated, + this, &TileTabGridRowColumnWidgets::stretchTypeActivated); + m_stretchTypeComboBox->getComboBox()->setFixedWidth(m_stretchTypeComboBox->getComboBox()->sizeHint().width()); + m_stretchTypeComboBox->getComboBox()->setToolTip(typeToolTip); + + /* + * Stretch value spin box + */ + m_stretchValueSpinBox = new QDoubleSpinBox(); + m_stretchValueSpinBox->setKeyboardTracking(false); + m_stretchValueSpinBox->setRange(0.0, 1000.0); + m_stretchValueSpinBox->setDecimals(2); + m_stretchValueSpinBox->setSingleStep(0.1); + QObject::connect(m_stretchValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), + this, &TileTabGridRowColumnWidgets::stretchValueChanged); + m_stretchValueSpinBox->setFixedWidth(m_stretchValueSpinBox->sizeHint().width()); + m_stretchValueSpinBox->setToolTip(stretchToolTip); + + m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); + const int32_t rowIndex(gridLayout->rowCount()); + int32_t columnIndex(0); + m_gridLayoutGroup->addWidget(m_indexLabel, rowIndex, columnIndex++, Qt::AlignRight); + m_gridLayoutGroup->addWidget(m_constructionToolButton, rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_contentTypeComboBox->getWidget(), rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_stretchTypeComboBox->getWidget(), rowIndex, columnIndex++); + m_gridLayoutGroup->addWidget(m_stretchValueSpinBox, rowIndex, columnIndex++); +} + +/** + * Destructor. + */ +TileTabGridRowColumnWidgets::~TileTabGridRowColumnWidgets() +{ + +} + +/** + * @return The construction menu. + * + * @param toolButton + * The parent toolbutton. + */ +QMenu* +TileTabGridRowColumnWidgets::createConstructionMenu(QToolButton* toolButton) +{ + const AString deleteText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Delete this Column" + : "Delete this Row"); + + const AString duplicateAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Duplicate this Column to Right" + : "Duplicate this Row Below"); + + const AString duplicateBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Duplicate this Column to Left" + : "Duplicate this Row Above"); + + const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Insert Spacer Column to Right" + : "Insert Spacer Row Below"); + const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Insert Spacer Column to Left" + : "Insert Spacer Row Above"); + const AString moveAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Move this Column to Right" + : "Move this Row Down"); + + const AString moveBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) + ? "Move this Column to Left" + : "Move this Row Up"); + + m_menuDeleteAction = new QAction(deleteText); + m_menuDeleteAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DELETE_IT)); + + m_menuDuplicateAfterAction = new QAction(duplicateAfterText); + m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER)); + + m_menuDuplicateBeforeAction = new QAction(duplicateBeforeText); + m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE)); + + m_insertSpacerAfterAction = new QAction(insertSpacerAfterText); + m_insertSpacerAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER)); + + m_insertSpacerBeforeAction = new QAction(insertSpacerBeforeText); + m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE)); + + m_menuMoveAfterAction = new QAction(moveAfterText); + m_menuMoveAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER)); + + m_menuMoveBeforeAction = new QAction(moveBeforeText); + m_menuMoveBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE)); + + QMenu* menu = new QMenu(toolButton); + menu->addAction(m_menuDuplicateBeforeAction); + menu->addAction(m_menuDuplicateAfterAction); + menu->addSeparator(); + menu->addAction(m_insertSpacerBeforeAction); + menu->addAction(m_insertSpacerAfterAction); + menu->addSeparator(); + menu->addAction(m_menuMoveBeforeAction); + menu->addAction(m_menuMoveAfterAction); + menu->addSeparator(); + menu->addAction(m_menuDeleteAction); + + return menu; +} + +/** + * Update with the given row/column element. + */ +void +TileTabGridRowColumnWidgets::updateContent(TileTabsGridRowColumnElement* element) +{ + m_element = element; + const bool showFlag(m_element != NULL); + + if (showFlag) { + m_contentTypeComboBox->setSelectedItem(element->getContentType()); + m_stretchTypeComboBox->setSelectedItem(element->getStretchType()); + QSignalBlocker valueBlocker(m_stretchValueSpinBox); + switch (m_element->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + m_stretchValueSpinBox->setRange(0.0, 100.0); + m_stretchValueSpinBox->setSingleStep(1.0); + m_stretchValueSpinBox->setValue(m_element->getPercentStretch()); + m_stretchValueSpinBox->setSuffix("%"); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + m_stretchValueSpinBox->setRange(0.0, 1000.0); + m_stretchValueSpinBox->setSingleStep(0.1); + m_stretchValueSpinBox->setValue(m_element->getWeightStretch()); + m_stretchValueSpinBox->setSuffix(""); + break; + } + } + + m_gridLayoutGroup->setVisible(showFlag); +} + +/** + * Called when an item is selected from the construction menu + * + * @param action + * Action that was selected. + */ +void +TileTabGridRowColumnWidgets::constructionMenuTriggered(QAction* action) +{ + if (action != NULL) { + const EventTileTabsGridConfigurationModification::Operation operation + = static_cast(action->data().toInt()); + + /* + * This switch is here so that it will cause a compilation error + * if the operations are changed. + */ + switch (operation) { + case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: + break; + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: + break; + case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: + break; + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: + break; + case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: + break; + case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: + break; + case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: + break; + } + + EventTileTabsGridConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(), + m_index, + m_rowColumnType, + operation); + emit modificationRequested(modification); + } + +} + +/** + * Called when construction menu is about to show. + */ +void +TileTabGridRowColumnWidgets::constructionMenuAboutToShow() +{ + const TileTabsLayoutGridConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(); + if (config != NULL) { + int32_t numItems(-1); + switch (m_rowColumnType) { + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: + numItems = config->getNumberOfColumns(); + break; + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: + numItems = config->getNumberOfRows(); + break; + } + + m_menuDeleteAction->setEnabled(numItems > 1); + m_menuDuplicateAfterAction->setEnabled(numItems >= 1); + m_menuDuplicateBeforeAction->setEnabled(numItems >= 1); + m_menuMoveAfterAction->setEnabled((numItems > 1) + && (m_index < (numItems - 1))); + m_menuMoveBeforeAction->setEnabled((numItems > 1) + && (m_index > 0)); + } +} + + +/** + * Called when content type combo box changed. + */ +void +TileTabGridRowColumnWidgets::contentTypeActivated() +{ + if (m_element != NULL) { + m_element->setContentType(m_contentTypeComboBox->getSelectedItem()); + emit itemChanged(); + } +} + +/** + * Called when stretch type combo box changed. + */ +void +TileTabGridRowColumnWidgets::stretchTypeActivated() +{ + if (m_element != NULL) { + m_element->setStretchType(m_stretchTypeComboBox->getSelectedItem()); + emit itemChanged(); + } +} + +/** + * Called when stretch value changed. + */ +void +TileTabGridRowColumnWidgets::stretchValueChanged(double) +{ + if (m_element != NULL) { + switch (m_element->getStretchType()) { + case TileTabsGridRowColumnStretchTypeEnum::PERCENT: + m_element->setPercentStretch(m_stretchValueSpinBox->value()); + break; + case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: + m_element->setWeightStretch(m_stretchValueSpinBox->value()); + break; + } + emit itemChanged(); + } +} + diff --git a/src/GuiQt/TileTabGridRowColumnWidgets.h b/src/GuiQt/TileTabGridRowColumnWidgets.h new file mode 100644 index 000000000..c77830980 --- /dev/null +++ b/src/GuiQt/TileTabGridRowColumnWidgets.h @@ -0,0 +1,112 @@ +#ifndef __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_H__ +#define __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +#include "EventTileTabsGridConfigurationModification.h" + +class QAction; +class QDoubleSpinBox; +class QGridLayout; +class QLabel; +class QMenu; +class QToolButton; + +namespace caret { + + class EnumComboBoxTemplate; + class TileTabsConfigurationDialog; + class TileTabsGridRowColumnElement; + class WuQGridLayoutGroup; + + /** + * Contains widgets for one row or column of stretching. + */ + class TileTabGridRowColumnWidgets : public QObject { + Q_OBJECT + + public: + TileTabGridRowColumnWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent); + + virtual ~TileTabGridRowColumnWidgets(); + + void updateContent(TileTabsGridRowColumnElement* element); + + signals: + void itemChanged(); + + void modificationRequested(EventTileTabsGridConfigurationModification& modification); + + private slots: + void constructionMenuAboutToShow(); + + void constructionMenuTriggered(QAction*); + + void contentTypeActivated(); + + void stretchTypeActivated(); + + void stretchValueChanged(double); + + private: + QMenu* createConstructionMenu(QToolButton* toolButton); + + TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; + const EventTileTabsGridConfigurationModification::RowColumnType m_rowColumnType; + const int32_t m_index; + TileTabsGridRowColumnElement* m_element; + + QLabel* m_indexLabel; + QAction* m_constructionAction; + QToolButton* m_constructionToolButton; + EnumComboBoxTemplate* m_contentTypeComboBox; + EnumComboBoxTemplate* m_stretchTypeComboBox; + QDoubleSpinBox* m_stretchValueSpinBox; + + QAction* m_menuDeleteAction; + QAction* m_menuDuplicateAfterAction; + QAction* m_menuDuplicateBeforeAction; + QAction* m_insertSpacerAfterAction; + QAction* m_insertSpacerBeforeAction; + QAction* m_menuMoveAfterAction; + QAction* m_menuMoveBeforeAction; + + WuQGridLayoutGroup* m_gridLayoutGroup; + + }; + + +#ifdef __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_DECLARE__ + // +#endif // __TILE_TAB_GRID_ROW_COLUMN_WIDGETS_DECLARE__ + +} // namespace +#endif //__TILE_TAB_GRID_ROW_COLUMN_WIDGETS_H__ diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 33a12d946..06080e2e3 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -56,6 +56,7 @@ #include "TileTabsLayoutGridConfiguration.h" #include "TileTabsLayoutManualConfiguration.h" #include "TileTabsGridRowColumnElement.h" +#include "TileTabGridRowColumnWidgets.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" @@ -640,7 +641,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridCon void TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, - std::vector& elementVector) + std::vector& elementVector) { const int32_t index = static_cast(elementVector.size()); if (index == 0) { @@ -656,14 +657,14 @@ TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsGridCo } } - TileTabElementWidgets* elementWidget = new TileTabElementWidgets(this, + TileTabGridRowColumnWidgets* elementWidget = new TileTabGridRowColumnWidgets(this, rowColumnType, index, gridLayout, this); - QObject::connect(elementWidget, &TileTabElementWidgets::itemChanged, + QObject::connect(elementWidget, &TileTabGridRowColumnWidgets::itemChanged, this, &TileTabsConfigurationDialog::configurationStretchFactorWasChanged); - QObject::connect(elementWidget, &TileTabElementWidgets::modificationRequested, + QObject::connect(elementWidget, &TileTabGridRowColumnWidgets::modificationRequested, this, &TileTabsConfigurationDialog::tileTabsModificationRequested); elementVector.push_back(elementWidget); @@ -1123,336 +1124,3 @@ TileTabsConfigurationDialog::helpButtonClicked() } -/** - * Constructor. - * - * @param tileTabsConfigurationDialog - * The tile tabs configuration dialog. - * @param rowColumnType - * 'Row' or 'Column' - * @param index - * Index of the row/column - * @param gridLayout - * Gridlayout for widgets - * @param parent - * Parent QObject - */ -TileTabElementWidgets::TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, - const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, - const int32_t index, - QGridLayout* gridLayout, - QObject* parent) -: QObject(parent), -m_tileTabsConfigurationDialog(tileTabsConfigurationDialog), -m_rowColumnType(rowColumnType), -m_index(index), -m_element(NULL) -{ - m_indexLabel = new QLabel(QString::number(m_index + 1)); - m_indexLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - const AString rowColText((rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::ROW) - ? "Row" - : "Column"); - const AString contructionToolTip(WuQtUtilities::createWordWrappedToolTipText("Delete, Duplicate, or Move " - + rowColText)); - const AString contentToolTip(WuQtUtilities::createWordWrappedToolTipText("Content of the " - + rowColText - + ": Spacer (empty space for Annotations) " - "or Tabs (Browser Tabs)")); - const AString typeToolTip(WuQtUtilities::createWordWrappedToolTipText("Type of Stretching: Percent or Weight")); - const AString stretchToolTip(WuQtUtilities::createWordWrappedToolTipText("Value of Stretching Percentage [0, 100] or Stretching Weight")); - - /* - * Construction Tool Button - */ - QIcon constructionIcon; - const bool constructionIconValid = WuQtUtilities::loadIcon(":/LayersPanel/construction.png", - constructionIcon); - m_constructionAction = WuQtUtilities::createAction("M", - "Add/Move/Remove", - this); - if (constructionIconValid) { - m_constructionAction->setIcon(constructionIcon); - } - m_constructionToolButton = new QToolButton(); - QMenu* constructionMenu = createConstructionMenu(m_constructionToolButton); - QObject::connect(constructionMenu, &QMenu::aboutToShow, - this, &TileTabElementWidgets::constructionMenuAboutToShow); - QObject::connect(constructionMenu, &QMenu::triggered, - this, &TileTabElementWidgets::constructionMenuTriggered); - m_constructionAction->setMenu(constructionMenu); - m_constructionToolButton->setDefaultAction(m_constructionAction); - m_constructionToolButton->setPopupMode(QToolButton::InstantPopup); - m_constructionToolButton->setFixedWidth(m_constructionToolButton->sizeHint().width()); - m_constructionToolButton->setToolTip(contructionToolTip); - - /* - * Content type combo box - */ - m_contentTypeComboBox = new EnumComboBoxTemplate(this); - m_contentTypeComboBox->setup(); - QObject::connect(m_contentTypeComboBox, &EnumComboBoxTemplate::itemActivated, - this, &TileTabElementWidgets::contentTypeActivated); - m_contentTypeComboBox->getComboBox()->setFixedWidth(m_contentTypeComboBox->getComboBox()->sizeHint().width()); - m_contentTypeComboBox->getComboBox()->setToolTip(contentToolTip); - - /* - * Stretch type combo box - */ - m_stretchTypeComboBox = new EnumComboBoxTemplate(this); - m_stretchTypeComboBox->setup(); - QObject::connect(m_stretchTypeComboBox, &EnumComboBoxTemplate::itemActivated, - this, &TileTabElementWidgets::stretchTypeActivated); - m_stretchTypeComboBox->getComboBox()->setFixedWidth(m_stretchTypeComboBox->getComboBox()->sizeHint().width()); - m_stretchTypeComboBox->getComboBox()->setToolTip(typeToolTip); - - /* - * Stretch value spin box - */ - m_stretchValueSpinBox = new QDoubleSpinBox(); - m_stretchValueSpinBox->setKeyboardTracking(false); - m_stretchValueSpinBox->setRange(0.0, 1000.0); - m_stretchValueSpinBox->setDecimals(2); - m_stretchValueSpinBox->setSingleStep(0.1); - QObject::connect(m_stretchValueSpinBox, static_cast(&QDoubleSpinBox::valueChanged), - this, &TileTabElementWidgets::stretchValueChanged); - m_stretchValueSpinBox->setFixedWidth(m_stretchValueSpinBox->sizeHint().width()); - m_stretchValueSpinBox->setToolTip(stretchToolTip); - - m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); - const int32_t rowIndex(gridLayout->rowCount()); - int32_t columnIndex(0); - m_gridLayoutGroup->addWidget(m_indexLabel, rowIndex, columnIndex++, Qt::AlignRight); - m_gridLayoutGroup->addWidget(m_constructionToolButton, rowIndex, columnIndex++); - m_gridLayoutGroup->addWidget(m_contentTypeComboBox->getWidget(), rowIndex, columnIndex++); - m_gridLayoutGroup->addWidget(m_stretchTypeComboBox->getWidget(), rowIndex, columnIndex++); - m_gridLayoutGroup->addWidget(m_stretchValueSpinBox, rowIndex, columnIndex++); -} - -/** - * Destructor. - */ -TileTabElementWidgets::~TileTabElementWidgets() -{ - -} - -/** - * @return The construction menu. - * - * @param toolButton - * The parent toolbutton. - */ -QMenu* -TileTabElementWidgets::createConstructionMenu(QToolButton* toolButton) -{ - const AString deleteText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Delete this Column" - : "Delete this Row"); - - const AString duplicateAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Duplicate this Column to Right" - : "Duplicate this Row Below"); - - const AString duplicateBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Duplicate this Column to Left" - : "Duplicate this Row Above"); - - const AString insertSpacerAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Insert Spacer Column to Right" - : "Insert Spacer Row Below"); - const AString insertSpacerBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Insert Spacer Column to Left" - : "Insert Spacer Row Above"); - const AString moveAfterText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Move this Column to Right" - : "Move this Row Down"); - - const AString moveBeforeText((m_rowColumnType == EventTileTabsGridConfigurationModification::RowColumnType::COLUMN) - ? "Move this Column to Left" - : "Move this Row Up"); - - m_menuDeleteAction = new QAction(deleteText); - m_menuDeleteAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DELETE_IT)); - - m_menuDuplicateAfterAction = new QAction(duplicateAfterText); - m_menuDuplicateAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER)); - - m_menuDuplicateBeforeAction = new QAction(duplicateBeforeText); - m_menuDuplicateBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE)); - - m_insertSpacerAfterAction = new QAction(insertSpacerAfterText); - m_insertSpacerAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER)); - - m_insertSpacerBeforeAction = new QAction(insertSpacerBeforeText); - m_insertSpacerBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE)); - - m_menuMoveAfterAction = new QAction(moveAfterText); - m_menuMoveAfterAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER)); - - m_menuMoveBeforeAction = new QAction(moveBeforeText); - m_menuMoveBeforeAction->setData(static_cast(EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE)); - - QMenu* menu = new QMenu(toolButton); - menu->addAction(m_menuDuplicateBeforeAction); - menu->addAction(m_menuDuplicateAfterAction); - menu->addSeparator(); - menu->addAction(m_insertSpacerBeforeAction); - menu->addAction(m_insertSpacerAfterAction); - menu->addSeparator(); - menu->addAction(m_menuMoveBeforeAction); - menu->addAction(m_menuMoveAfterAction); - menu->addSeparator(); - menu->addAction(m_menuDeleteAction); - - return menu; -} - -/** - * Update with the given row/column element. - */ -void -TileTabElementWidgets::updateContent(TileTabsGridRowColumnElement* element) -{ - m_element = element; - const bool showFlag(m_element != NULL); - - if (showFlag) { - m_contentTypeComboBox->setSelectedItem(element->getContentType()); - m_stretchTypeComboBox->setSelectedItem(element->getStretchType()); - QSignalBlocker valueBlocker(m_stretchValueSpinBox); - switch (m_element->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - m_stretchValueSpinBox->setRange(0.0, 100.0); - m_stretchValueSpinBox->setSingleStep(1.0); - m_stretchValueSpinBox->setValue(m_element->getPercentStretch()); - m_stretchValueSpinBox->setSuffix("%"); - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - m_stretchValueSpinBox->setRange(0.0, 1000.0); - m_stretchValueSpinBox->setSingleStep(0.1); - m_stretchValueSpinBox->setValue(m_element->getWeightStretch()); - m_stretchValueSpinBox->setSuffix(""); - break; - } - } - - m_gridLayoutGroup->setVisible(showFlag); -} - -/** - * Called when an item is selected from the construction menu - * - * @param action - * Action that was selected. - */ -void -TileTabElementWidgets::constructionMenuTriggered(QAction* action) -{ - if (action != NULL) { - const EventTileTabsGridConfigurationModification::Operation operation - = static_cast(action->data().toInt()); - - /* - * This switch is here so that it will cause a compilation error - * if the operations are changed. - */ - switch (operation) { - case EventTileTabsGridConfigurationModification::Operation::DELETE_IT: - break; - case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_AFTER: - break; - case EventTileTabsGridConfigurationModification::Operation::DUPLICATE_BEFORE: - break; - case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_BEFORE: - break; - case EventTileTabsGridConfigurationModification::Operation::INSERT_SPACER_AFTER: - break; - case EventTileTabsGridConfigurationModification::Operation::MOVE_AFTER: - break; - case EventTileTabsGridConfigurationModification::Operation::MOVE_BEFORE: - break; - } - - EventTileTabsGridConfigurationModification modification(m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(), - m_index, - m_rowColumnType, - operation); - emit modificationRequested(modification); - } - -} - -/** - * Called when construction menu is about to show. - */ -void -TileTabElementWidgets::constructionMenuAboutToShow() -{ - const TileTabsLayoutGridConfiguration* config = m_tileTabsConfigurationDialog->getCustomTileTabsGridConfiguration(); - if (config != NULL) { - int32_t numItems(-1); - switch (m_rowColumnType) { - case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: - numItems = config->getNumberOfColumns(); - break; - case EventTileTabsGridConfigurationModification::RowColumnType::ROW: - numItems = config->getNumberOfRows(); - break; - } - - m_menuDeleteAction->setEnabled(numItems > 1); - m_menuDuplicateAfterAction->setEnabled(numItems >= 1); - m_menuDuplicateBeforeAction->setEnabled(numItems >= 1); - m_menuMoveAfterAction->setEnabled((numItems > 1) - && (m_index < (numItems - 1))); - m_menuMoveBeforeAction->setEnabled((numItems > 1) - && (m_index > 0)); - } -} - - -/** - * Called when content type combo box changed. - */ -void -TileTabElementWidgets::contentTypeActivated() -{ - if (m_element != NULL) { - m_element->setContentType(m_contentTypeComboBox->getSelectedItem()); - emit itemChanged(); - } -} - -/** - * Called when stretch type combo box changed. - */ -void -TileTabElementWidgets::stretchTypeActivated() -{ - if (m_element != NULL) { - m_element->setStretchType(m_stretchTypeComboBox->getSelectedItem()); - emit itemChanged(); - } -} - -/** - * Called when stretch value changed. - */ -void -TileTabElementWidgets::stretchValueChanged(double) -{ - if (m_element != NULL) { - switch (m_element->getStretchType()) { - case TileTabsGridRowColumnStretchTypeEnum::PERCENT: - m_element->setPercentStretch(m_stretchValueSpinBox->value()); - break; - case TileTabsGridRowColumnStretchTypeEnum::WEIGHT: - m_element->setWeightStretch(m_stretchValueSpinBox->value()); - break; - } - emit itemChanged(); - } -} - diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index a229c72ad..aefa58aec 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -47,7 +47,7 @@ namespace caret { class TileTabsLayoutBaseConfiguration; class TileTabsLayoutGridConfiguration; class TileTabsLayoutManualConfiguration; - class TileTabElementWidgets; + class TileTabGridRowColumnWidgets; class TileTabsGridRowColumnElement; class WuQGridLayoutGroup; class WuQListWidget; @@ -132,7 +132,7 @@ namespace caret { void addRowColumnStretchWidget(const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, QGridLayout* gridLayout, - std::vector& elementVector); + std::vector& elementVector); void updateStretchFactors(); @@ -174,9 +174,9 @@ namespace caret { QSpinBox* m_numberOfColumnsSpinBox; - std::vector m_columnElements; + std::vector m_columnElements; - std::vector m_rowElements; + std::vector m_rowElements; QGridLayout* m_rowElementsGridLayout = NULL; @@ -194,72 +194,13 @@ namespace caret { */ CaretPreferences* m_caretPreferences; - friend class TileTabElementWidgets; + friend class TileTabGridRowColumnWidgets; + friend class TileTabGridRowColumnWidgets; static const int32_t s_maximumRowsColumns = 50; }; - /** - * Contains widgets for one row or column of stretching. - */ - class TileTabElementWidgets : public QObject { - Q_OBJECT - - public: - TileTabElementWidgets(TileTabsConfigurationDialog* tileTabsConfigurationDialog, - const EventTileTabsGridConfigurationModification::RowColumnType rowColumnType, - const int32_t index, - QGridLayout* gridLayout, - QObject* parent); - - virtual ~TileTabElementWidgets(); - - void updateContent(TileTabsGridRowColumnElement* element); - - signals: - void itemChanged(); - - void modificationRequested(EventTileTabsGridConfigurationModification& modification); - - private slots: - void constructionMenuAboutToShow(); - - void constructionMenuTriggered(QAction*); - - void contentTypeActivated(); - - void stretchTypeActivated(); - - void stretchValueChanged(double); - - private: - QMenu* createConstructionMenu(QToolButton* toolButton); - - TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; - const EventTileTabsGridConfigurationModification::RowColumnType m_rowColumnType; - const int32_t m_index; - TileTabsGridRowColumnElement* m_element; - - QLabel* m_indexLabel; - QAction* m_constructionAction; - QToolButton* m_constructionToolButton; - EnumComboBoxTemplate* m_contentTypeComboBox; - EnumComboBoxTemplate* m_stretchTypeComboBox; - QDoubleSpinBox* m_stretchValueSpinBox; - - QAction* m_menuDeleteAction; - QAction* m_menuDuplicateAfterAction; - QAction* m_menuDuplicateBeforeAction; - QAction* m_insertSpacerAfterAction; - QAction* m_insertSpacerBeforeAction; - QAction* m_menuMoveAfterAction; - QAction* m_menuMoveBeforeAction; - - WuQGridLayoutGroup* m_gridLayoutGroup; - - }; - #ifdef __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ // const AString TileTabsConfigurationDialog::s_automaticConfigurationPrefix = "Automatic Configuration"; #endif // __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ -- GitLab From 2cc0e735de0bc6fb2ed6f2ddc856745f5d084805 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 12 Aug 2019 14:42:02 -0500 Subject: [PATCH 005/584] WB-859 Manual Tile Tabs Layout System: Continue development. Manual tab layouts and editing through Tile Tabs Dialog is functioning. --- src/Brain/BrainOpenGLViewportContent.cxx | 182 ++++- src/Brain/BrainOpenGLViewportContent.h | 1 - src/Brain/BrowserTabContent.cxx | 36 +- src/Brain/BrowserTabContent.h | 8 + src/Brain/BrowserWindowContent.cxx | 53 +- src/Brain/BrowserWindowContent.h | 10 +- src/Common/CMakeLists.txt | 6 +- src/Common/CaretPreferences.cxx | 2 +- .../TileTabsLayoutBaseConfiguration.cxx | 6 +- src/Common/TileTabsLayoutBaseConfiguration.h | 1 - .../TileTabsLayoutConfigurationTypeEnum.cxx | 9 +- .../TileTabsLayoutGridConfiguration.cxx | 46 +- src/Common/TileTabsLayoutGridConfiguration.h | 10 +- .../TileTabsLayoutManualConfiguration.cxx | 78 +- .../TileTabsLayoutManualConfiguration.h | 15 +- src/GuiQt/BrainBrowserWindow.cxx | 52 +- src/GuiQt/BrainBrowserWindow.h | 5 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 9 +- src/GuiQt/BrainOpenGLWidget.cxx | 79 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/ChartHistoryViewController.cxx | 2 +- src/GuiQt/TileTabGridRowColumnWidgets.h | 2 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 773 ++++++++++++++---- src/GuiQt/TileTabsConfigurationDialog.h | 77 +- 24 files changed, 1084 insertions(+), 381 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 4866836f1..a73044872 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -40,6 +40,7 @@ #include "ModelSurfaceMontage.h" #include "SpacerTabContent.h" #include "SurfaceMontageConfigurationAbstract.h" +#include "TileTabsBrowserTabGeometry.h" #include "TileTabsLayoutGridConfiguration.h" #include "TileTabsLayoutManualConfiguration.h" @@ -612,11 +613,12 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetSelectedTileTabsConfiguration(); - CaretAssert(tileTabsConfiguration); - switch (tileTabsConfiguration->getLayoutType()) { + switch (browserWindowContent->getTileTabsConfigurationMode()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); + CaretAssert(tileTabsConfiguration); viewportContentsOut = createViewportContentForGridTileTabs(tabContents, browserWindowContent, tileTabsConfiguration->castToGridConfiguration(), @@ -624,11 +626,11 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorcastToManualConfiguration(), gapsAndMargins, windowViewport, windowIndex, @@ -956,51 +958,147 @@ BrainOpenGLViewportContent::createViewportContentForGridTileTabs(std::vectorgetTabIndex() == 0) { + std::cout << "TAB 1: " << vpc->toString() << std::endl << std::endl; + } + } + } -// for (auto vpc : viewportContentsOut) { -// if (vpc->getTabIndex() == 0) { -// std::cout << "TAB 1: " << vpc->toString() << std::endl << std::endl; -// } -// } return viewportContentsOut; } - /** - * Create Viewport Contents for the given tab contents, window sizes, and tile sizes - * for a manual configuration. - * - * @param tabContents - * Content of each tab. - * @param browserWindowContent - * Content of window. - * @param manualConfiguration - * The manual configuration - * @param gapsAndMargins - * Contains margins around edges of tabs - * @param windowViewport - * The window's viewport. - * @param windowIndex - * Index of the window. - * @param hightlightTabIndex - * Index of tab that is highlighted when selected by user. - * @return - * Vector containing data for drawing each model. - */ - std::vector - BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vector& tabContents, - BrowserWindowContent* browserWindowContent, - TileTabsLayoutManualConfiguration* manualConfiguration, - const GapsAndMargins* gapsAndMargins, - const int32_t windowViewport[4], - const int32_t windowIndex, - const int32_t highlightTabIndex) - { - std::vector viewportContentsOut; +/** + * Create Viewport Contents for the given tab contents, window sizes, and tile sizes + * for a manual configuration. + * + * @param tabContents + * Content of each tab. + * @param browserWindowContent + * Content of window. + * @param gapsAndMargins + * Contains margins around edges of tabs + * @param windowViewport + * The window's viewport. + * @param windowIndex + * Index of the window. + * @param hightlightTabIndex + * Index of tab that is highlighted when selected by user. + * @return + * Vector containing data for drawing each model. + */ +std::vector +BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vector& tabContents, + BrowserWindowContent* browserWindowContent, + const GapsAndMargins* gapsAndMargins, + const int32_t windowViewport[4], + const int32_t /*windowIndex*/, + const int32_t highlightTabIndex) +{ + const bool allTabsAspectLockedFlag = browserWindowContent->isAllTabsInWindowAspectRatioLocked(); + + std::vector viewportContentsOut; + + CaretAssert(browserWindowContent); + CaretAssert(gapsAndMargins); + + int32_t windowX = windowViewport[0]; + int32_t windowY = windowViewport[1]; + const int32_t windowWidth = windowViewport[2]; + const int32_t windowHeight = windowViewport[3]; + + for (const auto tab : tabContents) { + CaretAssert(tab); - CaretAssertToDoFatal(); + /* + * Tab Geometry is in percentages ranging [0.0, 100.0] + */ + const TileTabsBrowserTabGeometry* tabGeometry = tab->getManualLayoutGeometry(); + int32_t tabX(((tabGeometry->getMinX() / 100.0) * windowWidth) + windowX); + int32_t tabY(((tabGeometry->getMinY() / 100.0) * windowHeight) + windowY); + int32_t tabWidth((tabGeometry->getWidth() / 100.0) * windowWidth); + int32_t tabHeight((tabGeometry->getHeight() / 100.0) * windowHeight); + + /* + * Is aspect ratio locked for all tabs ? + */ + if (allTabsAspectLockedFlag) { + /** + * Update aspect locking for any tabs that have not been locked + * Locking is done here so that it will work for new tabs and + * for tabs from old scenes before "lock all" + * Aspect locking is also performed here so that it works + * with both GUI and Command Line Show Scene + */ + if ( ! tab->isAspectRatioLocked()) { + if (tabWidth > 0) { + const float aspectRatio = (static_cast(tabHeight) + / static_cast(tabWidth)); + + tab->setAspectRatio(aspectRatio); + tab->setAspectRatioLocked(true); + } + } + } - return viewportContentsOut; + /* + * Adjust size of tab to match aspect ratio + */ + if (tab->isAspectRatioLocked()) { + const int32_t nonLockedWidth(tabWidth); + const int32_t nonLockedHeight(tabHeight); + BrainOpenGLViewportContent::adjustWidthHeightForAspectRatio(tab->getAspectRatio(), + tabWidth, + tabHeight); + + /* + * Center tab within its region + */ + const int32_t offsetX = nonLockedWidth - tabWidth; + if (offsetX > 0) { + tabX += (offsetX / 2); + } + + const int32_t offsetY = nonLockedHeight - tabHeight; + if (offsetY > 0) { + tabY += (offsetY / 2); + } + } + + const int tabViewport[4] = { + tabX, + tabY, + tabWidth, + tabHeight + }; + + /* + * Model is drawn in the model viewport inside any margins. + */ + const int32_t tabIndex = tab->getTabNumber(); + const bool highlightTabFlag(highlightTabIndex == tabIndex); + int modelViewport[4] = { 0, 0, 0, 0 }; + createModelViewport(tabViewport, + tabIndex, + gapsAndMargins, + modelViewport); + + SpacerTabContent* invalidSpaceTabContent(NULL); + BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, + tabViewport, + modelViewport, + browserWindowContent->getWindowIndex(), + highlightTabFlag, + tab, + invalidSpaceTabContent); + viewportContentsOut.push_back(vpContent); } + + return viewportContentsOut; +} /** * Create viewport from the model using the tab's viewport and the tabs margins. diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index 2d3db3feb..f822b43ea 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -164,7 +164,6 @@ namespace caret { static std::vector createViewportContentForManualTileTabs(std::vector& tabContents, BrowserWindowContent* browserWindowContent, - TileTabsLayoutManualConfiguration* manualConfiguration, const GapsAndMargins* gapsAndMargins, const int32_t windowViewport[4], const int32_t windowIndex, diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index d26357bc8..41a520c85 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -85,6 +85,7 @@ #include "SurfaceMontageConfigurationFlatMaps.h" #include "SurfaceSelectionModel.h" #include "StructureEnum.h" +#include "TileTabsBrowserTabGeometry.h" #include "VolumeFile.h" #include "ViewingTransformations.h" #include "ViewingTransformationsCerebellum.h" @@ -153,6 +154,8 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_clippingPlaneGroup = new ClippingPlaneGroup(); + m_manualLayoutTabGeometry.reset(new TileTabsBrowserTabGeometry(m_tabNumber)); + m_sceneClassAssistant = new SceneClassAssistant(); m_sceneClassAssistant->add("m_tabNumber", &m_tabNumber); @@ -225,6 +228,9 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) &m_brainModelYokingGroup); m_sceneClassAssistant->add("m_chartModelYokingGroup", &m_chartModelYokingGroup); + + CaretAssertToDoWarning(); // need to save/restore m_manualLayoutTabGeometry + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET); EventManager::get()->addEventListener(this, @@ -1339,7 +1345,6 @@ BrowserTabContent::receiveEvent(Event* event) } break; case VolumeSliceProjectionTypeEnum::VOLUME_SLICE_PROJECTION_OBLIQUE: - //keepSliceCoordinateForSelectedAxis = true; break; } switch (m_volumeSliceSettings->getSliceDrawingType()) { @@ -1371,7 +1376,6 @@ BrowserTabContent::receiveEvent(Event* event) } selectSlicesAtCoordinate(volumeSliceXYZ); - //m_volumeSliceSettings->selectSlicesAtCoordinate(volumeSliceXYZ); } } } @@ -2742,14 +2746,6 @@ BrowserTabContent::applyMouseRotation(BrainOpenGLViewportContent* viewportConten float mouseDelta = std::sqrt(static_cast((mouseDeltaX * mouseDeltaX) + (mouseDeltaY * mouseDeltaY))); - // /* - // * Rotation needs to be oppposite for newer - // * oblique slice drawing for volumes that - // * do not have a voxel corresponding to - // * the origin. - // */ - // mouseDelta = -mouseDelta; - switch (slicePlane) { case VolumeSliceViewPlaneEnum::ALL: { @@ -3652,8 +3648,6 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, m.getRotation(rotationX, rotationY, rotationZ); - //rotationX = -rotationX; - //rotationY = 180.0 - rotationY; rotationY = 90 + rotationY; rotationZ = -rotationZ; m.identity(); @@ -4961,6 +4955,24 @@ BrowserTabContent::updateChartModelYokedBrowserTabs() } } +/** + * @return Pointer to the manual layout geometry + */ +TileTabsBrowserTabGeometry* +BrowserTabContent::getManualLayoutGeometry() +{ + return m_manualLayoutTabGeometry.get(); +} + +/** + * @return Pointer to the manual layout geometry (const method) + */ +const TileTabsBrowserTabGeometry* +BrowserTabContent::getManualLayoutGeometry() const +{ + return m_manualLayoutTabGeometry.get(); +} + diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index d9babb5bf..3f40f1ce9 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -63,6 +63,7 @@ namespace caret { class PlainTextStringBuilder; class SceneClassAssistant; class Surface; + class TileTabsBrowserTabGeometry; class ViewingTransformations; class ViewingTransformationsCerebellum; class ViewingTransformationsVolume; @@ -441,6 +442,10 @@ namespace caret { const ViewingTransformations* getViewingTransformation() const; + TileTabsBrowserTabGeometry* getManualLayoutGeometry(); + + const TileTabsBrowserTabGeometry* getManualLayoutGeometry() const; + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -596,6 +601,9 @@ namespace caret { */ bool isExecutingConstructor; + /** Manual tab layout geometry */ + std::unique_ptr m_manualLayoutTabGeometry; + /** Contains all active browser tab content instances */ static std::set s_allBrowserTabContent; diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index 837e5e072..703394d5d 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -47,8 +47,8 @@ BrowserWindowContent::BrowserWindowContent(const int32_t windowIndex) : CaretObject(), m_windowIndex(windowIndex) { - m_automaticGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); - m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); + m_automaticGridTileTabsConfiguration.reset(TileTabsLayoutGridConfiguration::newInstanceAutomaticGrid()); + m_customGridTileTabsConfiguration.reset(TileTabsLayoutGridConfiguration::newInstanceCustomGrid()); m_validFlag = false; reset(); @@ -58,8 +58,8 @@ m_windowIndex(windowIndex) m_sceneAssistant->add("m_windowAspectLockedRatio", &m_windowAspectLockedRatio); m_sceneAssistant->add("m_allTabsInWindowAspectRatioLocked", &m_allTabsInWindowAspectRatioLocked); m_sceneAssistant->add("m_tileTabsEnabled", &m_tileTabsEnabled); - m_sceneAssistant->add("m_tileTabsConfigurationMode", - &m_tileTabsConfigurationMode); + m_sceneAssistant->add("m_tileTabsConfigurationMode", + &m_tileTabsConfigurationMode); m_sceneAssistant->add("m_sceneGraphicsWidth", &m_sceneGraphicsWidth); m_sceneAssistant->add("m_sceneGraphicsHeight", &m_sceneGraphicsHeight); m_sceneAssistant->add("m_sceneSelectedTabIndex", &m_sceneSelectedTabIndex); @@ -108,7 +108,7 @@ BrowserWindowContent::reset() m_tileTabsEnabled = false; m_sceneGraphicsHeight = 0; m_sceneGraphicsWidth = 0; - m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID; m_automaticGridTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); /* sets rows/columns/factors to defaults */ m_customGridTileTabsConfiguration->updateAutomaticConfigurationRowsAndColumns(1); @@ -222,12 +222,15 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() TileTabsLayoutBaseConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: configMode = m_automaticGridTileTabsConfiguration.get(); break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: configMode = m_customGridTileTabsConfiguration.get(); break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + return NULL; + break; } CaretAssert(configMode); @@ -245,18 +248,30 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() const TileTabsLayoutBaseConfiguration* configMode = NULL; switch (m_tileTabsConfigurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: configMode = m_automaticGridTileTabsConfiguration.get(); break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: configMode = m_customGridTileTabsConfiguration.get(); break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssertToDoFatal(); + break; } CaretAssert(configMode); return configMode; } +/** + * @return The automatic grid tile tabs configuration + */ +TileTabsLayoutGridConfiguration* +BrowserWindowContent::getAutomaticGridTileTabsConfiguration() +{ + return m_automaticGridTileTabsConfiguration.get(); +} + /** * @return The automatic grid tile tabs configuration (const method) */ @@ -304,7 +319,7 @@ BrowserWindowContent::setCustomGridTileTabsConfiguration(const TileTabsLayoutGri /** * @return The tile tabs configuration mode. */ -TileTabsGridModeEnum::Enum +TileTabsLayoutConfigurationTypeEnum::Enum BrowserWindowContent::getTileTabsConfigurationMode() const { return m_tileTabsConfigurationMode; @@ -317,7 +332,7 @@ BrowserWindowContent::getTileTabsConfigurationMode() const * New value for configuration mode. */ void -BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode) +BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsLayoutConfigurationTypeEnum::Enum configMode) { m_tileTabsConfigurationMode = configMode; } @@ -539,7 +554,7 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, + "\" from BrowserWindowContent: \"" + tileTabsConfig + "\""); - m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); + m_customGridTileTabsConfiguration.reset(TileTabsLayoutGridConfiguration::newInstanceCustomGrid()); } /* @@ -555,10 +570,10 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, if (oldTileTabsAutoPrimitive != NULL) { const bool autoModeSelected = oldTileTabsAutoPrimitive->booleanValue(); if (autoModeSelected) { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID; } else { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID; } } @@ -568,10 +583,10 @@ BrowserWindowContent::restoreFromScene(const SceneAttributes* sceneAttributes, * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID; } else { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID; } } @@ -648,7 +663,7 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute + "\" from BrowserWindowContent: \"" + tileTabsConfigString + "\""); - m_customGridTileTabsConfiguration.reset(new TileTabsLayoutGridConfiguration()); + m_customGridTileTabsConfiguration.reset(TileTabsLayoutGridConfiguration::newInstanceCustomGrid()); } } @@ -670,10 +685,10 @@ BrowserWindowContent::restoreFromOldBrainBrowserWindowScene(const SceneAttribute * If tile tabs was enabled, use CUSTOM, otherwise AUTOMATIC */ if (m_tileTabsEnabled) { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::CUSTOM; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID; } else { - m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; + m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID; } } diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index b0e33cbdc..0e57304c1 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -28,7 +28,7 @@ #include "CaretObject.h" #include "SceneableInterface.h" -#include "TileTabsGridModeEnum.h" +#include "TileTabsLayoutConfigurationTypeEnum.h" namespace caret { class SceneClassAssistant; @@ -70,6 +70,8 @@ namespace caret { const TileTabsLayoutBaseConfiguration* getSelectedTileTabsConfiguration() const; + TileTabsLayoutGridConfiguration* getAutomaticGridTileTabsConfiguration(); + const TileTabsLayoutGridConfiguration* getAutomaticGridTileTabsConfiguration() const; TileTabsLayoutGridConfiguration* getCustomGridTileTabsConfiguration(); @@ -78,9 +80,9 @@ namespace caret { void setCustomGridTileTabsConfiguration(const TileTabsLayoutGridConfiguration* gridConfiguration); - TileTabsGridModeEnum::Enum getTileTabsConfigurationMode() const; + TileTabsLayoutConfigurationTypeEnum::Enum getTileTabsConfigurationMode() const; - void setTileTabsConfigurationMode(const TileTabsGridModeEnum::Enum configMode); + void setTileTabsConfigurationMode(const TileTabsLayoutConfigurationTypeEnum::Enum configMode); int32_t getSceneGraphicsWidth() const; @@ -143,7 +145,7 @@ namespace caret { bool m_tileTabsEnabled = false; - TileTabsGridModeEnum::Enum m_tileTabsConfigurationMode = TileTabsGridModeEnum::AUTOMATIC; + TileTabsLayoutConfigurationTypeEnum::Enum m_tileTabsConfigurationMode = TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID; int32_t m_sceneGraphicsWidth = 0; diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index d106fb766..5ceda0007 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -152,13 +152,12 @@ StereotaxicSpaceEnum.h StringTableModel.h StructureEnum.h SystemUtilities.h +TileTabsBrowserTabGeometry.h TileTabsLayoutBackgroundTypeEnum.h TileTabsLayoutBaseConfiguration.h TileTabsLayoutConfigurationTypeEnum.h TileTabsLayoutGridConfiguration.h TileTabsLayoutManualConfiguration.h -TileTabsLayoutTabInfo.h -TileTabsGridModeEnum.h TileTabsGridRowColumnContentTypeEnum.h TileTabsGridRowColumnElement.h TileTabsGridRowColumnStretchTypeEnum.h @@ -279,13 +278,12 @@ StereotaxicSpaceEnum.cxx StringTableModel.cxx StructureEnum.cxx SystemUtilities.cxx +TileTabsBrowserTabGeometry.cxx TileTabsLayoutBackgroundTypeEnum.cxx TileTabsLayoutBaseConfiguration.cxx TileTabsLayoutConfigurationTypeEnum.cxx TileTabsLayoutGridConfiguration.cxx TileTabsLayoutManualConfiguration.cxx -TileTabsLayoutTabInfo.cxx -TileTabsGridModeEnum.cxx TileTabsGridRowColumnContentTypeEnum.cxx TileTabsGridRowColumnElement.cxx TileTabsGridRowColumnStretchTypeEnum.cxx diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index de2675659..f8da799e0 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -524,7 +524,7 @@ CaretPreferences::readTileTabsUserConfigurations(const bool performSync) } TileTabsLayoutManualConfiguration* manualLayout = TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(gridConfig, - TileTabsGridModeEnum::CUSTOM, + TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID, tabIndices); if (manualLayout != NULL) { std::cout << "MANUAL VERSION OF GRID LAYOUT: " << std::endl; diff --git a/src/Common/TileTabsLayoutBaseConfiguration.cxx b/src/Common/TileTabsLayoutBaseConfiguration.cxx index d00d5f771..345eb31a5 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.cxx +++ b/src/Common/TileTabsLayoutBaseConfiguration.cxx @@ -124,7 +124,7 @@ TileTabsLayoutBaseConfiguration::copyHelperTileTabsLayoutBaseConfiguration(const } m_name = obj.m_name; - //DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier + /* DO NOT CHANGE THE UNIQUE IDENTIFIER: m_uniqueIdentifier */ } /** @@ -231,13 +231,13 @@ TileTabsLayoutBaseConfiguration::decodeFromXML(const AString& xmlString, if (xml.readNextStartElement()) { const QStringRef tagName(xml.name()); if (tagName == TileTabsLayoutGridConfiguration::s_v1_rootTagName) { - TileTabsLayoutGridConfiguration* v1 = new TileTabsLayoutGridConfiguration(); + TileTabsLayoutGridConfiguration* v1 = TileTabsLayoutGridConfiguration::newInstanceCustomGrid(); v1->decodeFromXMLString(xml, tagName.toString()); configurationOut = v1; } else if (tagName == TileTabsLayoutGridConfiguration::s_v2_rootTagName) { - TileTabsLayoutGridConfiguration* v2 = new TileTabsLayoutGridConfiguration(); + TileTabsLayoutGridConfiguration* v2 = TileTabsLayoutGridConfiguration::newInstanceCustomGrid(); v2->decodeFromXMLString(xml, tagName.toString()); configurationOut = v2; diff --git a/src/Common/TileTabsLayoutBaseConfiguration.h b/src/Common/TileTabsLayoutBaseConfiguration.h index 2769d1084..e37a1d800 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.h +++ b/src/Common/TileTabsLayoutBaseConfiguration.h @@ -24,7 +24,6 @@ #include "CaretException.h" #include "CaretObject.h" #include "TileTabsLayoutConfigurationTypeEnum.h" -#include "TileTabsGridModeEnum.h" #include "TileTabsGridRowColumnElement.h" class QXmlStreamReader; diff --git a/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx b/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx index eb0eec546..017a23d91 100644 --- a/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx +++ b/src/Common/TileTabsLayoutConfigurationTypeEnum.cxx @@ -106,6 +106,10 @@ TileTabsLayoutConfigurationTypeEnum::initialize() } initializedFlag = true; + enumData.push_back(TileTabsLayoutConfigurationTypeEnum(AUTOMATIC_GRID, + "AUTOMATIC_GRID", + "Automatic Grid")); + enumData.push_back(TileTabsLayoutConfigurationTypeEnum(CUSTOM_GRID, "CUSTOM_GRID", "Custom Grid")); @@ -170,7 +174,7 @@ TileTabsLayoutConfigurationTypeEnum::fromName(const AString& nameIn, bool* isVal if (initializedFlag == false) initialize(); /* - * Convert names from older versions of tile tab layouts + * Convert names from older versions of tile tab layout's TileTabsGridModeEnum */ QString name(nameIn); if (name == "AUTOMATIC") { @@ -211,7 +215,8 @@ TileTabsLayoutConfigurationTypeEnum::fromName(const AString& nameIn, bool* isVal * String representing enumerated value. */ AString -TileTabsLayoutConfigurationTypeEnum::toGuiName(Enum enumValue) { +TileTabsLayoutConfigurationTypeEnum::toGuiName(Enum enumValue) +{ if (initializedFlag == false) initialize(); const TileTabsLayoutConfigurationTypeEnum* enumInstance = findData(enumValue); diff --git a/src/Common/TileTabsLayoutGridConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx index 71194afaf..1b0e84cee 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -43,12 +43,42 @@ using namespace caret; * \ingroup Common */ +/** + * @return A new instance containing a automatic grid configuration + */ +TileTabsLayoutGridConfiguration* +TileTabsLayoutGridConfiguration::newInstanceAutomaticGrid() +{ + TileTabsLayoutGridConfiguration* config = new TileTabsLayoutGridConfiguration(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID); + return config; +} + +/** + * @return A new instance containing a custom grid configuration + */ +TileTabsLayoutGridConfiguration* +TileTabsLayoutGridConfiguration::newInstanceCustomGrid() +{ + TileTabsLayoutGridConfiguration* config = new TileTabsLayoutGridConfiguration(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); + return config; +} + /** * Constructor that creates a 2 by 2 configuration. */ -TileTabsLayoutGridConfiguration::TileTabsLayoutGridConfiguration() -: TileTabsLayoutBaseConfiguration(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID) +TileTabsLayoutGridConfiguration::TileTabsLayoutGridConfiguration(const TileTabsLayoutConfigurationTypeEnum::Enum gridConfigType) +: TileTabsLayoutBaseConfiguration(gridConfigType) { + switch (gridConfigType) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssert(0); + break; + } + initialize(); } @@ -235,7 +265,7 @@ bool TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, - const TileTabsGridModeEnum::Enum configurationMode, + const TileTabsLayoutConfigurationTypeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut) { @@ -254,7 +284,7 @@ TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const columnWidthsOut.clear(); switch (configurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: { /* * Update number of rows/columns in the default configuration @@ -271,8 +301,9 @@ TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const for (int32_t i = 0; i < numCols; i++) { columnWidthsOut.push_back(windowWidth / numCols); } - } break; - case TileTabsGridModeEnum::CUSTOM: + } + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: { /* * Rows/columns from user configuration @@ -368,6 +399,9 @@ TileTabsLayoutGridConfiguration::getRowHeightsAndColumnWidthsForWindowSize(const columnWidthsOut.push_back(w); } } break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + CaretAssert(0); + break; } if ((numRows == static_cast(rowHeightsOut.size())) diff --git a/src/Common/TileTabsLayoutGridConfiguration.h b/src/Common/TileTabsLayoutGridConfiguration.h index 031f52554..e776f47fa 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.h +++ b/src/Common/TileTabsLayoutGridConfiguration.h @@ -23,7 +23,7 @@ #include "CaretException.h" #include "TileTabsLayoutBaseConfiguration.h" -#include "TileTabsGridModeEnum.h" +#include "TileTabsLayoutConfigurationTypeEnum.h" #include "TileTabsGridRowColumnElement.h" class QXmlStreamReader; @@ -34,7 +34,11 @@ namespace caret { class TileTabsLayoutGridConfiguration : public TileTabsLayoutBaseConfiguration { public: - TileTabsLayoutGridConfiguration(); + static TileTabsLayoutGridConfiguration* newInstanceAutomaticGrid(); + + static TileTabsLayoutGridConfiguration* newInstanceCustomGrid(); + + TileTabsLayoutGridConfiguration(const TileTabsLayoutConfigurationTypeEnum::Enum gridConfigType); virtual ~TileTabsLayoutGridConfiguration(); @@ -49,7 +53,7 @@ namespace caret { bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, - const TileTabsGridModeEnum::Enum configurationMode, + const TileTabsLayoutConfigurationTypeEnum::Enum configurationMode, std::vector& rowHeightsOut, std::vector& columnWidthsOut); diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx index 54e367918..e1bb722be 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.cxx +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -33,7 +33,7 @@ #include "CaretLogger.h" #include "SystemUtilities.h" #include "TileTabsLayoutGridConfiguration.h" -#include "TileTabsLayoutTabInfo.h" +#include "TileTabsBrowserTabGeometry.h" using namespace caret; @@ -98,7 +98,7 @@ TileTabsLayoutManualConfiguration::copyHelperTileTabsLayoutManualConfiguration(c m_tabInfo.clear(); for (const auto& ti : obj.m_tabInfo) { - TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(*ti); + TileTabsBrowserTabGeometry* tabInfo = new TileTabsBrowserTabGeometry(*ti); addTabInfo(tabInfo); } } @@ -154,7 +154,7 @@ TileTabsLayoutManualConfiguration::newCopyWithNewUniqueIdentifier() const */ TileTabsLayoutManualConfiguration* TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(TileTabsLayoutGridConfiguration* gridLayout, - const TileTabsGridModeEnum::Enum gridMode, + const TileTabsLayoutConfigurationTypeEnum::Enum gridMode, const std::vector& tabIndices) { CaretAssert(gridLayout); @@ -191,29 +191,45 @@ TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(TileTabsLayoutGridC const float height = rowHeights[i]; yBottom -= height; - float xLeft(0.0); - for (int32_t j = 0; j < numCols; j++) { - CaretAssertVectorIndex(columnWidths, j); - const float width = columnWidths[j]; - - CaretAssertVectorIndex(tabIndices, tabCounter); - const int32_t tabIndex(tabIndices[tabCounter]); - - const float centerX = xLeft + (width / 2.0); - const float centerY = yBottom + (height / 2.0); - TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(tabIndex); - tabInfo->setCenterX((centerX / windowWidth) * 100.0f); - tabInfo->setCenterY((centerY / windowHeight) * 100.0f); - tabInfo->setWidth((width / windowWidth) * 100.0f); - tabInfo->setHeight((height / windowHeight) * 100.0f); - tabInfo->setStackingOrder(tabCounter); - tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); - - manualLayout->addTabInfo(tabInfo); - - xLeft += width; - - tabCounter++; + switch (gridLayout->getRow(i)->getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + { + float xLeft(0.0); + for (int32_t j = 0; j < numCols; j++) { + CaretAssertVectorIndex(columnWidths, j); + const float width = columnWidths[j]; + + switch (gridLayout->getColumn(j)->getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + { + CaretAssertVectorIndex(tabIndices, tabCounter); + const int32_t tabIndex(tabIndices[tabCounter]); + + const float centerX = xLeft + (width / 2.0); + const float centerY = yBottom + (height / 2.0); + TileTabsBrowserTabGeometry* tabInfo = new TileTabsBrowserTabGeometry(tabIndex); + tabInfo->setCenterX((centerX / windowWidth) * 100.0f); + tabInfo->setCenterY((centerY / windowHeight) * 100.0f); + tabInfo->setWidth((width / windowWidth) * 100.0f); + tabInfo->setHeight((height / windowHeight) * 100.0f); + tabInfo->setStackingOrder(tabCounter); + tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); + + manualLayout->addTabInfo(tabInfo); + + tabCounter++; + } + break; + } + + xLeft += width; + } + } + break; } } @@ -232,9 +248,9 @@ TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(TileTabsLayoutGridC * Tab info to add. */ void -TileTabsLayoutManualConfiguration::addTabInfo(TileTabsLayoutTabInfo* tabInfo) +TileTabsLayoutManualConfiguration::addTabInfo(TileTabsBrowserTabGeometry* tabInfo) { - std::unique_ptr ptr(tabInfo); + std::unique_ptr ptr(tabInfo); m_tabInfo.push_back(std::move(ptr)); } @@ -253,7 +269,7 @@ TileTabsLayoutManualConfiguration::getNumberOfTabs() const * @param index * Index of the tab info */ -TileTabsLayoutTabInfo* +TileTabsBrowserTabGeometry* TileTabsLayoutManualConfiguration::getTabInfo(const int32_t index) { CaretAssertVectorIndex(m_tabInfo, index); @@ -266,7 +282,7 @@ TileTabsLayoutManualConfiguration::getTabInfo(const int32_t index) * @param index * Index of the tab info */ -const TileTabsLayoutTabInfo* +const TileTabsBrowserTabGeometry* TileTabsLayoutManualConfiguration::getTabInfo(const int32_t index) const { CaretAssertVectorIndex(m_tabInfo, index); @@ -415,7 +431,7 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, const QString backStr = atts.value(s_tabInfoAttributeBackground).toString(); const TileTabsLayoutBackgroundTypeEnum::Enum backType = TileTabsLayoutBackgroundTypeEnum::fromName(backStr, NULL); - TileTabsLayoutTabInfo* tabInfo = new TileTabsLayoutTabInfo(tabIndex); + TileTabsBrowserTabGeometry* tabInfo = new TileTabsBrowserTabGeometry(tabIndex); tabInfo->setCenterX(xCenter); tabInfo->setCenterY(yCenter); tabInfo->setWidth(width); diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h index 82528d9bd..6e99d4cd7 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.h +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -26,18 +26,19 @@ #include #include "TileTabsLayoutBaseConfiguration.h" -#include "TileTabsGridModeEnum.h" +#include "TileTabsLayoutConfigurationTypeEnum.h" namespace caret { + class BrowserTabContent; class TileTabsLayoutGridConfiguration; - class TileTabsLayoutTabInfo; + class TileTabsBrowserTabGeometry; class TileTabsLayoutManualConfiguration : public TileTabsLayoutBaseConfiguration { public: static TileTabsLayoutManualConfiguration* newInstanceFromGridLayout(TileTabsLayoutGridConfiguration* gridLayout, - const TileTabsGridModeEnum::Enum gridMode, + const TileTabsLayoutConfigurationTypeEnum::Enum gridMode, const std::vector& tabIndices); TileTabsLayoutManualConfiguration(); @@ -54,13 +55,13 @@ namespace caret { virtual AString toString() const override; - void addTabInfo(TileTabsLayoutTabInfo* tabInfo); + void addTabInfo(TileTabsBrowserTabGeometry* tabInfo); int32_t getNumberOfTabs() const; - TileTabsLayoutTabInfo* getTabInfo(const int32_t index); + TileTabsBrowserTabGeometry* getTabInfo(const int32_t index); - const TileTabsLayoutTabInfo* getTabInfo(const int32_t index) const; + const TileTabsBrowserTabGeometry* getTabInfo(const int32_t index) const; virtual TileTabsLayoutManualConfiguration* castToManualConfiguration() override; @@ -77,7 +78,7 @@ namespace caret { private: void copyHelperTileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj); - std::vector> m_tabInfo; + std::vector> m_tabInfo; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 7dc39102e..455462285 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -1493,10 +1493,15 @@ BrainBrowserWindow::createActions() this); m_viewCustomTileTabsConfigurationAction->setCheckable(true); + m_viewManualTileTabsConfigurationAction = new QAction("Manual", + this); + m_viewManualTileTabsConfigurationAction->setCheckable(true); + QActionGroup* autoCustomGroup = new QActionGroup(this); autoCustomGroup->setExclusive(true); autoCustomGroup->addAction(m_viewAutomaticTileTabsConfigurationAction); autoCustomGroup->addAction(m_viewCustomTileTabsConfigurationAction); + autoCustomGroup->addAction(m_viewManualTileTabsConfigurationAction); QObject::connect(autoCustomGroup, &QActionGroup::triggered, this, &BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered); @@ -2451,19 +2456,24 @@ BrainBrowserWindow::processViewMenuAboutToShow() m_viewTileTabsAction->setText("Enter Tile Tabs"); } - m_viewAutomaticTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, - true)); - m_viewCustomTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, - true)); - + m_viewAutomaticTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID, + true)); + m_viewCustomTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID, + true)); + m_viewManualTileTabsConfigurationAction->setText(getTileTabsConfigurationLabelText(TileTabsLayoutConfigurationTypeEnum::MANUAL, + true)); + BrowserWindowContent* bwc = getBrowerWindowContent(); switch (bwc->getTileTabsConfigurationMode()) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: m_viewAutomaticTileTabsConfigurationAction->setChecked(true); break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: m_viewCustomTileTabsConfigurationAction->setChecked(true); break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + m_viewManualTileTabsConfigurationAction->setChecked(true); + break; } } @@ -2477,18 +2487,21 @@ BrainBrowserWindow::processViewMenuAboutToShow() * Include the number of rows and columns. */ AString -BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, +BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsLayoutConfigurationTypeEnum::Enum configurationMode, const bool includeRowsAndColumnsIn) const { bool includeRowsAndColumns = includeRowsAndColumnsIn; AString modeLabel; switch (configurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: modeLabel = "Automatic Grid"; break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: modeLabel = "Custom Grid"; break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + modeLabel = "Manual"; + break; } std::vector windowTabIndices; @@ -2498,12 +2511,12 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum const int32_t windowTabCount = static_cast(windowTabIndices.size()); AString errorText; switch (configurationMode) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: TileTabsLayoutGridConfiguration::getRowsAndColumnsForNumberOfTabs(windowTabCount, configRowCount, configColCount); break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: { const TileTabsLayoutGridConfiguration* customConfig = getBrowerWindowContent()->getCustomGridTileTabsConfiguration(); configRowCount = customConfig->getNumberOfRows(); @@ -2517,6 +2530,9 @@ BrainBrowserWindow::getTileTabsConfigurationLabelText(const TileTabsGridModeEnum } } break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + includeRowsAndColumns = false; + break; } AString rowsColumnsText; @@ -2612,10 +2628,13 @@ BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered(QAction* action) { BrowserWindowContent* bwc = getBrowerWindowContent(); if (action == m_viewAutomaticTileTabsConfigurationAction) { - bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); + bwc->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID); } else if (action == m_viewCustomTileTabsConfigurationAction) { - bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); + bwc->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); + } + else if (action == m_viewManualTileTabsConfigurationAction) { + bwc->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::MANUAL); } else { CaretAssert(0); @@ -2636,7 +2655,7 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QA const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); BrowserWindowContent* bwc = getBrowerWindowContent(); - bwc->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); + bwc->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); AString tileTabsConfigID; for (auto& config : m_viewCustomTileTabsConfigurationActions) { @@ -2700,9 +2719,10 @@ BrainBrowserWindow::createMenuView() QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(processViewMenuAboutToShow())); - QMenu* tileTabsModeMenu = new QMenu("Tile Tabs Configuration Mode"); + QMenu* tileTabsModeMenu = new QMenu("Tile Tabs Configuration Layout"); tileTabsModeMenu->addAction(m_viewAutomaticTileTabsConfigurationAction); tileTabsModeMenu->addAction(m_viewCustomTileTabsConfigurationAction); + tileTabsModeMenu->addAction(m_viewManualTileTabsConfigurationAction); m_viewMoveFeaturesToolBoxMenu = createMenuViewMoveFeaturesToolBox(); m_viewMoveOverlayToolBoxMenu = createMenuViewMoveOverlayToolBox(); diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index a285377ca..c7b212bd0 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -32,7 +32,7 @@ #include "DataFileTypeEnum.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" -#include "TileTabsGridModeEnum.h" +#include "TileTabsLayoutConfigurationTypeEnum.h" class QAction; class QActionGroup; @@ -150,7 +150,7 @@ namespace caret { bool isOpenGLContextSharingValid() const; - AString getTileTabsConfigurationLabelText(const TileTabsGridModeEnum::Enum configurationMode, + AString getTileTabsConfigurationLabelText(const TileTabsLayoutConfigurationTypeEnum::Enum configurationMode, const bool includeRowsAndColumns) const; void resizeDockWidgets(const QList &docks, const QList &sizes, Qt::Orientation orientation); @@ -391,6 +391,7 @@ namespace caret { QAction* m_viewTileTabsConfigurationDialogAction; QAction* m_viewAutomaticTileTabsConfigurationAction; QAction* m_viewCustomTileTabsConfigurationAction; + QAction* m_viewManualTileTabsConfigurationAction; std::vector> m_viewCustomTileTabsConfigurationActions; QAction* m_gapsAndMarginsAction; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f223183d2..e841a5013 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -956,13 +956,16 @@ BrainBrowserWindowToolBar::allowAddingNewTab() } /* - * Automatic configuration always shows all tabs + * Automatic configuration and manual configuration always show all tabs */ switch (browserWindowContent->getTileTabsConfigurationMode()) { - case TileTabsGridModeEnum::AUTOMATIC: + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: return true; break; - case TileTabsGridModeEnum::CUSTOM: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + return true; break; } diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 24bfb3ab0..7b17f780d 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -572,33 +572,59 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], BrowserWindowContent* browserWindowContent = getModelEvent.getBrowserWindowContent(); CaretAssert(browserWindowContent); + if (browserWindowContent->isTileTabsEnabled() && (numberOfTabs > 1)) { const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; - std::vector rowHeights; - std::vector columnsWidths; - - /* - * Determine if default configuration for tiles - */ - TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); - CaretAssert(tileTabsConfiguration); - - TileTabsLayoutGridConfiguration* gridConfiguration = tileTabsConfiguration->castToGridConfiguration(); - TileTabsLayoutManualConfiguration* manualConfiguration = tileTabsConfiguration->castToManualConfiguration(); - if (gridConfiguration != NULL) { - /* - * Get the sizes of the tab tiles from the tile tabs configuration - */ - if (gridConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numberOfTabs, - browserWindowContent->getTileTabsConfigurationMode(), - rowHeights, - columnsWidths)) { + const TileTabsLayoutConfigurationTypeEnum::Enum tileTabsConfigType = browserWindowContent->getTileTabsConfigurationMode(); + switch (tileTabsConfigType) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + std::vector rowHeights; + std::vector columnsWidths; + + /* + * Determine if default configuration for tiles + */ + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); + CaretAssert(tileTabsConfiguration); + TileTabsLayoutGridConfiguration* gridConfiguration = tileTabsConfiguration->castToGridConfiguration(); + CaretAssert(gridConfiguration); + if (gridConfiguration != NULL) { + /* + * Get the sizes of the tab tiles from the tile tabs configuration + */ + if (gridConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numberOfTabs, + browserWindowContent->getTileTabsConfigurationMode(), + rowHeights, + columnsWidths)) { + + /* + * Create the viewport drawing contents for all tabs + */ + std::vector tabViewportContent = BrainOpenGLViewportContent::createViewportContentForTileTabs(allTabs, + browserWindowContent, + gapsAndMargins, + windowViewport, + this->windowIndex, + getModelEvent.getTabIndexForTileTabsHighlighting()); + for (auto tabvp : tabViewportContent) { + windowContent.addTabViewport(tabvp); + } + } + else { + CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); + } + } + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: /* * Create the viewport drawing contents for all tabs */ @@ -611,16 +637,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], for (auto tabvp : tabViewportContent) { windowContent.addTabViewport(tabvp); } - } - else { - CaretLogSevere("Tile Tabs Row/Column sizing failed !!!"); - } - } - else if (manualConfiguration != NULL) { - CaretAssertToDoFatal(); - } - else { - CaretAssert(0); + break; } } else if (numberOfTabs >= 1) { diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 9e2bd576c..7adfdb533 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -187,6 +187,7 @@ ELSE() ThresholdingSetMapsDialog.h TileTabGridRowColumnWidgets.h TileTabsConfigurationDialog.h + TileTabsManualTabGeometryWidget.h UserInputModeAnnotationsContextMenu.h UserInputModeAnnotationsWidget.h UserInputModeBordersWidget.h @@ -448,6 +449,7 @@ ThresholdingSetMapsDialog.h TileTabGridRowColumnWidgets.h TileTabsConfigurationDialog.h TileTabsConfigurationModifier.h +TileTabsManualTabGeometryWidget.h UserInputModeAbstract.h UserInputModeAnnotations.h UserInputModeAnnotationsContextMenu.h @@ -721,6 +723,7 @@ ThresholdingSetMapsDialog.cxx TileTabGridRowColumnWidgets.cxx TileTabsConfigurationDialog.cxx TileTabsConfigurationModifier.cxx +TileTabsManualTabGeometryWidget.cxx UserInputModeAbstract.cxx UserInputModeAnnotations.cxx UserInputModeAnnotationsContextMenu.cxx diff --git a/src/GuiQt/ChartHistoryViewController.cxx b/src/GuiQt/ChartHistoryViewController.cxx index 997293d8e..1a0c5ceba 100644 --- a/src/GuiQt/ChartHistoryViewController.cxx +++ b/src/GuiQt/ChartHistoryViewController.cxx @@ -595,7 +595,7 @@ ChartHistoryViewController::chartDataConstructionToolButtonSignalMapped(int indx else if (selectedAction == removeAction) { chartModel->removeChartAtIndex(indx); } - else { + else if (selectedAction != NULL) { CaretAssertMessage(0, "Has a new action been added but not processed?"); } diff --git a/src/GuiQt/TileTabGridRowColumnWidgets.h b/src/GuiQt/TileTabGridRowColumnWidgets.h index c77830980..7dda2d9b4 100644 --- a/src/GuiQt/TileTabGridRowColumnWidgets.h +++ b/src/GuiQt/TileTabGridRowColumnWidgets.h @@ -65,7 +65,7 @@ namespace caret { void modificationRequested(EventTileTabsGridConfigurationModification& modification); - private slots: + private slots: void constructionMenuAboutToShow(); void constructionMenuTriggered(QAction*); diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 06080e2e3..05cf67ac7 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -19,6 +19,8 @@ */ /*LICENSE_END*/ +#include + #include #include #include @@ -32,6 +34,7 @@ #include #include #include +#include #include #include @@ -42,6 +45,7 @@ #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" +#include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretPreferences.h" @@ -52,14 +56,18 @@ #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "GuiManager.h" +#include "MathFunctions.h" #include "SessionManager.h" +#include "TileTabsBrowserTabGeometry.h" #include "TileTabsLayoutGridConfiguration.h" #include "TileTabsLayoutManualConfiguration.h" +#include "TileTabsManualTabGeometryWidget.h" #include "TileTabsGridRowColumnElement.h" #include "TileTabGridRowColumnWidgets.h" #include "WuQDataEntryDialog.h" #include "WuQFactory.h" #include "WuQGridLayoutGroup.h" +#include "WuQDataEntryDialog.h" #include "WuQListWidget.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -87,31 +95,37 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par m_blockReadConfigurationsFromPreferences = false; m_caretPreferences = SessionManager::get()->getCaretPreferences(); + QWidget* workbenchWindowWidget = createWorkbenchWindowWidget(); - QWidget* dialogWidget = new QWidget(); - QHBoxLayout* configurationLayout = new QHBoxLayout(dialogWidget); - configurationLayout->setSpacing(0); - configurationLayout->addWidget(createActiveConfigurationWidget(), - 0); - configurationLayout->addWidget(createCopyLoadPushButtonsWidget(), - 0, - Qt::AlignTop); - configurationLayout->addWidget(createUserConfigurationSelectionWidget(), - 100, - Qt::AlignTop); setApplyButtonText(""); setStandardButtonText(QDialogButtonBox::Help, "Help"); - updateDialogWithSelectedTileTabsFromWindow(parentBrainBrowserWindow); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + QWidget* dialogWidget = new QWidget(); + QGridLayout* dialogLayout = new QGridLayout(dialogWidget); + dialogLayout->setColumnStretch(0, 0); + dialogLayout->setColumnStretch(1, 0); + dialogLayout->setColumnStretch(2, 100); + dialogLayout->addWidget(workbenchWindowWidget, + 0, 0, Qt::AlignLeft); + dialogLayout->addWidget(createConfigurationTypeWidget(), + 1, 0); + dialogLayout->addWidget(createConfigurationSettingsWidget(), + 2, 0); + dialogLayout->addWidget(createCopyLoadPushButtonsWidget(), + 1, 1, 2, 1); + dialogLayout->addWidget(createUserConfigurationSelectionWidget(), + 1, 2, 2, 1); + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); - resize(750, + updateDialogWithSelectedTileTabsFromWindow(parentBrainBrowserWindow); + + resize(900, 500); disableAutoDefaultForAllPushButtons(); @@ -162,38 +176,37 @@ TileTabsConfigurationDialog::focusGained() QWidget* TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() { - m_addPushButton = new QPushButton("Add -->"); - m_addPushButton->setAutoDefault(false); - WuQtUtilities::setWordWrappedToolTip(m_addPushButton, - "Add a new User Configuration containing the Rows, Columns, and Stretch Factors " - "with those from the Custom Configuration"); - QObject::connect(m_addPushButton, SIGNAL(clicked()), + m_addConfigurationPushButton = new QPushButton("Add -->"); + m_addConfigurationPushButton->setAutoDefault(false); + WuQtUtilities::setWordWrappedToolTip(m_addConfigurationPushButton, + "Create a new User Configuration containg the Configuration Settings. " + "A dialog is displayed to enter the name."); + QObject::connect(m_addConfigurationPushButton, SIGNAL(clicked()), this, SLOT(addUserConfigurationPushButtonClicked())); - m_replacePushButton = new QPushButton("Replace -->"); - m_replacePushButton->setAutoDefault(false); - WuQtUtilities::setWordWrappedToolTip(m_replacePushButton, - "Replace the Rows, Columns, and Stretch Factors in the User Configuration " - "with those from the Custom Configuration"); - QObject::connect(m_replacePushButton, SIGNAL(clicked()), + m_replaceConfigurationPushButton = new QPushButton("Replace -->"); + m_replaceConfigurationPushButton->setAutoDefault(false); + WuQtUtilities::setWordWrappedToolTip(m_replaceConfigurationPushButton, + "Replace the User Configuration with the Configuration Settings."); + QObject::connect(m_replaceConfigurationPushButton, SIGNAL(clicked()), this, SLOT(replaceUserConfigurationPushButtonClicked())); - m_loadPushButton = new QPushButton("<-- Load"); - m_loadPushButton->setAutoDefault(false); - WuQtUtilities::setWordWrappedToolTip(m_loadPushButton, - "Load the User Configuration's Rows, Columns, and Stretch Factors into " - "the Custom Configuration"); - QObject::connect(m_loadPushButton, SIGNAL(clicked()), + m_loadConfigurationPushButton = new QPushButton("<-- Load"); + m_loadConfigurationPushButton->setAutoDefault(false); + WuQtUtilities::setWordWrappedToolTip(m_loadConfigurationPushButton, + "Load the selected User Configuration into the Configuration Type and Settings."); + QObject::connect(m_loadConfigurationPushButton, SIGNAL(clicked()), this, SLOT(loadIntoActiveConfigurationPushButtonClicked())); QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); layout->addSpacing(50); - layout->addWidget(m_addPushButton); + layout->addWidget(m_addConfigurationPushButton); layout->addSpacing(10); - layout->addWidget(m_replacePushButton); + layout->addWidget(m_replaceConfigurationPushButton); layout->addSpacing(50); - layout->addWidget(m_loadPushButton); + layout->addWidget(m_loadConfigurationPushButton); layout->addStretch(); return widget; @@ -264,7 +277,7 @@ TileTabsConfigurationDialog::getNewConfigurationName(QWidget* dialogParent) void TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() { - const AString newConfigName = getNewConfigurationName(m_addPushButton); + const AString newConfigName = getNewConfigurationName(m_addConfigurationPushButton); if (newConfigName.isEmpty()) { return; } @@ -300,7 +313,7 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() } else { const AString msg("Do you want to replace the configuration?"); - if ( ! WuQMessageBox::warningOkCancel(m_replacePushButton, + if ( ! WuQMessageBox::warningOkCancel(m_replaceConfigurationPushButton, msg)) { m_blockReadConfigurationsFromPreferences = false; return; @@ -313,7 +326,7 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() if ( ! m_caretPreferences->replaceTileTabsUserConfiguration(tileTabsUniqueID, activeConfiguration, errorMessage)) { - WuQMessageBox::errorOk(m_replacePushButton, + WuQMessageBox::errorOk(m_replaceConfigurationPushButton, errorMessage); } @@ -327,19 +340,19 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() void TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() { - if (m_automaticConfigurationRadioButton->isChecked()) { + if (m_automaticGridConfigurationRadioButton->isChecked()) { return; } const AString userConfigID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); if (userConfigID.isEmpty()) { - WuQMessageBox::errorOk(this, "No user configuration is selected."); + WuQMessageBox::errorOk(m_loadConfigurationPushButton, "No user configuration is selected."); return; } std::unique_ptr userConfiguration = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(userConfigID); if ( ! userConfiguration) { - WuQMessageBox::errorOk(this, + WuQMessageBox::errorOk(m_loadConfigurationPushButton, ("User configuration with UniqueID=" + userConfigID + " was not found")); @@ -364,7 +377,8 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() break; } - updateStretchFactors(); + updateGridStretchFactors(); + updateManualGeometryEditorWidget(); updateGraphicsWindow(); } @@ -473,7 +487,7 @@ TileTabsConfigurationDialog::createWorkbenchWindowWidget() * @return The rows/columns stretch layout */ QWidget* -TileTabsConfigurationDialog::createCustomOptionsWidget() +TileTabsConfigurationDialog::createGridCustomOptionsWidget() { const QString toolTip("" "Removes any space between rows and columns in the tile tabs configuration. " @@ -482,14 +496,14 @@ TileTabsConfigurationDialog::createCustomOptionsWidget() "problem. In addition, if the Lock Aspect option is selected prior to " "to enabling tile tabs, this option may improve the layout." ""); - m_centeringCorrectionCheckBox = new QCheckBox("Centering Correction"); - m_centeringCorrectionCheckBox->setToolTip(toolTip); - QObject::connect(m_centeringCorrectionCheckBox, &QCheckBox::clicked, + m_gridCenteringCorrectionCheckBox = new QCheckBox("Custom Grid Centering Correction"); + m_gridCenteringCorrectionCheckBox->setToolTip(toolTip); + QObject::connect(m_gridCenteringCorrectionCheckBox, &QCheckBox::clicked, this, &TileTabsConfigurationDialog::centeringCorrectionCheckBoxClicked); QGroupBox* groupBox = new QGroupBox("Options"); QVBoxLayout* layout = new QVBoxLayout(groupBox); - layout->addWidget(m_centeringCorrectionCheckBox); + layout->addWidget(m_gridCenteringCorrectionCheckBox); return groupBox; } @@ -518,7 +532,7 @@ TileTabsConfigurationDialog::updateCustomOptionsWidget() { const TileTabsLayoutGridConfiguration* config = getCustomTileTabsGridConfiguration(); if (config != NULL) { - m_centeringCorrectionCheckBox->setChecked(config->isCenteringCorrectionEnabled()); + m_gridCenteringCorrectionCheckBox->setChecked(config->isCenteringCorrectionEnabled()); } } @@ -526,23 +540,61 @@ TileTabsConfigurationDialog::updateCustomOptionsWidget() * @return The rows/columns stretch layout */ QWidget* -TileTabsConfigurationDialog::createRowColumnStretchWidget() +TileTabsConfigurationDialog::createGridRowColumnStretchWidget() { - QGroupBox* rowGroupBox = new QGroupBox("Rows"); - rowGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_rowElementsGridLayout = new QGridLayout(rowGroupBox); - WuQtUtilities::setLayoutSpacingAndMargins(m_rowElementsGridLayout, 4, 2); + /* + * Set number of rows + */ + QLabel* numberOfRowsLabel = new QLabel("Rows"); + m_numberOfGridRowsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, + s_maximumRowsColumns, + 1, + this, + SLOT(gridConfigurationNumberOfRowsOrColumnsChanged())); + m_numberOfGridRowsSpinBox->setToolTip("Number of rows for the tab configuration"); - QGroupBox* columnsGroupBox = new QGroupBox("Columns"); - m_columnElementsGridLayout = new QGridLayout(columnsGroupBox); - WuQtUtilities::setLayoutSpacingAndMargins(m_columnElementsGridLayout, 2, 2); + /* + * Edit content of rows + */ + QGroupBox* rowGroupBox = new QGroupBox(); + rowGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_gridRowElementsGridLayout = new QGridLayout(rowGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(m_gridRowElementsGridLayout, 4, 2); + + /* + * Set number of columns + */ + QLabel* numberOfColumnsLabel = new QLabel("Columns"); + m_numberOfGridColumnsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, + s_maximumRowsColumns, + 1, + this, + SLOT(gridConfigurationNumberOfRowsOrColumnsChanged())); + m_numberOfGridColumnsSpinBox->setToolTip("Number of columns for the tab configuration"); + QGroupBox* columnsGroupBox = new QGroupBox(); + columnsGroupBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_gridColumnElementsGridLayout = new QGridLayout(columnsGroupBox); + WuQtUtilities::setLayoutSpacingAndMargins(m_gridColumnElementsGridLayout, 2, 2); + + QHBoxLayout* rowsColumnsCountLayout = new QHBoxLayout(); + rowsColumnsCountLayout->setContentsMargins(0, 0, 0, 0); + rowsColumnsCountLayout->addWidget(numberOfRowsLabel); + rowsColumnsCountLayout->addWidget(m_numberOfGridRowsSpinBox); + rowsColumnsCountLayout->addWidget(numberOfColumnsLabel); + rowsColumnsCountLayout->addWidget(m_numberOfGridColumnsSpinBox); + rowsColumnsCountLayout->addStretch(); + + QWidget* customGridOptionsWidget = createGridCustomOptionsWidget(); + customGridOptionsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + QWidget* widget = new QWidget; QVBoxLayout* layout = new QVBoxLayout(widget); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(rowGroupBox); - layout->addSpacing(6); - layout->addWidget(columnsGroupBox); + layout->setSpacing(4); + layout->addLayout(rowsColumnsCountLayout, 0); + layout->addWidget(rowGroupBox, 0, Qt::AlignLeft); + layout->addWidget(columnsGroupBox, 0, Qt::AlignLeft); + layout->addWidget(customGridOptionsWidget, 0, Qt::AlignLeft); layout->addStretch(); return widget; @@ -562,7 +614,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridCon */ { const int32_t numRows = configuration->getNumberOfRows(); - int32_t numRowElements = static_cast(m_rowElements.size()); + int32_t numRowElements = static_cast(m_gridRowElements.size()); /** * Add elements as needed. @@ -570,25 +622,25 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridCon const int32_t numToAdd = numRows - numRowElements; for (int32_t iRow = 0; iRow < numToAdd; iRow++) { addRowColumnStretchWidget(EventTileTabsGridConfigurationModification::RowColumnType::ROW, - m_rowElementsGridLayout, - m_rowElements); + m_gridRowElementsGridLayout, + m_gridRowElements); } /* * Update widgets with element content */ - numRowElements = static_cast(m_rowElements.size()); + numRowElements = static_cast(m_gridRowElements.size()); for (int32_t iRow = 0; iRow < numRowElements; iRow++) { TileTabsGridRowColumnElement* element(NULL); if (iRow < numRows) { element = configuration->getRow(iRow); } - CaretAssertVectorIndex(m_rowElements, iRow); - m_rowElements[iRow]->updateContent(element); + CaretAssertVectorIndex(m_gridRowElements, iRow); + m_gridRowElements[iRow]->updateContent(element); } - m_rowElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + m_gridRowElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); } /* @@ -596,7 +648,7 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridCon */ { const int32_t numColumns = configuration->getNumberOfColumns(); - int32_t numColumnElements = static_cast(m_columnElements.size()); + int32_t numColumnElements = static_cast(m_gridColumnElements.size()); /** * Add elements as needed. @@ -604,25 +656,25 @@ TileTabsConfigurationDialog::updateRowColumnStretchWidgets(TileTabsLayoutGridCon const int32_t numToAdd = numColumns - numColumnElements; for (int32_t iColumn = 0; iColumn < numToAdd; iColumn++) { addRowColumnStretchWidget(EventTileTabsGridConfigurationModification::RowColumnType::COLUMN, - m_columnElementsGridLayout, - m_columnElements); + m_gridColumnElementsGridLayout, + m_gridColumnElements); } /* * Update widgets with element content */ - numColumnElements = static_cast(m_columnElements.size()); + numColumnElements = static_cast(m_gridColumnElements.size()); for (int32_t iColumn = 0; iColumn < numColumnElements; iColumn++) { TileTabsGridRowColumnElement* element(NULL); if (iColumn < numColumns) { element = configuration->getColumn(iColumn); } - CaretAssertVectorIndex(m_columnElements, iColumn); - m_columnElements[iColumn]->updateContent(element); + CaretAssertVectorIndex(m_gridColumnElements, iColumn); + m_gridColumnElements[iColumn]->updateContent(element); } - m_columnElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); + m_gridColumnElementsGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); } updateCustomOptionsWidget(); @@ -645,10 +697,19 @@ TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsGridCo { const int32_t index = static_cast(elementVector.size()); if (index == 0) { + QString title("Index"); + switch (rowColumnType) { + case EventTileTabsGridConfigurationModification::RowColumnType::COLUMN: + title = "Column"; + break; + case EventTileTabsGridConfigurationModification::RowColumnType::ROW: + title = "Row"; + break; + } int32_t columnIndex(0); int32_t row = gridLayout->rowCount(); - gridLayout->addWidget(new QLabel("Index"), row, columnIndex++, Qt::AlignRight); - gridLayout->addWidget(new QLabel(" "), row, columnIndex++); + gridLayout->addWidget(new QLabel(title), row, columnIndex++, 1, 2, Qt::AlignHCenter); + columnIndex++; gridLayout->addWidget(new QLabel("Content"), row, columnIndex++, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Type"), row, columnIndex++, Qt::AlignHCenter); gridLayout->addWidget(new QLabel("Stretch"), row, columnIndex++, Qt::AlignHCenter); @@ -663,97 +724,432 @@ TileTabsConfigurationDialog::addRowColumnStretchWidget(const EventTileTabsGridCo gridLayout, this); QObject::connect(elementWidget, &TileTabGridRowColumnWidgets::itemChanged, - this, &TileTabsConfigurationDialog::configurationStretchFactorWasChanged); + this, &TileTabsConfigurationDialog::gridConfigurationStretchFactorWasChanged); QObject::connect(elementWidget, &TileTabGridRowColumnWidgets::modificationRequested, this, &TileTabsConfigurationDialog::tileTabsModificationRequested); elementVector.push_back(elementWidget); } +/** + * Update the widget for manual geometry editing + */ +void +TileTabsConfigurationDialog::updateManualGeometryEditorWidget() +{ + BrainBrowserWindow* window = getBrowserWindow(); + CaretAssert(window); + std::vector allBrowserTabs; + window->getAllTabContent(allBrowserTabs); + + const int32_t numTabs = static_cast(allBrowserTabs.size()); + int32_t numWidgets = static_cast(m_manualGeometryEditorWidgets.size()); + + /* + * Add elements as needed + */ + const int32_t numToAdd = numTabs - numWidgets; + for (int32_t j = 0; j < numToAdd; j++) { + addManualGeometryWidget(m_manualGeometryGridLayout, + m_manualGeometryEditorWidgets); + } + + /* + * Update with element contents + */ + numWidgets = static_cast(m_manualGeometryEditorWidgets.size()); + for (int32_t iRow = 0; iRow < numWidgets; iRow++) { + + BrowserTabContent* tabContent(NULL); + if (iRow < numTabs) { + tabContent = allBrowserTabs[iRow]; + } + + m_manualGeometryEditorWidgets[iRow]->updateContent(tabContent); + } + + m_manualGeometryGridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); +} + +/** + * Called when the geomety is changed in a manual configuration + */ +void +TileTabsConfigurationDialog::manualConfigurationGeometryChanged() +{ + updateGraphicsWindow(); +} + +/** + * Add a manual geometry widget + * + * @param gridLayout + * The Qt layout + * @param widgetsVector + * Vector containing the manual editing widgets + */ +void +TileTabsConfigurationDialog::addManualGeometryWidget(QGridLayout* gridLayout, + std::vector& widgetsVector) +{ + const int32_t index = static_cast(widgetsVector.size()); + if (index == 0) { + int32_t columnIndex(0); + int32_t rowIndex = gridLayout->rowCount(); + + gridLayout->setHorizontalSpacing(8); + gridLayout->addWidget(new QLabel("Tab"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Left"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Right"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Bottom"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Top"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Order"), rowIndex, columnIndex++, Qt::AlignLeft); + } + + TileTabsManualTabGeometryWidget* geometryWidget = new TileTabsManualTabGeometryWidget(this, + index, + gridLayout, + this); + QObject::connect(geometryWidget, &TileTabsManualTabGeometryWidget::itemChanged, + this, &TileTabsConfigurationDialog::manualConfigurationGeometryChanged); + + widgetsVector.push_back(geometryWidget); +} + +/** + * @return New instance of the manual configuration tool button + */ +QToolButton* +TileTabsConfigurationDialog::createManualConfigurationSetToolButton() +{ + QToolButton* toolButton = new QToolButton(); + toolButton->setText("Set..."); + QObject::connect(toolButton, &QToolButton::clicked, + this, &TileTabsConfigurationDialog::manualConfigurationSetToolButtonClicked); + + return toolButton; +} + +/** + * Called when manual configuration set tool button is clicked + */ +void +TileTabsConfigurationDialog::manualConfigurationSetToolButtonClicked() +{ + QMenu menu(m_manualConfigurationSetButton); + QAction* setAutomaticGridAction = menu.addAction("Replace with Automatic Grid"); + QAction* setCustomGridAction = menu.addAction("Replace with Custom Grid"); + QAction* setColumnsAction = menu.addAction("Reset with Grid..."); + + QAction* selectedAction = menu.exec(m_manualConfigurationSetButton->mapToGlobal(QPoint(0,0))); + if (selectedAction == setColumnsAction) { + manualConfigurationSetMenuColumnsItemTriggered(); + } + else if (selectedAction == setAutomaticGridAction) { + manualConfigurationSetMenuFromAutomaticItemTriggered(); + } + else if (selectedAction == setCustomGridAction) { + manualConfigurationSetMenuFromCustomItemTriggered(); + } + else if (selectedAction != NULL) { + CaretAssertMessage(0, "Has a new action been added but not processed?"); + } + + updateDialog(); +} + +/** + * Called when manual configuration set columns menu item triggered + */ +void +TileTabsConfigurationDialog::manualConfigurationSetMenuColumnsItemTriggered() +{ + WuQDataEntryDialog ded("Set Columns for Manual Layout", + m_manualConfigurationSetButton); + QSpinBox* columnsSpinBox = ded.addSpinBox("Number of Columns", 2); + columnsSpinBox->setMinimum(1); + columnsSpinBox->setMaximum(100); + columnsSpinBox->setSingleStep(1); + const bool wrapTextFlag(true); + ded.setTextAtTop("Enter number of columns. Number of rows will sufficient to show all tabs.", + wrapTextFlag); + if (ded.exec() == WuQDataEntryDialog::Accepted) { + const int32_t numberOfColumns = columnsSpinBox->value(); + CaretAssert(numberOfColumns >= 1); + + const BrainBrowserWindow* window = getBrowserWindow(); + CaretAssert(window); + + std::vector allTabContent; + window->getAllTabContent(allTabContent); + const int32_t numberOfTabs = static_cast(allTabContent.size()); + + /* + * Note: Coordinates of manual tab geometry are in percentages [0, 100] + */ + const int32_t windowWidth(100); + const int32_t windowHeight(100); + if (numberOfTabs == 1) { + CaretAssertVectorIndex(allTabContent, 0); + TileTabsBrowserTabGeometry* tabGeom = allTabContent[0]->getManualLayoutGeometry(); + CaretAssert(tabGeom); + tabGeom->setMinX(0); + tabGeom->setMaxX(windowWidth); + tabGeom->setMinY(0); + tabGeom->setMaxY(windowHeight); + } + else if (numberOfTabs > 1) { + const int32_t remainder = (numberOfTabs % numberOfColumns); + int32_t numberOfRows = (numberOfTabs / numberOfColumns); + if (remainder > 0) { + numberOfRows++; + } + const int32_t tabWidth = (windowWidth / numberOfColumns); + const int32_t tabHeight = (windowHeight / numberOfRows); + int32_t tabY = windowHeight - tabHeight; + + int32_t tabContentIndex = 0; + for (int32_t iRow = 0; iRow < numberOfRows; iRow++) { + int32_t tabX = 0; + for (int32_t iCol = 0; iCol < numberOfColumns; iCol++) { + if (tabContentIndex < numberOfTabs) { + CaretAssertVectorIndex(allTabContent, tabContentIndex); + TileTabsBrowserTabGeometry* tabGeom = allTabContent[tabContentIndex]->getManualLayoutGeometry(); + CaretAssert(tabGeom); + tabGeom->setMinX(tabX); + tabGeom->setMaxX(tabX + tabWidth); + tabGeom->setMinY(tabY); + tabGeom->setMaxY(tabY + tabHeight); + } + + tabContentIndex++; + tabX += tabWidth; + } + + tabY -= tabHeight; + } + } + + updateDialog(); + updateGraphicsWindow(); + } +} + +/** + * Called when manual configuration set from automatic grid menu item is triggered + */ +void +TileTabsConfigurationDialog::manualConfigurationSetMenuFromAutomaticItemTriggered() +{ + BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); + TileTabsLayoutGridConfiguration* gridConfiguration = browserWindowContent->getAutomaticGridTileTabsConfiguration(); + CaretAssert(gridConfiguration); + manualConfigurationSetMenuFromGridConfiguration(gridConfiguration); +} + +/** + * Called when manual configuration set from custom grid menu item is triggered + */ +void +TileTabsConfigurationDialog::manualConfigurationSetMenuFromCustomItemTriggered() +{ + TileTabsLayoutGridConfiguration* gridConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(gridConfiguration); + manualConfigurationSetMenuFromGridConfiguration(gridConfiguration); +} /** - * @return The active configuration widget. + * Update the manual configuration to match a grid configuration + * + * @param gridConfiguration + * The grid configuration */ +void +TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(TileTabsLayoutGridConfiguration* gridConfiguration) +{ + const BrainBrowserWindow* window = getBrowserWindow(); + CaretAssert(window); + + std::vector allTabContent; + window->getAllTabContent(allTabContent); + const int32_t numTabs = static_cast(allTabContent.size()); + if (numTabs <= 0) { + return; + } + + const int32_t windowWidth(100); + const int32_t windowHeight(100); + std::vector rowHeightsInt; + std::vector columnWidthsInt; + + if (gridConfiguration->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numTabs, + gridConfiguration->getLayoutType(), + rowHeightsInt, + columnWidthsInt)) { + const int32_t numRows = static_cast(rowHeightsInt.size()); + const int32_t numCols = static_cast(columnWidthsInt.size()); + + const float rowSum = std::accumulate(rowHeightsInt.begin(), rowHeightsInt.end(), 0.0f); + std::vector rowHeights; + for (int32_t iRow = 0; iRow < numRows; iRow++) { + if (rowSum > 0.0) { + rowHeights.push_back((rowHeightsInt[iRow] / rowSum) * 100.0); + } + else { + rowHeights.push_back(rowHeightsInt[iRow]); + } + } + CaretAssert(rowHeights.size() == rowHeightsInt.size()); + + const float columnSum = std::accumulate(columnWidthsInt.begin(), columnWidthsInt.end(), 0.0f); + std::vector columnWidths; + for (int32_t iCol = 0; iCol < numCols; iCol++) { + if (columnSum > 0.0) { + columnWidths.push_back((columnWidthsInt[iCol] / columnSum) * 100.0); + } + else { + columnWidths.push_back(columnWidthsInt[iCol]); + } + } + CaretAssert(columnWidths.size() == columnWidthsInt.size()); + + TileTabsLayoutManualConfiguration* manualLayout = new TileTabsLayoutManualConfiguration(); + manualLayout->setName("From row:" + + AString::number(rowHeights.size()) + + " col:" + + AString::number(columnWidths.size())); + + int32_t tabCounter(0); + float yBottom(windowHeight); + for (int32_t i = 0; i < numRows; i++) { + CaretAssertVectorIndex(rowHeights, i); + const float height = rowHeights[i]; + yBottom -= height; + + switch (gridConfiguration->getRow(i)->getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + { + float xLeft(0.0); + for (int32_t j = 0; j < numCols; j++) { + CaretAssertVectorIndex(columnWidths, j); + const float width = columnWidths[j]; + + switch (gridConfiguration->getColumn(j)->getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + { + CaretAssertVectorIndex(allTabContent, tabCounter); + BrowserTabContent* tabContent(allTabContent[tabCounter]); + + TileTabsBrowserTabGeometry* tabInfo = tabContent->getManualLayoutGeometry(); + tabInfo->setMinX((xLeft / windowWidth) * 100.0); + tabInfo->setMaxX(((xLeft + width) / windowWidth) * 100.0); + tabInfo->setMinY((yBottom / windowHeight) * 100.0); + tabInfo->setMaxY(((yBottom + height) / windowHeight) * 100.0); + + tabInfo->setStackingOrder(tabCounter); + tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); + + tabCounter++; + } + break; + } + + xLeft += width; + } + } + break; + } + } + } + + updateDialog(); + updateGraphicsWindow(); +} + QWidget* -TileTabsConfigurationDialog::createActiveConfigurationWidget() +TileTabsConfigurationDialog::createConfigurationTypeWidget() { const AString autoToolTip("Workbench adjusts the number of rows and columns so " "that all tabs are displayed"); - m_automaticConfigurationRadioButton = new QRadioButton("Automatic Configuration"); - m_automaticConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(autoToolTip)); + m_automaticGridConfigurationRadioButton = new QRadioButton("Automatic Configuration"); + m_automaticGridConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(autoToolTip)); const AString customToolTip("User sets the number of row, columns, and stretch factors"); - m_customConfigurationRadioButton = new QRadioButton("Custom Configuration"); - m_customConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customToolTip)); + m_customGridConfigurationRadioButton = new QRadioButton("Custom Configuration"); + m_customGridConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(customToolTip)); + + const AString manualToolTip("User sets positions and sizes of all tabs"); + m_manualConfigurationRadioButton = new QRadioButton("Manual"); + m_manualConfigurationRadioButton->setToolTip(WuQtUtilities::createWordWrappedToolTipText(manualToolTip)); QButtonGroup* buttonGroup = new QButtonGroup(this); - buttonGroup->addButton(m_automaticConfigurationRadioButton); - buttonGroup->addButton(m_customConfigurationRadioButton); + buttonGroup->addButton(m_automaticGridConfigurationRadioButton); + buttonGroup->addButton(m_customGridConfigurationRadioButton); + buttonGroup->addButton(m_manualConfigurationRadioButton); QObject::connect(buttonGroup, static_cast(&QButtonGroup::buttonClicked), this, &TileTabsConfigurationDialog::automaticCustomButtonClicked); - QLabel* rowsLabel = new QLabel("Rows"); - m_numberOfRowsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, - s_maximumRowsColumns, - 1, - this, - SLOT(configurationNumberOfRowsOrColumnsChanged())); - m_numberOfRowsSpinBox->setToolTip("Number of rows for the tab configuration"); + m_manualConfigurationSetButton = createManualConfigurationSetToolButton(); + + QGroupBox* layoutTypeGroupBox = new QGroupBox("Configuration Type"); + QGridLayout* buttonTypeLayout = new QGridLayout(layoutTypeGroupBox); + buttonTypeLayout->setColumnStretch(0, 0); + buttonTypeLayout->setColumnStretch(1, 0); + buttonTypeLayout->setColumnStretch(2, 100); + buttonTypeLayout->addWidget(m_automaticGridConfigurationRadioButton, + 0, 0, 1, 3, Qt::AlignLeft); + buttonTypeLayout->addWidget(m_customGridConfigurationRadioButton, + 1, 0, 1, 3, Qt::AlignLeft); + buttonTypeLayout->addWidget(m_manualConfigurationRadioButton, + 2, 0, 1, 1); + buttonTypeLayout->addWidget(m_manualConfigurationSetButton, + 2, 1, 1, 2, Qt::AlignLeft); + + return layoutTypeGroupBox; +} + +QWidget* +TileTabsConfigurationDialog::createConfigurationSettingsWidget() +{ + m_customGridConfigurationWidget = createGridRowColumnStretchWidget(); + m_customGridConfigurationWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - QLabel* columnsLabel = new QLabel("Columns"); - m_numberOfColumnsSpinBox = WuQFactory::newSpinBoxWithMinMaxStepSignalInt(1, - s_maximumRowsColumns, - 1, - this, - SLOT(configurationNumberOfRowsOrColumnsChanged())); - m_numberOfColumnsSpinBox->setToolTip("Number of columns for the tab configuration"); + m_manualGeometryWidget = createManualGeometryEditingWidget(); - m_customConfigurationWidget = createRowColumnStretchWidget(); - m_customConfigurationWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_editConfigurationStackedWidget = new QStackedWidget(); + m_editConfigurationStackedWidget->addWidget(m_customGridConfigurationWidget); + m_editConfigurationStackedWidget->addWidget(m_manualGeometryWidget); - m_customOptionsWidget = createCustomOptionsWidget(); - m_customOptionsWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - QScrollArea* stretchFactorScrollArea = new QScrollArea(); - stretchFactorScrollArea->setWidget(m_customConfigurationWidget); + stretchFactorScrollArea->setWidget(m_editConfigurationStackedWidget); stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); stretchFactorScrollArea->setWidgetResizable(true); - QGroupBox* widget = new QGroupBox("Tile Tabs Configuration in Workbench Window"); - QGridLayout* widgetLayout = new QGridLayout(widget); - widgetLayout->setColumnStretch(0, 0); - widgetLayout->setColumnStretch(1, 0); - widgetLayout->setColumnStretch(2, 0); - widgetLayout->setColumnStretch(3, 0); - widgetLayout->setColumnStretch(4, 0); - widgetLayout->setColumnStretch(5, 100); - widgetLayout->setColumnMinimumWidth(0, 20); - widgetLayout->addWidget(createWorkbenchWindowWidget(), - 0, 0, 1, 6, - Qt::AlignLeft); - widgetLayout->addWidget(WuQtUtilities::createHorizontalLineWidget(), - 1, 0, 1, 6); - widgetLayout->addWidget(m_automaticConfigurationRadioButton, - 2, 0, 1, 6, - Qt::AlignLeft); - widgetLayout->addWidget(m_customConfigurationRadioButton, - 3, 0, 1, 1, - Qt::AlignLeft); - widgetLayout->addWidget(rowsLabel, - 3, 1, 1, 1); - widgetLayout->addWidget(m_numberOfRowsSpinBox, - 3, 2, 1, 1); - widgetLayout->addWidget(columnsLabel, - 3, 3, 1, 1); - widgetLayout->addWidget(m_numberOfColumnsSpinBox, - 3, 4, 1, 1); - widgetLayout->addWidget(stretchFactorScrollArea, - 4, 0, 1, 6); - widgetLayout->addWidget(m_customOptionsWidget, - 5, 0, 1, 6, Qt::AlignLeft); - - widget->setFixedWidth(widget->sizeHint().width()); + QGroupBox* layoutSettingsGroupBox = new QGroupBox("Configuration Settings"); + QVBoxLayout* settingsGroupBoxLayout = new QVBoxLayout(layoutSettingsGroupBox); + settingsGroupBoxLayout->addWidget(stretchFactorScrollArea); + + return layoutSettingsGroupBox; +} + +/** + * @return The rows/columns stretch layout + */ +QWidget* +TileTabsConfigurationDialog::createManualGeometryEditingWidget() +{ + m_manualGeometryGridLayout = new QGridLayout(); + QWidget* widget = new QWidget; + QVBoxLayout* layout = new QVBoxLayout(widget); + layout->addLayout(m_manualGeometryGridLayout); + layout->addStretch(); + WuQtUtilities::setLayoutSpacingAndMargins(m_manualGeometryGridLayout, 4, 2); return widget; } @@ -782,21 +1178,25 @@ void TileTabsConfigurationDialog::automaticCustomButtonClicked(QAbstractButton* button) { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); - if (button == m_automaticConfigurationRadioButton) { - browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::AUTOMATIC); + if (button == m_automaticGridConfigurationRadioButton) { + browserWindowContent->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID); + } + else if (button == m_customGridConfigurationRadioButton) { + browserWindowContent->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); } - else if (button == m_customConfigurationRadioButton) { - browserWindowContent->setTileTabsConfigurationMode(TileTabsGridModeEnum::CUSTOM); + else if (button == m_manualConfigurationRadioButton) { + browserWindowContent->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::MANUAL); } else { CaretAssert(0); } - updateStretchFactors(); + + updateConfigurationEditingWidget(); + updateGridStretchFactors(); + updateManualGeometryEditorWidget(); updateGraphicsWindow(); } - - /** * Update the content of the dialog. If tile tabs is selected in the given * window, the dialog will be initialized with the tile tabs configuration @@ -830,25 +1230,51 @@ TileTabsConfigurationDialog::readConfigurationsFromPreferences() } /** - * Update the content of the dialog. + * Read the configurations from the preferences. */ void -TileTabsConfigurationDialog::updateDialog() +TileTabsConfigurationDialog::updateConfigurationEditingWidget() { BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); if (browserWindowContent == NULL) { return; } + bool editingEnabledFlag(false); switch (browserWindowContent->getTileTabsConfigurationMode()) { - case TileTabsGridModeEnum::AUTOMATIC: - m_automaticConfigurationRadioButton->setChecked(true); + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + m_automaticGridConfigurationRadioButton->setChecked(true); + m_editConfigurationStackedWidget->setCurrentWidget(m_customGridConfigurationWidget); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + m_customGridConfigurationRadioButton->setChecked(true); + m_editConfigurationStackedWidget->setCurrentWidget(m_customGridConfigurationWidget); + editingEnabledFlag = true; break; - case TileTabsGridModeEnum::CUSTOM: - m_customConfigurationRadioButton->setChecked(true); + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + m_manualConfigurationRadioButton->setChecked(true); + m_editConfigurationStackedWidget->setCurrentWidget(m_manualGeometryWidget); + editingEnabledFlag = true; break; } + m_editConfigurationStackedWidget->setEnabled(editingEnabledFlag); +} + + +/** + * Update the content of the dialog. + */ +void +TileTabsConfigurationDialog::updateDialog() +{ + BrowserWindowContent* browserWindowContent = getBrowserWindowContent(); + if (browserWindowContent == NULL) { + return; + } + + updateConfigurationEditingWidget(); + readConfigurationsFromPreferences(); int defaultIndex = m_userConfigurationSelectionListWidget->currentRow(); @@ -880,32 +1306,35 @@ TileTabsConfigurationDialog::updateDialog() m_userConfigurationSelectionListWidget->setCurrentRow(defaultIndex); } - updateStretchFactors(); + updateGridStretchFactors(); + updateManualGeometryEditorWidget(); } /** * Update the stretch factors. */ void -TileTabsConfigurationDialog::updateStretchFactors() +TileTabsConfigurationDialog::updateGridStretchFactors() { BrainBrowserWindow* browserWindow = getBrowserWindow(); - m_automaticConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::AUTOMATIC, + m_automaticGridConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID, true)); - m_customConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsGridModeEnum::CUSTOM, - false)); + m_customGridConfigurationRadioButton->setText(browserWindow->getTileTabsConfigurationLabelText(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID, + true)); const TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration != NULL) { updateRowColumnStretchWidgets(const_cast(configuration)); - QSignalBlocker rowBlocker(m_numberOfRowsSpinBox); - m_numberOfRowsSpinBox->setValue(configuration->getNumberOfRows()); - QSignalBlocker columnBlocker(m_numberOfColumnsSpinBox); - m_numberOfColumnsSpinBox->setValue(configuration->getNumberOfColumns()); + QSignalBlocker rowBlocker(m_numberOfGridRowsSpinBox); + m_numberOfGridRowsSpinBox->setValue(configuration->getNumberOfRows()); + QSignalBlocker columnBlocker(m_numberOfGridColumnsSpinBox); + m_numberOfGridColumnsSpinBox->setValue(configuration->getNumberOfColumns()); } - const bool editableFlag = ( ! m_automaticConfigurationRadioButton->isChecked()); + const bool editableFlag = ( ! m_automaticGridConfigurationRadioButton->isChecked()); - m_loadPushButton->setEnabled(editableFlag); + m_addConfigurationPushButton->setEnabled(editableFlag); + m_loadConfigurationPushButton->setEnabled(editableFlag); + m_replaceConfigurationPushButton->setEnabled(editableFlag); } /** @@ -1048,14 +1477,14 @@ TileTabsConfigurationDialog::getSelectedUserTileTabsConfigurationUniqueIdentifie * Called when the number of rows or columns changes. */ void -TileTabsConfigurationDialog::configurationNumberOfRowsOrColumnsChanged() +TileTabsConfigurationDialog::gridConfigurationNumberOfRowsOrColumnsChanged() { TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration != NULL) { - configuration->setNumberOfRows(m_numberOfRowsSpinBox->value()); - configuration->setNumberOfColumns(m_numberOfColumnsSpinBox->value()); + configuration->setNumberOfRows(m_numberOfGridRowsSpinBox->value()); + configuration->setNumberOfColumns(m_numberOfGridColumnsSpinBox->value()); - updateStretchFactors(); + updateGridStretchFactors(); updateGraphicsWindow(); } @@ -1065,14 +1494,14 @@ TileTabsConfigurationDialog::configurationNumberOfRowsOrColumnsChanged() * Called when a configuration stretch factor value is changed. */ void -TileTabsConfigurationDialog::configurationStretchFactorWasChanged() +TileTabsConfigurationDialog::gridConfigurationStretchFactorWasChanged() { TileTabsLayoutGridConfiguration* configuration = getCustomTileTabsGridConfiguration(); if (configuration == NULL) { return; } - updateStretchFactors(); + updateGridStretchFactors(); updateGraphicsWindow(); } @@ -1092,7 +1521,9 @@ TileTabsConfigurationDialog::tileTabsModificationRequested(EventTileTabsGridConf EventManager::get()->sendEvent(modification.getPointer()); - updateStretchFactors(); + updateGridStretchFactors(); + + updateManualGeometryEditorWidget(); updateGraphicsWindow(); } diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index aefa58aec..125f19bbd 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -36,6 +36,7 @@ class QListWidgetItem; class QPushButton; class QRadioButton; class QSpinBox; +class QStackedWidget; class QToolButton; namespace caret { @@ -49,6 +50,7 @@ namespace caret { class TileTabsLayoutManualConfiguration; class TileTabGridRowColumnWidgets; class TileTabsGridRowColumnElement; + class TileTabsManualTabGeometryWidget; class WuQGridLayoutGroup; class WuQListWidget; @@ -83,9 +85,9 @@ namespace caret { void renameUserConfigurationButtonClicked(); - void configurationNumberOfRowsOrColumnsChanged(); + void gridConfigurationNumberOfRowsOrColumnsChanged(); - void configurationStretchFactorWasChanged(); + void gridConfigurationStretchFactorWasChanged(); void addUserConfigurationPushButtonClicked(); @@ -98,7 +100,17 @@ namespace caret { void tileTabsModificationRequested(EventTileTabsGridConfigurationModification& modification); void centeringCorrectionCheckBoxClicked(bool checked); + + void manualConfigurationGeometryChanged(); + void manualConfigurationSetToolButtonClicked(); + + void manualConfigurationSetMenuColumnsItemTriggered(); + + void manualConfigurationSetMenuFromAutomaticItemTriggered(); + + void manualConfigurationSetMenuFromCustomItemTriggered(); + protected: void focusGained(); @@ -122,11 +134,15 @@ namespace caret { QWidget* createUserConfigurationSelectionWidget(); - QWidget* createActiveConfigurationWidget(); + QWidget* createConfigurationTypeWidget(); - QWidget* createRowColumnStretchWidget(); + QWidget* createConfigurationSettingsWidget(); - QWidget* createCustomOptionsWidget(); + QWidget* createGridRowColumnStretchWidget(); + + QWidget* createGridCustomOptionsWidget(); + + QWidget* createManualGeometryEditingWidget(); void updateRowColumnStretchWidgets(TileTabsLayoutGridConfiguration* configuration); @@ -134,7 +150,16 @@ namespace caret { QGridLayout* gridLayout, std::vector& elementVector); - void updateStretchFactors(); + void updateConfigurationEditingWidget(); + + void updateManualGeometryEditorWidget(); + + void addManualGeometryWidget(QGridLayout* gridLayout, + std::vector& widgetsVector); + + QToolButton* createManualConfigurationSetToolButton(); + + void updateGridStretchFactors(); void updateGraphicsWindow(); @@ -142,6 +167,8 @@ namespace caret { void readConfigurationsFromPreferences(); + void manualConfigurationSetMenuFromGridConfiguration(TileTabsLayoutGridConfiguration* gridConfiguration); + BrainBrowserWindow* getBrowserWindow(); BrowserWindowContent* getBrowserWindowContent(); @@ -150,39 +177,49 @@ namespace caret { BrainBrowserWindowComboBox* m_browserWindowComboBox; - QWidget* m_customConfigurationWidget; + QStackedWidget* m_editConfigurationStackedWidget; + + QWidget* m_customGridConfigurationWidget; - QWidget* m_customOptionsWidget; + QRadioButton* m_automaticGridConfigurationRadioButton; - QRadioButton* m_automaticConfigurationRadioButton; + QRadioButton* m_customGridConfigurationRadioButton; - QRadioButton* m_customConfigurationRadioButton; + QRadioButton* m_manualConfigurationRadioButton; QPushButton* m_deleteConfigurationPushButton; QPushButton* m_renameConfigurationPushButton; - QPushButton* m_addPushButton; + QPushButton* m_addConfigurationPushButton; - QPushButton* m_replacePushButton; + QPushButton* m_replaceConfigurationPushButton; - QPushButton* m_loadPushButton; + QPushButton* m_loadConfigurationPushButton; WuQListWidget* m_userConfigurationSelectionListWidget; - QSpinBox* m_numberOfRowsSpinBox; + QSpinBox* m_numberOfGridRowsSpinBox; + + QSpinBox* m_numberOfGridColumnsSpinBox; + + std::vector m_gridColumnElements; + + std::vector m_gridRowElements; + + QGridLayout* m_gridRowElementsGridLayout = NULL; - QSpinBox* m_numberOfColumnsSpinBox; + QGridLayout* m_gridColumnElementsGridLayout = NULL; - std::vector m_columnElements; + QCheckBox* m_gridCenteringCorrectionCheckBox; - std::vector m_rowElements; + QWidget* m_manualGeometryWidget; - QGridLayout* m_rowElementsGridLayout = NULL; + QGridLayout* m_manualGeometryGridLayout; - QGridLayout* m_columnElementsGridLayout = NULL; + QToolButton* m_manualConfigurationSetButton; - QCheckBox* m_centeringCorrectionCheckBox; + std::vector m_manualGeometryEditorWidgets; /** Blocks reading of preferences since that may invalidate data pointers */ bool m_blockReadConfigurationsFromPreferences; -- GitLab From f1aa9a535f4c48f14fb530b5520cb31d5c79a5aa Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 14 Aug 2019 09:36:38 -0500 Subject: [PATCH 006/584] WB-859 Manual Tile Tabs Layout System: Continue development: Saving and restoring scenes with manual layouts now working. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 106 +++-- src/Brain/BrainOpenGLViewportContent.cxx | 10 + src/Brain/BrainOpenGLWindowContent.cxx | 26 +- src/Brain/BrowserTabContent.cxx | 31 +- src/Common/CaretPreferences.cxx | 31 +- src/Common/CaretPreferences.h | 3 +- ...nfo.cxx => TileTabsBrowserTabGeometry.cxx} | 166 +++++--- ...TabInfo.h => TileTabsBrowserTabGeometry.h} | 42 +- src/Common/TileTabsGridModeEnum.cxx | 373 ------------------ src/Common/TileTabsGridModeEnum.h | 104 ----- src/Common/TileTabsLayoutBackgroundTypeEnum.h | 4 +- .../TileTabsLayoutBaseConfiguration.cxx | 6 +- .../TileTabsLayoutGridConfiguration.cxx | 6 +- .../TileTabsLayoutManualConfiguration.cxx | 68 ++-- .../TileTabsLayoutManualConfiguration.h | 16 +- src/GuiQt/BrainBrowserWindow.cxx | 16 +- src/GuiQt/BrainBrowserWindow.h | 3 + src/GuiQt/TileTabsConfigurationDialog.cxx | 322 +++++++++++++-- src/GuiQt/TileTabsConfigurationDialog.h | 8 +- src/GuiQt/TileTabsManualTabGeometryWidget.cxx | 326 +++++++++++++++ src/GuiQt/TileTabsManualTabGeometryWidget.h | 117 ++++++ src/Scenes/CMakeLists.txt | 2 + .../TileTabsBrowserTabGeometrySceneHelper.cxx | 151 +++++++ .../TileTabsBrowserTabGeometrySceneHelper.h | 92 +++++ 24 files changed, 1351 insertions(+), 678 deletions(-) rename src/Common/{TileTabsLayoutTabInfo.cxx => TileTabsBrowserTabGeometry.cxx} (56%) rename src/Common/{TileTabsLayoutTabInfo.h => TileTabsBrowserTabGeometry.h} (71%) delete mode 100644 src/Common/TileTabsGridModeEnum.cxx delete mode 100644 src/Common/TileTabsGridModeEnum.h create mode 100644 src/GuiQt/TileTabsManualTabGeometryWidget.cxx create mode 100644 src/GuiQt/TileTabsManualTabGeometryWidget.h create mode 100644 src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx create mode 100644 src/Scenes/TileTabsBrowserTabGeometrySceneHelper.h diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 8f4002f62..5da029d6b 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -146,6 +146,7 @@ #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "SurfaceSelectionModel.h" +#include "TileTabsBrowserTabGeometry.h" #include "TopologyHelper.h" #include "VolumeFile.h" #include "VolumeMappableInterface.h" @@ -605,7 +606,8 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, this->checkForOpenGLError(NULL, "At middle of drawModels()"); - for (int32_t i = 0; i < static_cast(viewportContents.size()); i++) { + const int32_t numberOfTabs = static_cast(viewportContents.size()); + for (int32_t i = 0; i < numberOfTabs; i++) { const BrainOpenGLViewportContent* vpContent = viewportContents[i]; /* * Don't draw if off-screen @@ -659,34 +661,80 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, */ updateForegroundAndBackgroundColors(vpContent); - /* - * If the background color for this viewport content is - * different that the clear color, THEN - * draw a rectangle with the background color. - */ - if ((m_backgroundColorByte[0] != clearColorByte[0]) - || (m_backgroundColorByte[1] != clearColorByte[1]) - || (m_backgroundColorByte[2] != clearColorByte[2])) { - GLboolean depthEnabledFlag; - glGetBooleanv(GL_DEPTH_TEST, - &depthEnabledFlag); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glColor3ubv(m_backgroundColorByte); - glBegin(GL_POLYGON); - glVertex2f(0.0, 0.0); - glVertex2f(1.0, 0.0); - glVertex2f(1.0, 1.0); - glVertex2f(0.0, 1.0); - glEnd(); - - if (depthEnabledFlag) { - glEnable(GL_DEPTH_TEST); + bool tileTabsFlag(false); + const BrowserTabContent* tabContent = vpContent->getBrowserTabContent(); + if (tabContent != NULL) { + if (numberOfTabs > 1) { + bool opaqueFlag(false); + switch (tabContent->getManualLayoutGeometry()->getBackgroundType()) { + case TileTabsLayoutBackgroundTypeEnum::OPAQUE: + opaqueFlag = true; + break; + case TileTabsLayoutBackgroundTypeEnum::TRANSPARENT: + break; + } + + glPushAttrib(GL_COLOR_BUFFER_BIT + | GL_DEPTH_BUFFER_BIT + | GL_SCISSOR_BIT); + + GLint tabViewport[4]; + vpContent->getTabViewportBeforeApplyingMargins(tabViewport); + glClearColor(m_backgroundColorFloat[0], + m_backgroundColorFloat[1], + m_backgroundColorFloat[2], + m_backgroundColorFloat[3]); + + glEnable(GL_SCISSOR_TEST); + glScissor(tabViewport[0], + tabViewport[1], + tabViewport[2], + tabViewport[3]); + + if (opaqueFlag) { + glClear(GL_COLOR_BUFFER_BIT + | GL_DEPTH_BUFFER_BIT); + } + else { + glClear(GL_DEPTH_BUFFER_BIT); + } + + glPopAttrib(); + + tileTabsFlag = true; + } + } + + if ( ! tileTabsFlag) { + /* + * If the background color for this viewport content is + * different that the clear color, THEN + * draw a rectangle with the background color. + */ + if ((m_backgroundColorByte[0] != clearColorByte[0]) + || (m_backgroundColorByte[1] != clearColorByte[1]) + || (m_backgroundColorByte[2] != clearColorByte[2])) { + GLboolean depthEnabledFlag; + glGetBooleanv(GL_DEPTH_TEST, + &depthEnabledFlag); + glDisable(GL_DEPTH_TEST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glColor3ubv(m_backgroundColorByte); + glBegin(GL_POLYGON); + glVertex2f(0.0, 0.0); + glVertex2f(1.0, 0.0); + glVertex2f(1.0, 1.0); + glVertex2f(0.0, 1.0); + glEnd(); + + if (depthEnabledFlag) { + glEnable(GL_DEPTH_TEST); + } } } diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index a73044872..8e6e3300b 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -1009,6 +1009,16 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vector 1) { + /* + * Sort tabs by stacking order + */ + std::sort(tabContents.begin(), + tabContents.end(), + [](BrowserTabContent* a, BrowserTabContent* b) { return (a->getManualLayoutGeometry()->getStackingOrder() + < b->getManualLayoutGeometry()->getStackingOrder()); } ); + } for (const auto tab : tabContents) { CaretAssert(tab); diff --git a/src/Brain/BrainOpenGLWindowContent.cxx b/src/Brain/BrainOpenGLWindowContent.cxx index 89eebccab..dcfaf7527 100644 --- a/src/Brain/BrainOpenGLWindowContent.cxx +++ b/src/Brain/BrainOpenGLWindowContent.cxx @@ -23,7 +23,10 @@ #include "BrainOpenGLWindowContent.h" #undef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ +#include "BrowserTabContent.h" #include "CaretAssert.h" +#include "TileTabsBrowserTabGeometry.h" + using namespace caret; @@ -157,6 +160,8 @@ const BrainOpenGLViewportContent* BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, const int32_t y) const { + BrainOpenGLViewportContent* viewportContentOut(NULL); + for (const auto& vp : m_tabViewports) { int32_t viewport[4]; vp->getTabViewportBeforeApplyingMargins(viewport); @@ -164,10 +169,27 @@ BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, && (x < (viewport[0] + viewport[2])) && (y >= viewport[1]) && (y < (viewport[1] + viewport[3]))) { - return vp.get(); + if (viewportContentOut == NULL) { + viewportContentOut = vp.get(); + } + else { + /* + * Note: The tabs ONLY overlay in a manual tile tabs layout + */ + const BrowserTabContent* btc = vp.get()->getBrowserTabContent(); + const BrowserTabContent* btcOut = viewportContentOut->getBrowserTabContent(); + if ((btc != NULL) + && (btcOut != NULL)) { + if (btc->getManualLayoutGeometry()->getStackingOrder() + > btcOut->getManualLayoutGeometry()->getStackingOrder()) { + viewportContentOut = vp.get(); + } + } + } } } - return NULL; + + return viewportContentOut; } diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 41a520c85..8729d5939 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -86,6 +86,7 @@ #include "SurfaceSelectionModel.h" #include "StructureEnum.h" #include "TileTabsBrowserTabGeometry.h" +#include "TileTabsBrowserTabGeometrySceneHelper.h" #include "VolumeFile.h" #include "ViewingTransformations.h" #include "ViewingTransformationsCerebellum.h" @@ -228,9 +229,7 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) &m_brainModelYokingGroup); m_sceneClassAssistant->add("m_chartModelYokingGroup", &m_chartModelYokingGroup); - - CaretAssertToDoWarning(); // need to save/restore m_manualLayoutTabGeometry - + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_COLOR_BAR_GET); EventManager::get()->addEventListener(this, @@ -371,6 +370,22 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) } m_volumeSurfaceOutlineSetModel->copyVolumeSurfaceOutlineSetModel(tabToClone->getVolumeSurfaceOutlineSet()); + + /* + * For manual layout, make tab same size but put in bottom left corner + */ + const TileTabsBrowserTabGeometry* cloneGeometry = tabToClone->getManualLayoutGeometry(); + CaretAssert(cloneGeometry); + const float minXY(10.0f); + const float maxWidthHeight(100.0f - (minXY * 2)); + float tabWidth = MathFunctions::limitRange(cloneGeometry->getMaxX() - cloneGeometry->getMinX(), minXY, maxWidthHeight); + float tabHeight = MathFunctions::limitRange(cloneGeometry->getMaxY() - cloneGeometry->getMinY(), minXY, maxWidthHeight); + TileTabsBrowserTabGeometry* geometry = getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setMinX(minXY); + geometry->setMaxX(geometry->getMinX() + tabWidth); + geometry->setMinY(minXY); + geometry->setMaxY(geometry->getMinY() + tabHeight); } /** @@ -3560,7 +3575,11 @@ BrowserTabContent::saveToScene(const SceneAttributes* sceneAttributes, m_obliqueVolumeRotationMatrix->getMatrixForOpenGL(obliqueMatrix); sceneClass->addFloatArray("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); - m_sceneClassAssistant->saveMembers(sceneAttributes, + TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); + sceneClass->addClass(geometryHelper.saveToScene(sceneAttributes, + "m_manualLayoutTabGeometry")); + + m_sceneClassAssistant->saveMembers(sceneAttributes, sceneClass); return sceneClass; @@ -3589,6 +3608,10 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_A; m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; + TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); + geometryHelper.restoreFromScene(sceneAttributes, + sceneClass->getClass("m_manualLayoutTabGeometry")); + m_sceneClassAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index f8da799e0..0462dc363 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -571,13 +571,25 @@ CaretPreferences::getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const std::vector> nameIDs; for (const auto ttc : this->tileTabsConfigurations) { - nameIDs.push_back(std::make_pair(ttc->getName(), + QString typeString; + switch (ttc->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + typeString = " (AG)"; + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + typeString = " (G)"; + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + typeString = " (M)"; + break; + } + nameIDs.push_back(std::make_pair(ttc->getName() + typeString, ttc->getUniqueIdentifier())); } std::sort(nameIDs.begin(), nameIDs.end(), - [](std::pair& a, std::pair& b) { return a.first < b.first; }); + [](const std::pair& a, const std::pair& b) { return a.first < b.first; }); return nameIDs; } @@ -638,12 +650,19 @@ CaretPreferences::getTileTabsUserConfigurationByName(const AString& name) const * Add a new tile tabs user configuration. * * @param tileTabsConfiguration - * New tile tabs configuration that is added. + * New tile tabs configuration that is copied and added. + * @param configurationName + * New name for copied configuration (ignored if empty) */ void -CaretPreferences::addTileTabsUserConfiguration(TileTabsLayoutBaseConfiguration* tileTabsConfiguration) +CaretPreferences::addTileTabsUserConfiguration(const TileTabsLayoutBaseConfiguration* tileTabsConfiguration, + const AString& configurationName) { - this->tileTabsConfigurations.push_back(tileTabsConfiguration); + TileTabsLayoutBaseConfiguration* configCopy = tileTabsConfiguration->newCopyWithNewUniqueIdentifier(); + if ( ! configurationName.isEmpty()) { + configCopy->setName(configurationName); + } + this->tileTabsConfigurations.push_back(configCopy); this->writeTileTabsUserConfigurations(); } @@ -689,11 +708,13 @@ CaretPreferences::replaceTileTabsUserConfiguration(const AString& replaceUserTil * Delete configuration since it may be a different subclass than other configuration */ CaretAssertVectorIndex(this->tileTabsConfigurations, replaceIndex); + const AString name = this->tileTabsConfigurations[replaceIndex]->getName(); const AString uuid = this->tileTabsConfigurations[replaceIndex]->getUniqueIdentifier(); delete this->tileTabsConfigurations[replaceIndex]; TileTabsLayoutBaseConfiguration* newConfig = replaceWithConfiguration->newCopyWithUniqueIdentifier(uuid); CaretAssert(newConfig); + newConfig->setName(name); this->tileTabsConfigurations[replaceIndex] = newConfig; this->writeTileTabsUserConfigurations(); diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index 0fa6b8ddb..f6de7a89f 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -144,7 +144,8 @@ namespace caret { TileTabsLayoutBaseConfiguration* getTileTabsUserConfigurationByName(const AString& name) const; - void addTileTabsUserConfiguration(TileTabsLayoutBaseConfiguration* tileTabsConfiguration); + void addTileTabsUserConfiguration(const TileTabsLayoutBaseConfiguration* tileTabsConfiguration, + const AString& configurationName); bool replaceTileTabsUserConfiguration(const AString& replaceUserTileTabsUniqueIdentifier, const TileTabsLayoutBaseConfiguration* replaceWithConfiguration, diff --git a/src/Common/TileTabsLayoutTabInfo.cxx b/src/Common/TileTabsBrowserTabGeometry.cxx similarity index 56% rename from src/Common/TileTabsLayoutTabInfo.cxx rename to src/Common/TileTabsBrowserTabGeometry.cxx index 52b02449a..11e5071a1 100644 --- a/src/Common/TileTabsLayoutTabInfo.cxx +++ b/src/Common/TileTabsBrowserTabGeometry.cxx @@ -19,9 +19,11 @@ */ /*LICENSE_END*/ -#define __TILE_TABS_TAB_INFO_DECLARE__ -#include "TileTabsLayoutTabInfo.h" -#undef __TILE_TABS_TAB_INFO_DECLARE__ +#define __TILE_TABS_BROWSER_TAB_GEOMETRY_DECLARE__ +#include "TileTabsBrowserTabGeometry.h" +#undef __TILE_TABS_BROWSER_TAB_GEOMETRY_DECLARE__ + +#include #include @@ -31,7 +33,7 @@ using namespace caret; /** - * \class caret::TileTabsLayoutTabInfo + * \class caret::TileTabsBrowserTabGeometry * \brief Information about a tab's position in the window using percentage coordinates * \ingroup Common * @@ -42,17 +44,25 @@ using namespace caret; /** * Constructor. */ -TileTabsLayoutTabInfo::TileTabsLayoutTabInfo(const int32_t tabIndex) +TileTabsBrowserTabGeometry::TileTabsBrowserTabGeometry(const int32_t tabIndex) : CaretObject(), m_tabIndex(tabIndex) { - + const float offset(2.0); + const float widthHeight(20.0); + const float minValue(offset * (m_tabIndex + 2.0)); + const float maxValue(minValue + widthHeight); + m_minX = minValue; + m_maxX = maxValue; + m_minY = minValue; + m_maxY = maxValue; + m_stackingOrder = tabIndex; } /** * Destructor. */ -TileTabsLayoutTabInfo::~TileTabsLayoutTabInfo() +TileTabsBrowserTabGeometry::~TileTabsBrowserTabGeometry() { } @@ -61,10 +71,10 @@ TileTabsLayoutTabInfo::~TileTabsLayoutTabInfo() * @param obj * Object that is copied. */ -TileTabsLayoutTabInfo::TileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj) +TileTabsBrowserTabGeometry::TileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj) : CaretObject(obj) { - this->copyHelperTileTabsLayoutTabInfo(obj); + this->copyHelperTileTabsBrowserTabGeometry(obj); } /** @@ -74,12 +84,12 @@ TileTabsLayoutTabInfo::TileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj) * @return * Reference to this object. */ -TileTabsLayoutTabInfo& -TileTabsLayoutTabInfo::operator=(const TileTabsLayoutTabInfo& obj) +TileTabsBrowserTabGeometry& +TileTabsBrowserTabGeometry::operator=(const TileTabsBrowserTabGeometry& obj) { if (this != &obj) { CaretObject::operator=(obj); - this->copyHelperTileTabsLayoutTabInfo(obj); + this->copyHelperTileTabsBrowserTabGeometry(obj); } return *this; } @@ -90,22 +100,34 @@ TileTabsLayoutTabInfo::operator=(const TileTabsLayoutTabInfo& obj) * Object that is copied. */ void -TileTabsLayoutTabInfo::copyHelperTileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj) +TileTabsBrowserTabGeometry::copyHelperTileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj) { m_tabIndex = obj.m_tabIndex; - m_xCenter = obj.m_xCenter; - m_yCenter = obj.m_yCenter; - m_width = obj.m_width; - m_height = obj.m_height; + m_minX = obj.m_minX; + m_maxX = obj.m_maxX; + m_minY = obj.m_minY; + m_maxY = obj.m_maxY; m_stackingOrder = obj.m_stackingOrder; m_backgroundType = obj.m_backgroundType; } +/** + * Copy the given geometry to 'this' + * + * @param geometry + * Geometry that is copied + */ +void +TileTabsBrowserTabGeometry::copyGeometry(const TileTabsBrowserTabGeometry& geometry) +{ + copyHelperTileTabsBrowserTabGeometry(geometry); +} + /** * @return Index of the tab */ int32_t -TileTabsLayoutTabInfo::getTabIndex() const +TileTabsBrowserTabGeometry::getTabIndex() const { return m_tabIndex; } @@ -115,17 +137,17 @@ TileTabsLayoutTabInfo::getTabIndex() const * @return String describing this object's content. */ AString -TileTabsLayoutTabInfo::toString() const +TileTabsBrowserTabGeometry::toString() const { AString str; QTextStream ts(&str); - ts << "TileTabsLayoutTabInfo: " + ts << "TileTabsBrowserTabGeometry: " << "m_tabIndex=" << m_tabIndex - << " m_xCenter=" << m_xCenter - << " m_yCenter=" << m_yCenter - << " m_width=" << m_width - << " m_height=" << m_height + << " m_minX=" << m_minX + << " m_maxX=" << m_maxX + << " m_minY=" << m_minY + << " m_maxY=" << m_maxY << " m_stackingOrder=" << m_stackingOrder << " m_backgroundType=" << TileTabsLayoutBackgroundTypeEnum::toName(m_backgroundType); @@ -136,9 +158,9 @@ TileTabsLayoutTabInfo::toString() const * @return center x-coordinate as percentage 0% to 100% */ float -TileTabsLayoutTabInfo::getCenterX() const +TileTabsBrowserTabGeometry::getCenterX() const { - return m_xCenter; + return ((m_minX + m_maxX) / 2.0); } /** @@ -148,18 +170,20 @@ TileTabsLayoutTabInfo::getCenterX() const * New value for center x-coordinate as percentage 0% to 100% */ void -TileTabsLayoutTabInfo::setCenterX(const float x) +TileTabsBrowserTabGeometry::setCenterX(const float x) { - m_xCenter = x; + const float dx = x - getCenterX(); + m_minX += dx; + m_maxX += dx; } /** * @return center y-coordinate as percentage 0% to 100% */ float -TileTabsLayoutTabInfo::getCenterY() const +TileTabsBrowserTabGeometry::getCenterY() const { - return m_yCenter; + return ((m_minY + m_maxY) / 2.0); } /** @@ -169,18 +193,20 @@ TileTabsLayoutTabInfo::getCenterY() const * New value for center y-coordinate as percentage 0% to 100% */ void -TileTabsLayoutTabInfo::setCenterY(const float y) +TileTabsBrowserTabGeometry::setCenterY(const float y) { - m_yCenter = y; + const float dy = y - getCenterY(); + m_minY += dy; + m_maxY += dy; } /** * @return width as percentage 0% to 100% */ float -TileTabsLayoutTabInfo::getWidth() const +TileTabsBrowserTabGeometry::getWidth() const { - return m_width; + return (m_maxX - m_minX); } /** @@ -190,18 +216,21 @@ TileTabsLayoutTabInfo::getWidth() const * New value for width as percentage 0% to 100% */ void -TileTabsLayoutTabInfo::setWidth(const float width) +TileTabsBrowserTabGeometry::setWidth(const float width) { - m_width = width; + const float cx = getCenterX(); + const float half = width / 2.0; + m_minX = cx - half; + m_maxX = cx + half; } /** * @return height as percentage 0% to 100% */ float -TileTabsLayoutTabInfo::getHeight() const +TileTabsBrowserTabGeometry::getHeight() const { - return m_height; + return (m_maxY - m_minY); } /** @@ -211,18 +240,21 @@ TileTabsLayoutTabInfo::getHeight() const * New value for height as percentage 0% to 100% */ void -TileTabsLayoutTabInfo::setHeight(const float height) +TileTabsBrowserTabGeometry::setHeight(const float height) { - m_height = height; + const float cy = getCenterY(); + const float half = height / 2.0; + m_minY = cy - half; + m_maxY = cy + half; } /** * @return minimum x percentage 0% to 100% at left */ float -TileTabsLayoutTabInfo::getMinX() const +TileTabsBrowserTabGeometry::getMinX() const { - return (m_xCenter - (m_width / 2.0)); + return m_minX; } /** @@ -232,18 +264,20 @@ TileTabsLayoutTabInfo::getMinX() const * New value for minimum x percentage 0% to 100% at left */ void -TileTabsLayoutTabInfo::setMinX(const float minX) +TileTabsBrowserTabGeometry::setMinX(const float minX) { - m_xCenter = minX + (m_width / 2.0); + m_minX = minX; + m_maxX = std::max(m_maxX, + m_minX + 1.0f); } /** * @return maximum x percentage 0% to 100% at rigth */ float -TileTabsLayoutTabInfo::getMaxX() const +TileTabsBrowserTabGeometry::getMaxX() const { - return (m_xCenter + (m_width / 2.0)); + return m_maxX; } /** @@ -253,18 +287,20 @@ TileTabsLayoutTabInfo::getMaxX() const * New value for maximum x percentage 0% to 100% at right */ void -TileTabsLayoutTabInfo::setMaxX(const float maxX) +TileTabsBrowserTabGeometry::setMaxX(const float maxX) { - m_xCenter = maxX - (m_width / 2.0); + m_maxX = maxX; + m_minX = std::min(m_minX, + m_maxX - 1.0f); } /** * @return minimum y percentage 0% to 100% at bottom */ float -TileTabsLayoutTabInfo::getMinY() const +TileTabsBrowserTabGeometry::getMinY() const { - return (m_yCenter - (m_height / 2.0)); + return m_minY; } /** @@ -274,18 +310,20 @@ TileTabsLayoutTabInfo::getMinY() const * New value for minimum y percentage 0% to 100% at bottom */ void -TileTabsLayoutTabInfo::setMinY(const float minY) +TileTabsBrowserTabGeometry::setMinY(const float minY) { - m_yCenter = minY + (m_height / 2.0); + m_minY = minY; + m_maxY = std::max(m_maxY, + m_minY + 1.0f); } /** * @return maximum y percentage 0% to 100% at top */ float -TileTabsLayoutTabInfo::getMaxY() const +TileTabsBrowserTabGeometry::getMaxY() const { - return (m_xCenter + (m_height / 2.0)); + return m_maxY; } /** @@ -295,9 +333,11 @@ TileTabsLayoutTabInfo::getMaxY() const * New value for maximum y percentage 0% to 100% at top */ void -TileTabsLayoutTabInfo::setMaxY(const float maxY) +TileTabsBrowserTabGeometry::setMaxY(const float maxY) { - m_xCenter = maxY - (m_height / 2.0); + m_maxY = maxY; + m_minY = std::min(m_minY, + m_maxY - 1.0f); } /** @@ -311,9 +351,9 @@ TileTabsLayoutTabInfo::setMaxY(const float maxY) * Output containing lower-left X, Y, Width, and Height in window coordinates */ void -TileTabsLayoutTabInfo::getWindowViewport(const int32_t windowWidth, - const int32_t windowHeight, - int32_t viewportOut[4]) const +TileTabsBrowserTabGeometry::getWindowViewport(const int32_t windowWidth, + const int32_t windowHeight, + int32_t viewportOut[4]) const { viewportOut[0] = static_cast((getMinX() / 100.0) * windowWidth); viewportOut[1] = static_cast((getMinY() / 100.0) * windowHeight); @@ -325,7 +365,7 @@ TileTabsLayoutTabInfo::getWindowViewport(const int32_t windowWidth, * @return Stacking order (depth in screen) of tab, greater value is 'in front' */ int32_t -TileTabsLayoutTabInfo::getStackingOrder() const +TileTabsBrowserTabGeometry::getStackingOrder() const { return m_stackingOrder; } @@ -337,7 +377,7 @@ TileTabsLayoutTabInfo::getStackingOrder() const * New value for Stacking order (depth in screen) of tab, greater value is 'in front' */ void -TileTabsLayoutTabInfo::setStackingOrder(const int32_t stackingOrder) +TileTabsBrowserTabGeometry::setStackingOrder(const int32_t stackingOrder) { m_stackingOrder = stackingOrder; } @@ -346,7 +386,7 @@ TileTabsLayoutTabInfo::setStackingOrder(const int32_t stackingOrder) * @return Type of background (opaque / transparent) for tab */ TileTabsLayoutBackgroundTypeEnum::Enum -TileTabsLayoutTabInfo::getBackgroundType() const +TileTabsBrowserTabGeometry::getBackgroundType() const { return m_backgroundType; } @@ -358,7 +398,7 @@ TileTabsLayoutTabInfo::getBackgroundType() const * New value for Type of background (opaque / transparent) for tab */ void -TileTabsLayoutTabInfo::setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType) +TileTabsBrowserTabGeometry::setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType) { m_backgroundType = backgroundType; } diff --git a/src/Common/TileTabsLayoutTabInfo.h b/src/Common/TileTabsBrowserTabGeometry.h similarity index 71% rename from src/Common/TileTabsLayoutTabInfo.h rename to src/Common/TileTabsBrowserTabGeometry.h index b124204d0..024d58fcb 100644 --- a/src/Common/TileTabsLayoutTabInfo.h +++ b/src/Common/TileTabsBrowserTabGeometry.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_LAYOUT_TAB_INFO_H__ -#define __TILE_TABS_LAYOUT_TAB_INFO_H__ +#ifndef __TILE_TABS_BROWSER_TAB_GEOMETRY_H__ +#define __TILE_TABS_BROWSER_TAB_GEOMETRY_H__ /*LICENSE_START*/ /* @@ -31,17 +31,19 @@ namespace caret { - class TileTabsLayoutTabInfo : public CaretObject { + class TileTabsBrowserTabGeometry : public CaretObject { public: - TileTabsLayoutTabInfo(const int32_t tabIndex); + TileTabsBrowserTabGeometry(const int32_t tabIndex); - virtual ~TileTabsLayoutTabInfo(); + virtual ~TileTabsBrowserTabGeometry(); - TileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj); + TileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj); - TileTabsLayoutTabInfo& operator=(const TileTabsLayoutTabInfo& obj); + TileTabsBrowserTabGeometry& operator=(const TileTabsBrowserTabGeometry& obj); + void copyGeometry(const TileTabsBrowserTabGeometry& geometry); + int32_t getTabIndex() const; float getCenterX() const; @@ -93,22 +95,22 @@ namespace caret { virtual AString toString() const; private: - void copyHelperTileTabsLayoutTabInfo(const TileTabsLayoutTabInfo& obj); + void copyHelperTileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj); /** index of tab */ int32_t m_tabIndex; - /** center x-coordinate as percentage*/ - float m_xCenter = 50.0; + /** left as percentage*/ + float m_minX = 10.0; - /** center y-coordinate as percentage*/ - float m_yCenter = 50.0; + /** right as percentage*/ + float m_maxX = 20.0; - /** width of window as percentage*/ - float m_width = 20.0; + /** bottom as percentage*/ + float m_minY = 10.0; - /** height of window as percentage*/ - float m_height = 20.0; + /** topas percentage*/ + float m_maxY = 20.0; /** Stacking order (depth in screen) of tab, greater value is 'in front'*/ int32_t m_stackingOrder = 1; @@ -118,11 +120,13 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + /** IF NEW MEMBERS ADDED, MUST UPDATE THIS CLASS */ + friend class TileTabsBrowserTabGeometrySceneHelper; }; -#ifdef __TILE_TABS_TAB_INFO_DECLARE__ +#ifdef __TILE_TABS_BROWSER_TAB_GEOMETRY_DECLARE__ // -#endif // __TILE_TABS_TAB_INFO_DECLARE__ +#endif // __TILE_TABS_BROWSER_TAB_GEOMETRY_DECLARE__ } // namespace -#endif //__TILE_TABS_LAYOUT_TAB_INFO_H__ +#endif //__TILE_TABS_BROWSER_TAB_GEOMETRY_H__ diff --git a/src/Common/TileTabsGridModeEnum.cxx b/src/Common/TileTabsGridModeEnum.cxx deleted file mode 100644 index 15547e3df..000000000 --- a/src/Common/TileTabsGridModeEnum.cxx +++ /dev/null @@ -1,373 +0,0 @@ - -/*LICENSE_START*/ -/* - * Copyright (C) 2018 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - -#include -#define __TILE_TABS_GRID_MODE_ENUM_DECLARE__ -#include "TileTabsGridModeEnum.h" -#undef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ - -#include "CaretAssert.h" - -using namespace caret; - - -/** - * \class caret::TileTabsGridModeEnum - * \brief Enumerated type for Grid Tile Tab Configuration Mode (auto, custom) - * - * Using this enumerated type in the GUI with an EnumComboBoxTemplate - * - * Header File (.h) - * Forward declare the data type: - * class EnumComboBoxTemplate; - * - * Declare the member: - * EnumComboBoxTemplate* m_TileTabsGridModeEnumComboBox; - * - * Declare a slot that is called when user changes selection - * private slots: - * void TileTabsGridModeEnumComboBoxItemActivated(); - * - * Implementation File (.cxx) - * Include the header files - * #include "EnumComboBoxTemplate.h" - * #include "TileTabsGridModeEnum.h" - * - * Instatiate: - * m_TileTabsGridModeEnumComboBox = new EnumComboBoxTemplate(this); - * m_TileTabsGridModeEnumComboBox->setup(); - * - * Get notified when the user changes the selection: - * QObject::connect(m_TileTabsGridModeEnumComboBox, SIGNAL(itemActivated()), - * this, SLOT(TileTabsGridModeEnumComboBoxItemActivated())); - * - * Update the selection: - * m_TileTabsGridModeEnumComboBox->setSelectedItem(NEW_VALUE); - * - * Read the selection: - * const TileTabsGridModeEnum::Enum VARIABLE = m_TileTabsGridModeEnumComboBox->getSelectedItem(); - * - */ - -/** - * Constructor. - * - * @param enumValue - * An enumerated value. - * @param name - * Name of enumerated value. - * - * @param guiName - * User-friendly name for use in user-interface. - */ -TileTabsGridModeEnum::TileTabsGridModeEnum(const Enum enumValue, - const AString& name, - const AString& guiName) -{ - this->enumValue = enumValue; - this->integerCode = integerCodeCounter++; - this->name = name; - this->guiName = guiName; -} - -/** - * Destructor. - */ -TileTabsGridModeEnum::~TileTabsGridModeEnum() -{ -} - -/** - * Initialize the enumerated metadata. - */ -void -TileTabsGridModeEnum::initialize() -{ - if (initializedFlag) { - return; - } - initializedFlag = true; - - enumData.push_back(TileTabsGridModeEnum(AUTOMATIC, - "AUTOMATIC", - "Automatic")); - - enumData.push_back(TileTabsGridModeEnum(CUSTOM, - "CUSTOM", - "Custom")); - -} - -/** - * Find the data for and enumerated value. - * @param enumValue - * The enumerated value. - * @return Pointer to data for this enumerated type - * or NULL if no data for type or if type is invalid. - */ -const TileTabsGridModeEnum* -TileTabsGridModeEnum::findData(const Enum enumValue) -{ - if (initializedFlag == false) initialize(); - - size_t num = enumData.size(); - for (size_t i = 0; i < num; i++) { - const TileTabsGridModeEnum* d = &enumData[i]; - if (d->enumValue == enumValue) { - return d; - } - } - - return NULL; -} - -/** - * Get a string representation of the enumerated type. - * @param enumValue - * Enumerated value. - * @return - * String representing enumerated value. - */ -AString -TileTabsGridModeEnum::toName(Enum enumValue) { - if (initializedFlag == false) initialize(); - - const TileTabsGridModeEnum* enumInstance = findData(enumValue); - return enumInstance->name; -} - -/** - * Get an enumerated value corresponding to its name. - * @param name - * Name of enumerated value. - * @param isValidOut - * If not NULL, it is set indicating that a - * enum value exists for the input name. - * @return - * Enumerated value. - */ -TileTabsGridModeEnum::Enum -TileTabsGridModeEnum::fromName(const AString& name, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const TileTabsGridModeEnum& d = *iter; - if (d.name == name) { - enumValue = d.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsGridModeEnum")); - } - return enumValue; -} - -/** - * Get a GUI string representation of the enumerated type. - * @param enumValue - * Enumerated value. - * @return - * String representing enumerated value. - */ -AString -TileTabsGridModeEnum::toGuiName(Enum enumValue) { - if (initializedFlag == false) initialize(); - - const TileTabsGridModeEnum* enumInstance = findData(enumValue); - return enumInstance->guiName; -} - -/** - * Get an enumerated value corresponding to its GUI name. - * @param s - * Name of enumerated value. - * @param isValidOut - * If not NULL, it is set indicating that a - * enum value exists for the input name. - * @return - * Enumerated value. - */ -TileTabsGridModeEnum::Enum -TileTabsGridModeEnum::fromGuiName(const AString& guiName, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const TileTabsGridModeEnum& d = *iter; - if (d.guiName == guiName) { - enumValue = d.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("guiName " + guiName + "failed to match enumerated value for type TileTabsGridModeEnum")); - } - return enumValue; -} - -/** - * Get the integer code for a data type. - * - * @return - * Integer code for data type. - */ -int32_t -TileTabsGridModeEnum::toIntegerCode(Enum enumValue) -{ - if (initializedFlag == false) initialize(); - const TileTabsGridModeEnum* enumInstance = findData(enumValue); - return enumInstance->integerCode; -} - -/** - * Find the data type corresponding to an integer code. - * - * @param integerCode - * Integer code for enum. - * @param isValidOut - * If not NULL, on exit isValidOut will indicate if - * integer code is valid. - * @return - * Enum for integer code. - */ -TileTabsGridModeEnum::Enum -TileTabsGridModeEnum::fromIntegerCode(const int32_t integerCode, bool* isValidOut) -{ - if (initializedFlag == false) initialize(); - - bool validFlag = false; - Enum enumValue = TileTabsGridModeEnum::enumData[0].enumValue; - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - const TileTabsGridModeEnum& enumInstance = *iter; - if (enumInstance.integerCode == integerCode) { - enumValue = enumInstance.enumValue; - validFlag = true; - break; - } - } - - if (isValidOut != 0) { - *isValidOut = validFlag; - } - else if (validFlag == false) { - CaretAssertMessage(0, AString("Integer code " + AString::number(integerCode) + "failed to match enumerated value for type TileTabsGridModeEnum")); - } - return enumValue; -} - -/** - * Get all of the enumerated type values. The values can be used - * as parameters to toXXX() methods to get associated metadata. - * - * @param allEnums - * A vector that is OUTPUT containing all of the enumerated values. - */ -void -TileTabsGridModeEnum::getAllEnums(std::vector& allEnums) -{ - if (initializedFlag == false) initialize(); - - allEnums.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allEnums.push_back(iter->enumValue); - } -} - -/** - * Get all of the names of the enumerated type values. - * - * @param allNames - * A vector that is OUTPUT containing all of the names of the enumerated values. - * @param isSorted - * If true, the names are sorted in alphabetical order. - */ -void -TileTabsGridModeEnum::getAllNames(std::vector& allNames, const bool isSorted) -{ - if (initializedFlag == false) initialize(); - - allNames.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allNames.push_back(TileTabsGridModeEnum::toName(iter->enumValue)); - } - - if (isSorted) { - std::sort(allNames.begin(), allNames.end()); - } -} - -/** - * Get all of the GUI names of the enumerated type values. - * - * @param allNames - * A vector that is OUTPUT containing all of the GUI names of the enumerated values. - * @param isSorted - * If true, the names are sorted in alphabetical order. - */ -void -TileTabsGridModeEnum::getAllGuiNames(std::vector& allGuiNames, const bool isSorted) -{ - if (initializedFlag == false) initialize(); - - allGuiNames.clear(); - - for (std::vector::iterator iter = enumData.begin(); - iter != enumData.end(); - iter++) { - allGuiNames.push_back(TileTabsGridModeEnum::toGuiName(iter->enumValue)); - } - - if (isSorted) { - std::sort(allGuiNames.begin(), allGuiNames.end()); - } -} - diff --git a/src/Common/TileTabsGridModeEnum.h b/src/Common/TileTabsGridModeEnum.h deleted file mode 100644 index 4478b4fb3..000000000 --- a/src/Common/TileTabsGridModeEnum.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef __TILE_TABS_GRID_MODE_ENUM_H__ -#define __TILE_TABS_GRID_MODE_ENUM_H__ - -/*LICENSE_START*/ -/* - * Copyright (C) 2018 Washington University School of Medicine - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/*LICENSE_END*/ - - -#include -#include -#include "AString.h" - -namespace caret { - -class TileTabsGridModeEnum { - -public: - /** - * Enumerated values. - */ - enum Enum { - /** Workbench creates tab layout */ - AUTOMATIC, - /** User customizes tab layout */ - CUSTOM - }; - - - ~TileTabsGridModeEnum(); - - static AString toName(Enum enumValue); - - static Enum fromName(const AString& name, bool* isValidOut); - - static AString toGuiName(Enum enumValue); - - static Enum fromGuiName(const AString& guiName, bool* isValidOut); - - static int32_t toIntegerCode(Enum enumValue); - - static Enum fromIntegerCode(const int32_t integerCode, bool* isValidOut); - - static void getAllEnums(std::vector& allEnums); - - static void getAllNames(std::vector& allNames, const bool isSorted); - - static void getAllGuiNames(std::vector& allGuiNames, const bool isSorted); - -private: - TileTabsGridModeEnum(const Enum enumValue, - const AString& name, - const AString& guiName); - - static const TileTabsGridModeEnum* findData(const Enum enumValue); - - /** Holds all instance of enum values and associated metadata */ - static std::vector enumData; - - /** Initialize instances that contain the enum values and metadata */ - static void initialize(); - - /** Indicates instance of enum values and metadata have been initialized */ - static bool initializedFlag; - - /** Auto generated integer codes */ - static int32_t integerCodeCounter; - - /** The enumerated type value for an instance */ - Enum enumValue; - - /** The integer code associated with an enumerated value */ - int32_t integerCode; - - /** The name, a text string that is identical to the enumerated value */ - AString name; - - /** A user-friendly name that is displayed in the GUI */ - AString guiName; -}; - -#ifdef __TILE_TABS_GRID_MODE_ENUM_DECLARE__ -std::vector TileTabsGridModeEnum::enumData; -bool TileTabsGridModeEnum::initializedFlag = false; -int32_t TileTabsGridModeEnum::integerCodeCounter = 0; -#endif // __TILE_TABS_GRID_MODE_ENUM_DECLARE__ - -} // namespace -#endif //__TILE_TABS_GRID_MODE_ENUM_H__ diff --git a/src/Common/TileTabsLayoutBackgroundTypeEnum.h b/src/Common/TileTabsLayoutBackgroundTypeEnum.h index 91a243737..abec04a3b 100644 --- a/src/Common/TileTabsLayoutBackgroundTypeEnum.h +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.h @@ -35,9 +35,9 @@ public: * Enumerated values. */ enum Enum { - /** */ + /** Opaque */ OPAQUE, - /** */ + /** Transparent */ TRANSPARENT }; diff --git a/src/Common/TileTabsLayoutBaseConfiguration.cxx b/src/Common/TileTabsLayoutBaseConfiguration.cxx index 345eb31a5..a69e98ff3 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.cxx +++ b/src/Common/TileTabsLayoutBaseConfiguration.cxx @@ -66,8 +66,6 @@ TileTabsLayoutBaseConfiguration::~TileTabsLayoutBaseConfiguration() /** * Copy constructor. * - * NOTE: Unique identifier remains the same ! See also: newCopyWithNewUniqueIdentifier() - * * @param obj * Object that is copied. */ @@ -75,9 +73,7 @@ TileTabsLayoutBaseConfiguration::TileTabsLayoutBaseConfiguration(const TileTabsL : CaretObject(obj), m_layoutType(obj.m_layoutType) { - const AString savedUniqueID = m_uniqueIdentifier; initializeTileTabsLayoutBaseConfiguration(); - m_uniqueIdentifier = savedUniqueID; this->copyHelperTileTabsLayoutBaseConfiguration(obj); } @@ -96,7 +92,9 @@ TileTabsLayoutBaseConfiguration::operator=(const TileTabsLayoutBaseConfiguration { if (this != &obj) { CaretObject::operator=(obj); + const QString savedUniqueID = m_uniqueIdentifier; this->copyHelperTileTabsLayoutBaseConfiguration(obj); + m_uniqueIdentifier = savedUniqueID; } return *this; } diff --git a/src/Common/TileTabsLayoutGridConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx index 1b0e84cee..30c8f6104 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -159,9 +159,9 @@ TileTabsLayoutGridConfiguration::initialize() void TileTabsLayoutGridConfiguration::copyHelperTileTabsLayoutGridConfiguration(const TileTabsLayoutGridConfiguration& obj) { - if (this == &obj) { - return; - } +// if (this == &obj) { +// return; +// } copyHelperTileTabsLayoutBaseConfiguration(obj); m_columns = obj.m_columns; diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx index e1bb722be..43f8ff4b8 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.cxx +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -95,6 +95,7 @@ TileTabsLayoutManualConfiguration::operator=(const TileTabsLayoutManualConfigura void TileTabsLayoutManualConfiguration::copyHelperTileTabsLayoutManualConfiguration(const TileTabsLayoutManualConfiguration& obj) { + copyHelperTileTabsLayoutBaseConfiguration(obj); m_tabInfo.clear(); for (const auto& ti : obj.m_tabInfo) { @@ -334,14 +335,14 @@ TileTabsLayoutManualConfiguration::encodeInXMLString(AString& xmlTextOut) const writer.writeStartElement(s_tabInfoElementName); writer.writeAttribute(s_tabInfoAttributeTabIndex, AString::number(tabInfo->getTabIndex())); - writer.writeAttribute(s_tabInfoAttributeCenterX, - AString::number(tabInfo->getCenterX(), 'f', 2)); - writer.writeAttribute(s_tabInfoAttributeCenterY, - AString::number(tabInfo->getCenterY(), 'f', 2)); - writer.writeAttribute(s_tabInfoAttributeWidth, - AString::number(tabInfo->getWidth(), 'f', 2)); - writer.writeAttribute(s_tabInfoAttributeHeight, - AString::number(tabInfo->getHeight(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeMinX, + AString::number(tabInfo->getMinX(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeMaxX, + AString::number(tabInfo->getMaxX(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeMinY, + AString::number(tabInfo->getMinY(), 'f', 2)); + writer.writeAttribute(s_tabInfoAttributeMaxY, + AString::number(tabInfo->getMaxY(), 'f', 2)); writer.writeAttribute(s_tabInfoAttributeStackingOrder, AString::number(tabInfo->getStackingOrder())); writer.writeAttribute(s_tabInfoAttributeBackground, @@ -393,9 +394,9 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, CaretLogWarning("Tile Tabs Manual Configuration is missing name and has been assigned name \"" + name + "\""); - setName(name); } - + setName(name); + AString uniqueID = rootAttributes.value(s_rootElementAttributeUniqueID).toString(); if (uniqueID.isEmpty()) { uniqueID = SystemUtilities::createUniqueID(); @@ -421,25 +422,42 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, const QString elementName(xml.name().toString()); if (elementName == s_tabInfoElementName) { + bool tabIndexValid(false); + bool minXValid(false); + bool maxXValid(false); + bool minYValid(false); + bool maxYValid(false); + bool stackingValid(false); const QXmlStreamAttributes atts = xml.attributes(); - const int32_t tabIndex = atts.value(s_tabInfoAttributeTabIndex).toInt(); - const float xCenter = atts.value(s_tabInfoAttributeCenterX).toFloat(); - const float yCenter = atts.value(s_tabInfoAttributeCenterY).toFloat(); - const float width = atts.value(s_tabInfoAttributeWidth).toFloat(); - const float height = atts.value(s_tabInfoAttributeHeight).toFloat(); - const int32_t stacking = atts.value(s_tabInfoAttributeStackingOrder).toInt(); + const int32_t tabIndex = atts.value(s_tabInfoAttributeTabIndex).toInt(&tabIndexValid); + const float minX = atts.value(s_tabInfoAttributeMinX).toFloat(&minXValid); + const float maxX = atts.value(s_tabInfoAttributeMaxX).toFloat(&maxXValid); + const float minY = atts.value(s_tabInfoAttributeMinY).toFloat(&minYValid); + const float maxY = atts.value(s_tabInfoAttributeMaxY).toFloat(&maxYValid); + const int32_t stacking = atts.value(s_tabInfoAttributeStackingOrder).toInt(&stackingValid); const QString backStr = atts.value(s_tabInfoAttributeBackground).toString(); const TileTabsLayoutBackgroundTypeEnum::Enum backType = TileTabsLayoutBackgroundTypeEnum::fromName(backStr, NULL); - TileTabsBrowserTabGeometry* tabInfo = new TileTabsBrowserTabGeometry(tabIndex); - tabInfo->setCenterX(xCenter); - tabInfo->setCenterY(yCenter); - tabInfo->setWidth(width); - tabInfo->setHeight(height); - tabInfo->setStackingOrder(stacking); - tabInfo->setBackgroundType(backType); - - addTabInfo(tabInfo); + if (tabIndexValid + && minXValid + && maxXValid + && minYValid + && maxYValid + && stackingValid) { + TileTabsBrowserTabGeometry* tabInfo = new TileTabsBrowserTabGeometry(tabIndex); + tabInfo->setMinX(minX); + tabInfo->setMaxX(maxX); + tabInfo->setMinY(minY); + tabInfo->setMaxY(maxY); + tabInfo->setStackingOrder(stacking); + tabInfo->setBackgroundType(backType); + + addTabInfo(tabInfo); + } + else { + CaretLogWarning("Failed to parse Manual Tile Tabs Configuration from Preferences: " + + xml.tokenString()); + } } else { invalidElementNames.insert(elementName); diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h index 6e99d4cd7..df77bb12e 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.h +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -92,10 +92,10 @@ namespace caret { static const AString s_tabInfoElementName; static const AString s_tabInfoAttributeTabIndex; - static const AString s_tabInfoAttributeCenterX; - static const AString s_tabInfoAttributeCenterY; - static const AString s_tabInfoAttributeWidth; - static const AString s_tabInfoAttributeHeight; + static const AString s_tabInfoAttributeMinX; + static const AString s_tabInfoAttributeMaxX; + static const AString s_tabInfoAttributeMinY; + static const AString s_tabInfoAttributeMaxY; static const AString s_tabInfoAttributeStackingOrder; static const AString s_tabInfoAttributeBackground; @@ -112,10 +112,10 @@ namespace caret { const AString TileTabsLayoutManualConfiguration::s_tabInfoElementName = "TabInfo"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeTabIndex = "TabIndex"; - const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeCenterX = "CenterX"; - const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeCenterY = "CenterY"; - const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeWidth = "Width"; - const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeHeight = "Height"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMinX = "MinX"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMaxX = "MaxX"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMinY = "MinY"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMaxY = "MaxY"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeStackingOrder = "StackingOrder"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeBackground = "Background"; #endif // __TILE_TABS_LAYOUT_MANUAL_CONFIGURATION_DECLARE__ diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 455462285..db4894754 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -2699,7 +2699,7 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QA QMenu* BrainBrowserWindow::createMenuViewTileTabsLoadUserConfiguration() { - QMenu* menu = new QMenu("Load Custom With User Configuration"); + QMenu* menu = new QMenu("Set Tile Tabs to User Configuration"); QObject::connect(menu, &QMenu::aboutToShow, this, &BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow); QObject::connect(menu, &QMenu::triggered, @@ -4474,6 +4474,20 @@ BrainBrowserWindow::getBrowerWindowContent() const return m_browserWindowContent; } +/** + * Get the Brain OpenGL Viewport content for all tabs + * + * @param viewportContentOut + * Contains viewport content on exit + */ +void +BrainBrowserWindow::getAllBrainOpenGLViewportContent(std::vector& viewportContentOut) const +{ + viewportContentOut.clear(); + + viewportContentOut = m_openGLWidget->getViewportContent(); +} + /** * Returns a popup menu for the main window. * Overrides that in QMainWindow and prevents the diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index c7b212bd0..9190a82d4 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -44,6 +44,7 @@ namespace caret { class BrainBrowserWindowToolBar; class BrainBrowserWindowOrientedToolBox; class BrainOpenGLWidget; + class BrainOpenGLViewportContent; class BrowserWindowContent; class BrowserTabContent; class EventTileTabsGridConfigurationModification; @@ -83,6 +84,8 @@ namespace caret { void removeAndReturnAllTabs(std::vector& allTabContent); + void getAllBrainOpenGLViewportContent(std::vector& viewportContentOut) const; + int32_t getBrowserWindowIndex() const; bool isTileTabsSelected() const; diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 05cf67ac7..f9abc96fe 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -45,9 +45,11 @@ #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" +#include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" +#include "CaretLogger.h" #include "CaretPreferences.h" #include "EnumComboBoxTemplate.h" #include "EventBrowserWindowGraphicsRedrawn.h" @@ -284,13 +286,34 @@ TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() m_blockReadConfigurationsFromPreferences = true; - const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); - CaretAssert(activeConfiguration); - - TileTabsLayoutGridConfiguration* configCopy = new TileTabsLayoutGridConfiguration(*activeConfiguration); - CaretAssert(configCopy); - configCopy->setName(newConfigName); - m_caretPreferences->addTileTabsUserConfiguration(configCopy); + switch (getBrowserWindowContent()->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(activeConfiguration); + + m_caretPreferences->addTileTabsUserConfiguration(activeConfiguration, + newConfigName); + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + { + TileTabsLayoutManualConfiguration* manualConfig = createManualConfigurationFromCurrentTabs(); + if (manualConfig != NULL) { + m_caretPreferences->addTileTabsUserConfiguration(manualConfig, + newConfigName); + delete manualConfig; + } + else { + WuQMessageBox::errorOk(m_addConfigurationPushButton, + "Tile Tabs MUST be enabled."); + } + } + break; + } m_blockReadConfigurationsFromPreferences = false; updateDialog(); @@ -302,9 +325,6 @@ TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() void TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() { - const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); - CaretAssert(activeConfiguration); - const AString tileTabsUniqueID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); if (tileTabsUniqueID.isEmpty()) { WuQMessageBox::errorOk(this, @@ -322,12 +342,43 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() m_blockReadConfigurationsFromPreferences = true; - AString errorMessage; - if ( ! m_caretPreferences->replaceTileTabsUserConfiguration(tileTabsUniqueID, - activeConfiguration, - errorMessage)) { - WuQMessageBox::errorOk(m_replaceConfigurationPushButton, - errorMessage); + switch (getBrowserWindowContent()->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + const TileTabsLayoutGridConfiguration* activeConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(activeConfiguration); + + AString errorMessage; + if ( ! m_caretPreferences->replaceTileTabsUserConfiguration(tileTabsUniqueID, + activeConfiguration, + errorMessage)) { + WuQMessageBox::errorOk(m_replaceConfigurationPushButton, + errorMessage); + } + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + { + TileTabsLayoutManualConfiguration* manualConfig = createManualConfigurationFromCurrentTabs(); + if (manualConfig != NULL) { + AString errorMessage; + if ( ! m_caretPreferences->replaceTileTabsUserConfiguration(tileTabsUniqueID, + manualConfig, + errorMessage)) { + WuQMessageBox::errorOk(m_replaceConfigurationPushButton, + errorMessage); + } + delete manualConfig; + } + else { + WuQMessageBox::errorOk(m_addConfigurationPushButton, + "Tile Tabs MUST be enabled."); + } + } + break; } m_blockReadConfigurationsFromPreferences = false; @@ -361,19 +412,97 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() switch (userConfiguration->getLayoutType()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + CaretAssert(0); + break; case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: { - TileTabsLayoutGridConfiguration* activeGridConfiguration = getCustomTileTabsGridConfiguration(); - CaretAssert(activeGridConfiguration); + TileTabsLayoutGridConfiguration* customGridConfiguration = getCustomTileTabsGridConfiguration(); + CaretAssert(customGridConfiguration); + + const TileTabsLayoutGridConfiguration* userGridConfig = userConfiguration->castToGridConfiguration(); + CaretAssert(userGridConfig); - const TileTabsLayoutGridConfiguration* copyConfig = userConfiguration->castToGridConfiguration(); - CaretAssert(copyConfig); + customGridConfiguration->copy(*userGridConfig); - activeGridConfiguration->copy(*copyConfig); + getBrowserWindowContent()->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); } break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: - CaretAssertToDoFatal(); + { + const TileTabsLayoutManualConfiguration* userManualConfig = userConfiguration->castToManualConfiguration(); + CaretAssert(userManualConfig); + const int32_t numConfigTabs = userManualConfig->getNumberOfTabs(); + + if (numConfigTabs <= 0) { + WuQMessageBox::errorOk(m_loadConfigurationPushButton, + ("User configuration \"" + + userManualConfig->getName() + + "\" is invalid (does not have any tabs)")); + return; + } + + std::vector allTabContent; + getBrowserWindow()->getAllTabContent(allTabContent); + const int32_t numBrowserTabs = static_cast(allTabContent.size()); + + const int numMissingTabs = numBrowserTabs - numConfigTabs; + if (numMissingTabs > 0) { + const QString msg("User configuration \"" + + userManualConfig->getName() + + "\" contains fewer tabs than in window. The last " + + AString::number(numMissingTabs) + + " will not change position."); + if ( ! WuQMessageBox::warningOkCancel(m_loadConfigurationPushButton, msg)) { + return; + } + } + + std::vector tabViewports; + getBrowserWindow()->getAllBrainOpenGLViewportContent(tabViewports); + const int32_t numViewportContent = static_cast(tabViewports.size()); + + for (int32_t i = 0; i < numBrowserTabs; i++) { + CaretAssertVectorIndex(allTabContent, i); + TileTabsBrowserTabGeometry* tabGeometry = allTabContent[i]->getManualLayoutGeometry(); + CaretAssert(tabGeometry); + + if (i < numConfigTabs) { + const TileTabsBrowserTabGeometry* configGeometry = userManualConfig->getTabInfo(i); + CaretAssert(configGeometry); + + tabGeometry->copyGeometry(*configGeometry); + } + else { + if (i < numViewportContent) { + /* + * Since no geometry available from the user configuration, + * keep this tab in its current window position + */ + const BrainOpenGLViewportContent* tabViewportContent = getViewportContentForTab(allTabContent[i]->getTabNumber()); + if (tabViewportContent != NULL) { + int32_t windowViewport[4]; + tabViewportContent->getWindowViewport(windowViewport); + const float minX(windowViewport[0]); + const float maxX(minX + windowViewport[2]); + const float minY(windowViewport[1]); + const float maxY(minY + windowViewport[3]); + + + tabGeometry->setMinX(minX); + tabGeometry->setMaxX(maxX); + tabGeometry->setMinY(minY); + tabGeometry->setMaxY(maxY); + } + else { + CaretLogWarning("Unable to find viewport content for tab number " + + AString::number(allTabContent[i]->getTabNumber())); + } + } + } + } + + getBrowserWindowContent()->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::MANUAL); + } break; } @@ -382,6 +511,95 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() updateGraphicsWindow(); } +/** + * @return the BrainOpenGLViewportContent for the tab with the given index (NULL if not found) + */ +const BrainOpenGLViewportContent* +TileTabsConfigurationDialog::getViewportContentForTab(const int32_t tabIndex) const +{ + std::vector tabViewports; + getBrowserWindow()->getAllBrainOpenGLViewportContent(tabViewports); + + for (const auto tv : tabViewports) { + if (tv->getTabIndex() == tabIndex) { + return tv; + } + } + + return NULL; +} + +/** + * @return A manual configuration from the geometry of the current tabs. If Tile Tabs + * is NOT enabled, NULL is returned. + */ +TileTabsLayoutManualConfiguration* +TileTabsConfigurationDialog::createManualConfigurationFromCurrentTabs() const +{ + const BrainBrowserWindow* window = getBrowserWindow(); + std::vector allTabContent; + window->getAllTabContent(allTabContent); + + TileTabsLayoutManualConfiguration* manualConfig = new TileTabsLayoutManualConfiguration(); + for (const auto btc : allTabContent) { + CaretAssert(btc); + const TileTabsBrowserTabGeometry* tabGeometry = btc->getManualLayoutGeometry(); + TileTabsBrowserTabGeometry* geometryCopy = new TileTabsBrowserTabGeometry(*tabGeometry); + manualConfig->addTabInfo(geometryCopy); + } + + +// { +// std::vector tabViewports; +// window->getAllBrainOpenGLViewportContent(tabViewports); +// +// const float windowWidth = window->width(); +// const float windowHeight = window->height(); +// +// TileTabsLayoutManualConfiguration* manualConfig = new TileTabsLayoutManualConfiguration(); +// +// for (const auto tv : tabViewports) { +// const int32_t tabIndex = tv->getTabIndex(); +// if (tabIndex >= 0) { +// int32_t viewport[4]; +// tv->getTabViewportBeforeApplyingMargins(viewport); +// +// const float minX = viewport[0]; +// const float maxX = viewport[0] + viewport[2]; +// const float minY = viewport[1]; +// const float maxY = viewport[1] + viewport[3]; +// +// TileTabsBrowserTabGeometry* geometry = new TileTabsBrowserTabGeometry(tabIndex); +// geometry->setMinX((minX / windowWidth) * 100.0); +// geometry->setMaxX((maxX / windowWidth) * 100.0); +// geometry->setMinY((minY / windowHeight) * 100.0); +// geometry->setMaxY((maxY / windowHeight) * 100.0); +// +// geometry->setStackingOrder(tabIndex); +// +// manualConfig->addTabInfo(geometry); +// } +// } +// } + + return manualConfig; +} + + +/** + * @return The browser window selected window index. + */ +const BrainBrowserWindow* +TileTabsConfigurationDialog::getBrowserWindow() const +{ + m_browserWindowComboBox->updateComboBox(); + /* + * This can be NULL when wb_view is closing. + */ + BrainBrowserWindow* bbw = m_browserWindowComboBox->getSelectedBrowserWindow(); + return bbw; +} + /** * @return The browser window selected window index. */ @@ -803,6 +1021,7 @@ TileTabsConfigurationDialog::addManualGeometryWidget(QGridLayout* gridLayout, gridLayout->addWidget(new QLabel("Right"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Bottom"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Top"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Background"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Order"), rowIndex, columnIndex++, Qt::AlignLeft); } @@ -1015,11 +1234,11 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(Til } CaretAssert(columnWidths.size() == columnWidthsInt.size()); - TileTabsLayoutManualConfiguration* manualLayout = new TileTabsLayoutManualConfiguration(); - manualLayout->setName("From row:" - + AString::number(rowHeights.size()) - + " col:" - + AString::number(columnWidths.size())); +// TileTabsLayoutManualConfiguration* manualLayout = new TileTabsLayoutManualConfiguration(); +// manualLayout->setName("From row:" +// + AString::number(rowHeights.size()) +// + " col:" +// + AString::number(columnWidths.size())); int32_t tabCounter(0); float yBottom(windowHeight); @@ -1042,7 +1261,7 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(Til case TileTabsGridRowColumnContentTypeEnum::SPACE: break; case TileTabsGridRowColumnContentTypeEnum::TAB: - { + if (tabCounter < numTabs) { CaretAssertVectorIndex(allTabContent, tabCounter); BrowserTabContent* tabContent(allTabContent[tabCounter]); @@ -1382,12 +1601,18 @@ TileTabsConfigurationDialog::deleteUserConfigurationButtonClicked() void TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() { - AString oldName; - AString uniqueID; - if (getSelectedUserConfigurationNameAndUniqueID(oldName, - uniqueID)) { + const AString uniqueID(getSelectedUserTileTabsConfigurationUniqueIdentifier()); + if (uniqueID.isEmpty()) { + WuQMessageBox::errorOk(m_renameConfigurationPushButton, + "Selected configuration is missing Unique Identifier (Program Error)"); + return; + } + + std::unique_ptr config = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(uniqueID); + if (config) { + const AString oldName = config->getName(); bool ok = false; - const AString newName = QInputDialog::getText(m_deleteConfigurationPushButton, + const AString newName = QInputDialog::getText(m_renameConfigurationPushButton, "Rename Configuration", "Name", QLineEdit::Normal, @@ -1408,8 +1633,37 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() m_blockReadConfigurationsFromPreferences = false; updateDialog(); } - } + else { + WuQMessageBox::errorOk(m_renameConfigurationPushButton, ("Unable to find configuration with unique ID=" + + uniqueID)); + } +// if (getSelectedUserConfigurationNameAndUniqueID(oldName, +// uniqueID)) { +// bool ok = false; +// const AString newName = QInputDialog::getText(m_renameConfigurationPushButton, +// "Rename Configuration", +// "Name", +// QLineEdit::Normal, +// oldName, +// &ok); +// if (ok +// && ( ! newName.isEmpty())) { +// m_blockReadConfigurationsFromPreferences = true; +// AString errorMessage; +// if (m_caretPreferences->renameTileTabsUserConfiguration(uniqueID, +// newName, +// errorMessage)) { +// } +// else { +// WuQMessageBox::errorOk(m_renameConfigurationPushButton, +// errorMessage); +// } +// m_blockReadConfigurationsFromPreferences = false; +// updateDialog(); +// } +// +// } } /** diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index 125f19bbd..d909e817b 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -42,6 +42,7 @@ class QToolButton; namespace caret { class BrainBrowserWindow; class BrainBrowserWindowComboBox; + class BrainOpenGLViewportContent; class BrowserWindowContent; class CaretPreferences; class EnumComboBoxTemplate; @@ -171,10 +172,16 @@ namespace caret { BrainBrowserWindow* getBrowserWindow(); + const BrainBrowserWindow* getBrowserWindow() const; + BrowserWindowContent* getBrowserWindowContent(); AString getNewConfigurationName(QWidget* dialogParent); + const BrainOpenGLViewportContent* getViewportContentForTab(const int32_t tabIndex) const; + + TileTabsLayoutManualConfiguration* createManualConfigurationFromCurrentTabs() const; + BrainBrowserWindowComboBox* m_browserWindowComboBox; QStackedWidget* m_editConfigurationStackedWidget; @@ -231,7 +238,6 @@ namespace caret { */ CaretPreferences* m_caretPreferences; - friend class TileTabGridRowColumnWidgets; friend class TileTabGridRowColumnWidgets; static const int32_t s_maximumRowsColumns = 50; diff --git a/src/GuiQt/TileTabsManualTabGeometryWidget.cxx b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx new file mode 100644 index 000000000..309d95ae3 --- /dev/null +++ b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx @@ -0,0 +1,326 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_DECLARE__ +#include "TileTabsManualTabGeometryWidget.h" +#undef __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_DECLARE__ + +#include +#include +#include + +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EnumComboBoxTemplate.h" +#include "TileTabsConfigurationDialog.h" +#include "TileTabsBrowserTabGeometry.h" +#include "WuQGridLayoutGroup.h" +#include "WuQtUtilities.h" + +using namespace caret; + +/** + * \class caret::TileTabsManualTabGeometryWidget + * \brief Contains widgets for adjusting a manual layout tab's geometry + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param tileTabsConfigurationDialog + * The tile tabs configuration dialog. + * @param index + * Index of this item in dialog (NOT the tab index) + * @param gridLayout + * Gridlayout for widgets + * @param parent + * Parent QObject + */ +TileTabsManualTabGeometryWidget::TileTabsManualTabGeometryWidget(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent) +: QObject(parent), +m_tileTabsConfigurationDialog(tileTabsConfigurationDialog), +m_index(index) +{ + CaretAssert(tileTabsConfigurationDialog); + CaretAssert(gridLayout); + + m_tabNumberLabel = new QLabel(" "); + m_tabNumberLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + m_xMinSpinBox = createPercentSpinBox("Left edge of tab", true); + QObject::connect(m_xMinSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &TileTabsManualTabGeometryWidget::xMinSpinBoxValueChanged); + + m_xMaxSpinBox = createPercentSpinBox("Right edge of tab", false); + QObject::connect(m_xMaxSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &TileTabsManualTabGeometryWidget::xMaxSpinBoxValueChanged); + + m_yMinSpinBox = createPercentSpinBox("Bottom edge of tab", true); + QObject::connect(m_yMinSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &TileTabsManualTabGeometryWidget::yMinSpinBoxValueChanged); + + m_yMaxSpinBox = createPercentSpinBox("Top edge of tab", false); + QObject::connect(m_yMaxSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &TileTabsManualTabGeometryWidget::yMaxSpinBoxValueChanged); + + const QString stackOrderToolTipText("Larger numbers are in front of other tabs. This value only needs adjustment " + "if this tab overlaps with another tab"); + m_stackingOrderSpinBox = new QSpinBox(); + m_stackingOrderSpinBox->setMinimum(-100); + m_stackingOrderSpinBox->setMaximum(100); + m_stackingOrderSpinBox->setSingleStep(1); + m_stackingOrderSpinBox->setToolTip(WuQtUtilities::createWordWrappedToolTipText(stackOrderToolTipText)); + QObject::connect(m_stackingOrderSpinBox, QOverload::of(&QSpinBox::valueChanged), + this, &TileTabsManualTabGeometryWidget::stackingOrderValueChanged); + + m_TileTabsLayoutBackgroundTypeEnumComboBox = new EnumComboBoxTemplate(this); + m_TileTabsLayoutBackgroundTypeEnumComboBox->setup(); + m_TileTabsLayoutBackgroundTypeEnumComboBox->getComboBox()->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); + QObject::connect(m_TileTabsLayoutBackgroundTypeEnumComboBox, SIGNAL(itemActivated()), + this, SLOT(tileTabsLayoutBackgroundTypeEnumComboBoxItemActivated())); + + m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); + const int32_t rowIndex(gridLayout->rowCount()); + int32_t columnIndex(0); + m_gridLayoutGroup->addWidget(m_tabNumberLabel, rowIndex, columnIndex++, Qt::AlignLeft); + m_gridLayoutGroup->addWidget(m_xMinSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); + m_gridLayoutGroup->addWidget(m_xMaxSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); + m_gridLayoutGroup->addWidget(m_yMinSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); + m_gridLayoutGroup->addWidget(m_yMaxSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); + m_gridLayoutGroup->addWidget(m_TileTabsLayoutBackgroundTypeEnumComboBox->getWidget(), rowIndex, columnIndex++, Qt::AlignHCenter); + m_gridLayoutGroup->addWidget(m_stackingOrderSpinBox, rowIndex, columnIndex++); +} + +/** + * Destructor. + */ +TileTabsManualTabGeometryWidget::~TileTabsManualTabGeometryWidget() +{ +} + +/** + * Update the content of this item + * + * @param browserTabContent + * Tab content for the widgets + */ +void +TileTabsManualTabGeometryWidget::updateContent(BrowserTabContent* browserTabContent) +{ + m_browserTabContent = browserTabContent; + const bool showFlag(m_browserTabContent != NULL); + + if (showFlag) { + m_tabNumberLabel->setText(browserTabContent->getTabName()); + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + + updatePercentSpinBox(m_xMinSpinBox, geometry->getMinX()); + updatePercentSpinBox(m_xMaxSpinBox, geometry->getMaxX()); + updatePercentSpinBox(m_yMinSpinBox, geometry->getMinY()); + updatePercentSpinBox(m_yMaxSpinBox, geometry->getMaxY()); + + const TileTabsLayoutBackgroundTypeEnum::Enum background = geometry->getBackgroundType(); + m_TileTabsLayoutBackgroundTypeEnumComboBox->setSelectedItem(background); + + QSignalBlocker blocker(m_stackingOrderSpinBox); // setValue() causes signal + m_stackingOrderSpinBox->setValue(geometry->getStackingOrder()); + } + + m_gridLayoutGroup->setVisible(showFlag); + +} + +/** + * Update a percentage spin box value + * + * @param spinBox + * The spin box + * @param value + * New value for spin box + */ +void +TileTabsManualTabGeometryWidget::updatePercentSpinBox(QDoubleSpinBox* spinBox, + const double value) +{ + CaretAssert(spinBox); + + /* + * Must block signal because setValue() trigger's the signal + */ + QSignalBlocker blocker(spinBox); + spinBox->setValue(value); +} + +/** + * Create a double spin box for percentage value + * + * @param toolTip + * Tooltip for the spin box + * @param minValueFlag + * True if spin box is for a minimum value, else a maximum value + * @return + * The spin box + */ +QDoubleSpinBox* +TileTabsManualTabGeometryWidget::createPercentSpinBox(const QString& toolTip, + const bool minValueFlag) +{ + QDoubleSpinBox* dsb = new QDoubleSpinBox(); + if (minValueFlag) { + dsb->setMinimum(-99.0); + dsb->setMaximum(99.0); + } + else { + dsb->setMinimum(1.0); + dsb->setMaximum(199.0); + } + dsb->setDecimals(1); + dsb->setSingleStep(0.1); + dsb->setToolTip(toolTip); + + /* + * If keyboard tracking is on and user types values 4, 0 then two signals are + * emitted 4 and 40. We do not want this since we want to keep minimum values + * less than maximum values + */ + dsb->setKeyboardTracking(false); + + return dsb; +} + +/** + * Called when x-min value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::xMinSpinBoxValueChanged(double value) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setMinX(value); + updateContent(m_browserTabContent); // 'geometry' ensures min < max + emit itemChanged(); + } +} + +/** + * Called when x-max value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::xMaxSpinBoxValueChanged(double value) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setMaxX(value); + updateContent(m_browserTabContent); // 'geometry' ensures min < max + emit itemChanged(); + } +} + +/** + * Called when y-min value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::yMinSpinBoxValueChanged(double value) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setMinY(value); + updateContent(m_browserTabContent); // 'geometry' ensures min < max + emit itemChanged(); + } +} + +/** + * Called when x-max value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::yMaxSpinBoxValueChanged(double value) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setMaxY(value); + updateContent(m_browserTabContent); // 'geometry' ensures min < max + emit itemChanged(); + } +} + +/** + * Called when stacking order value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::stackingOrderValueChanged(int value) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setStackingOrder(value); + emit itemChanged(); + } +} + +/** + * Called when background value is changed + * + * @param value + * New value + */ +void +TileTabsManualTabGeometryWidget::tileTabsLayoutBackgroundTypeEnumComboBoxItemActivated() +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); + CaretAssert(geometry); + + const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType = m_TileTabsLayoutBackgroundTypeEnumComboBox->getSelectedItem(); + geometry->setBackgroundType(backgroundType); + emit itemChanged(); + } +} diff --git a/src/GuiQt/TileTabsManualTabGeometryWidget.h b/src/GuiQt/TileTabsManualTabGeometryWidget.h new file mode 100644 index 000000000..5d75d854c --- /dev/null +++ b/src/GuiQt/TileTabsManualTabGeometryWidget.h @@ -0,0 +1,117 @@ +#ifndef __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_H__ +#define __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include + +class QGridLayout; +class QLabel; +class QDoubleSpinBox; +class QSpinBox; + +namespace caret { + + class BrowserTabContent; + class EnumComboBoxTemplate; + class TileTabsConfigurationDialog; + class WuQGridLayoutGroup; + + class TileTabsManualTabGeometryWidget : public QObject { + + Q_OBJECT + + public: + TileTabsManualTabGeometryWidget(TileTabsConfigurationDialog* tileTabsConfigurationDialog, + const int32_t index, + QGridLayout* gridLayout, + QObject* parent); + + virtual ~TileTabsManualTabGeometryWidget(); + + TileTabsManualTabGeometryWidget(const TileTabsManualTabGeometryWidget&) = delete; + + TileTabsManualTabGeometryWidget& operator=(const TileTabsManualTabGeometryWidget&) = delete; + + void updateContent(BrowserTabContent* browserTabContent); + + // ADD_NEW_METHODS_HERE + + signals: + void itemChanged(); + + private slots: + void xMinSpinBoxValueChanged(double value); + + void xMaxSpinBoxValueChanged(double value); + + void yMinSpinBoxValueChanged(double value); + + void yMaxSpinBoxValueChanged(double value); + + void stackingOrderValueChanged(int value); + + void tileTabsLayoutBackgroundTypeEnumComboBoxItemActivated(); + + private: + QDoubleSpinBox* createPercentSpinBox(const QString& toolTip, + const bool minValueFlag); + + void updatePercentSpinBox(QDoubleSpinBox* spinBox, + const double value); + + TileTabsConfigurationDialog* m_tileTabsConfigurationDialog; + + /** index of this item; NOT the tab index */ + const int32_t m_index; + + BrowserTabContent* m_browserTabContent = NULL; + + QLabel* m_tabNumberLabel; + + QDoubleSpinBox* m_xMinSpinBox; + + QDoubleSpinBox* m_xMaxSpinBox; + + QDoubleSpinBox* m_yMinSpinBox; + + QDoubleSpinBox* m_yMaxSpinBox; + + QSpinBox* m_stackingOrderSpinBox; + + EnumComboBoxTemplate* m_TileTabsLayoutBackgroundTypeEnumComboBox; + + WuQGridLayoutGroup* m_gridLayoutGroup; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_DECLARE__ + // +#endif // __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_DECLARE__ + +} // namespace +#endif //__TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_H__ diff --git a/src/Scenes/CMakeLists.txt b/src/Scenes/CMakeLists.txt index abc7defab..3ff44a971 100644 --- a/src/Scenes/CMakeLists.txt +++ b/src/Scenes/CMakeLists.txt @@ -77,6 +77,7 @@ SceneXmlStreamBase.h SceneXmlStreamReader.h SceneXmlStreamWriter.h SceneableInterface.h +TileTabsBrowserTabGeometrySceneHelper.h BackgroundAndForegroundColorsSceneHelper.cxx DisplayGroupAndTabItemHelper.cxx @@ -118,6 +119,7 @@ SceneWriterXml.cxx SceneXmlStreamBase.cxx SceneXmlStreamReader.cxx SceneXmlStreamWriter.cxx +TileTabsBrowserTabGeometrySceneHelper.cxx ) TARGET_LINK_LIBRARIES(Scenes ${CARET_QT5_LINK}) diff --git a/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx new file mode 100644 index 000000000..8b3dd3f09 --- /dev/null +++ b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx @@ -0,0 +1,151 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_DECLARE__ +#include "TileTabsBrowserTabGeometrySceneHelper.h" +#undef __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_DECLARE__ + +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" +#include "TileTabsBrowserTabGeometry.h" + +using namespace caret; + + + +/** + * \class caret::TileTabsBrowserTabGeometrySceneHelper + * \brief Helps with saving/restoring tile tabs geometry from scene + * \ingroup Scenes + */ + +/** + * Constructor. + * + * @param geometry + * Tile tabs geometry saved to or restored from scene + */ +TileTabsBrowserTabGeometrySceneHelper::TileTabsBrowserTabGeometrySceneHelper(TileTabsBrowserTabGeometry* geometry) +: CaretObject(), +m_geometry(geometry) +{ + CaretAssert(m_geometry); + m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + + m_sceneAssistant->add("m_tabIndex", + &m_geometry->m_tabIndex); + m_sceneAssistant->add("m_minX", + &m_geometry->m_minX); + m_sceneAssistant->add("m_maxX", + &m_geometry->m_maxX); + m_sceneAssistant->add("m_minY", + &m_geometry->m_minY); + m_sceneAssistant->add("m_maxY", + &m_geometry->m_maxY); + m_sceneAssistant->add("m_stackingOrder", + &m_geometry->m_stackingOrder); + m_sceneAssistant->add("m_backgroundType", + &m_geometry->m_backgroundType); +} + +/** + * Destructor. + */ +TileTabsBrowserTabGeometrySceneHelper::~TileTabsBrowserTabGeometrySceneHelper() +{ +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TileTabsBrowserTabGeometrySceneHelper::toString() const +{ + return "TileTabsBrowserTabGeometrySceneHelper"; +} + +/** + * Save information specific to this type of model to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * saving the scene. + * + * @param instanceName + * Name of instance in the scene. + */ +SceneClass* +TileTabsBrowserTabGeometrySceneHelper::saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName) +{ + SceneClass* sceneClass = new SceneClass(instanceName, + "TileTabsBrowserTabGeometrySceneHelper", + 1); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); + + // Uncomment if sub-classes must save to scene + //saveSubClassDataToScene(sceneAttributes, + // sceneClass); + + return sceneClass; +} + +/** + * Restore information specific to the type of model from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass from which model specific information is obtained. + */ +void +TileTabsBrowserTabGeometrySceneHelper::restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + if (sceneClass == NULL) { + return; + } + + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); + + //Uncomment if sub-classes must restore from scene + //restoreSubClassDataFromScene(sceneAttributes, + // sceneClass); + +} + +/** + * @return True if the geometry was restored from the scene, else false. + */ +bool +TileTabsBrowserTabGeometrySceneHelper::wasRestoredFromScene() const +{ + return m_wasRestoredFromSceneFlag; +} + diff --git a/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.h b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.h new file mode 100644 index 000000000..8ba3c5ebd --- /dev/null +++ b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.h @@ -0,0 +1,92 @@ +#ifndef __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_H__ +#define __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + +#include "SceneableInterface.h" + + +namespace caret { + class SceneClassAssistant; + class TileTabsBrowserTabGeometry; + + class TileTabsBrowserTabGeometrySceneHelper : public CaretObject, public SceneableInterface { + + public: + TileTabsBrowserTabGeometrySceneHelper(TileTabsBrowserTabGeometry* geometry); + + virtual ~TileTabsBrowserTabGeometrySceneHelper(); + + TileTabsBrowserTabGeometrySceneHelper(const TileTabsBrowserTabGeometrySceneHelper&) = delete; + + TileTabsBrowserTabGeometrySceneHelper& operator=(const TileTabsBrowserTabGeometrySceneHelper&) = delete; + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, + const AString& instanceName); + + virtual void restoreFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + bool wasRestoredFromScene() const; + + + + + +// If there will be sub-classes of this class that need to save +// and restore data from scenes, these pure virtual methods can +// be uncommented to force their implementation by sub-classes. +// protected: +// virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, +// SceneClass* sceneClass) = 0; +// +// virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, +// const SceneClass* sceneClass) = 0; + + private: + TileTabsBrowserTabGeometry* m_geometry; + + std::unique_ptr m_sceneAssistant; + + bool m_wasRestoredFromSceneFlag = false; + + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_DECLARE__ + // +#endif // __TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_DECLARE__ + +} // namespace +#endif //__TILE_TABS_BROWSER_TAB_GEOMETRY_SCENE_HELPER_H__ -- GitLab From dd803fc35d4cf301a85ac58da943ad7fc33fdb35 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 14 Aug 2019 10:38:18 -0500 Subject: [PATCH 007/584] WB-859 Manual Tile Tabs Layout System: Continue development: OPAQUE and TRANSPARENT enums in TileTabsLayoutBackgroundTypeEnum clashed with symbol in Windows OpenGL so they were renamed to OPAQUE_BG and TRANSPARENT_BG. --- src/Brain/BrainOpenGLFixedPipeline.cxx | 4 ++-- src/Common/TileTabsBrowserTabGeometry.h | 2 +- src/Common/TileTabsLayoutBackgroundTypeEnum.cxx | 17 ++++++++++++----- src/Common/TileTabsLayoutBackgroundTypeEnum.h | 8 ++++---- .../TileTabsLayoutManualConfiguration.cxx | 2 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 2 +- src/GuiQt/UserInputModeViewContextMenu.cxx | 2 +- 7 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 5da029d6b..9b63d6257 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -667,10 +667,10 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, if (numberOfTabs > 1) { bool opaqueFlag(false); switch (tabContent->getManualLayoutGeometry()->getBackgroundType()) { - case TileTabsLayoutBackgroundTypeEnum::OPAQUE: + case TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG: opaqueFlag = true; break; - case TileTabsLayoutBackgroundTypeEnum::TRANSPARENT: + case TileTabsLayoutBackgroundTypeEnum::TRANSPARENT_BG: break; } diff --git a/src/Common/TileTabsBrowserTabGeometry.h b/src/Common/TileTabsBrowserTabGeometry.h index 024d58fcb..3a6454c9d 100644 --- a/src/Common/TileTabsBrowserTabGeometry.h +++ b/src/Common/TileTabsBrowserTabGeometry.h @@ -116,7 +116,7 @@ namespace caret { int32_t m_stackingOrder = 1; /** Type of background (opaque / transparent) for tab*/ - TileTabsLayoutBackgroundTypeEnum::Enum m_backgroundType = TileTabsLayoutBackgroundTypeEnum::OPAQUE; + TileTabsLayoutBackgroundTypeEnum::Enum m_backgroundType = TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG; // ADD_NEW_MEMBERS_HERE diff --git a/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx index 4d75ca484..7e988595d 100644 --- a/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx @@ -106,12 +106,12 @@ TileTabsLayoutBackgroundTypeEnum::initialize() } initializedFlag = true; - enumData.push_back(TileTabsLayoutBackgroundTypeEnum(OPAQUE, - "OPAQUE", + enumData.push_back(TileTabsLayoutBackgroundTypeEnum(OPAQUE_BG, + "OPAQUE_BG", "Opaque")); - enumData.push_back(TileTabsLayoutBackgroundTypeEnum(TRANSPARENT, - "TRANSPARENT", + enumData.push_back(TileTabsLayoutBackgroundTypeEnum(TRANSPARENT_BG, + "TRANSPARENT_BG", "Transparent")); } @@ -165,10 +165,17 @@ TileTabsLayoutBackgroundTypeEnum::toName(Enum enumValue) { * Enumerated value. */ TileTabsLayoutBackgroundTypeEnum::Enum -TileTabsLayoutBackgroundTypeEnum::fromName(const AString& name, bool* isValidOut) +TileTabsLayoutBackgroundTypeEnum::fromName(const AString& nameIn, bool* isValidOut) { if (initializedFlag == false) initialize(); + AString name(nameIn); + if (name == "OPAQUE") { + name = "OPAQUED_BG"; + } + else if (name == "TRANSPARENT") { + name = "TRANSPARENT_BG"; + } bool validFlag = false; Enum enumValue = TileTabsLayoutBackgroundTypeEnum::enumData[0].enumValue; diff --git a/src/Common/TileTabsLayoutBackgroundTypeEnum.h b/src/Common/TileTabsLayoutBackgroundTypeEnum.h index abec04a3b..7cd99ac64 100644 --- a/src/Common/TileTabsLayoutBackgroundTypeEnum.h +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.h @@ -35,10 +35,10 @@ public: * Enumerated values. */ enum Enum { - /** Opaque */ - OPAQUE, - /** Transparent */ - TRANSPARENT + /** Opaque Note: 'OPAQUE' clashes with symbol in Window OpenGL */ + OPAQUE_BG, + /** Transparent Note: 'TRANSPARENT' clashes with symbol in Window OpenGL*/ + TRANSPARENT_BG }; diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx index 43f8ff4b8..7ec3c798c 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.cxx +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -218,7 +218,7 @@ TileTabsLayoutManualConfiguration::newInstanceFromGridLayout(TileTabsLayoutGridC tabInfo->setWidth((width / windowWidth) * 100.0f); tabInfo->setHeight((height / windowHeight) * 100.0f); tabInfo->setStackingOrder(tabCounter); - tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); + tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG); manualLayout->addTabInfo(tabInfo); diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index f9abc96fe..33cc11b34 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -1272,7 +1272,7 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(Til tabInfo->setMaxY(((yBottom + height) / windowHeight) * 100.0); tabInfo->setStackingOrder(tabCounter); - tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE); + tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG); tabCounter++; } diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index 141684efb..411ce0bc0 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -458,7 +458,7 @@ UserInputModeViewContextMenu::createParcelConnectivities() if (idNode->isValid() && idVoxel->isValid()) { - std::cout << "Have both surface and volume ID" << std::endl; + /* std::cout << "Have both surface and volume ID" << std::endl; */ } /* -- GitLab From 1c44f7bf8903e19bb4c71e91683f280d2aa38034 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 15 Aug 2019 16:30:25 -0500 Subject: [PATCH 008/584] WB-859 Manual Tile Tabs Layout System: Continue development: Implemented context menu (popup menu) items for manual layouts Bring to Front, Send to Back, Bring Forward, and Send Backward. --- src/Common/TileTabsBrowserTabGeometry.cxx | 99 +++++++ src/Common/TileTabsBrowserTabGeometry.h | 12 + .../TileTabsLayoutBackgroundTypeEnum.cxx | 6 +- src/GuiQt/BrainBrowserWindow.cxx | 4 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 212 +++++++++++---- src/GuiQt/BrainBrowserWindowToolBar.h | 9 +- src/GuiQt/CMakeLists.txt | 6 +- .../EventBrowserWindowTileTabOperation.cxx | 75 +++++- .../EventBrowserWindowTileTabOperation.h | 24 +- ... => TileTabsGridConfigurationModifier.cxx} | 52 ++-- ....h => TileTabsGridConfigurationModifier.h} | 20 +- .../TileTabsManualConfigurationModifier.cxx | 224 ++++++++++++++++ .../TileTabsManualConfigurationModifier.h | 93 +++++++ src/GuiQt/UserInputModeView.cxx | 3 +- src/GuiQt/UserInputModeViewContextMenu.cxx | 246 +++++++++++------- src/GuiQt/UserInputModeViewContextMenu.h | 14 +- src/GuiQt/UserInputTileTabsContextMenu.cxx | 110 +++++--- src/GuiQt/UserInputTileTabsContextMenu.h | 29 ++- 18 files changed, 1012 insertions(+), 226 deletions(-) rename src/GuiQt/{TileTabsConfigurationModifier.cxx => TileTabsGridConfigurationModifier.cxx} (90%) rename src/GuiQt/{TileTabsConfigurationModifier.h => TileTabsGridConfigurationModifier.h} (84%) create mode 100644 src/GuiQt/TileTabsManualConfigurationModifier.cxx create mode 100644 src/GuiQt/TileTabsManualConfigurationModifier.h diff --git a/src/Common/TileTabsBrowserTabGeometry.cxx b/src/Common/TileTabsBrowserTabGeometry.cxx index 11e5071a1..5e3900676 100644 --- a/src/Common/TileTabsBrowserTabGeometry.cxx +++ b/src/Common/TileTabsBrowserTabGeometry.cxx @@ -154,6 +154,54 @@ TileTabsBrowserTabGeometry::toString() const return str; } +/** + * Set the bounds + * + * @param minX + * The minimum X value + * @param maxX + * The maximum X value + * @param minY + * The minimum Y value + * @param maxY + * The maximum Y value + */ +void +TileTabsBrowserTabGeometry::setBounds(const float minX, + const float maxX, + const float minY, + const float maxY) +{ + m_minX = minX; + m_maxX = maxX; + m_minY = minY; + m_maxY = maxY; +} + +/** + * Get the bounds + * + * @param minX + * The minimum X value + * @param maxX + * The maximum X value + * @param minY + * The minimum Y value + * @param maxY + * The maximum Y value + */ +void +TileTabsBrowserTabGeometry::getBounds(float& minX, + float& maxX, + float& minY, + float& maxY) const +{ + minX = m_minX; + maxX = m_maxX; + minY = m_minY; + maxY = m_maxY; +} + /** * @return center x-coordinate as percentage 0% to 100% */ @@ -402,3 +450,54 @@ TileTabsBrowserTabGeometry::setBackgroundType(const TileTabsLayoutBackgroundType { m_backgroundType = backgroundType; } + +/** + * @return true if this and the given geometry intersect. + * NOTE: if 'other' is 'this' true is returned (overlaps self) but this + * could change so it is best to avoid testing overlap of self. + * + * @param other + * Other geometry for intersection test + */ +bool +TileTabsBrowserTabGeometry::intersectionTest(const TileTabsBrowserTabGeometry* other) const +{ + CaretAssert(other); + + /* + * Does self overlap + */ + if (this == other) { + return true; + } + + /* + * Note: Since the geometry is aligned with the X- and Y-axes, + * we only need to test for one to be above or the the right of the other + * + * https://www.geeksforgeeks.org/find-two-rectangles-overlap/ + * https://leetcode.com/articles/rectangle-overlap/ + */ + /* 'this' is on right side of 'other' */ + if (m_minX >= other->m_maxX) { + return false; + } + + /* 'other' is on right side of 'this' */ + if (other->m_minX >= m_maxX) { + return false; + } + + /* 'this' is above 'other */ + if (m_minY >= other->m_maxY) { + return false; + } + + /* 'other' is above 'this' */ + if (other->m_minY >= m_maxY) { + return false; + } + + return true; +} + diff --git a/src/Common/TileTabsBrowserTabGeometry.h b/src/Common/TileTabsBrowserTabGeometry.h index 3a6454c9d..94756b6aa 100644 --- a/src/Common/TileTabsBrowserTabGeometry.h +++ b/src/Common/TileTabsBrowserTabGeometry.h @@ -46,6 +46,16 @@ namespace caret { int32_t getTabIndex() const; + void setBounds(const float minX, + const float maxX, + const float minY, + const float maxY); + + void getBounds(float& minX, + float& maxX, + float& minY, + float& maxY) const; + float getCenterX() const; void setCenterX(const float x); @@ -90,6 +100,8 @@ namespace caret { void setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType); + bool intersectionTest(const TileTabsBrowserTabGeometry* other) const; + // ADD_NEW_METHODS_HERE virtual AString toString() const; diff --git a/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx index 7e988595d..a6036bf3f 100644 --- a/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx +++ b/src/Common/TileTabsLayoutBackgroundTypeEnum.cxx @@ -171,7 +171,7 @@ TileTabsLayoutBackgroundTypeEnum::fromName(const AString& nameIn, bool* isValidO AString name(nameIn); if (name == "OPAQUE") { - name = "OPAQUED_BG"; + name = "OPAQUE_BG"; } else if (name == "TRANSPARENT") { name = "TRANSPARENT_BG"; @@ -193,8 +193,8 @@ TileTabsLayoutBackgroundTypeEnum::fromName(const AString& nameIn, bool* isValidO if (isValidOut != 0) { *isValidOut = validFlag; } - else if (validFlag == false) { - CaretAssertMessage(0, AString("Name " + name + "failed to match enumerated value for type TileTabsLayoutBackgroundTypeEnum")); + else if ( ! validFlag) { + CaretAssertMessage(0, AString("Name " + name + " failed to match enumerated value for type TileTabsLayoutBackgroundTypeEnum")); } return enumValue; } diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index db4894754..1b9805a2b 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -111,7 +111,7 @@ #include "SurfaceSelectionViewController.h" #include "TileTabsLayoutGridConfiguration.h" #include "TileTabsLayoutManualConfiguration.h" -#include "TileTabsConfigurationModifier.h" +#include "TileTabsGridConfigurationModifier.h" #include "WuQDataEntryDialog.h" #include "WuQDoubleSpinBox.h" #include "WuQMacroManager.h" @@ -2571,7 +2571,7 @@ BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsGridConfigurationMo vpContent = m_openGLWidget->getViewportContent(); } - TileTabsConfigurationModifier modifier(vpContent, + TileTabsGridConfigurationModifier modifier(vpContent, modEvent); AString errorMessage; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index e841a5013..eff8556d9 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -121,6 +121,8 @@ #include "SurfaceSelectionViewController.h" #include "StructureSurfaceSelectionControl.h" #include "TileTabsLayoutGridConfiguration.h" +#include "TileTabsBrowserTabGeometry.h" +#include "TileTabsManualConfigurationModifier.h" #include "UserInputModeAbstract.h" #include "VolumeFile.h" #include "VolumeSliceViewPlaneEnum.h" @@ -825,11 +827,14 @@ BrainBrowserWindowToolBar::replaceBrowserTabs(const std::vector= 0){ @@ -877,6 +884,8 @@ BrainBrowserWindowToolBar::insertNewTabAtTabBarIndex(const int32_t tabBarIndex) EventManager::get()->sendEvent(EventSurfaceColoringInvalidate().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(this->browserWindowIndex).getPointer()); + + return tabContent; } @@ -912,16 +921,18 @@ BrainBrowserWindowToolBar::insertTabContentPrivate(const InsertTabMode insertTab } break; } - - this->tabBar->setTabData(newTabIndex, - qVariantFromValue((void*)browserTabContent)); - - const int32_t numOpenTabs = this->tabBar->count(); - this->tabBar->setTabsClosable(numOpenTabs > 1); - - this->updateTabName(newTabIndex); - - this->tabBar->setCurrentIndex(newTabIndex); + + if (newTabIndex >= 0) { + this->tabBar->setTabData(newTabIndex, + qVariantFromValue((void*)browserTabContent)); + + const int32_t numOpenTabs = this->tabBar->count(); + this->tabBar->setTabsClosable(numOpenTabs > 1); + + this->updateTabName(newTabIndex); + + this->tabBar->setCurrentIndex(newTabIndex); + } this->tabBar->blockSignals(false); } @@ -4535,36 +4546,7 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) EventBrowserWindowTileTabOperation* tileTabsEvent = dynamic_cast(event); CaretAssert(tileTabsEvent); - - if (tileTabsEvent->getWindowIndex() == this->browserWindowIndex) { - const int32_t browserTabIndex = tileTabsEvent->getBrowserTabIndex(); - int32_t tabBarIndex = getTabBarIndexWithBrowserTabIndex(browserTabIndex); - const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); - switch (operation) { - case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER: - if (tabBarIndex >= 0) { - insertNewTabAtTabBarIndex(tabBarIndex + 1); - } - break; - case EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE: - if (tabBarIndex >= 0) { - insertNewTabAtTabBarIndex(tabBarIndex); - } - break; - case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: - if (tabBarIndex >= 0) { - m_tileTabsHighlightingTimerEnabledFlag = false; - this->tabBar->setCurrentIndex(tabBarIndex); - m_tileTabsHighlightingTimerEnabledFlag = true; - } - break; - case EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS: - replaceBrowserTabs(tileTabsEvent->getBrowserTabsForReplaceOperation()); - break; - } - - tileTabsEvent->setEventProcessed(); - } + processTileTabOperationEvent(tileTabsEvent); } else if (event->getEventType() == EventTypeEnum::EVENT_UPDATE_YOKED_WINDOWS) { EventUpdateYokedWindows* yokeUpdateEvent = @@ -4610,6 +4592,146 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) } } +/** + * Process a tile tab operation event. + * + * @param tileTabOperation + */ +void +BrainBrowserWindowToolBar::processTileTabOperationEvent(EventBrowserWindowTileTabOperation* tileTabsEvent) +{ + if (tileTabsEvent->getWindowIndex() == this->browserWindowIndex) { + const int32_t browserTabIndex = tileTabsEvent->getBrowserTabIndex(); + int32_t tabBarIndex = getTabBarIndexWithBrowserTabIndex(browserTabIndex); + const EventBrowserWindowTileTabOperation::Operation operation = tileTabsEvent->getOperation(); + switch (operation) { + case EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_AFTER: + if (tabBarIndex >= 0) { + insertNewTabAtTabBarIndex(tabBarIndex + 1); + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_BEFORE: + if (tabBarIndex >= 0) { + insertNewTabAtTabBarIndex(tabBarIndex); + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB: + { + BrowserTabContent* btc = addNewTab(); + if (btc != NULL) { + int32_t windowViewport[4]; + tileTabsEvent->getWindowViewport(windowViewport); + + const float windowWidth = windowViewport[2]; + const float windowHeight = windowViewport[3]; + const float windowArea = windowWidth * windowHeight; + + float tabWidth(250); + float tabHeight(250); + const float numTabs = getNumberOfTabs(); + if (windowArea > 100.0) { + if (numTabs > 1) { + const float area = windowArea / numTabs; + tabWidth = std::sqrt(area); + tabHeight = std::sqrt(area); + } + } + + const float mouseX(tileTabsEvent->getMouseX()); + const float mouseY(tileTabsEvent->getMouseY()); + + /* + * Coordinates are in percentages + */ + float tabMinX = (mouseX - (tabWidth / 2.0)); + float tabMaxX = (mouseX + (tabWidth / 2.0)); + float tabMinY = (mouseY - (tabHeight / 2.0)); + float tabMaxY = (mouseY + (tabHeight / 2.0)); + + tabMinX = (tabMinX / windowWidth) * 100.0; + tabMaxX = (tabMaxX / windowWidth) * 100.0; + tabMinY = (tabMinY / windowHeight) * 100.0; + tabMaxY = (tabMaxY / windowHeight) * 100.0; + + TileTabsBrowserTabGeometry* geometry = btc->getManualLayoutGeometry(); + CaretAssert(geometry); + geometry->setBounds(tabMinX, + tabMaxX, + tabMinY, + tabMaxY); + updateGraphicsWindow(); + } + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT: + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD: + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK: + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD: + { + TileTabsManualConfigurationModifier::TabOrderOperation tabOrderOperation = TileTabsManualConfigurationModifier::TabOrderOperation::BRING_TO_FRONT; + switch (operation) { + case EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_AFTER: + case EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_BEFORE: + case EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB: + CaretAssert(0); + break; + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT: + tabOrderOperation = TileTabsManualConfigurationModifier::TabOrderOperation::BRING_TO_FRONT; + break; + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD: + tabOrderOperation = TileTabsManualConfigurationModifier::TabOrderOperation::BRING_FORWARD; + break; + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK: + tabOrderOperation = TileTabsManualConfigurationModifier::TabOrderOperation::SEND_TO_BACK; + break; + case EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD: + tabOrderOperation = TileTabsManualConfigurationModifier::TabOrderOperation::SEND_BACKWARD; + break; + case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: + case EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS: + CaretAssert(0); + break; + } + + std::vector allTabContent; + getAllTabContent(allTabContent); + AString errorMessage; + TileTabsManualConfigurationModifier modifier(allTabContent); + if (! modifier.runTabOrderOperation(tabOrderOperation, + browserTabIndex, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + } + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB: + if (tabBarIndex >= 0) { + /* + * Highlighting places outline around tab in graphics region + */ + const bool highlightTabWithOutlineFlag(true); + if ( ! highlightTabWithOutlineFlag) { + m_tileTabsHighlightingTimerEnabledFlag = false; + } + this->tabBar->setCurrentIndex(tabBarIndex); + if ( ! highlightTabWithOutlineFlag) { + m_tileTabsHighlightingTimerEnabledFlag = true; + } + } + break; + case EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS: + replaceBrowserTabs(tileTabsEvent->getBrowserTabsForReplaceOperation()); + break; + } + + tileTabsEvent->setEventProcessed(); + + updateGraphicsWindow(); + } +} + + /** * Get the tab bar index containing the browser tab index. * diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 99d3516df..64ec3bd3e 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -67,6 +67,7 @@ namespace caret { class BrainBrowserWindowToolBarVolumeMontage; class BrainBrowserWindow; class BrowserTabContent; + class EventBrowserWindowTileTabOperation; class Model; class ModelSurface; class ModelVolumeInterface; @@ -93,7 +94,7 @@ namespace caret { ~BrainBrowserWindowToolBar(); - void addNewTab(); + BrowserTabContent* addNewTab(); void addNewDuplicatedTab(BrowserTabContent* browserTabContentToBeCloned); @@ -241,6 +242,8 @@ namespace caret { void removeTabWithContent(BrowserTabContent* browserTabContent); + void processTileTabOperationEvent(EventBrowserWindowTileTabOperation* tileTabsEvent); + public slots: void closeSelectedTab(); @@ -279,11 +282,11 @@ namespace caret { void insertTabContentPrivate(const InsertTabMode insertTabMode, BrowserTabContent* browserTabContent, const int32_t tabBarIndex); - + void removeTab(int index); void tabClosed(int index); - void insertNewTabAtTabBarIndex(int32_t tabBarIndex); + BrowserTabContent* insertNewTabAtTabBarIndex(int32_t tabBarIndex); void insertAndCloneTabContentAtTabBarIndex(const BrowserTabContent* tabContentToBeCloned, const int32_t tabBarIndex); void replaceBrowserTabs(const std::vector& browserTabs); diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 7adfdb533..8ddd873a7 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -448,7 +448,8 @@ SurfaceSelectionViewController.h ThresholdingSetMapsDialog.h TileTabGridRowColumnWidgets.h TileTabsConfigurationDialog.h -TileTabsConfigurationModifier.h +TileTabsGridConfigurationModifier.h +TileTabsManualConfigurationModifier.h TileTabsManualTabGeometryWidget.h UserInputModeAbstract.h UserInputModeAnnotations.h @@ -722,7 +723,8 @@ SurfaceSelectionViewController.cxx ThresholdingSetMapsDialog.cxx TileTabGridRowColumnWidgets.cxx TileTabsConfigurationDialog.cxx -TileTabsConfigurationModifier.cxx +TileTabsGridConfigurationModifier.cxx +TileTabsManualConfigurationModifier.cxx TileTabsManualTabGeometryWidget.cxx UserInputModeAbstract.cxx UserInputModeAnnotations.cxx diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.cxx b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx index 9cd4f3788..d6cb6d889 100644 --- a/src/GuiQt/EventBrowserWindowTileTabOperation.cxx +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.cxx @@ -50,26 +50,59 @@ using namespace caret; * Index of the window. * @param browserTabIndex * Index of the browser tab. + * @param windowViewport + * The window viewport + * @param mouseX + * X-position of mouse + * @param mouseY + * Y-position of mouse + * @param browserTabsForReplaceOperation + * Tabs for replacement */ EventBrowserWindowTileTabOperation::EventBrowserWindowTileTabOperation(const Operation operation, QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex, + const int32_t windowViewport[4], + const int32_t mouseX, + const int32_t mouseY, const std::vector& browserTabsForReplaceOperation) : Event(EventTypeEnum::EVENT_BROWSER_WINDOW_TILE_TAB_OPERATION), m_operation(operation), m_parentWidget(parentWidget), m_windowIndex(windowIndex), m_browserTabIndex(browserTabIndex), +m_mouseX(mouseX), +m_mouseY(mouseY), m_browserTabsForReplaceOperation(browserTabsForReplaceOperation) { CaretAssert(m_parentWidget); CaretAssert(m_windowIndex >= 0); + + m_windowViewport[0] = windowViewport[0]; + m_windowViewport[1] = windowViewport[1]; + m_windowViewport[2] = windowViewport[2]; + m_windowViewport[3] = windowViewport[3]; + switch (m_operation) { - case OPERATION_NEW_TAB_AFTER: + case OPERATION_GRID_NEW_TAB_AFTER: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_GRID_NEW_TAB_BEFORE: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_MANUAL_NEW_TAB: + break; + case OPERATION_ORDER_BRING_TO_FRONT: CaretAssert(m_browserTabIndex >= 0); break; - case OPERATION_NEW_TAB_BEFORE: + case OPERATION_ORDER_BRING_FORWARD: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_ORDER_SEND_TO_BACK: + CaretAssert(m_browserTabIndex >= 0); + break; + case OPERATION_ORDER_SEND_BACKWARD: CaretAssert(m_browserTabIndex >= 0); break; case OPERATION_REPLACE_TABS: @@ -102,11 +135,17 @@ EventBrowserWindowTileTabOperation::selectTabInWindow(QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex) { + const int32_t dummyMouseX(-1); + const int32_t dummyMouseY(-1); + const int32_t dummyWindowViewport[4] { -1, -1, -1, -1 }; std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tabOperation(Operation::OPERATION_SELECT_TAB, parentWidget, windowIndex, browserTabIndex, + dummyWindowViewport, + dummyMouseX, + dummyMouseY, emptyBrowserTabs); EventManager::get()->sendEvent(tabOperation.getPointer()); @@ -153,4 +192,36 @@ EventBrowserWindowTileTabOperation::getBrowserTabsForReplaceOperation() const return m_browserTabsForReplaceOperation; } +/** + * @return Mouse X-coordinate (invalid if negative) + */ +int +EventBrowserWindowTileTabOperation::getMouseX() const +{ + return m_mouseX; +} + +/** + * @return Mouse Y-coordinate (invalid if negative) + */ +int +EventBrowserWindowTileTabOperation::getMouseY() const +{ + return m_mouseY; +} + +/** + * Get the window viewport + * + * @param windowViewport + * Output containing window viewport (negative values if invalid) + */ +void +EventBrowserWindowTileTabOperation::getWindowViewport(int32_t windowViewportOut[4]) const +{ + windowViewportOut[0] = m_windowViewport[0]; + windowViewportOut[1] = m_windowViewport[1]; + windowViewportOut[2] = m_windowViewport[2]; + windowViewportOut[3] = m_windowViewport[3]; +} diff --git a/src/GuiQt/EventBrowserWindowTileTabOperation.h b/src/GuiQt/EventBrowserWindowTileTabOperation.h index 87a6aa0de..7a707d7e0 100644 --- a/src/GuiQt/EventBrowserWindowTileTabOperation.h +++ b/src/GuiQt/EventBrowserWindowTileTabOperation.h @@ -41,8 +41,13 @@ namespace caret { const int32_t windowIndex, const int32_t browserTabIndex); enum Operation { - OPERATION_NEW_TAB_AFTER, - OPERATION_NEW_TAB_BEFORE, + OPERATION_GRID_NEW_TAB_AFTER, + OPERATION_GRID_NEW_TAB_BEFORE, + OPERATION_MANUAL_NEW_TAB, + OPERATION_ORDER_BRING_TO_FRONT, + OPERATION_ORDER_BRING_FORWARD, + OPERATION_ORDER_SEND_TO_BACK, + OPERATION_ORDER_SEND_BACKWARD, OPERATION_REPLACE_TABS, OPERATION_SELECT_TAB }; @@ -51,6 +56,9 @@ namespace caret { QWidget* parentWidget, const int32_t windowIndex, const int32_t browserTabIndex, + const int32_t windowViewport[4], + const int32_t mouseX, + const int32_t mouseY, const std::vector& browserTabsForReplaceOperation); virtual ~EventBrowserWindowTileTabOperation(); @@ -63,6 +71,12 @@ namespace caret { const std::vector getBrowserTabsForReplaceOperation() const; + void getWindowViewport(int32_t windowViewportOut[4]) const; + + int getMouseX() const; + + int getMouseY() const; + // ADD_NEW_METHODS_HERE private: @@ -78,8 +92,14 @@ namespace caret { const int32_t m_browserTabIndex; + const int32_t m_mouseX; + + const int32_t m_mouseY; + const std::vector m_browserTabsForReplaceOperation; + int m_windowViewport[4]; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/TileTabsConfigurationModifier.cxx b/src/GuiQt/TileTabsGridConfigurationModifier.cxx similarity index 90% rename from src/GuiQt/TileTabsConfigurationModifier.cxx rename to src/GuiQt/TileTabsGridConfigurationModifier.cxx index 914647de9..afff88b78 100644 --- a/src/GuiQt/TileTabsConfigurationModifier.cxx +++ b/src/GuiQt/TileTabsGridConfigurationModifier.cxx @@ -21,9 +21,9 @@ #include -#define __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ -#include "TileTabsConfigurationModifier.h" -#undef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ +#define __TILE_TABS_GRID_CONFIGURATION_MODIFIER_DECLARE__ +#include "TileTabsGridConfigurationModifier.h" +#undef __TILE_TABS_GRID_CONFIGURATION_MODIFIER_DECLARE__ #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" @@ -44,8 +44,8 @@ using namespace caret; static bool debugFlag = false; /** - * \class caret::TileTabsConfigurationModifier - * \brief Modifies a tile tabs configuration. + * \class caret::TileTabsGridConfigurationModifier + * \brief Modifies a tile tabs grid configuration. * \ingroup GuiQt */ @@ -57,7 +57,7 @@ static bool debugFlag = false; * @param modifyEvent * Event describing modification. */ -TileTabsConfigurationModifier::TileTabsConfigurationModifier(const std::vector& existingTabs, +TileTabsGridConfigurationModifier::TileTabsGridConfigurationModifier(const std::vector& existingTabs, EventTileTabsGridConfigurationModification* modifyEvent) : CaretObject(), m_existingTabs(existingTabs), @@ -71,7 +71,7 @@ m_modifyEvent(modifyEvent) /** * Destructor. */ -TileTabsConfigurationModifier::~TileTabsConfigurationModifier() +TileTabsGridConfigurationModifier::~TileTabsGridConfigurationModifier() { for (auto rc : m_rowColumns) { delete rc; @@ -84,7 +84,7 @@ TileTabsConfigurationModifier::~TileTabsConfigurationModifier() * @return String describing this object's content. */ AString -TileTabsConfigurationModifier::toString() const +TileTabsGridConfigurationModifier::toString() const { AString s; for (const auto rc : m_rowColumns) { @@ -105,7 +105,7 @@ TileTabsConfigurationModifier::toString() const * True if successful, else false. */ bool -TileTabsConfigurationModifier::run(AString& errorMessageOut) +TileTabsGridConfigurationModifier::run(AString& errorMessageOut) { errorMessageOut.clear(); @@ -129,7 +129,7 @@ TileTabsConfigurationModifier::run(AString& errorMessageOut) * Load the rows or columns from the Tile Tabs Configuration */ void -TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() +TileTabsGridConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() { const int32_t numRows = m_currentTileTabsConfiguration->getNumberOfRows(); const int32_t numColumns = m_currentTileTabsConfiguration->getNumberOfColumns(); @@ -163,7 +163,7 @@ TileTabsConfigurationModifier::loadRowColumnsFromTileTabsConfiguration() * True if successful, else false. */ bool -TileTabsConfigurationModifier::performModification(AString& errorMessageOut) +TileTabsGridConfigurationModifier::performModification(AString& errorMessageOut) { const int32_t rowColumnIndex = m_modifyEvent->getRowColumnIndex(); @@ -315,7 +315,7 @@ TileTabsConfigurationModifier::performModification(AString& errorMessageOut) * True if successful, else false. */ bool -TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut) +TileTabsGridConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& errorMessageOut) { TileTabsLayoutGridConfiguration newConfiguration(*m_currentTileTabsConfiguration); std::vector browserTabs; @@ -390,10 +390,16 @@ TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& */ QWidget* parentWindow(GuiManager::get()->getBrowserWindowByWindowIndex(m_modifyEvent->getWindowIndex())); const int32_t invalidTabIndex(-1); + const int32_t dummyWindowViewport[4] { -1, -1, -1, -1 }; + const int32_t dummyMouseX(-1); + const int32_t dummyMouseY(-1); EventBrowserWindowTileTabOperation updateTabsEvent(EventBrowserWindowTileTabOperation::OPERATION_REPLACE_TABS, parentWindow, m_modifyEvent->getWindowIndex(), invalidTabIndex, + dummyWindowViewport, + dummyMouseX, + dummyMouseY, browserTabs); EventManager::get()->sendEvent(updateTabsEvent.getPointer()); @@ -431,7 +437,7 @@ TileTabsConfigurationModifier::loadRowColumnsIntoTileTabsConfiguration(AString& * Browser tab content at (rowIndex, columnIndex) in the current * Tile Tabs Configuration */ -TileTabsConfigurationModifier::Element::Element(const int32_t rowIndex, +TileTabsGridConfigurationModifier::Element::Element(const int32_t rowIndex, const int32_t columnIndex, BrowserTabContent* browserTabContent) : @@ -448,7 +454,7 @@ m_browserTabContent(browserTabContent) * @return String representation of object. */ AString -TileTabsConfigurationModifier::Element::toString() const +TileTabsGridConfigurationModifier::Element::toString() const { AString s("(row=%1, column=%2)"); s = s.arg(m_sourceRowIndex).arg(m_sourceColumnIndex); @@ -468,7 +474,7 @@ TileTabsConfigurationModifier::Element::toString() const * @param rowFlag * True if rows are being operated upon, false if operating on columns */ -TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const std::vector& existingTabs, +TileTabsGridConfigurationModifier::RowColumnContent::RowColumnContent(const std::vector& existingTabs, TileTabsLayoutGridConfiguration* tileTabsConfiguration, const int32_t rowColumnIndex, const bool rowFlag) @@ -517,7 +523,7 @@ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const std::vec * @param numberOfElements * Number of elements for row/column. */ -TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const int32_t numberOfElements) +TileTabsGridConfigurationModifier::RowColumnContent::RowColumnContent(const int32_t numberOfElements) { for (int32_t i = 0; i < numberOfElements; i++) { m_tabElements.push_back(new Element(i, i, NULL)); @@ -531,8 +537,8 @@ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const int32_t * @param numberOfElements * Number of elements for row/column. */ -TileTabsConfigurationModifier::RowColumnContent* -TileTabsConfigurationModifier::RowColumnContent::newInstanceContainingSpacers(const int32_t numberOfElements) +TileTabsGridConfigurationModifier::RowColumnContent* +TileTabsGridConfigurationModifier::RowColumnContent::newInstanceContainingSpacers(const int32_t numberOfElements) { RowColumnContent* content = new RowColumnContent(numberOfElements); @@ -546,7 +552,7 @@ TileTabsConfigurationModifier::RowColumnContent::newInstanceContainingSpacers(co /** * Destructor. */ -TileTabsConfigurationModifier::RowColumnContent::~RowColumnContent() +TileTabsGridConfigurationModifier::RowColumnContent::~RowColumnContent() { for (auto te : m_tabElements) { delete te; @@ -563,7 +569,7 @@ TileTabsConfigurationModifier::RowColumnContent::~RowColumnContent() * @param obj * Instance that is copied. */ -TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const RowColumnContent& obj) +TileTabsGridConfigurationModifier::RowColumnContent::RowColumnContent(const RowColumnContent& obj) : CaretObject(obj) { for (auto te : obj.m_tabElements) { @@ -577,7 +583,7 @@ TileTabsConfigurationModifier::RowColumnContent::RowColumnContent(const RowColum * @return String representation of object. */ AString -TileTabsConfigurationModifier::RowColumnContent::toString() const +TileTabsGridConfigurationModifier::RowColumnContent::toString() const { AString s; for (const auto te : m_tabElements) { @@ -594,8 +600,8 @@ TileTabsConfigurationModifier::RowColumnContent::toString() const * @return * True if successful, else false */ -TileTabsConfigurationModifier::RowColumnContent* -TileTabsConfigurationModifier::RowColumnContent::clone(AString& errorMessageOut) const +TileTabsGridConfigurationModifier::RowColumnContent* +TileTabsGridConfigurationModifier::RowColumnContent::clone(AString& errorMessageOut) const { RowColumnContent* cloned = new RowColumnContent(*this); CaretAssert(cloned); diff --git a/src/GuiQt/TileTabsConfigurationModifier.h b/src/GuiQt/TileTabsGridConfigurationModifier.h similarity index 84% rename from src/GuiQt/TileTabsConfigurationModifier.h rename to src/GuiQt/TileTabsGridConfigurationModifier.h index 9f9be37b2..413742748 100644 --- a/src/GuiQt/TileTabsConfigurationModifier.h +++ b/src/GuiQt/TileTabsGridConfigurationModifier.h @@ -1,5 +1,5 @@ -#ifndef __TILE_TABS_CONFIGURATION_MODIFIER_H__ -#define __TILE_TABS_CONFIGURATION_MODIFIER_H__ +#ifndef __TILE_TABS_GRID_CONFIGURATION_MODIFIER_H__ +#define __TILE_TABS_GRID_CONFIGURATION_MODIFIER_H__ /*LICENSE_START*/ /* @@ -38,17 +38,17 @@ namespace caret { class TileTabsLayoutGridConfiguration; class TileTabsGridRowColumnElement; - class TileTabsConfigurationModifier : public CaretObject { + class TileTabsGridConfigurationModifier : public CaretObject { public: - TileTabsConfigurationModifier(const std::vector& existingTabs, + TileTabsGridConfigurationModifier(const std::vector& existingTabs, EventTileTabsGridConfigurationModification* modifyEvent); - virtual ~TileTabsConfigurationModifier(); + virtual ~TileTabsGridConfigurationModifier(); - TileTabsConfigurationModifier(const TileTabsConfigurationModifier&) = delete; + TileTabsGridConfigurationModifier(const TileTabsGridConfigurationModifier&) = delete; - TileTabsConfigurationModifier& operator=(const TileTabsConfigurationModifier&) = delete; + TileTabsGridConfigurationModifier& operator=(const TileTabsGridConfigurationModifier&) = delete; bool run(AString& errorMessageOut); @@ -130,9 +130,9 @@ namespace caret { }; -#ifdef __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ +#ifdef __TILE_TABS_GRID_CONFIGURATION_MODIFIER_DECLARE__ // -#endif // __TILE_TABS_CONFIGURATION_MODIFIER_DECLARE__ +#endif // __TILE_TABS_GRID_CONFIGURATION_MODIFIER_DECLARE__ } // namespace -#endif //__TILE_TABS_CONFIGURATION_MODIFIER_H__ +#endif //__TILE_TABS_GRID_CONFIGURATION_MODIFIER_H__ diff --git a/src/GuiQt/TileTabsManualConfigurationModifier.cxx b/src/GuiQt/TileTabsManualConfigurationModifier.cxx new file mode 100644 index 000000000..4610123a2 --- /dev/null +++ b/src/GuiQt/TileTabsManualConfigurationModifier.cxx @@ -0,0 +1,224 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_DECLARE__ +#include "TileTabsManualConfigurationModifier.h" +#undef __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_DECLARE__ + +#include + +#include "BrainOpenGLViewportContent.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "TileTabsBrowserTabGeometry.h" +#include "TileTabsManualTabGeometryWidget.h" + +using namespace caret; + + + +/** + * \class caret::TileTabsManualConfigurationModifier + * \brief Perform an operation on a manual configuration layout + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param browserTabContents + * The current tab content + */ +TileTabsManualConfigurationModifier::TileTabsManualConfigurationModifier(const std::vector& browserTabContents) +: CaretObject(), +m_browserTabs(browserTabContents) +{ +} + +/** + * Destructor. + */ +TileTabsManualConfigurationModifier::~TileTabsManualConfigurationModifier() +{ +} + +/** + * Run a tab order operation + * + * @param operation + * The tab order operation + * @param tabIndex + * Index of tab that has order changed + * @param errorMessageOut + * Output with error information + * @return + * True if successful, else false + */ +bool +TileTabsManualConfigurationModifier::runTabOrderOperation(const TabOrderOperation operation, + const int32_t browserTabIndex, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + if (m_browserTabs.size() <= 1) { + return true; + } + + CaretAssert(browserTabIndex >= 0); + + BrowserTabContent* browserTabContent(NULL); + for (auto tabContent : m_browserTabs) { + CaretAssert(tabContent); + if (tabContent->getTabNumber() == browserTabIndex) { + browserTabContent = tabContent; + break; + } + } + if (browserTabContent == NULL) { + errorMessageOut = ("Tab " + + AString::number(browserTabIndex + 1) + + " not found in browser tabs."); + return false; + } + + /* + * Sort tabs by current stacking order + */ + std::vector tabOrderAndContent; + for (const auto tabContent : m_browserTabs) { + CaretAssert(tabContent); + + tabOrderAndContent.emplace_back(tabContent, + tabContent->getManualLayoutGeometry()->getStackingOrder()); + } + std::sort(tabOrderAndContent.begin(), + tabOrderAndContent.end()); + + /* + * Now that that tab are sorted by stacking order, order tabs with even + * numbers which will make order changing easier. + * Also find closest tab behind and in front of 'browserTabContent' + */ + int32_t indexOfTab(-1); + int32_t indexOfTabBehind(-1); + int32_t indexOfTabInFront(-1); + const int32_t numTabs = static_cast(tabOrderAndContent.size()); + CaretAssert(numTabs > 2); + for (int32_t i = 0; i < numTabs; i++) { + CaretAssertVectorIndex(tabOrderAndContent, i); + tabOrderAndContent[i].m_stackOrder = i * 2; + + if (tabOrderAndContent[i].m_tabContent == browserTabContent) { + indexOfTab = i; + } + else if (indexOfTab < 0) { /* have not yet found index of 'browserTabContent' */ + /* + * Find tab that is closest to 'browserTabContent' but behind and intersects it + */ + if (browserTabContent->getManualLayoutGeometry()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry())) { + indexOfTabBehind = i; + } + } + else if (indexOfTabInFront < 0) { + /* + * Find first (closest) tab that is in front of and intersects 'browserTabContent' + */ + if (browserTabContent->getManualLayoutGeometry()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry())) { + indexOfTabInFront = i; + } + } + } + + CaretAssert(indexOfTab >= 0); + + /* + * Now change the stack order of the tab. + * Since earlier, the stacking orders were made (0, 2, 4, ...) we only need to + * add or subtract 1 to the stack order using the reference tab that is in front or back + */ + switch (operation) { + case TabOrderOperation::BRING_FORWARD: + if (indexOfTabInFront >= 0) { + /* + * Move forward one position + */ + CaretAssertVectorIndex(tabOrderAndContent, indexOfTabInFront); + CaretAssertVectorIndex(tabOrderAndContent, indexOfTab); + tabOrderAndContent[indexOfTab].m_stackOrder = tabOrderAndContent[indexOfTabInFront].m_stackOrder + 1; + } + break; + case TabOrderOperation::BRING_TO_FRONT: + { + /* + * Move to in front of all tabs + */ + const int32_t frontIndex = static_cast(tabOrderAndContent.size() - 1); + CaretAssertVectorIndex(tabOrderAndContent, frontIndex); + CaretAssertVectorIndex(tabOrderAndContent, indexOfTab); + tabOrderAndContent[indexOfTab].m_stackOrder = tabOrderAndContent[frontIndex].m_stackOrder + 1; + } + break; + case TabOrderOperation::SEND_BACKWARD: + if (indexOfTabBehind >= 0) { + /* + * Move back one position + */ + CaretAssertVectorIndex(tabOrderAndContent, indexOfTabBehind); + CaretAssertVectorIndex(tabOrderAndContent, indexOfTab); + tabOrderAndContent[indexOfTab].m_stackOrder = tabOrderAndContent[indexOfTabBehind].m_stackOrder - 1; + } + break; + case TabOrderOperation::SEND_TO_BACK: + { + /* + * Move to behind all tabs + */ + const int32_t backIndex = 0; + CaretAssertVectorIndex(tabOrderAndContent, backIndex); + CaretAssertVectorIndex(tabOrderAndContent, indexOfTab); + tabOrderAndContent[indexOfTab].m_stackOrder = tabOrderAndContent[backIndex].m_stackOrder - 1; + } + break; + } + + /* + * Now order tabs sequentially to clean up stacking order + */ + std::sort(tabOrderAndContent.begin(), + tabOrderAndContent.end()); + for (int32_t i = 0; i < numTabs; i++) { + CaretAssertVectorIndex(tabOrderAndContent, i); + tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry()->setStackingOrder(i); + } + + return true; +} + +/** + * Get a description of this object's content. + * @return String describing this object's content. + */ +AString +TileTabsManualConfigurationModifier::toString() const +{ + return "TileTabsManualConfigurationModifier"; +} + diff --git a/src/GuiQt/TileTabsManualConfigurationModifier.h b/src/GuiQt/TileTabsManualConfigurationModifier.h new file mode 100644 index 000000000..9c405c22e --- /dev/null +++ b/src/GuiQt/TileTabsManualConfigurationModifier.h @@ -0,0 +1,93 @@ +#ifndef __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_H__ +#define __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "CaretObject.h" + + + +namespace caret { + + class BrowserTabContent; + + class TileTabsManualConfigurationModifier : public CaretObject { + + public: + enum class TabOrderOperation { + BRING_TO_FRONT, + BRING_FORWARD, + SEND_TO_BACK, + SEND_BACKWARD + }; + + TileTabsManualConfigurationModifier(const std::vector& browserTabContents); + + virtual ~TileTabsManualConfigurationModifier(); + + TileTabsManualConfigurationModifier(const TileTabsManualConfigurationModifier&) = delete; + + TileTabsManualConfigurationModifier& operator=(const TileTabsManualConfigurationModifier&) = delete; + + bool runTabOrderOperation(const TabOrderOperation operation, + const int32_t tabIndex, + AString& errorMessageOut); + + + // ADD_NEW_METHODS_HERE + + virtual AString toString() const; + + private: + /** + * Sort tab content by stack order + */ + class TabInfo { + public: + TabInfo(BrowserTabContent* tabContent, + const int32_t stackOrder) + : m_tabContent(tabContent), + m_stackOrder(stackOrder) { } + + bool operator<(const TabInfo& tabInfo) const { + return m_stackOrder < tabInfo.m_stackOrder; + } + + BrowserTabContent* m_tabContent = NULL; + int32_t m_stackOrder = -1; + }; + + std::vector m_browserTabs; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_DECLARE__ + // +#endif // __TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_DECLARE__ + +} // namespace +#endif //__TILE_TABS_MANUAL_CONFIGURATION_MODIFIER_H__ diff --git a/src/GuiQt/UserInputModeView.cxx b/src/GuiQt/UserInputModeView.cxx index c92d5b611..ad131df28 100644 --- a/src/GuiQt/UserInputModeView.cxx +++ b/src/GuiQt/UserInputModeView.cxx @@ -414,7 +414,8 @@ UserInputModeView::showContextMenu(const MouseEvent& mouseEvent, mouseY, false); - UserInputModeViewContextMenu contextMenu(viewportContent, + UserInputModeViewContextMenu contextMenu(mouseEvent, + viewportContent, idManager, openGLWidget); contextMenu.exec(menuPosition); diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index 411ce0bc0..73615790e 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -97,6 +97,8 @@ using namespace caret; /** * Constructor. * + * @param mouseEvent + * The mouse event * @param viewportContent * Content of the viewport. * @param selectionManager @@ -104,7 +106,8 @@ using namespace caret; * @param parentOpenGLWidget * Parent OpenGL Widget on which the menu is displayed. */ -UserInputModeViewContextMenu::UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, +UserInputModeViewContextMenu::UserInputModeViewContextMenu(const MouseEvent& mouseEvent, + BrainOpenGLViewportContent* viewportContent, SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget) : QMenu(parentOpenGLWidget) @@ -116,11 +119,11 @@ UserInputModeViewContextMenu::UserInputModeViewContextMenu(BrainOpenGLViewportCo this->browserTabContent = viewportContent->getBrowserTabContent(); CaretAssert(this->browserTabContent); - UserInputTileTabsContextMenu* tabMenu = new UserInputTileTabsContextMenu(this->parentOpenGLWidget, + UserInputTileTabsContextMenu* tabMenu = new UserInputTileTabsContextMenu(mouseEvent, + this->parentOpenGLWidget, this->viewportContent); if (tabMenu->isValid()) { - addSubMenuToMenu(tabMenu, - true); + addMenu(tabMenu); } else { delete tabMenu; @@ -129,72 +132,42 @@ UserInputModeViewContextMenu::UserInputModeViewContextMenu(BrainOpenGLViewportCo /* * Add the identification actions. */ - addIdentificationActions(); + QMenu* identifyMenu = createIdentifyMenu(); + if (identifyMenu != NULL) { + addMenu(identifyMenu); + } /* * Add the border options. */ - addBorderRegionOfInterestActions(); + QMenu* borderMenu = createBorderRegionOfInterestMenu(); + if (borderMenu != NULL) { + addMenu(borderMenu); + } /* * Add the chart actions */ - addChartActions(); + QMenu* chartMenu = createChartMenu(); + if (chartMenu != NULL) { + addMenu(chartMenu); + } /* * Add the foci actions. */ - addFociActions(); + QMenu* fociMenu = createFociMenu(); + if (fociMenu != NULL) { + addMenu(fociMenu); + } /* * Show Label ROI operations only for surfaces */ - addLabelRegionOfInterestActions(); - - const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); - - bool showRemoveVertexSymbolsFlag = false; - if (this->browserTabContent != NULL) { - switch (this->browserTabContent->getSelectedModelType()) { - case ModelTypeEnum::MODEL_TYPE_CHART: - break; - case ModelTypeEnum::MODEL_TYPE_CHART_TWO: - break; - case ModelTypeEnum::MODEL_TYPE_INVALID: - break; - case ModelTypeEnum::MODEL_TYPE_SURFACE: - showRemoveVertexSymbolsFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: - showRemoveVertexSymbolsFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: - showRemoveVertexSymbolsFlag = true; - break; - case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: - showRemoveVertexSymbolsFlag = true; - break; - } - } - if (showRemoveVertexSymbolsFlag) { - if (this->actions().count() > 0) { - this->addSeparator(); - } - this->addAction("Remove All Vertex Identification Symbols", - this, - SLOT(removeAllNodeIdentificationSymbolsSelected())); - } - - if (idSymbol->isValid()) { - const AString text = ("Remove Identification of Vertices " - + AString::number(idSymbol->getNodeNumber())); - - this->addAction(WuQtUtilities::createAction(text, - "", - this, - this, - SLOT(removeNodeIdentificationSymbolSelected()))); - } + QMenu* labelMenu = createLabelRegionOfInterestMenu(); + if (labelMenu != NULL) { + addMenu(labelMenu); + } } /** @@ -259,10 +232,10 @@ UserInputModeViewContextMenu::addSubMenuToMenu(QMenu* menu, } /** - * Add the identification actions to the menu. + * @return The identification menu */ -void -UserInputModeViewContextMenu::addIdentificationActions() +QMenu* +UserInputModeViewContextMenu::createIdentifyMenu() { /* * Accumlate identification actions @@ -351,15 +324,68 @@ UserInputModeViewContextMenu::addIdentificationActions() SLOT(identifyVolumeFocusSelected()))); } - addActionsToMenu(identificationActions, - true); + const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = this->selectionManager->getSurfaceNodeIdentificationSymbol(); + + bool showRemoveVertexSymbolsFlag = false; + if (this->browserTabContent != NULL) { + switch (this->browserTabContent->getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + showRemoveVertexSymbolsFlag = true; + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + showRemoveVertexSymbolsFlag = true; + break; + } + } + if (showRemoveVertexSymbolsFlag) { + identificationActions.push_back(WuQtUtilities::createAction("Remove All Vertex Identification Symbols", + "", + this, + this, + SLOT(removeAllNodeIdentificationSymbolsSelected()))); + } + + if (idSymbol->isValid()) { + const AString text = ("Remove Identification of Vertices " + + AString::number(idSymbol->getNodeNumber())); + + identificationActions.push_back(WuQtUtilities::createAction(text, + "", + this, + this, + SLOT(removeNodeIdentificationSymbolSelected()))); + } + + QMenu* menu(NULL); + + if ( ! identificationActions.isEmpty()) { + menu = new QMenu("Identify"); + + for (auto action : identificationActions) { + menu->addAction(action); + } + } + + return menu; } /** - * Add the border region of interest actions to the menu. + * @return the border menu. */ -void -UserInputModeViewContextMenu::addBorderRegionOfInterestActions() +QMenu* +UserInputModeViewContextMenu::createBorderRegionOfInterestMenu() { SelectionItemBorderSurface* borderID = this->selectionManager->getSurfaceBorderIdentification(); @@ -408,8 +434,19 @@ UserInputModeViewContextMenu::addBorderRegionOfInterestActions() } } + QMenu* menu(NULL); + + if ( ! borderActions.isEmpty()) { + menu = new QMenu("Borders"); + + for (auto action : borderActions) { + menu->addAction(action); + } + } addActionsToMenu(borderActions, true); + + return menu; } /** @@ -668,10 +705,10 @@ UserInputModeViewContextMenu::createParcelConnectivities() } /** - * Add all label region of interest options to the menu + * @return The label region of interest menu */ -void -UserInputModeViewContextMenu::addLabelRegionOfInterestActions() +QMenu* +UserInputModeViewContextMenu::createLabelRegionOfInterestMenu() { createParcelConnectivities(); @@ -834,19 +871,29 @@ UserInputModeViewContextMenu::addLabelRegionOfInterestActions() } } - addActionsToMenu(connectivityActions, - true); - addActionsToMenu(ciftiFiberTrajectoryActions, - true); - addActionsToMenu(chartableDataActions, - true); + std::vector allActions; + allActions.insert(allActions.end(), connectivityActions.begin(), connectivityActions.end()); + allActions.insert(allActions.end(), ciftiFiberTrajectoryActions.begin(), ciftiFiberTrajectoryActions.end()); + allActions.insert(allActions.end(), chartableDataActions.begin(), chartableDataActions.end()); + + QMenu* menu(NULL); + + if ( ! allActions.empty()) { + menu = new QMenu("Label ROI"); + + for (auto action : allActions) { + menu->addAction(action); + } + } + + return menu; } /** * Add chart options to the menu */ -void -UserInputModeViewContextMenu::addChartActions() +QMenu* +UserInputModeViewContextMenu::createChartMenu() { QList chartActions; @@ -859,7 +906,17 @@ UserInputModeViewContextMenu::addChartActions() SLOT(editChartLabelSelected()))); } - addActionsToMenu(chartActions, true); + QMenu* menu(NULL); + + if ( ! chartActions.isEmpty()) { + QMenu* menu = new QMenu("Chart"); + + for (auto action : chartActions) { + menu->addAction(action); + } + } + + return menu; } /** @@ -894,12 +951,12 @@ UserInputModeViewContextMenu::editChartLabelSelected() } /** - * Add the foci options to the menu. + * @return The foci menu */ -void -UserInputModeViewContextMenu::addFociActions() +QMenu* +UserInputModeViewContextMenu::createFociMenu() { - QList fociCreateActions; + QList fociActions; const SelectionItemSurfaceNodeIdentificationSymbol* idSymbol = selectionManager->getSurfaceNodeIdentificationSymbol(); SelectionItemFocusSurface* focusID = this->selectionManager->getSurfaceFocusIdentification(); @@ -921,7 +978,7 @@ UserInputModeViewContextMenu::addFociActions() + AString::fromNumbers(surface->getCoordinate(nodeIndex), 3, ",") + ")..."); - fociCreateActions.push_back(WuQtUtilities::createAction(text, + fociActions.push_back(WuQtUtilities::createAction(text, "", this, this, @@ -937,7 +994,7 @@ UserInputModeViewContextMenu::addFociActions() + AString::fromNumbers(surface->getCoordinate(nodeIndex), 3, ",") + ")..."); - fociCreateActions.push_back(WuQtUtilities::createAction(text, + fociActions.push_back(WuQtUtilities::createAction(text, "", this, this, @@ -960,21 +1017,13 @@ UserInputModeViewContextMenu::addFociActions() + ") XYZ (" + AString::fromNumbers(xyz, 3, ",") + ")..."); - fociCreateActions.push_back(WuQtUtilities::createAction(text, + fociActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(createVolumeFocusSelected()))); } - addActionsToMenu(fociCreateActions, - true); - - /* - * Actions for editing - */ - QList fociEditActions; - /* * Edit Surface Focus */ @@ -982,7 +1031,7 @@ UserInputModeViewContextMenu::addFociActions() const QString text = ("Edit Surface Focus (" + focusID->getFocus()->getName() + ")"); - fociEditActions.push_back(WuQtUtilities::createAction(text, + fociActions.push_back(WuQtUtilities::createAction(text, "", this, this, @@ -996,15 +1045,24 @@ UserInputModeViewContextMenu::addFociActions() const QString text = ("Edit Volume Focus (" + focusVolID->getFocus()->getName() + ")"); - fociEditActions.push_back(WuQtUtilities::createAction(text, + fociActions.push_back(WuQtUtilities::createAction(text, "", this, this, SLOT(editVolumeFocusSelected()))); } - - addActionsToMenu(fociEditActions, - true); + + QMenu* menu(NULL); + + if ( ! fociActions.isEmpty()) { + menu = new QMenu("Foci"); + + for (auto action : fociActions) { + menu->addAction(action); + } + } + + return menu; } /** diff --git a/src/GuiQt/UserInputModeViewContextMenu.h b/src/GuiQt/UserInputModeViewContextMenu.h index 1f2021948..0685b56cf 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.h +++ b/src/GuiQt/UserInputModeViewContextMenu.h @@ -42,6 +42,7 @@ namespace caret { class CiftiConnectivityMatrixDataFileManager; class CiftiFiberTrajectoryManager; class ChartingDataManager; + class MouseEvent; class SelectionManager; class LabelFile; class Surface; @@ -51,7 +52,8 @@ namespace caret { Q_OBJECT public: - UserInputModeViewContextMenu(BrainOpenGLViewportContent* viewportContent, + UserInputModeViewContextMenu(const MouseEvent& mouseEvent, + BrainOpenGLViewportContent* viewportContent, SelectionManager* selectionManager, BrainOpenGLWidget* parentOpenGLWidget); @@ -146,15 +148,15 @@ namespace caret { bool enableDataSeriesGraphsIfNoneEnabled(); - void addIdentificationActions(); + QMenu* createIdentifyMenu(); - void addBorderRegionOfInterestActions(); + QMenu* createBorderRegionOfInterestMenu(); - void addChartActions(); + QMenu* createChartMenu(); - void addFociActions(); + QMenu* createFociMenu(); - void addLabelRegionOfInterestActions(); + QMenu* createLabelRegionOfInterestMenu(); void addSubMenuToMenu(QMenu* menu, const bool addSeparatorBeforeMenu); diff --git a/src/GuiQt/UserInputTileTabsContextMenu.cxx b/src/GuiQt/UserInputTileTabsContextMenu.cxx index 2efb41af3..58ce3b5de 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.cxx +++ b/src/GuiQt/UserInputTileTabsContextMenu.cxx @@ -26,11 +26,13 @@ #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "EventBrowserTabGet.h" #include "EventBrowserWindowTileTabOperation.h" #include "EventManager.h" #include "GuiManager.h" +#include "MouseEvent.h" using namespace caret; @@ -45,12 +47,15 @@ using namespace caret; /** * Constructor. * + * @param mouseEvent + * The mouse event that caused menu display * @param parentWidget * Parent widget on which error message dialogs are displayed * @param viewportContent * Content of the viewport under the mouse. */ -UserInputTileTabsContextMenu::UserInputTileTabsContextMenu(QWidget* parentWidget, +UserInputTileTabsContextMenu::UserInputTileTabsContextMenu(const MouseEvent& mouseEvent, + QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent) : QMenu("Tabs"), m_parentWidget(parentWidget), @@ -62,21 +67,61 @@ m_tabIndex(viewportContent->getTabIndex()) CaretAssert(m_windowIndex >= 0); CaretAssert(m_tabIndex >= 0); + int32_t tabViewport[4]; + viewportContent->getTabViewportBeforeApplyingMargins(tabViewport); + + viewportContent->getWindowViewport(m_windowViewport); + + m_mouseWindowX = mouseEvent.getX(); + m_mouseWindowY = mouseEvent.getY(); + EventBrowserTabGet tabContentEvent(m_tabIndex); EventManager::get()->sendEvent(tabContentEvent.getPointer()); BrowserTabContent* tabContent = tabContentEvent.getBrowserTab(); - if (tabContent != NULL) { - const AString tabNumberText(AString::number(m_tabIndex + 1)); - - if (bbw->isTileTabsSelected()) { - m_createNewTabBeforeAction = addAction("Create New Tab Before This Tab"); - m_createNewTabAfterAction = addAction("Create New Tab After This Tab"); - m_selectTabAction = addAction("Select This Tab"); + + if (bbw->isTileTabsSelected()) { + switch (bbw->getBrowerWindowContent()->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + if (tabContent != NULL) { + addItemToMenu("Insert New Tab Before This Tab", + EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_BEFORE); + addItemToMenu("Insert New Tab After This Tab", + EventBrowserWindowTileTabOperation::OPERATION_GRID_NEW_TAB_AFTER); + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + addItemToMenu("Insert Tab at Mouse", + EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB); + + if (tabContent != NULL) { + if (actions().count() > 0) { + addSeparator(); + } + addItemToMenu("Bring to Front", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT); + addItemToMenu("Bring Forward", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD); + addItemToMenu("Send to Back", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK); + addItemToMenu("Send Backward", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); + } + break; } - QObject::connect(this, &QMenu::triggered, - this, &UserInputTileTabsContextMenu::actionTriggered); + if (tabContent != NULL) { + if (actions().count() > 0) { + addSeparator(); + } + addItemToMenu("Select This Tab", + EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB); + } } + + QObject::connect(this, &QMenu::triggered, + this, &UserInputTileTabsContextMenu::actionTriggered); } /** @@ -95,6 +140,23 @@ UserInputTileTabsContextMenu::isValid() const return (actions().size() > 0); } +/** + * Add an operation to the menu with the given text + * + * @param text + * Text for menu + * @param operation + * The operation + */ +void +UserInputTileTabsContextMenu::addItemToMenu(const QString& text, + const EventBrowserWindowTileTabOperation::Operation operation) +{ + QAction* action = addAction(text); + action->setData(static_cast(operation)); +} + + /** * Gets called when an action is selected from the menu. @@ -105,33 +167,21 @@ UserInputTileTabsContextMenu::isValid() const void UserInputTileTabsContextMenu::actionTriggered(QAction* action) { - EventBrowserWindowTileTabOperation::Operation operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; - bool validOperationFlag = false; - - if (action == m_createNewTabBeforeAction) { - operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_BEFORE; - validOperationFlag = true; - } - else if (action == m_createNewTabAfterAction) { - operation = EventBrowserWindowTileTabOperation::OPERATION_NEW_TAB_AFTER; - validOperationFlag = true; + if (action == NULL) { + return; } - else if (action == m_selectTabAction) { - operation = EventBrowserWindowTileTabOperation::OPERATION_SELECT_TAB; - validOperationFlag = true; - } - else if (action != NULL) { - CaretAssertMessage(0, "Invalid menu action. Has a new menu action been added?"); - } - - if (validOperationFlag) { + + const int operationInt = action->data().toInt(); + const EventBrowserWindowTileTabOperation::Operation operation = static_cast(operationInt); std::vector emptyBrowserTabs; EventBrowserWindowTileTabOperation tileTabOperation(operation, m_parentWidget, m_windowIndex, m_tabIndex, + m_windowViewport, + m_mouseWindowX, + m_mouseWindowY, emptyBrowserTabs); EventManager::get()->sendEvent(tileTabOperation.getPointer()); - } } diff --git a/src/GuiQt/UserInputTileTabsContextMenu.h b/src/GuiQt/UserInputTileTabsContextMenu.h index bcb533891..303997fd5 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.h +++ b/src/GuiQt/UserInputTileTabsContextMenu.h @@ -27,18 +27,22 @@ #include +#include "EventBrowserWindowTileTabOperation.h" + class QWidget; namespace caret { class BrainOpenGLViewportContent; + class MouseEvent; class UserInputTileTabsContextMenu : public QMenu { Q_OBJECT public: - UserInputTileTabsContextMenu(QWidget* parentWidget, + UserInputTileTabsContextMenu(const MouseEvent& mouseEvent, + QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent); virtual ~UserInputTileTabsContextMenu(); @@ -55,15 +59,34 @@ namespace caret { UserInputTileTabsContextMenu& operator=(const UserInputTileTabsContextMenu&); + void addItemToMenu(const QString& text, + const EventBrowserWindowTileTabOperation::Operation operation); + QWidget* m_parentWidget; const int32_t m_windowIndex; const int32_t m_tabIndex; + + int32_t m_windowViewport[4]; + + int32_t m_mouseWindowX = 0; + + int32_t m_mouseWindowY = 0; + + QAction* m_createNewGridTabBeforeAction = nullptr; + + QAction* m_createNewGridTabAfterAction = nullptr; + + QAction* m_createNewManualTabAction = nullptr; + + QAction* m_orderBringToFrontAction = nullptr; + + QAction* m_orderBringForwardAction = nullptr; - QAction* m_createNewTabBeforeAction = nullptr; + QAction* m_orderSendToBackAction = nullptr; - QAction* m_createNewTabAfterAction = nullptr; + QAction* m_orderSendBackwardAction = nullptr; QAction* m_selectTabAction = nullptr; -- GitLab From 54f5147eb5da0b163545104e27a54102de99b3b9 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Aug 2019 14:00:06 -0500 Subject: [PATCH 009/584] WB-859 Manual Tile Tabs Layout System: Continue development: Now able to move and resize tiles (tabs) in Annotation Mode. --- src/Annotations/Annotation.cxx | 163 ++------ src/Annotations/AnnotationBrowserTab.cxx | 394 ++++++++++++++++++ src/Annotations/AnnotationBrowserTab.h | 120 ++++++ src/Annotations/AnnotationRedoUndoCommand.cxx | 2 + .../AnnotationTwoDimensionalShape.cxx | 7 +- src/Annotations/AnnotationTypeEnum.cxx | 4 + src/Annotations/AnnotationTypeEnum.h | 2 + src/Annotations/CMakeLists.txt | 2 + src/Brain/AnnotationManager.cxx | 18 + ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 287 ++++++++----- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 4 + src/Brain/BrainOpenGLFixedPipeline.cxx | 58 ++- src/Brain/BrainOpenGLFixedPipeline.h | 5 +- src/Brain/BrainOpenGLViewportContent.cxx | 19 +- src/Brain/BrainOpenGLWindowContent.cxx | 6 +- src/Brain/BrowserTabContent.cxx | 50 ++- src/Brain/BrowserTabContent.h | 13 +- src/Files/AnnotationFileXmlWriter.cxx | 36 +- src/GuiQt/AnnotationColorWidget.cxx | 2 + .../AnnotationCoordinateSelectionWidget.cxx | 3 + src/GuiQt/AnnotationCoordinateWidget.cxx | 4 + src/GuiQt/AnnotationCreateDialog.cxx | 10 + src/GuiQt/AnnotationInsertNewWidget.cxx | 3 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 14 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 122 ++---- .../TileTabsManualConfigurationModifier.cxx | 9 +- src/GuiQt/TileTabsManualTabGeometryWidget.cxx | 70 ++-- 27 files changed, 983 insertions(+), 444 deletions(-) create mode 100644 src/Annotations/AnnotationBrowserTab.cxx create mode 100644 src/Annotations/AnnotationBrowserTab.h diff --git a/src/Annotations/Annotation.cxx b/src/Annotations/Annotation.cxx index dac133aaa..6e2335e9d 100644 --- a/src/Annotations/Annotation.cxx +++ b/src/Annotations/Annotation.cxx @@ -24,6 +24,7 @@ #undef __ANNOTATION_DECLARE__ #include "AnnotationBox.h" +#include "AnnotationBrowserTab.h" #include "AnnotationColorBar.h" #include "AnnotationCoordinate.h" #include "AnnotationGroup.h" @@ -179,6 +180,13 @@ Annotation::clone() const myClone = new AnnotationBox(*box); } break; + case AnnotationTypeEnum::BROWSER_TAB: + { + const AnnotationBrowserTab* browserTab = dynamic_cast(this); + CaretAssert(browserTab); + myClone = new AnnotationBrowserTab(*browserTab); + } + break; case AnnotationTypeEnum::COLOR_BAR: { const AnnotationColorBar* colorBar = dynamic_cast(this); @@ -348,6 +356,9 @@ Annotation::newAnnotationOfType(const AnnotationTypeEnum::Enum annotationType, case AnnotationTypeEnum::BOX: annotation = new AnnotationBox(attributeDefaultType); break; + case AnnotationTypeEnum::BROWSER_TAB: + annotation = new AnnotationBrowserTab(attributeDefaultType); + break; case AnnotationTypeEnum::COLOR_BAR: annotation = new AnnotationColorBar(attributeDefaultType); break; @@ -418,6 +429,9 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + m_colorBackground = CaretColorEnum::NONE; + break; case AnnotationTypeEnum::COLOR_BAR: m_colorBackground = CaretColorEnum::BLACK; break; @@ -470,6 +484,9 @@ Annotation::initializeAnnotationMembers() m_colorBackground = defaultColor; } break; + case AnnotationTypeEnum::BROWSER_TAB: + m_colorBackground = CaretColorEnum::NONE; + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -515,6 +532,9 @@ Annotation::initializeAnnotationMembers() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + disallowLineColorNoneFlag = true; + break; case AnnotationTypeEnum::COLOR_BAR: disallowLineColorNoneFlag = true; break; @@ -623,6 +643,8 @@ Annotation::getTextForPasteMenuItems(AString& pasteMenuItemText, switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -932,129 +954,6 @@ Annotation::initializeSurfaceSpaceWithTangentOffsetRotation(const StructureEnum: } return; - - - - - -// AnnotationTwoDimensionalShape* twoDimAnn = dynamic_cast(this); -// if (twoDimAnn != NULL) { -// if (isInSurfaceSpaceWithTangentOffset()) { -// enum class OrientationType { -// LEFT_TO_RIGHT = 0, -// RIGHT_TO_LEFT = 1, -// POSTERIOR_TO_ANTERIOR = 2, -// ANTERIOR_TO_POSTERIOR = 3, -// INFERIOR_TO_SUPERIOR = 4, -// SUPERIOR_TO_INFERIOR = 5 -// }; -// -// const OrientationType orientations[6] = { -// OrientationType::LEFT_TO_RIGHT, -// OrientationType::RIGHT_TO_LEFT, -// OrientationType::POSTERIOR_TO_ANTERIOR, -// OrientationType::ANTERIOR_TO_POSTERIOR, -// OrientationType::INFERIOR_TO_SUPERIOR, -// OrientationType::SUPERIOR_TO_INFERIOR -// }; -// const float orientationVectors[6][3] { -// { 1.0, 0.0, 0.0 }, -// { -1.0, 0.0, 0.0 }, -// { 0.0, 1.0, 0.0 }, -// { 0.0, -1.0, 0.0 }, -// { 0.0, 0.0, 1.0 }, -// { 0.0, 0.0, -1.0 } -// }; -// -// -// /* -// * Find orientation that aligns with the vertex's normal vector -// */ -// OrientationType matchingOrientation = OrientationType::LEFT_TO_RIGHT; -// float matchingAngle = 10000.0f; -// for (int32_t i = 0; i < 6; i++) { -// const float angle = MathFunctions::angleInDegreesBetweenVectors(orientationVectors[i], -// vertexNormal); -// if (angle < matchingAngle) { -// matchingAngle = angle; -// matchingOrientation = orientations[i]; -// } -// } -// -// float surfaceUpAxisVector[3] = { 0.0f, 0.0f, 1.0f }; -// switch (matchingOrientation) { -// case OrientationType::LEFT_TO_RIGHT: -// break; -// case OrientationType::RIGHT_TO_LEFT: -// break; -// case OrientationType::POSTERIOR_TO_ANTERIOR: -// break; -// case OrientationType::ANTERIOR_TO_POSTERIOR: -// break; -// case OrientationType::INFERIOR_TO_SUPERIOR: -// surfaceUpAxisVector[0] = 1.0; -// surfaceUpAxisVector[0] = 0.0; -// surfaceUpAxisVector[0] = 0.0; -// break; -// case OrientationType::SUPERIOR_TO_INFERIOR: -// surfaceUpAxisVector[0] = -1.0; -// surfaceUpAxisVector[0] = 0.0; -// surfaceUpAxisVector[0] = 0.0; -// break; -// } -// -// /* -// * Vector for annotation's Y (vector from bottom to top of annotation) -// */ -// const float annotationUpYVector[3] { -// 0.0, -// 1.0, -// 0.0 -// }; -// -// /* -// * Initialize the rotation angle so that the annotation's vertical axis -// * is aligned with the screen vertical axis when the surface is in the -// * analogous surface view. For a text annotation, the text should be -// * flowing left to right across screen. -// */ -// Matrix4x4 rotationMatrix; -// rotationMatrix.setMatrixToOpenGLRotationFromVector(vertexNormal); -// Matrix4x4 inverseMatrix(rotationMatrix); -// inverseMatrix.invert(); -// inverseMatrix.multiplyPoint3(surfaceUpAxisVector); -// const float alignRotationAngle = MathFunctions::angleInDegreesBetweenVectors(annotationUpYVector, -// surfaceUpAxisVector); -// float rotationAngle = alignRotationAngle; -// switch (matchingOrientation) { -// case OrientationType::LEFT_TO_RIGHT: -// rotationAngle = 360.0 - rotationAngle; -// break; -// case OrientationType::RIGHT_TO_LEFT: -// break; -// case OrientationType::POSTERIOR_TO_ANTERIOR: -// if (StructureEnum::isRight(structure)) { -// rotationAngle = 360.0 - rotationAngle; -// } -// break; -// case OrientationType::ANTERIOR_TO_POSTERIOR: -// if (StructureEnum::isRight(structure)) { -// rotationAngle = 360.0 - rotationAngle; -// } -// break; -// case OrientationType::INFERIOR_TO_SUPERIOR: -// if (StructureEnum::isRight(structure)) { -// rotationAngle += 180.0; -// } -// break; -// case OrientationType::SUPERIOR_TO_INFERIOR: -// rotationAngle += 90.0; -// break; -// } -// -// twoDimAnn->setRotationAngle(rotationAngle); -// } -// } } /** @@ -1575,6 +1474,7 @@ Annotation::initializeProperties() CaretAssert(m_properties.size() >= static_cast::type>(Property::COUNT_FOR_BITSET)); m_properties.set(); + bool browserTabFlag(false); bool colorBarFlag = false; bool fillColorFlag = true; bool lineArrowsFlag = false; @@ -1582,6 +1482,10 @@ Annotation::initializeProperties() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + browserTabFlag = true; + fillColorFlag = false; + break; case AnnotationTypeEnum::COLOR_BAR: colorBarFlag = true; break; @@ -1617,6 +1521,17 @@ Annotation::initializeProperties() resetProperty(Property::INVALID); resetProperty(Property::COUNT_FOR_BITSET); + if (browserTabFlag) { + resetProperty(Property::COPY_CUT_PASTE); + resetProperty(Property::DELETION); + resetProperty(Property::DISPLAY_GROUP); + resetProperty(Property::GROUP); + resetProperty(Property::LINE_COLOR); + resetProperty(Property::LINE_THICKNESS); + resetProperty(Property::TEXT_COLOR); + resetProperty(Property::TEXT_EDIT); + } + if (colorBarFlag) { resetProperty(Property::ARRANGE); resetProperty(Property::COPY_CUT_PASTE); @@ -1912,6 +1827,8 @@ Annotation::textAnnotationResetName() switch (m_type) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/Annotations/AnnotationBrowserTab.cxx b/src/Annotations/AnnotationBrowserTab.cxx new file mode 100644 index 000000000..d42d05724 --- /dev/null +++ b/src/Annotations/AnnotationBrowserTab.cxx @@ -0,0 +1,394 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __ANNOTATION_BROWSER_TAB_DECLARE__ +#include "AnnotationBrowserTab.h" +#undef __ANNOTATION_BROWSER_TAB_DECLARE__ + +#include "AnnotationCoordinate.h" +#include "CaretAssert.h" +#include "SceneClass.h" +#include "SceneClassAssistant.h" +#include "TileTabsBrowserTabGeometry.h" + +using namespace caret; + + + +/** + * \class caret::AnnotationBrowserTab + * \brief An annotation box. + * \ingroup Annotations + */ + +/** + * Constructor. + * + * @param attributeDefaultType + * Type for attribute defaults + */ +AnnotationBrowserTab::AnnotationBrowserTab(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType) +: AnnotationTwoDimensionalShape(AnnotationTypeEnum::BROWSER_TAB, + attributeDefaultType) +{ + initializeMembersAnnotationBrowserTab(); +} + +/** + * Destructor. + */ +AnnotationBrowserTab::~AnnotationBrowserTab() +{ +} + +/** + * Copy constructor. + * @param obj + * Object that is copied. + */ +AnnotationBrowserTab::AnnotationBrowserTab(const AnnotationBrowserTab& obj) +: AnnotationTwoDimensionalShape(obj) +{ + this->initializeMembersAnnotationBrowserTab(); + this->copyHelperAnnotationBrowserTab(obj); +} + +/** + * Assignment operator. + * @param obj + * Data copied from obj to this. + * @return + * Reference to this object. + */ +AnnotationBrowserTab& +AnnotationBrowserTab::operator=(const AnnotationBrowserTab& obj) +{ + if (this != &obj) { + AnnotationTwoDimensionalShape::operator=(obj); + this->copyHelperAnnotationBrowserTab(obj); + } + return *this; +} + +/** + * Initialize a new instance of this class. + */ +void +AnnotationBrowserTab::initializeMembersAnnotationBrowserTab() +{ + m_sceneAssistant.grabNew(new SceneClassAssistant()); + + if (testProperty(Property::SCENE_CONTAINS_ATTRIBUTES)) { + + } + + setCoordinateSpace(AnnotationCoordinateSpaceEnum::WINDOW); +} + +/** + * Helps with copying an object of this type. + * @param obj + * Object that is copied. + */ +void +AnnotationBrowserTab::copyHelperAnnotationBrowserTab(const AnnotationBrowserTab& /*obj*/) +{ + /* nothing to copy here */ +} + +/** + * Save subclass data to the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass to which data members should be added. Will always + * be valid (non-NULL). + */ +void +AnnotationBrowserTab::saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass) +{ + AnnotationTwoDimensionalShape::saveSubClassDataToScene(sceneAttributes, + sceneClass); + m_sceneAssistant->saveMembers(sceneAttributes, + sceneClass); +} + +/** + * Restore file data from the scene. + * + * @param sceneAttributes + * Attributes for the scene. Scenes may be of different types + * (full, generic, etc) and the attributes should be checked when + * restoring the scene. + * + * @param sceneClass + * sceneClass for the instance of a class that implements + * this interface. Will NEVER be NULL. + */ +void +AnnotationBrowserTab::restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass) +{ + AnnotationTwoDimensionalShape::restoreSubClassDataFromScene(sceneAttributes, + sceneClass); + m_sceneAssistant->restoreMembers(sceneAttributes, + sceneClass); +} + +/** + * Set the browser tab and index that owns this annotation + * + * @param browserTabContent + * Browser tab that owns this annotation + * @param tabIndex + * Index of the browser tab + */ +void +AnnotationBrowserTab::setBrowserTabContent(BrowserTabContent* browserTabContent, + const int32_t tabIndex) +{ + m_browserTabContent = browserTabContent; + m_tabIndex = tabIndex; +} + +/** + * @return The browser tab that owns this annotation + */ +BrowserTabContent* +AnnotationBrowserTab::getBrowserTabContent() +{ + return m_browserTabContent; +} + +/** + * @return The browser tab that owns this annotation (const method) + */ +const BrowserTabContent* +AnnotationBrowserTab::getBrowserTabContent() const +{ + return m_browserTabContent; +} + +/** + * @return Index of browser tab that owns this annotation + */ +int32_t +AnnotationBrowserTab::getTabIndex() const +{ + return m_tabIndex; +} + + +/** + * Set the browser tab annotation dimensions using the tile tabs geometry + * + * @param geometry + * The tile tabs geometry + */ +void +AnnotationBrowserTab::setFromTileTabsGeometry(const TileTabsBrowserTabGeometry* geometry) +{ + CaretAssert(geometry); + setBounds2D(geometry->getMinX(), + geometry->getMaxX(), + geometry->getMinY(), + geometry->getMaxY()); + m_stackingOrder = geometry->getStackingOrder(); + m_backgroundType = geometry->getBackgroundType(); +} + +/** + * Load the browser tab annotation dimensions into the tile tabs geometry + * + * @param geometry + * The tile tabs geometry + */ +void +AnnotationBrowserTab::getTileTabsGeometry(TileTabsBrowserTabGeometry* geometryOut) const +{ + CaretAssert(geometryOut); + + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + getBounds2D(minX, maxX, minY, maxY); + + geometryOut->setBounds(minX, maxX, minY, maxY); + geometryOut->setStackingOrder(m_stackingOrder); + geometryOut->setBackgroundType(m_backgroundType); +} + +/** + * Get the 2D bounds (note: BrowserTab is always aligned with X/Y axes) + * + * @param minX + * Output with minimum X + * @param maxX + * Output with maximum X + * @param minY + * Output with minimum X + * @param maxY + * Output with maximum X + */ +void +AnnotationBrowserTab::getBounds2D(float& minX, + float& maxX, + float& minY, + float& maxY) const +{ + float xyz[3]; + getCoordinate()->getXYZ(xyz); + + minX = xyz[0] - (getWidth() / 2.0); + maxX = minX + getWidth(); + minY = xyz[1] - (getHeight() / 2.0); + maxY = minY + getHeight(); +} + +/** + * Set the 2D bounds (note: BrowserTab is always aligned with X/Y axes) + * + * @param minX + * The minimum X + * @param maxX + * The maximum X + * @param minY + * The minimum X + * @param maxY + * The maximum X + */ +void +AnnotationBrowserTab::setBounds2D(const float minX, + const float maxX, + const float minY, + const float maxY) +{ + const float centerX = (minX + maxX) / 2.0; + const float centerY = (minY + maxY) / 2.0; + const float width = (maxX - minX); + const float height = (maxY - minY); + + getCoordinate()->setXYZ(centerX, centerY, 0.0); + setWidth(width); + setHeight(height); +} + +/** + * @return Stacking order (depth in screen) of tab, greater value is 'in front' + */ +int32_t +AnnotationBrowserTab::getStackingOrder() const +{ + return m_stackingOrder; +} + +/** + * Set Stacking order (depth in screen) of tab, greater value is 'in front' + * + * @param stackingOrder + * New value for Stacking order (depth in screen) of tab, greater value is 'in front' + */ +void +AnnotationBrowserTab::setStackingOrder(const int32_t stackingOrder) +{ + m_stackingOrder = stackingOrder; +} + +/** + * @return Type of background (opaque / transparent) for tab + */ +TileTabsLayoutBackgroundTypeEnum::Enum +AnnotationBrowserTab::getBackgroundType() const +{ + return m_backgroundType; +} + +/** + * Set Type of background (opaque / transparent) for tab + * + * @param backgroundType + * New value for Type of background (opaque / transparent) for tab + */ +void +AnnotationBrowserTab::setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType) +{ + m_backgroundType = backgroundType; +} + +/** + * @return true if this and the given geometry intersect. + * NOTE: if 'other' is 'this' true is returned (overlaps self) but this + * could change so it is best to avoid testing overlap of self. + * + * @param other + * Other geometry for intersection test + */ +bool +AnnotationBrowserTab::intersectionTest(const AnnotationBrowserTab* other) const +{ + CaretAssert(other); + + /* + * Does self overlap + */ + if (this == other) { + return true; + } + + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + getBounds2D(minX, maxX, minY, maxY); + + float otherMinX(0.0), otherMaxX(0.0), otherMinY(0.0), otherMaxY(0.0); + other->getBounds2D(otherMinX, otherMaxX, otherMinY, otherMaxY); + + /* + * Note: Since the geometry is aligned with the X- and Y-axes, + * we only need to test for one to be above or the the right of the other + * + * https://www.geeksforgeeks.org/find-two-rectangles-overlap/ + * https://leetcode.com/articles/rectangle-overlap/ + */ + /* 'this' is on right side of 'other' */ + if (minX >= otherMaxX) { + return false; + } + + /* 'other' is on right side of 'this' */ + if (otherMinX >= maxX) { + return false; + } + + /* 'this' is above 'other */ + if (minY >= otherMaxY) { + return false; + } + + /* 'other' is above 'this' */ + if (otherMinY >= maxY) { + return false; + } + + return true; +} + diff --git a/src/Annotations/AnnotationBrowserTab.h b/src/Annotations/AnnotationBrowserTab.h new file mode 100644 index 000000000..252d8c6b9 --- /dev/null +++ b/src/Annotations/AnnotationBrowserTab.h @@ -0,0 +1,120 @@ +#ifndef __ANNOTATION_BROWSER_TAB_H__ +#define __ANNOTATION_BROWSER_TAB_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include "AnnotationTwoDimensionalShape.h" +#include "CaretPointer.h" +#include "TileTabsLayoutBackgroundTypeEnum.h" + +namespace caret { + + class BrowserTabContent; + class TileTabsBrowserTabGeometry; + + class AnnotationBrowserTab : public AnnotationTwoDimensionalShape { + + public: + AnnotationBrowserTab(const AnnotationAttributesDefaultTypeEnum::Enum attributeDefaultType); + + virtual ~AnnotationBrowserTab(); + + AnnotationBrowserTab(const AnnotationBrowserTab& obj); + + AnnotationBrowserTab& operator=(const AnnotationBrowserTab& obj); + + void setFromTileTabsGeometry(const TileTabsBrowserTabGeometry* geometry); + + void getTileTabsGeometry(TileTabsBrowserTabGeometry* geometryOut) const; + + void setBrowserTabContent(BrowserTabContent* browserTabContent, + const int32_t tabIndex); + + BrowserTabContent* getBrowserTabContent(); + + const BrowserTabContent* getBrowserTabContent() const; + + int32_t getTabIndex() const; + + int32_t getStackingOrder() const; + + void setStackingOrder(const int32_t stackingOrder); + + TileTabsLayoutBackgroundTypeEnum::Enum getBackgroundType() const; + + void setBackgroundType(const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType); + + bool intersectionTest(const AnnotationBrowserTab* other) const; + + void getBounds2D(float& minX, + float& maxX, + float& minY, + float& maxY) const; + + void setBounds2D(const float minX, + const float maxX, + const float minY, + const float maxY); + + // ADD_NEW_METHODS_HERE + + + + + + + protected: + virtual void saveSubClassDataToScene(const SceneAttributes* sceneAttributes, + SceneClass* sceneClass); + + virtual void restoreSubClassDataFromScene(const SceneAttributes* sceneAttributes, + const SceneClass* sceneClass); + + private: + void copyHelperAnnotationBrowserTab(const AnnotationBrowserTab& obj); + + void initializeMembersAnnotationBrowserTab(); + + CaretPointer m_sceneAssistant; + + /** Browser tab that owns this annotation DO NOT DELETE */ + BrowserTabContent* m_browserTabContent = NULL; + + /** Index of browser tab that owns this annotation */ + int32_t m_tabIndex = -1; + + /** Stacking order (depth in screen) of tab, greater value is 'in front'*/ + int32_t m_stackingOrder = 1; + + /** Type of background (opaque / transparent) for tab*/ + TileTabsLayoutBackgroundTypeEnum::Enum m_backgroundType = TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __ANNOTATION_BROWSER_TAB_DECLARE__ + // +#endif // __ANNOTATION_BROWSER_TAB_DECLARE__ + +} // namespace +#endif //__ANNOTATION_BROWSER_TAB_H__ diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index f5466cc2f..a65e8e89e 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -1601,6 +1601,8 @@ AnnotationRedoUndoCommand::setModeTextCharacters(const AString& text, switch (annotation->getType()) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/Annotations/AnnotationTwoDimensionalShape.cxx b/src/Annotations/AnnotationTwoDimensionalShape.cxx index 53fd31615..31a31771a 100644 --- a/src/Annotations/AnnotationTwoDimensionalShape.cxx +++ b/src/Annotations/AnnotationTwoDimensionalShape.cxx @@ -390,6 +390,11 @@ AnnotationTwoDimensionalShape::isSizeHandleValid(const AnnotationSizingHandleTyp allowsSideResizingFlag = true; allowsRotationFlag = true; break; + case AnnotationTypeEnum::BROWSER_TAB: + allowsMovingFlag = true; + allowsCornerResizingFlag = true; + allowsSideResizingFlag = true; + break; case AnnotationTypeEnum::COLOR_BAR: allowsMovingFlag = true; allowsCornerResizingFlag = true; @@ -1326,7 +1331,7 @@ AnnotationTwoDimensionalShape::rotationAngleTest(const float previousMouseXYZ[3] shapeXYZ, previousMouseXYZ); - static const float MINIMUM_ANGLE = 0.025; //0.01; + static const float MINIMUM_ANGLE = 0.025; if (angle > MINIMUM_ANGLE) { return true; diff --git a/src/Annotations/AnnotationTypeEnum.cxx b/src/Annotations/AnnotationTypeEnum.cxx index 1f316d521..03bca2479 100644 --- a/src/Annotations/AnnotationTypeEnum.cxx +++ b/src/Annotations/AnnotationTypeEnum.cxx @@ -110,6 +110,10 @@ AnnotationTypeEnum::initialize() "BOX", "Box")); + enumData.push_back(AnnotationTypeEnum(BROWSER_TAB, + "BROWSER_TAB", + "Browser Tab")); + enumData.push_back(AnnotationTypeEnum(COLOR_BAR, "COLOR_BAR", "Color Bar")); diff --git a/src/Annotations/AnnotationTypeEnum.h b/src/Annotations/AnnotationTypeEnum.h index a0650752a..809c4c371 100644 --- a/src/Annotations/AnnotationTypeEnum.h +++ b/src/Annotations/AnnotationTypeEnum.h @@ -37,6 +37,8 @@ public: enum Enum { /** Box */ BOX, + /** Browser Tab */ + BROWSER_TAB, /** Colorbar */ COLOR_BAR, /** Image */ diff --git a/src/Annotations/CMakeLists.txt b/src/Annotations/CMakeLists.txt index 7ff91220d..5d857735d 100644 --- a/src/Annotations/CMakeLists.txt +++ b/src/Annotations/CMakeLists.txt @@ -27,6 +27,7 @@ Annotation.h AnnotationAlignmentEnum.h AnnotationAttributesDefaultTypeEnum.h AnnotationBox.h +AnnotationBrowserTab.h AnnotationColorBar.h AnnotationColorBarNumericText.h AnnotationColorBarPositionModeEnum.h @@ -72,6 +73,7 @@ Annotation.cxx AnnotationAlignmentEnum.cxx AnnotationAttributesDefaultTypeEnum.cxx AnnotationBox.cxx +AnnotationBrowserTab.cxx AnnotationColorBar.cxx AnnotationColorBarNumericText.cxx AnnotationColorBarPositionModeEnum.cxx diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index d45af9e5a..85f176a97 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -25,6 +25,7 @@ #include "Annotation.h" #include "AnnotationArrangerExecutor.h" +#include "AnnotationBrowserTab.h" #include "AnnotationColorBar.h" #include "AnnotationFile.h" #include "AnnotationGroup.h" @@ -32,6 +33,7 @@ #include "AnnotationRedoUndoCommand.h" #include "AnnotationEditingSelectionInformation.h" #include "AnnotationTwoDimensionalShape.h" +#include "BrowserTabContent.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -40,6 +42,7 @@ #include "EventAnnotationChartLabelGet.h" #include "EventAnnotationColorBarGet.h" #include "EventAnnotationGroupGetWithKey.h" +#include "EventBrowserTabGetAll.h" #include "EventGetDisplayedDataFiles.h" #include "EventManager.h" #include "SceneClass.h" @@ -207,6 +210,14 @@ AnnotationManager::deselectAllAnnotationsForEditing(const int32_t windowIndex) label->setSelectedForEditing(windowIndex, false); } + + EventBrowserTabGetAll allTabsEvent; + EventManager::get()->sendEvent(allTabsEvent.getPointer()); + std::vector allTabs = allTabsEvent.getAllBrowserTabs(); + for (auto tab : allTabs) { + tab->getManualLayoutBrowserTabAnnotation()->setSelectedForEditing(windowIndex, + false); + } } /** @@ -450,6 +461,13 @@ AnnotationManager::getAllAnnotations() const chartLabels.begin(), chartLabels.end()); + EventBrowserTabGetAll allTabsEvent; + EventManager::get()->sendEvent(allTabsEvent.getPointer()); + std::vector allTabs = allTabsEvent.getAllBrowserTabs(); + for (auto tab : allTabs) { + allAnnotations.push_back(tab->getManualLayoutBrowserTabAnnotation()); + } + return allAnnotations; } diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 75c5a92c7..b8a77520b 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -29,6 +29,7 @@ #undef __BRAIN_OPEN_G_L_ANNOTATION_DRAWING_FIXED_PIPELINE_DECLARE__ #include "AnnotationBox.h" +#include "AnnotationBrowserTab.h" #include "AnnotationColorBar.h" #include "AnnotationColorBarSection.h" #include "AnnotationColorBarNumericText.h" @@ -413,10 +414,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::getAnnotationTwoDimShapeBounds(const if (textFlag) { m_brainOpenGLFixedPipeline->getTextRenderer()->getBoundsForTextAtViewportCoords(*textAnnotation, m_textDrawingFlags, - windowXYZ[0], windowXYZ[1], windowXYZ[2], - viewportWidth, viewportHeight, - bottomLeftOut, bottomRightOut, topRightOut, topLeftOut); - + windowXYZ[0], windowXYZ[1], windowXYZ[2], + viewportWidth, viewportHeight, + bottomLeftOut, bottomRightOut, topRightOut, topLeftOut); + boundsValid = true; } else { @@ -905,41 +906,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat } break; } - -// /* -// * Skip annotation in a different window -// */ -// if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::WINDOW) { -// const int32_t annotationWindowIndex = annotation->getWindowIndex(); -// if ((annotationWindowIndex < 0) -// || (annotationWindowIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS)) { -// CaretLogSevere("Annotation has invalid window index=" -// + AString::number(annotationWindowIndex) -// + " " -// + annotation->toString()); -// } -// if (m_inputs->m_windowIndex != annotationWindowIndex) { -// continue; -// } -// } -// -// /* -// * Skip annotations in a different tab -// */ -// if (annotationCoordinateSpace == AnnotationCoordinateSpaceEnum::TAB) { -// const int32_t annotationTabIndex = annotation->getTabIndex(); -// if ((annotationTabIndex < 0) -// || (annotationTabIndex >= BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_TABS)) { -// CaretLogSevere("Annotation has invalid tab index=" -// + AString::number(annotationTabIndex) -// + " " -// + annotation->toString()); -// } -// if (m_inputs->m_tabIndex != annotationTabIndex) { -// continue; -// } -// } - + drawAnnotation(annotationFile, annotation, surfaceDisplayed); @@ -1165,6 +1132,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotation(AnnotationFile* annota dynamic_cast(annotation), surfaceDisplayed); break; + case AnnotationTypeEnum::BROWSER_TAB: + drawnFlag = drawBrowserTab(annotationFile, + dynamic_cast(annotation)); + break; case AnnotationTypeEnum::COLOR_BAR: drawColorBar(annotationFile, dynamic_cast(annotation)); @@ -1410,6 +1381,9 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawTwoDimAnnotationSurfaceTextureOff surfaceExtentZ, vertexXYZ); break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssertMessage(0, "Browser Tab is NEVER drawn in surface space"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color Bar is NEVER drawn in surface space"); break; @@ -1501,6 +1475,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOneDimAnnotationSurfaceTextureOff glPushMatrix(); switch (annotation->getType()) { case AnnotationTypeEnum::BOX: + case AnnotationTypeEnum::BROWSER_TAB: case AnnotationTypeEnum::COLOR_BAR: case AnnotationTypeEnum::IMAGE: case AnnotationTypeEnum::OVAL: @@ -1796,6 +1771,143 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBoxSurfaceTangentOffset(Annotatio return drawnFlag; } +/** + * Draw an annotation browser tab. + * + * @param annotationFile + * File containing the annotation. + * @param browserTab + * Browser tab to draw. + */ +bool +BrainOpenGLAnnotationDrawingFixedPipeline::drawBrowserTab(AnnotationFile* annotationFile, + AnnotationBrowserTab* browserTab) +{ + CaretAssert(browserTab); + CaretAssert(browserTab->getType() == AnnotationTypeEnum::BROWSER_TAB); + + float annXYZ[3]; + Surface* nullSurface(NULL); + if ( ! getAnnotationDrawingSpaceCoordinate(browserTab, + browserTab->getCoordinate(), + nullSurface, + annXYZ)) { + return false; + } + + float bottomLeft[3]; + float bottomRight[3]; + float topRight[3]; + float topLeft[3]; + if ( ! getAnnotationTwoDimShapeBounds(browserTab, annXYZ, + bottomLeft, bottomRight, topRight, topLeft)) { + return false; + } + + const float selectionCenterXYZ[3] = { + (bottomLeft[0] + bottomRight[0] + topRight[0] + topLeft[0]) / 4.0f, + (bottomLeft[1] + bottomRight[1] + topRight[1] + topLeft[1]) / 4.0f, + (bottomLeft[2] + bottomRight[2] + topRight[2] + topLeft[2]) / 4.0f + }; + + if (browserTab->getLineWidthPercentage() <= 0.0f) { + convertObsoleteLineWidthPixelsToPercentageWidth(browserTab); + } + + const Surface* surfaceDisplayed(NULL); + const bool depthTestFlag = isDrawnWithDepthTesting(browserTab, + surfaceDisplayed); + const bool savedDepthTestStatus = setDepthTestingStatus(depthTestFlag); + + uint8_t backgroundRGBA[4]; + browserTab->getBackgroundColorRGBA(backgroundRGBA); + uint8_t foregroundRGBA[4]; + browserTab->getLineColorRGBA(foregroundRGBA); + + const bool drawBackgroundFlag = (backgroundRGBA[3] > 0); + const bool drawForegroundFlag = (foregroundRGBA[3] > 0); + const bool drawAnnotationFlag = (drawBackgroundFlag || drawForegroundFlag); + + bool drawnFlag = false; + + if (drawAnnotationFlag) { + if (m_selectionModeFlag) { + uint8_t selectionColorRGBA[4]; + getIdentificationColor(selectionColorRGBA); + + const bool alwaysDrawBackgroundForSelectionFlag(true); + if (drawBackgroundFlag + || alwaysDrawBackgroundForSelectionFlag) { + /* + * When selecting draw only background if it is enabled + * since it is opaque and prevents "behind" annotations + * from being selected + */ + GraphicsShape::drawBoxFilledByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA); + } + else { + /* + * Drawing foreground as line will still allow user to + * select annotation that are inside of the box + */ + const float percentHeight = getLineWidthPercentageInSelectionMode(browserTab); + GraphicsShape::drawBoxOutlineByteColor(bottomLeft, + bottomRight, + topRight, + topLeft, + selectionColorRGBA, + GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, + percentHeight); + } + + m_selectionInfo.push_back(SelectionInfo(annotationFile, + browserTab, + AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, + selectionCenterXYZ)); + } + else { + if (drawBackgroundFlag) { + /* may or may not need for transparent background */ +// GraphicsShape::drawBoxFilledByteColor(bottomLeft, +// bottomRight, +// topRight, +// topLeft, +// backgroundRGBA); + drawnFlag = true; + } + + if (drawForegroundFlag) { +// GraphicsShape::drawBoxOutlineByteColor(bottomLeft, +// bottomRight, +// topRight, +// topLeft, +// foregroundRGBA, +// GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, +// browserTab->getLineWidthPercentage()); + drawnFlag = true; + } + } + if (browserTab->isSelectedForEditing(m_inputs->m_windowIndex)) { + drawAnnotationTwoDimSizingHandles(annotationFile, + browserTab, + bottomLeft, + bottomRight, + topRight, + topLeft, + s_sizingHandleLineWidthInPixels, + browserTab->getRotationAngle()); + } + } + + setDepthTestingStatus(savedDepthTestStatus); + + return drawnFlag; +} + /** * Draw an annotation color bar. @@ -2823,11 +2935,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOvalSurfaceTangentOffset(Annotati minorAxis, foregroundRGBA, lineThickness); -// GraphicsShape::drawEllipseOutlineByteColor(majorAxis, -// minorAxis, -// foregroundRGBA, -// GraphicsPrimitive::LineWidthType::PIXELS, -// lineThickness); glDisable(GL_POLYGON_OFFSET_FILL); drawnFlag = true; } @@ -4080,18 +4187,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(Annotati selectionColorRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); - // if ( ! startArrowCoordinates.empty()) { - // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, - // selectionColorRGBA, - // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - // lineThickness); - // } - // if ( ! endArrowCoordinates.empty()) { - // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, - // selectionColorRGBA, - // GraphicsPrimitive::LineWidthType::PERCENTAGE_VIEWPORT_HEIGHT, - // lineThickness); - // } m_selectionInfo.push_back(SelectionInfo(annotationFile, line, AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE, @@ -4099,40 +4194,10 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(Annotati } else { if (drawForegroundFlag) { - // float floatRGBA[4]; - // line->getLineColorRGBA(floatRGBA); - // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, - // lineHeadXYZ, - // lineTailXYZ, - // lineThickness / 2); GraphicsShape::drawLinesByteColor(lineCoordinates, foregroundRGBA, GraphicsPrimitive::LineWidthType::PIXELS, lineThickness); - // if ( ! startArrowCoordinates.empty()) { - // if (startArrowCoordinates.size() == 9) { - // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, - // &startArrowCoordinates[0], - // &startArrowCoordinates[3], - // lineThickness / 2); - // m_brainOpenGLFixedPipeline->drawCylinder(floatRGBA, - // &startArrowCoordinates[3], - // &startArrowCoordinates[6], - // lineThickness / 2); - // } - // else { - // GraphicsShape::drawLineStripMiterJoinByteColor(startArrowCoordinates, - // foregroundRGBA, - // GraphicsPrimitive::LineWidthType::PIXELS, - // lineThickness); - // } - // } - // if ( ! endArrowCoordinates.empty()) { - // GraphicsShape::drawLineStripMiterJoinByteColor(endArrowCoordinates, - // foregroundRGBA, - // GraphicsPrimitive::LineWidthType::PIXELS, - // lineThickness); - // } drawnFlag = true; } } @@ -4147,7 +4212,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(Annotati line, lineHeadXYZ, lineTailXYZ, - handleThickness); //lineThickness * 2.0); //s_sizingHandleLineWidthInPixels); + handleThickness); } } @@ -4268,6 +4333,13 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi break; } + if (annotation->getType() == AnnotationTypeEnum::BROWSER_TAB) { + drawFilledCircleFlag = false; + drawOutlineCircleFlag = false; + drawSphereFlag = false; + drawSquareFlag = true; + } + if (m_selectionModeFlag) { uint8_t identificationRGBA[4]; getIdentificationColor(identificationRGBA); @@ -4350,7 +4422,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann float cornerSquareSize = 3.0 + lineThickness; if (tangentSurfaceOffsetFlag) { - cornerSquareSize = lineThickness;// * 4.0; + cornerSquareSize = lineThickness; cornerSquareSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(cornerSquareSize); } @@ -4385,7 +4457,7 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationOneDimSizingHandles(Ann */ float startSquareSize = cornerSquareSize + 2.0; if (tangentSurfaceOffsetFlag) { - startSquareSize = cornerSquareSize;// * 1.5; + startSquareSize = cornerSquareSize; } drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_LINE_START, annotationFile, @@ -4465,6 +4537,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann if (modelSpaceTangentTextFlag) { innerSpacing = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(innerSpacing); } + + /* + * Must shrink box around browser tab or else the box is outside of the + * browser tab and not seen + */ + if (annotation->getType() == AnnotationTypeEnum::BROWSER_TAB) { + innerSpacing = -innerSpacing; + } + float handleTopLeft[3]; float handleTopRight[3]; float handleBottomRight[3]; @@ -4483,35 +4564,45 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann m_selectionBoxRGBA, GraphicsPrimitive::LineWidthType::PIXELS, 2.0f); } + float sizeHandleSize = 5.0; + if (modelSpaceTangentTextFlag) { + sizeHandleSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(sizeHandleSize); + } + + float handleOffset(0.0); + if (annotation->getType() == AnnotationTypeEnum::BROWSER_TAB) { + if (m_selectionModeFlag) { + sizeHandleSize *= 4.0; + } + else { + sizeHandleSize *= 2.0; + MathFunctions::expandBox(handleBottomLeft, handleBottomRight, handleTopRight, handleTopLeft, -sizeHandleSize, -sizeHandleSize); + } + } const float handleLeft[3] = { - (handleBottomLeft[0] + handleTopLeft[0]) / 2.0f, + (handleBottomLeft[0] + handleTopLeft[0]) / 2.0f + handleOffset, (handleBottomLeft[1] + handleTopLeft[1]) / 2.0f, (handleBottomLeft[2] + handleTopLeft[2]) / 2.0f, }; const float handleRight[3] = { - (handleBottomRight[0] + handleTopRight[0]) / 2.0f, + (handleBottomRight[0] + handleTopRight[0]) / 2.0f - handleOffset, (handleBottomRight[1] + handleTopRight[1]) / 2.0f, (handleBottomRight[2] + handleTopRight[2]) / 2.0f, }; const float handleBottom[3] = { (handleBottomLeft[0] + handleBottomRight[0]) / 2.0f, - (handleBottomLeft[1] + handleBottomRight[1]) / 2.0f, + (handleBottomLeft[1] + handleBottomRight[1]) / 2.0f + handleOffset, (handleBottomLeft[2] + handleBottomRight[2]) / 2.0f, }; const float handleTop[3] = { (handleTopLeft[0] + handleTopRight[0]) / 2.0f, - (handleTopLeft[1] + handleTopRight[1]) / 2.0f, + (handleTopLeft[1] + handleTopRight[1]) / 2.0f - handleOffset, (handleTopLeft[2] + handleTopRight[2]) / 2.0f, }; - float sizeHandleSize = 5.0; - if (modelSpaceTangentTextFlag) { - sizeHandleSize = GraphicsUtilitiesOpenGL::convertPixelsToMillimeters(sizeHandleSize); - } - if (annotation->isSizeHandleValid(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT)) { drawSizingHandle(AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_BOX_BOTTOM_LEFT, annotationFile, diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 0207f0f6e..95d703473 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -39,6 +39,7 @@ namespace caret { class Annotation; class AnnotationBox; + class AnnotationBrowserTab; class AnnotationColorBar; class AnnotationCoordinate; class AnnotationFile; @@ -211,6 +212,9 @@ namespace caret { AnnotationBox* box, const Surface* surfaceDisplayed); + bool drawBrowserTab(AnnotationFile* annotationFile, + AnnotationBrowserTab* browserTab); + bool drawBoxSurfaceTangentOffset(AnnotationFile* annotationFile, AnnotationBox* box, const float surfaceExtentZ, diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 9b63d6257..c9ab352d7 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -35,6 +35,7 @@ #include #include +#include "AnnotationBrowserTab.h" #include "AnnotationColorBar.h" #include "AnnotationManager.h" #include "AnnotationPointSizeText.h" @@ -56,6 +57,7 @@ #include "BrainOpenGLViewportContent.h" #include "BrainStructure.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "BoundingBox.h" #include "CaretAssert.h" #include "CaretDataFileSelectionModel.h" @@ -86,6 +88,7 @@ #include "DisplayPropertiesVolume.h" #include "ElapsedTimer.h" #include "EventAnnotationColorBarGet.h" +#include "EventBrowserWindowContent.h" #include "EventManager.h" #include "EventModelSurfaceGet.h" #include "EventNodeIdentificationColorsGetFromCharts.h" @@ -146,7 +149,6 @@ #include "SurfaceProjectionBarycentric.h" #include "SurfaceProjectionVanEssen.h" #include "SurfaceSelectionModel.h" -#include "TileTabsBrowserTabGeometry.h" #include "TopologyHelper.h" #include "VolumeFile.h" #include "VolumeMappableInterface.h" @@ -269,7 +271,7 @@ BrainOpenGLFixedPipeline::selectModelImplementation(const int32_t windowIndex, std::vector viewportContentsVector; viewportContentsVector.push_back(viewportContent); - setAnnotationColorBarsForDrawing(viewportContentsVector); + setAnnotationColorBarsAndBrowserTabsForDrawing(viewportContentsVector); m_clippingPlaneGroup = NULL; @@ -500,13 +502,13 @@ BrainOpenGLFixedPipeline::setTabViewport(const BrainOpenGLViewportContent* vpCon } /** - * Get colorbars in window space. + * Get colorbars and browser tabs for drawing * * @param viewportContents * Contents of the viewports. */ void -BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector& viewportContents) +BrainOpenGLFixedPipeline::setAnnotationColorBarsAndBrowserTabsForDrawing(const std::vector& viewportContents) { m_annotationColorBarsForDrawing.clear(); @@ -539,6 +541,36 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsForDrawing(const std::vector windowContentEvent = EventBrowserWindowContent::getWindowContent(m_windowIndex); + EventManager::get()->sendEvent(windowContentEvent->getPointer()); + const BrowserWindowContent* windowContent = windowContentEvent->getBrowserWindowContent(); + bool drawBrowserTabAnnotationsFlag(false); + if (windowContent != NULL) { + switch (windowContent->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + drawBrowserTabAnnotationsFlag = true; + break; + } + } + + m_annotationBrowserTabsForDrawing.clear(); + + if (drawBrowserTabAnnotationsFlag) { + for (const auto vc : viewportContents) { + BrowserTabContent* tabContent = vc->getBrowserTabContent(); + if (tabContent != NULL) { + AnnotationBrowserTab* abt = tabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(abt); + abt->setWindowIndex(vc->getWindowIndex()); + m_annotationBrowserTabsForDrawing.push_back(abt); + } + } + } } @@ -570,7 +602,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, setTabViewport(NULL); m_specialCaseGraphicsAnnotations.clear(); - setAnnotationColorBarsForDrawing(viewportContents); + setAnnotationColorBarsAndBrowserTabsForDrawing(viewportContents); m_tileTabsActiveFlag = (viewportContents.size() > 1); @@ -666,7 +698,7 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, if (tabContent != NULL) { if (numberOfTabs > 1) { bool opaqueFlag(false); - switch (tabContent->getManualLayoutGeometry()->getBackgroundType()) { + switch (tabContent->getManualLayoutBrowserTabAnnotation()->getBackgroundType()) { case TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG: opaqueFlag = true; break; @@ -981,7 +1013,7 @@ BrainOpenGLFixedPipeline::drawSpacerAnnotations(const BrainOpenGLViewportContent CaretAssert(m_windowIndex == tabContent->getWindowIndex()); this->browserTabContent = NULL; - m_clippingPlaneGroup = NULL; //const_cast(tabContent->getBrowserTabContent()->getClippingPlaneGroup()); + m_clippingPlaneGroup = NULL; this->windowTabIndex = -1; @@ -1119,10 +1151,17 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) windowDrawingMode, annotationModeFlag); + std::vector notInFileAnnotations; + notInFileAnnotations.insert(notInFileAnnotations.end(), + m_specialCaseGraphicsAnnotations.begin(), + m_specialCaseGraphicsAnnotations.end()); + notInFileAnnotations.insert(notInFileAnnotations.end(), + m_annotationBrowserTabsForDrawing.begin(), + m_annotationBrowserTabsForDrawing.end()); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::WINDOW, m_annotationColorBarsForDrawing, - m_specialCaseGraphicsAnnotations, + notInFileAnnotations, annotationDrawingNullSurface, annotationDrawingUnusedSurfaceScaling); @@ -1909,9 +1948,6 @@ BrainOpenGLFixedPipeline::disableLineAntiAliasing() if (glIsEnabled(GL_MULTISAMPLE)) { return; } - -// glDisable(GL_LINE_SMOOTH); -// glDisable(GL_BLEND); } /** diff --git a/src/Brain/BrainOpenGLFixedPipeline.h b/src/Brain/BrainOpenGLFixedPipeline.h index 172935495..d21c47a24 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.h +++ b/src/Brain/BrainOpenGLFixedPipeline.h @@ -43,6 +43,7 @@ namespace caret { class Annotation; + class AnnotationBrowserTab; class AnnotationText; class BoundingBox; class Brain; @@ -507,7 +508,7 @@ namespace caret { void setTabViewport(const BrainOpenGLViewportContent* vpContent); - void setAnnotationColorBarsForDrawing(const std::vector& viewportContents); + void setAnnotationColorBarsAndBrowserTabsForDrawing(const std::vector& viewportContents); void drawTabHighlighting(const float width, const float height, @@ -606,6 +607,8 @@ namespace caret { CaretPointer m_annotationDrawing; + std::vector m_annotationBrowserTabsForDrawing; + std::vector m_annotationColorBarsForDrawing; /** Some graphics using annotations for some elements so user can select and edit them */ diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 8e6e3300b..798cd51fc 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -28,6 +28,7 @@ #include #include +#include "AnnotationBrowserTab.h" #include "BrowserTabContent.h" #include "BrowserWindowContent.h" #include "CaretAssert.h" @@ -1016,8 +1017,8 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vectorgetManualLayoutGeometry()->getStackingOrder() - < b->getManualLayoutGeometry()->getStackingOrder()); } ); + [](BrowserTabContent* a, BrowserTabContent* b) { return (a->getManualLayoutBrowserTabAnnotation()->getStackingOrder() + < b->getManualLayoutBrowserTabAnnotation()->getStackingOrder()); } ); } for (const auto tab : tabContents) { @@ -1026,11 +1027,15 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vectorgetManualLayoutGeometry(); - int32_t tabX(((tabGeometry->getMinX() / 100.0) * windowWidth) + windowX); - int32_t tabY(((tabGeometry->getMinY() / 100.0) * windowHeight) + windowY); - int32_t tabWidth((tabGeometry->getWidth() / 100.0) * windowWidth); - int32_t tabHeight((tabGeometry->getHeight() / 100.0) * windowHeight); + const AnnotationBrowserTab* tabAnnotation = tab->getManualLayoutBrowserTabAnnotation(); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + tabAnnotation->getBounds2D(minX, maxX, minY, maxY); + const float tabAnnWidth(maxX - minX); + const float tabAnnHeight(maxY - minY); + int32_t tabX(((minX / 100.0) * windowWidth) + windowX); + int32_t tabY(((minY / 100.0) * windowHeight) + windowY); + int32_t tabWidth((tabAnnWidth / 100.0) * windowWidth); + int32_t tabHeight((tabAnnHeight / 100.0) * windowHeight); /* * Is aspect ratio locked for all tabs ? diff --git a/src/Brain/BrainOpenGLWindowContent.cxx b/src/Brain/BrainOpenGLWindowContent.cxx index dcfaf7527..34595a4f8 100644 --- a/src/Brain/BrainOpenGLWindowContent.cxx +++ b/src/Brain/BrainOpenGLWindowContent.cxx @@ -23,9 +23,9 @@ #include "BrainOpenGLWindowContent.h" #undef __BRAIN_OPEN_G_L_WINDOW_CONTENT_DECLARE__ +#include "AnnotationBrowserTab.h" #include "BrowserTabContent.h" #include "CaretAssert.h" -#include "TileTabsBrowserTabGeometry.h" using namespace caret; @@ -180,8 +180,8 @@ BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, const BrowserTabContent* btcOut = viewportContentOut->getBrowserTabContent(); if ((btc != NULL) && (btcOut != NULL)) { - if (btc->getManualLayoutGeometry()->getStackingOrder() - > btcOut->getManualLayoutGeometry()->getStackingOrder()) { + if (btc->getManualLayoutBrowserTabAnnotation()->getStackingOrder() + > btcOut->getManualLayoutBrowserTabAnnotation()->getStackingOrder()) { viewportContentOut = vp.get(); } } diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index 8729d5939..be27c3bc2 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -26,6 +26,7 @@ #include "BrowserTabContent.h" #undef __BROWSER_TAB_CONTENT_DECLARE__ +#include "AnnotationBrowserTab.h" #include "AnnotationColorBar.h" #include "BorderFile.h" #include "Brain.h" @@ -155,6 +156,9 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_clippingPlaneGroup = new ClippingPlaneGroup(); + m_manualLayoutBrowserTabAnnotation.reset(new AnnotationBrowserTab(AnnotationAttributesDefaultTypeEnum::NORMAL)); //;m_tabNumber)); + m_manualLayoutBrowserTabAnnotation->setBrowserTabContent(this, + m_tabNumber); m_manualLayoutTabGeometry.reset(new TileTabsBrowserTabGeometry(m_tabNumber)); m_sceneClassAssistant = new SceneClassAssistant(); @@ -374,18 +378,19 @@ BrowserTabContent::cloneBrowserTabContent(BrowserTabContent* tabToClone) /* * For manual layout, make tab same size but put in bottom left corner */ - const TileTabsBrowserTabGeometry* cloneGeometry = tabToClone->getManualLayoutGeometry(); - CaretAssert(cloneGeometry); + const AnnotationBrowserTab* cloneAnnotationBrowerTab = tabToClone->getManualLayoutBrowserTabAnnotation(); + CaretAssert(cloneAnnotationBrowerTab); const float minXY(10.0f); const float maxWidthHeight(100.0f - (minXY * 2)); - float tabWidth = MathFunctions::limitRange(cloneGeometry->getMaxX() - cloneGeometry->getMinX(), minXY, maxWidthHeight); - float tabHeight = MathFunctions::limitRange(cloneGeometry->getMaxY() - cloneGeometry->getMinY(), minXY, maxWidthHeight); - TileTabsBrowserTabGeometry* geometry = getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setMinX(minXY); - geometry->setMaxX(geometry->getMinX() + tabWidth); - geometry->setMinY(minXY); - geometry->setMaxY(geometry->getMinY() + tabHeight); + float tabWidth = MathFunctions::limitRange(cloneAnnotationBrowerTab->getWidth(), minXY, maxWidthHeight); + float tabHeight = MathFunctions::limitRange(cloneAnnotationBrowerTab->getHeight(), minXY, maxWidthHeight); + + AnnotationBrowserTab* annotationBrowserTab = getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + annotationBrowserTab->setBounds2D(minXY, + minXY + tabWidth, + minXY, + minXY + tabHeight); } /** @@ -3575,6 +3580,7 @@ BrowserTabContent::saveToScene(const SceneAttributes* sceneAttributes, m_obliqueVolumeRotationMatrix->getMatrixForOpenGL(obliqueMatrix); sceneClass->addFloatArray("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); + m_manualLayoutBrowserTabAnnotation->getTileTabsGeometry(m_manualLayoutTabGeometry.get()); TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); sceneClass->addClass(geometryHelper.saveToScene(sceneAttributes, "m_manualLayoutTabGeometry")); @@ -3611,6 +3617,7 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); geometryHelper.restoreFromScene(sceneAttributes, sceneClass->getClass("m_manualLayoutTabGeometry")); + m_manualLayoutBrowserTabAnnotation->setFromTileTabsGeometry(m_manualLayoutTabGeometry.get()); m_sceneClassAssistant->restoreMembers(sceneAttributes, sceneClass); @@ -3828,7 +3835,7 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, boundingBox->getDifferenceY()), zDiff); if (zDiff > 0.0) { - const float scaleAdjustment = zDiff / maxDim; //maxDim / zDiff; + const float scaleAdjustment = zDiff / maxDim; float scaling = getScaling(); scaling *= scaleAdjustment; setScaling(scaling); @@ -4979,23 +4986,20 @@ BrowserTabContent::updateChartModelYokedBrowserTabs() } /** - * @return Pointer to the manual layout geometry + * @return Pointer to the manual layout browser tab annotation */ -TileTabsBrowserTabGeometry* -BrowserTabContent::getManualLayoutGeometry() +AnnotationBrowserTab* +BrowserTabContent::getManualLayoutBrowserTabAnnotation() { - return m_manualLayoutTabGeometry.get(); + return m_manualLayoutBrowserTabAnnotation.get(); } /** - * @return Pointer to the manual layout geometry (const method) + * @return Pointer to the manual layout browser tab annotation (const method) */ -const TileTabsBrowserTabGeometry* -BrowserTabContent::getManualLayoutGeometry() const +const +AnnotationBrowserTab* +BrowserTabContent::getManualLayoutBrowserTabAnnotation() const { - return m_manualLayoutTabGeometry.get(); + return m_manualLayoutBrowserTabAnnotation.get(); } - - - - diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index 3f40f1ce9..b42588c17 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -41,6 +41,7 @@ namespace caret { + class AnnotationBrowserTab; class AnnotationColorBar; class BrainOpenGLViewportContent; class CaretDataFile; @@ -442,9 +443,9 @@ namespace caret { const ViewingTransformations* getViewingTransformation() const; - TileTabsBrowserTabGeometry* getManualLayoutGeometry(); + AnnotationBrowserTab* getManualLayoutBrowserTabAnnotation(); - const TileTabsBrowserTabGeometry* getManualLayoutGeometry() const; + const AnnotationBrowserTab* getManualLayoutBrowserTabAnnotation() const; virtual SceneClass* saveToScene(const SceneAttributes* sceneAttributes, const AString& instanceName); @@ -472,11 +473,6 @@ namespace caret { BrowserTabContent& operator=(const BrowserTabContent&); -// VolumeSliceViewPlaneEnum::Enum getSliceViewPlaneForVolumeAllSliceView(const int viewport[4], -// const int32_t mousePressX, -// const int32_t mousePressY, -// int sliceViewportOut[4]) const; - void updateBrainModelYokedBrowserTabs(); void updateYokedModelBrowserTabs(); @@ -604,6 +600,9 @@ namespace caret { /** Manual tab layout geometry */ std::unique_ptr m_manualLayoutTabGeometry; + /** Manual layout brower tab annotation */ + std::unique_ptr m_manualLayoutBrowserTabAnnotation; + /** Contains all active browser tab content instances */ static std::set s_allBrowserTabContent; diff --git a/src/Files/AnnotationFileXmlWriter.cxx b/src/Files/AnnotationFileXmlWriter.cxx index e3c2812a5..ffc71477f 100644 --- a/src/Files/AnnotationFileXmlWriter.cxx +++ b/src/Files/AnnotationFileXmlWriter.cxx @@ -183,36 +183,6 @@ AnnotationFileXmlWriter::writeFileContentToXmlStreamWriter(const AnnotationFile* m_streamHelper->writeMetaData(annotationFile->getFileMetaData()); -// std::vector annotations; -// annotationFile->getAllAnnotations(annotations); -// const int32_t numberOfAnnotations = static_cast(annotations.size()); -// for (int32_t i = 0; i < numberOfAnnotations; i++) { -// CaretAssertVectorIndex(annotations, i); -// const Annotation* annotation = annotations[i]; -// CaretAssert(annotation); -// -// switch (annotation->getType()) { -// case AnnotationTypeEnum::BOX: -// writeBox(dynamic_cast(annotation)); -// break; -// case AnnotationTypeEnum::COLOR_BAR: -// CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); -// break; -// case AnnotationTypeEnum::IMAGE: -// writeImage(dynamic_cast(annotation)); -// break; -// case AnnotationTypeEnum::LINE: -// writeLine(dynamic_cast(annotation)); -// break; -// case AnnotationTypeEnum::OVAL: -// writeOval(dynamic_cast(annotation)); -// break; -// case AnnotationTypeEnum::TEXT: -// writeText(dynamic_cast(annotation)); -// break; -// } -// } - std::vector annotationGroups; annotationFile->getAllAnnotationGroups(annotationGroups); @@ -269,6 +239,9 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) case AnnotationTypeEnum::BOX: writeBox(dynamic_cast(annotation)); break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssertMessage(0, "Browser Tab is NEVER written to an annotation file"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Color bar is NEVER written to an annotation file"); break; @@ -287,9 +260,6 @@ AnnotationFileXmlWriter::writeGroup(const AnnotationGroup* group) } } - // const AString indicesString = AString::fromNumbers(group->getAnnotationUniqueIdentifiers(), " "); - // m_stream->writeCharacters(indicesString); - m_stream->writeEndElement(); } diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index fc51bbf82..cae142d8c 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -507,6 +507,8 @@ AnnotationColorWidget::isBothColorsSetToNoneAllowed(QWidget* widget, case AnnotationTypeEnum::BOX: allowBothColorsNoneFlag = false; break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index 585465448..fb0812692 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -95,6 +95,9 @@ m_optionalSecondCoordInfo(optionalSecondCoordInfo) enableModelSpaceFlag = true; enableSurfaceSpaceFlag = true; break; + case AnnotationTypeEnum::BROWSER_TAB: + enableTabSpaceFlag = false; + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 4595898a1..e6069e8f3 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -482,6 +482,10 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_zCoordSpinBox->setDecimals(digitsRightOfDecimalZ); m_zCoordSpinBox->blockSignals(false); + if (annotation->getType() == AnnotationTypeEnum::BROWSER_TAB) { + m_zCoordSpinBox->setEnabled(false); + } + if (surfaceFlag) { StructureEnum::Enum structure = StructureEnum::INVALID; int32_t surfaceNumberOfNodes = -1; diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 042c7e75c..8727779ed 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -190,6 +190,9 @@ AnnotationCreateDialog::newAnnotationFromSpaceTypeAndCoords(const Mode mode, switch (annotationType) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssertMessage(0, "Browser Tabs do not get created !!!"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "Colorbars do not get created !!!"); break; @@ -356,6 +359,8 @@ AnnotationCreateDialog::createAnnotation(NewAnnotationInfo& newAnnotationInfo, switch (newAnnotationInfo.m_annotationType) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -880,6 +885,8 @@ m_annotationFile(annotationFile) switch (annotationType) { case AnnotationTypeEnum::BOX: break; + case AnnotationTypeEnum::BROWSER_TAB: + break; case AnnotationTypeEnum::COLOR_BAR: break; case AnnotationTypeEnum::IMAGE: @@ -942,6 +949,9 @@ AnnotationCreateDialog::NewAnnotationInfo::processTwoCoordInfo() case AnnotationTypeEnum::BOX: useAverageFlag = true; break; + case AnnotationTypeEnum::BROWSER_TAB: + useAverageFlag = true; + break; case AnnotationTypeEnum::COLOR_BAR: useAverageFlag = true; break; diff --git a/src/GuiQt/AnnotationInsertNewWidget.cxx b/src/GuiQt/AnnotationInsertNewWidget.cxx index b768fa26b..65abffd61 100644 --- a/src/GuiQt/AnnotationInsertNewWidget.cxx +++ b/src/GuiQt/AnnotationInsertNewWidget.cxx @@ -561,6 +561,9 @@ AnnotationInsertNewWidget::createShapePixmap(const QWidget* widget, case AnnotationTypeEnum::BOX: painter->drawRect(1, 1, width - 2, height - 2); break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssertMessage(0, "No pixmap for browser tab as user does not create them like other annotations"); + break; case AnnotationTypeEnum::COLOR_BAR: CaretAssertMessage(0, "No pixmap for colorbar as user does not create them like other annotations"); break; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index eff8556d9..b42f7e706 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -48,6 +48,7 @@ #include #include +#include "AnnotationBrowserTab.h" #include "AnnotationManager.h" #include "Brain.h" #include "BrainBrowserWindow.h" @@ -121,7 +122,6 @@ #include "SurfaceSelectionViewController.h" #include "StructureSurfaceSelectionControl.h" #include "TileTabsLayoutGridConfiguration.h" -#include "TileTabsBrowserTabGeometry.h" #include "TileTabsManualConfigurationModifier.h" #include "UserInputModeAbstract.h" #include "VolumeFile.h" @@ -4653,12 +4653,12 @@ BrainBrowserWindowToolBar::processTileTabOperationEvent(EventBrowserWindowTileTa tabMinY = (tabMinY / windowHeight) * 100.0; tabMaxY = (tabMaxY / windowHeight) * 100.0; - TileTabsBrowserTabGeometry* geometry = btc->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setBounds(tabMinX, - tabMaxX, - tabMinY, - tabMaxY); + AnnotationBrowserTab* tabAnnotation = btc->getManualLayoutBrowserTabAnnotation(); + CaretAssert(tabAnnotation); + tabAnnotation->setBounds2D(tabMinX, + tabMaxX, + tabMinY, + tabMaxY); updateGraphicsWindow(); } } diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 33cc11b34..d0bd6743d 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -43,6 +43,7 @@ #include "TileTabsConfigurationDialog.h" #undef __TILE_TABS_CONFIGURATION_DIALOG_DECLARE__ +#include "AnnotationBrowserTab.h" #include "BrainBrowserWindow.h" #include "BrainBrowserWindowComboBox.h" #include "BrainOpenGLViewportContent.h" @@ -463,14 +464,14 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() for (int32_t i = 0; i < numBrowserTabs; i++) { CaretAssertVectorIndex(allTabContent, i); - TileTabsBrowserTabGeometry* tabGeometry = allTabContent[i]->getManualLayoutGeometry(); - CaretAssert(tabGeometry); + AnnotationBrowserTab* browserTabAnnotation = allTabContent[i]->getManualLayoutBrowserTabAnnotation(); + CaretAssert(browserTabAnnotation); if (i < numConfigTabs) { const TileTabsBrowserTabGeometry* configGeometry = userManualConfig->getTabInfo(i); CaretAssert(configGeometry); - tabGeometry->copyGeometry(*configGeometry); + browserTabAnnotation->setFromTileTabsGeometry(configGeometry); } else { if (i < numViewportContent) { @@ -487,11 +488,7 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() const float minY(windowViewport[1]); const float maxY(minY + windowViewport[3]); - - tabGeometry->setMinX(minX); - tabGeometry->setMaxX(maxX); - tabGeometry->setMinY(minY); - tabGeometry->setMaxY(maxY); + browserTabAnnotation->setBounds2D(minX, maxX, minY, maxY); } else { CaretLogWarning("Unable to find viewport content for tab number " @@ -543,44 +540,12 @@ TileTabsConfigurationDialog::createManualConfigurationFromCurrentTabs() const TileTabsLayoutManualConfiguration* manualConfig = new TileTabsLayoutManualConfiguration(); for (const auto btc : allTabContent) { CaretAssert(btc); - const TileTabsBrowserTabGeometry* tabGeometry = btc->getManualLayoutGeometry(); - TileTabsBrowserTabGeometry* geometryCopy = new TileTabsBrowserTabGeometry(*tabGeometry); - manualConfig->addTabInfo(geometryCopy); + const AnnotationBrowserTab* browserTabAnnotation = btc->getManualLayoutBrowserTabAnnotation(); + CaretAssert(browserTabAnnotation); + TileTabsBrowserTabGeometry* geometry = new TileTabsBrowserTabGeometry(browserTabAnnotation->getTabIndex()); + browserTabAnnotation->getTileTabsGeometry(geometry); + manualConfig->addTabInfo(geometry); } - - -// { -// std::vector tabViewports; -// window->getAllBrainOpenGLViewportContent(tabViewports); -// -// const float windowWidth = window->width(); -// const float windowHeight = window->height(); -// -// TileTabsLayoutManualConfiguration* manualConfig = new TileTabsLayoutManualConfiguration(); -// -// for (const auto tv : tabViewports) { -// const int32_t tabIndex = tv->getTabIndex(); -// if (tabIndex >= 0) { -// int32_t viewport[4]; -// tv->getTabViewportBeforeApplyingMargins(viewport); -// -// const float minX = viewport[0]; -// const float maxX = viewport[0] + viewport[2]; -// const float minY = viewport[1]; -// const float maxY = viewport[1] + viewport[3]; -// -// TileTabsBrowserTabGeometry* geometry = new TileTabsBrowserTabGeometry(tabIndex); -// geometry->setMinX((minX / windowWidth) * 100.0); -// geometry->setMaxX((maxX / windowWidth) * 100.0); -// geometry->setMinY((minY / windowHeight) * 100.0); -// geometry->setMaxY((maxY / windowHeight) * 100.0); -// -// geometry->setStackingOrder(tabIndex); -// -// manualConfig->addTabInfo(geometry); -// } -// } -// } return manualConfig; } @@ -1110,12 +1075,9 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuColumnsItemTriggered() const int32_t windowHeight(100); if (numberOfTabs == 1) { CaretAssertVectorIndex(allTabContent, 0); - TileTabsBrowserTabGeometry* tabGeom = allTabContent[0]->getManualLayoutGeometry(); - CaretAssert(tabGeom); - tabGeom->setMinX(0); - tabGeom->setMaxX(windowWidth); - tabGeom->setMinY(0); - tabGeom->setMaxY(windowHeight); + AnnotationBrowserTab* browserTabAnnotation = allTabContent[0]->getManualLayoutBrowserTabAnnotation(); + CaretAssert(browserTabAnnotation); + browserTabAnnotation->setBounds2D(0, windowWidth, 0, windowHeight); } else if (numberOfTabs > 1) { const int32_t remainder = (numberOfTabs % numberOfColumns); @@ -1133,12 +1095,9 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuColumnsItemTriggered() for (int32_t iCol = 0; iCol < numberOfColumns; iCol++) { if (tabContentIndex < numberOfTabs) { CaretAssertVectorIndex(allTabContent, tabContentIndex); - TileTabsBrowserTabGeometry* tabGeom = allTabContent[tabContentIndex]->getManualLayoutGeometry(); - CaretAssert(tabGeom); - tabGeom->setMinX(tabX); - tabGeom->setMaxX(tabX + tabWidth); - tabGeom->setMinY(tabY); - tabGeom->setMaxY(tabY + tabHeight); + AnnotationBrowserTab* browserTabAnnotation = allTabContent[tabContentIndex]->getManualLayoutBrowserTabAnnotation(); + CaretAssert(browserTabAnnotation); + browserTabAnnotation->setBounds2D(tabX, tabX + tabWidth, tabY, tabY + tabHeight); } tabContentIndex++; @@ -1234,12 +1193,6 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(Til } CaretAssert(columnWidths.size() == columnWidthsInt.size()); -// TileTabsLayoutManualConfiguration* manualLayout = new TileTabsLayoutManualConfiguration(); -// manualLayout->setName("From row:" -// + AString::number(rowHeights.size()) -// + " col:" -// + AString::number(columnWidths.size())); - int32_t tabCounter(0); float yBottom(windowHeight); for (int32_t i = 0; i < numRows; i++) { @@ -1264,15 +1217,14 @@ TileTabsConfigurationDialog::manualConfigurationSetMenuFromGridConfiguration(Til if (tabCounter < numTabs) { CaretAssertVectorIndex(allTabContent, tabCounter); BrowserTabContent* tabContent(allTabContent[tabCounter]); - - TileTabsBrowserTabGeometry* tabInfo = tabContent->getManualLayoutGeometry(); - tabInfo->setMinX((xLeft / windowWidth) * 100.0); - tabInfo->setMaxX(((xLeft + width) / windowWidth) * 100.0); - tabInfo->setMinY((yBottom / windowHeight) * 100.0); - tabInfo->setMaxY(((yBottom + height) / windowHeight) * 100.0); - - tabInfo->setStackingOrder(tabCounter); - tabInfo->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG); + AnnotationBrowserTab* browserTabAnnotation = tabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(browserTabAnnotation); + browserTabAnnotation->setBounds2D((xLeft / windowWidth) * 100.0, + ((xLeft + width) / windowWidth) * 100.0, + (yBottom / windowHeight) * 100.0, + ((yBottom + height) / windowHeight) * 100.0); + browserTabAnnotation->setStackingOrder(tabCounter); + browserTabAnnotation->setBackgroundType(TileTabsLayoutBackgroundTypeEnum::OPAQUE_BG); tabCounter++; } @@ -1638,32 +1590,6 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() WuQMessageBox::errorOk(m_renameConfigurationPushButton, ("Unable to find configuration with unique ID=" + uniqueID)); } -// if (getSelectedUserConfigurationNameAndUniqueID(oldName, -// uniqueID)) { -// bool ok = false; -// const AString newName = QInputDialog::getText(m_renameConfigurationPushButton, -// "Rename Configuration", -// "Name", -// QLineEdit::Normal, -// oldName, -// &ok); -// if (ok -// && ( ! newName.isEmpty())) { -// m_blockReadConfigurationsFromPreferences = true; -// AString errorMessage; -// if (m_caretPreferences->renameTileTabsUserConfiguration(uniqueID, -// newName, -// errorMessage)) { -// } -// else { -// WuQMessageBox::errorOk(m_renameConfigurationPushButton, -// errorMessage); -// } -// m_blockReadConfigurationsFromPreferences = false; -// updateDialog(); -// } -// -// } } /** diff --git a/src/GuiQt/TileTabsManualConfigurationModifier.cxx b/src/GuiQt/TileTabsManualConfigurationModifier.cxx index 4610123a2..8f62b8243 100644 --- a/src/GuiQt/TileTabsManualConfigurationModifier.cxx +++ b/src/GuiQt/TileTabsManualConfigurationModifier.cxx @@ -25,6 +25,7 @@ #include +#include "AnnotationBrowserTab.h" #include "BrainOpenGLViewportContent.h" #include "BrowserTabContent.h" #include "CaretAssert.h" @@ -107,7 +108,7 @@ TileTabsManualConfigurationModifier::runTabOrderOperation(const TabOrderOperatio CaretAssert(tabContent); tabOrderAndContent.emplace_back(tabContent, - tabContent->getManualLayoutGeometry()->getStackingOrder()); + tabContent->getManualLayoutBrowserTabAnnotation()->getStackingOrder()); } std::sort(tabOrderAndContent.begin(), tabOrderAndContent.end()); @@ -133,7 +134,7 @@ TileTabsManualConfigurationModifier::runTabOrderOperation(const TabOrderOperatio /* * Find tab that is closest to 'browserTabContent' but behind and intersects it */ - if (browserTabContent->getManualLayoutGeometry()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry())) { + if (browserTabContent->getManualLayoutBrowserTabAnnotation()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutBrowserTabAnnotation())) { indexOfTabBehind = i; } } @@ -141,7 +142,7 @@ TileTabsManualConfigurationModifier::runTabOrderOperation(const TabOrderOperatio /* * Find first (closest) tab that is in front of and intersects 'browserTabContent' */ - if (browserTabContent->getManualLayoutGeometry()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry())) { + if (browserTabContent->getManualLayoutBrowserTabAnnotation()->intersectionTest(tabOrderAndContent[i].m_tabContent->getManualLayoutBrowserTabAnnotation())) { indexOfTabInFront = i; } } @@ -206,7 +207,7 @@ TileTabsManualConfigurationModifier::runTabOrderOperation(const TabOrderOperatio tabOrderAndContent.end()); for (int32_t i = 0; i < numTabs; i++) { CaretAssertVectorIndex(tabOrderAndContent, i); - tabOrderAndContent[i].m_tabContent->getManualLayoutGeometry()->setStackingOrder(i); + tabOrderAndContent[i].m_tabContent->getManualLayoutBrowserTabAnnotation()->setStackingOrder(i); } return true; diff --git a/src/GuiQt/TileTabsManualTabGeometryWidget.cxx b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx index 309d95ae3..71a951a6b 100644 --- a/src/GuiQt/TileTabsManualTabGeometryWidget.cxx +++ b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx @@ -27,6 +27,7 @@ #include #include +#include "AnnotationBrowserTab.h" #include "BrowserTabContent.h" #include "CaretAssert.h" #include "EnumComboBoxTemplate.h" @@ -134,19 +135,20 @@ TileTabsManualTabGeometryWidget::updateContent(BrowserTabContent* browserTabCont if (showFlag) { m_tabNumberLabel->setText(browserTabContent->getTabName()); - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - - updatePercentSpinBox(m_xMinSpinBox, geometry->getMinX()); - updatePercentSpinBox(m_xMaxSpinBox, geometry->getMaxX()); - updatePercentSpinBox(m_yMinSpinBox, geometry->getMinY()); - updatePercentSpinBox(m_yMaxSpinBox, geometry->getMaxY()); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + updatePercentSpinBox(m_xMinSpinBox, minX); + updatePercentSpinBox(m_xMaxSpinBox, maxX); + updatePercentSpinBox(m_yMinSpinBox, minY); + updatePercentSpinBox(m_yMaxSpinBox, maxY); - const TileTabsLayoutBackgroundTypeEnum::Enum background = geometry->getBackgroundType(); + const TileTabsLayoutBackgroundTypeEnum::Enum background = annotationBrowserTab->getBackgroundType(); m_TileTabsLayoutBackgroundTypeEnumComboBox->setSelectedItem(background); QSignalBlocker blocker(m_stackingOrderSpinBox); // setValue() causes signal - m_stackingOrderSpinBox->setValue(geometry->getStackingOrder()); + m_stackingOrderSpinBox->setValue(annotationBrowserTab->getStackingOrder()); } m_gridLayoutGroup->setVisible(showFlag); @@ -222,9 +224,12 @@ TileTabsManualTabGeometryWidget::xMinSpinBoxValueChanged(double value) { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setMinX(value); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + minX = value; + annotationBrowserTab->setBounds2D(minX, maxX, minY, maxY); updateContent(m_browserTabContent); // 'geometry' ensures min < max emit itemChanged(); } @@ -241,9 +246,12 @@ TileTabsManualTabGeometryWidget::xMaxSpinBoxValueChanged(double value) { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setMaxX(value); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + maxX = value; + annotationBrowserTab->setBounds2D(minX, maxX, minY, maxY); updateContent(m_browserTabContent); // 'geometry' ensures min < max emit itemChanged(); } @@ -260,9 +268,12 @@ TileTabsManualTabGeometryWidget::yMinSpinBoxValueChanged(double value) { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setMinY(value); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + minY = value; + annotationBrowserTab->setBounds2D(minX, maxX, minY, maxY); updateContent(m_browserTabContent); // 'geometry' ensures min < max emit itemChanged(); } @@ -279,9 +290,12 @@ TileTabsManualTabGeometryWidget::yMaxSpinBoxValueChanged(double value) { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setMaxY(value); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + maxY = value; + annotationBrowserTab->setBounds2D(minX, maxX, minY, maxY); updateContent(m_browserTabContent); // 'geometry' ensures min < max emit itemChanged(); } @@ -298,9 +312,9 @@ TileTabsManualTabGeometryWidget::stackingOrderValueChanged(int value) { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - geometry->setStackingOrder(value); + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + annotationBrowserTab->setStackingOrder(value); emit itemChanged(); } } @@ -316,11 +330,11 @@ TileTabsManualTabGeometryWidget::tileTabsLayoutBackgroundTypeEnumComboBoxItemAct { CaretAssert(m_browserTabContent); if (m_browserTabContent != NULL) { - TileTabsBrowserTabGeometry* geometry = m_browserTabContent->getManualLayoutGeometry(); - CaretAssert(geometry); - + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + const TileTabsLayoutBackgroundTypeEnum::Enum backgroundType = m_TileTabsLayoutBackgroundTypeEnumComboBox->getSelectedItem(); - geometry->setBackgroundType(backgroundType); + annotationBrowserTab->setBackgroundType(backgroundType); emit itemChanged(); } } -- GitLab From aa937bbf79005c181e0f0d0b67dce120c297827c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 19 Aug 2019 15:26:17 -0500 Subject: [PATCH 010/584] Fixed selection box color for browser tab manual layout edited as annotations. --- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 32 +++++++++++-- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 2 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 48 +++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index b8a77520b..8e1e2a3b4 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -582,8 +582,6 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat m_volumeSliceThickness = sliceThickness; - setSelectionBoxColor(); - m_brainOpenGLFixedPipeline->checkForOpenGLError(NULL, ("At beginning of annotation drawing in space " + AnnotationCoordinateSpaceEnum::toName(drawingCoordinateSpace))); @@ -907,6 +905,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationsInternal(const Annotat break; } + setSelectionBoxColor(annotation); + drawAnnotation(annotationFile, annotation, surfaceDisplayed); @@ -4728,10 +4728,15 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann /** * Set the color for drawing the selection box and handles. + * + * @param annotation + * Annotation this is being drawn. */ void -BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() +BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor(const Annotation* annotation) { + CaretAssert(annotation); + /* * Use the foreground color but reduce the intensity and saturation. */ @@ -4740,6 +4745,27 @@ BrainOpenGLAnnotationDrawingFixedPipeline::setSelectionBoxColor() m_selectionBoxRGBA[2] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[2]; m_selectionBoxRGBA[3] = m_brainOpenGLFixedPipeline->m_foregroundColorByte[3]; + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + /* + * Foreground color is loaded into browser tab by BrainOpenGLFixedPipeline + */ + annotation->getLineColorRGBA(m_selectionBoxRGBA); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + QColor color(m_selectionBoxRGBA[0], m_selectionBoxRGBA[1], m_selectionBoxRGBA[2], diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 95d703473..41f2c3940 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -333,7 +333,7 @@ namespace caret { std::vector& lineCoordinatesOut, std::vector& arrowCoordinatesOut) const; - void setSelectionBoxColor(); + void setSelectionBoxColor(const Annotation* annotation); void startOpenGLForDrawing(GLint* savedShadeModelOut, GLboolean* savedLightingEnabledOut); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c9ab352d7..749c7e995 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -561,11 +561,59 @@ BrainOpenGLFixedPipeline::setAnnotationColorBarsAndBrowserTabsForDrawing(const s m_annotationBrowserTabsForDrawing.clear(); if (drawBrowserTabAnnotationsFlag) { + const CaretPreferences* preferences = SessionManager::get()->getCaretPreferences(); + const BackgroundAndForegroundColors* colors = preferences->getBackgroundAndForegroundColors(); for (const auto vc : viewportContents) { BrowserTabContent* tabContent = vc->getBrowserTabContent(); if (tabContent != NULL) { + uint8_t foregroundColor[4] = { 255, 255, 255, 255 }; + uint8_t backgroundColor[4] = { 0, 0, 0, 255 }; + colors->getColorBackgroundWindow(backgroundColor); + colors->getColorForegroundWindow(foregroundColor); + + switch (tabContent->getSelectedModelType()) { + case ModelTypeEnum::MODEL_TYPE_CHART: + colors->getColorBackgroundChartView(backgroundColor); + colors->getColorForegroundChartView(foregroundColor); + break; + case ModelTypeEnum::MODEL_TYPE_CHART_TWO: + colors->getColorBackgroundChartView(backgroundColor); + colors->getColorForegroundChartView(foregroundColor); + break; + case ModelTypeEnum::MODEL_TYPE_INVALID: + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE: + colors->getColorBackgroundSurfaceView(backgroundColor); + colors->getColorForegroundSurfaceView(foregroundColor); + break; + case ModelTypeEnum::MODEL_TYPE_SURFACE_MONTAGE: + colors->getColorBackgroundSurfaceView(backgroundColor); + colors->getColorForegroundSurfaceView(foregroundColor); + break; + case ModelTypeEnum::MODEL_TYPE_VOLUME_SLICES: + colors->getColorBackgroundVolumeView(backgroundColor); + colors->getColorForegroundVolumeView(foregroundColor); + break; + case ModelTypeEnum::MODEL_TYPE_WHOLE_BRAIN: + colors->getColorBackgroundAllView(backgroundColor); + colors->getColorForegroundAllView(foregroundColor); + break; + } + + /* + * Update the line and background colors using the + * appropriate model color from preferences + */ AnnotationBrowserTab* abt = tabContent->getManualLayoutBrowserTabAnnotation(); CaretAssert(abt); + const bool modStatus = abt->isModified(); + abt->setCustomLineColor(foregroundColor); + abt->setLineColor(CaretColorEnum::CUSTOM); + abt->setCustomBackgroundColor(backgroundColor); + abt->setBackgroundColor(CaretColorEnum::CUSTOM); + if ( ! modStatus) { + abt->clearModified(); + } abt->setWindowIndex(vc->getWindowIndex()); m_annotationBrowserTabsForDrawing.push_back(abt); } -- GitLab From a9babcbf6e1e4d38bc26dca6fba738ff711b94c7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 20 Aug 2019 15:50:32 -0500 Subject: [PATCH 011/584] WB-859 Manual Tile Tabs Layout System: Updates to handle switching to manual layout when the window contains a different number of tabs than in the new manual configuration. --- src/Brain/BrowserTabContent.cxx | 14 +++ src/Brain/SessionManager.cxx | 23 ++++ src/Brain/SessionManager.h | 2 + src/Common/CaretPreferences.cxx | 8 +- src/Common/EventManager.cxx | 2 + src/Common/EventTypeEnum.cxx | 10 +- src/Common/EventTypeEnum.h | 4 + src/Common/TileTabsLayoutBaseConfiguration.h | 1 + .../TileTabsLayoutGridConfiguration.cxx | 10 ++ src/Common/TileTabsLayoutGridConfiguration.h | 2 + .../TileTabsLayoutManualConfiguration.h | 2 +- src/GuiQt/BrainBrowserWindowToolBar.cxx | 29 ++++- src/GuiQt/BrainOpenGLWidget.cxx | 4 +- src/GuiQt/CMakeLists.txt | 4 + src/GuiQt/EventBrowserTabDeleteInGUI.cxx | 69 ++++++++++ src/GuiQt/EventBrowserTabDeleteInGUI.h | 57 +++++++++ src/GuiQt/EventBrowserTabNewInGUI.cxx | 69 ++++++++++ src/GuiQt/EventBrowserTabNewInGUI.h | 54 ++++++++ src/GuiQt/TileTabsConfigurationDialog.cxx | 118 +++++++++++++++--- 19 files changed, 458 insertions(+), 24 deletions(-) create mode 100644 src/GuiQt/EventBrowserTabDeleteInGUI.cxx create mode 100644 src/GuiQt/EventBrowserTabDeleteInGUI.h create mode 100644 src/GuiQt/EventBrowserTabNewInGUI.cxx create mode 100644 src/GuiQt/EventBrowserTabNewInGUI.h diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index be27c3bc2..ba116361a 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -250,6 +250,20 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) setBrainModelYokingGroup(YokingGroupEnum::YOKING_GROUP_A); setChartModelYokingGroup(YokingGroupEnum::YOKING_GROUP_OFF); } + + /* + * For manual layout, make tab same size but put in bottom left corner + */ + float xy(10.0f + (5.0 * m_tabNumber)); + const float widthHeight(20.0); + xy = MathFunctions::limitRange(xy, 5.0f, 95.0f - widthHeight); + + AnnotationBrowserTab* annotationBrowserTab = getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + annotationBrowserTab->setBounds2D(xy, + xy + widthHeight, + xy, + xy + widthHeight); } /** diff --git a/src/Brain/SessionManager.cxx b/src/Brain/SessionManager.cxx index 7907d2ead..993823a89 100644 --- a/src/Brain/SessionManager.cxx +++ b/src/Brain/SessionManager.cxx @@ -25,6 +25,7 @@ #include "SessionManager.h" #undef __SESSION_MANAGER_DECLARE__ +#include "AnnotationBrowserTab.h" #include "ApplicationInformation.h" #include "BackgroundAndForegroundColorsSceneHelper.h" #include "Brain.h" @@ -294,6 +295,25 @@ SessionManager::toString() const return "SessionManager"; } +/** + * Get the maximum stack order from all tabs + */ +int32_t +SessionManager::getMaximumManualTabStackOrder() const +{ + int32_t maxStackOrder(0); + + for (const auto bt : m_browserTabs) { + if (bt != NULL) { + maxStackOrder = std::max(bt->getManualLayoutBrowserTabAnnotation()->getStackingOrder(), + maxStackOrder); + } + } + + return maxStackOrder; +} + + /** * Receive events. * @@ -316,6 +336,7 @@ SessionManager::receiveEvent(Event* event) BrowserTabContent* tab = new BrowserTabContent(i); tab->update(m_models); m_browserTabs[i] = tab; + tab->getManualLayoutBrowserTabAnnotation()->setStackingOrder(getMaximumManualTabStackOrder() + 1); tabEvent->setBrowserTab(tab); createdTab = true; break; @@ -351,6 +372,8 @@ SessionManager::receiveEvent(Event* event) m_browserTabs[newTabIndex] = new BrowserTabContent(newTabIndex); m_browserTabs[newTabIndex]->update(m_models); m_browserTabs[newTabIndex]->cloneBrowserTabContent(m_browserTabs[cloneTabIndex]); + m_browserTabs[newTabIndex]->getManualLayoutBrowserTabAnnotation()->setStackingOrder(getMaximumManualTabStackOrder() + 1); + cloneTabEvent->setNewBrowserTab(m_browserTabs[newTabIndex], newTabIndex); } diff --git a/src/Brain/SessionManager.h b/src/Brain/SessionManager.h index 319985f1a..327733abb 100644 --- a/src/Brain/SessionManager.h +++ b/src/Brain/SessionManager.h @@ -116,6 +116,8 @@ namespace caret { void restorePreferencesFromScene(const SceneAttributes* sceneAttributes, const SceneClass* sceneClass); + int32_t getMaximumManualTabStackOrder() const; + /** The session manager */ static SessionManager* s_singletonSessionManager; diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 0462dc363..4ef29c01a 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -577,10 +577,14 @@ CaretPreferences::getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const typeString = " (AG)"; break; case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: - typeString = " (G)"; + typeString = (" (G," + + AString::number(ttc->getNumberOfTabs()) + + ")"); break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: - typeString = " (M)"; + typeString = (" (M," + + AString::number(ttc->getNumberOfTabs()) + + ")"); break; } nameIDs.push_back(std::make_pair(ttc->getName() + typeString, diff --git a/src/Common/EventManager.cxx b/src/Common/EventManager.cxx index 17ce49d8c..a5132e0d5 100644 --- a/src/Common/EventManager.cxx +++ b/src/Common/EventManager.cxx @@ -397,11 +397,13 @@ EventManager::sendSimpleEvent(const EventTypeEnum::Enum eventType) case EventTypeEnum::EVENT_BRAIN_RESET: case EventTypeEnum::EVENT_BRAIN_STRUCTURE_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_DELETE: + case EventTypeEnum::EVENT_BROWSER_TAB_DELETE_IN_GUI: case EventTypeEnum::EVENT_BROWSER_TAB_GET: case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED: case EventTypeEnum::EVENT_BROWSER_TAB_INDICES_GET_ALL: case EventTypeEnum::EVENT_BROWSER_TAB_NEW: + case EventTypeEnum::EVENT_BROWSER_TAB_NEW_IN_GUI: case EventTypeEnum::EVENT_BROWSER_TAB_NEW_CLONE: case EventTypeEnum::EVENT_BROWSER_WINDOW_CONTENT: case EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS: diff --git a/src/Common/EventTypeEnum.cxx b/src/Common/EventTypeEnum.cxx index 8e3619a83..c041c9269 100644 --- a/src/Common/EventTypeEnum.cxx +++ b/src/Common/EventTypeEnum.cxx @@ -122,7 +122,11 @@ EventTypeEnum::initialize() "EVENT_BROWSER_TAB_DELETE", "Delete a browser tab")); - enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_GET, + enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_DELETE_IN_GUI, + "EVENT_BROWSER_TAB_DELETE_IN_GUI", + "Delete a browser tab from/in the GUI so toolbar updated")); + + enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_GET, "EVENT_BROWSER_TAB_GET", "Get a browser tab by number")); @@ -142,6 +146,10 @@ EventTypeEnum::initialize() "EVENT_BROWSER_TAB_NEW", "Create a browser tab")); + enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_NEW_IN_GUI, + "EVENT_BROWSER_TAB_NEW_IN_GUI", + "Create a browser tab from/in the GUI so toolbar is updated")); + enumData.push_back(EventTypeEnum(EVENT_BROWSER_TAB_NEW_CLONE, "EVENT_BROWSER_TAB_NEW_CLONE", "Create a browser tab by cloning an existing browser tab")); diff --git a/src/Common/EventTypeEnum.h b/src/Common/EventTypeEnum.h index ade6bdd81..49a81e6f1 100644 --- a/src/Common/EventTypeEnum.h +++ b/src/Common/EventTypeEnum.h @@ -66,6 +66,8 @@ public: EVENT_BRAIN_STRUCTURE_GET_ALL, /** Delete a browser tab. */ EVENT_BROWSER_TAB_DELETE, + /** Delete a browser tab from code within the GUI so toolbar is updated. */ + EVENT_BROWSER_TAB_DELETE_IN_GUI, /** Get a browser tab by tab number */ EVENT_BROWSER_TAB_GET, /** Get indices of all valid browser tabs */ @@ -76,6 +78,8 @@ public: EVENT_BROWSER_TAB_GET_ALL_VIEWED, /** Create a new browser tab */ EVENT_BROWSER_TAB_NEW, + /** Create a new browser tab from code within the GUI so toolbar is updated */ + EVENT_BROWSER_TAB_NEW_IN_GUI, /** Create a new browser tab by cloning an existing browser tab */ EVENT_BROWSER_TAB_NEW_CLONE, /** Event for browser window content */ diff --git a/src/Common/TileTabsLayoutBaseConfiguration.h b/src/Common/TileTabsLayoutBaseConfiguration.h index e37a1d800..475e42afa 100644 --- a/src/Common/TileTabsLayoutBaseConfiguration.h +++ b/src/Common/TileTabsLayoutBaseConfiguration.h @@ -68,6 +68,7 @@ namespace caret { AString getUniqueIdentifier() const; + virtual int32_t getNumberOfTabs() const = 0; AString encodeInXML() const; diff --git a/src/Common/TileTabsLayoutGridConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx index 30c8f6104..d93533b8a 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -194,6 +194,16 @@ TileTabsLayoutGridConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs } } +/** + * @return Number of tabs in this layout + */ +int32_t +TileTabsLayoutGridConfiguration::getNumberOfTabs() const +{ + const int32_t numTabs = getNumberOfRows() * getNumberOfColumns(); + return numTabs; +} + /** * Get infoformation for the given elemnent in the columns. * diff --git a/src/Common/TileTabsLayoutGridConfiguration.h b/src/Common/TileTabsLayoutGridConfiguration.h index e776f47fa..7f1895aef 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.h +++ b/src/Common/TileTabsLayoutGridConfiguration.h @@ -50,6 +50,8 @@ namespace caret { virtual TileTabsLayoutBaseConfiguration* newCopyWithNewUniqueIdentifier() const override; + virtual int32_t getNumberOfTabs() const override; + bool getRowHeightsAndColumnWidthsForWindowSize(const int32_t windowWidth, const int32_t windowHeight, const int32_t numberOfModelsToDraw, diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h index df77bb12e..ee0bc1db6 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.h +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -57,7 +57,7 @@ namespace caret { void addTabInfo(TileTabsBrowserTabGeometry* tabInfo); - int32_t getNumberOfTabs() const; + virtual int32_t getNumberOfTabs() const override; TileTabsBrowserTabGeometry* getTabInfo(const int32_t index); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index b42f7e706..33771ead2 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -81,10 +81,12 @@ #include "DisplayPropertiesBorders.h" #include "EventBrowserTabNewClone.h" #include "EventBrowserTabDelete.h" +#include "EventBrowserTabDeleteInGUI.h" #include "EventBrowserTabGet.h" #include "EventBrowserTabGetAll.h" #include "EventBrowserTabGetAllViewed.h" #include "EventBrowserTabNew.h" +#include "EventBrowserTabNewInGUI.h" #include "EventBrowserWindowDrawingContent.h" #include "EventBrowserWindowCreateTabs.h" #include "EventBrowserWindowNew.h" @@ -536,6 +538,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow this->isContructorFinished = true; m_tileTabsHighlightingTimerEnabledFlag = true; + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_DELETE_IN_GUI); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_NEW_IN_GUI); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_TAB_GET_ALL_VIEWED); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET); EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_CREATE_TABS); @@ -4468,7 +4472,30 @@ BrainBrowserWindowToolBar::surfaceSelectionControlChanged( void BrainBrowserWindowToolBar::receiveEvent(Event* event) { - if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { + if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_DELETE_IN_GUI) { + EventBrowserTabDeleteInGUI* deleteTabInGuiEvent = dynamic_cast(event); + CaretAssert(deleteTabInGuiEvent); + + BrowserTabContent* tabToDelete = deleteTabInGuiEvent->getBrowserTab(); + CaretAssert(tabToDelete); + + for (int32_t iTab = 0; iTab < this->tabBar->count(); iTab++) { + if (tabToDelete == getTabContentFromTab(iTab)) { + tabCloseSelected(iTab); + deleteTabInGuiEvent->setEventProcessed(); + break; + } + } + } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_TAB_NEW_IN_GUI) { + EventBrowserTabNewInGUI* newTabEvent = dynamic_cast(event); + CaretAssert(newTabEvent); + + BrowserTabContent* newTabContent = addNewTab(); + newTabEvent->setBrowserTab(newTabContent); + newTabEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_DRAWING_CONTENT_GET) { EventBrowserWindowDrawingContent* getModelEvent = dynamic_cast(event); CaretAssert(getModelEvent); diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 7b17f780d..bfc436d2f 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -572,9 +572,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], BrowserWindowContent* browserWindowContent = getModelEvent.getBrowserWindowContent(); CaretAssert(browserWindowContent); - - if (browserWindowContent->isTileTabsEnabled() - && (numberOfTabs > 1)) { + if (browserWindowContent->isTileTabsEnabled()) { const int32_t windowWidth = windowViewport[2]; const int32_t windowHeight = windowViewport[3]; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 8ddd873a7..b2ea91e99 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -355,6 +355,8 @@ DisplayGroupEnumComboBox.h EnumComboBoxTemplate.h EventAnnotationCreateNewType.h EventAnnotationGetDrawnInWindow.h +EventBrowserTabDeleteInGUI.h +EventBrowserTabNewInGUI.h EventBrowserWindowDrawingContent.h EventBrowserWindowCreateTabs.h EventBrowserWindowGraphicsRedrawn.h @@ -628,6 +630,8 @@ DataFileContentCopyMoveDialog.cxx DisplayGroupAndTabItemTreeWidgetItem.cxx DisplayGroupAndTabItemViewController.cxx DisplayGroupEnumComboBox.cxx +EventBrowserTabDeleteInGUI.cxx +EventBrowserTabNewInGUI.cxx EventAnnotationCreateNewType.cxx EventAnnotationGetDrawnInWindow.cxx EventBrowserWindowDrawingContent.cxx diff --git a/src/GuiQt/EventBrowserTabDeleteInGUI.cxx b/src/GuiQt/EventBrowserTabDeleteInGUI.cxx new file mode 100644 index 000000000..05a19d375 --- /dev/null +++ b/src/GuiQt/EventBrowserTabDeleteInGUI.cxx @@ -0,0 +1,69 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include "CaretAssert.h" +#include "EventBrowserTabDeleteInGUI.h" + +using namespace caret; + +/** + * Constructor. + */ +EventBrowserTabDeleteInGUI::EventBrowserTabDeleteInGUI(BrowserTabContent* browserTab, + const int32_t browserTabIndex) +: Event(EventTypeEnum::EVENT_BROWSER_TAB_DELETE_IN_GUI), +m_browserTab(browserTab), +m_browserTabIndex(browserTabIndex) +{ + CaretAssert(browserTab); +} + +/** + * Destructor. + */ +EventBrowserTabDeleteInGUI::~EventBrowserTabDeleteInGUI() +{ + +} + +/** + * Get the browser tab that is to be deleted. + * Note that this may point to a browser tab that + * has been deleted and using the pointer in this + * case could be a disaster. + * + * @return + * Pointer to browser tab that is to be deleted. + */ +BrowserTabContent* +EventBrowserTabDeleteInGUI::getBrowserTab() +{ + return m_browserTab; +} + +/** + * @return Index of browser tab being deleted. + */ +int32_t +EventBrowserTabDeleteInGUI::getBrowserTabIndex() const +{ + return m_browserTabIndex; +} + diff --git a/src/GuiQt/EventBrowserTabDeleteInGUI.h b/src/GuiQt/EventBrowserTabDeleteInGUI.h new file mode 100644 index 000000000..da6a6ff0a --- /dev/null +++ b/src/GuiQt/EventBrowserTabDeleteInGUI.h @@ -0,0 +1,57 @@ +#ifndef __EVENT_BROWSER_TAB_DELETE_IN_GUI_H__ +#define __EVENT_BROWSER_TAB_DELETE_IN_GUI_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "Event.h" + +namespace caret { + + class BrowserTabContent; + + /// Event for deleting a browser tab + class EventBrowserTabDeleteInGUI : public Event { + + public: + EventBrowserTabDeleteInGUI(BrowserTabContent* browserTab, + const int32_t browserTabIndex); + + virtual ~EventBrowserTabDeleteInGUI(); + + BrowserTabContent* getBrowserTab(); + + int32_t getBrowserTabIndex() const; + + private: + EventBrowserTabDeleteInGUI(const EventBrowserTabDeleteInGUI&); + + EventBrowserTabDeleteInGUI& operator=(const EventBrowserTabDeleteInGUI&); + + BrowserTabContent* m_browserTab; + + const int32_t m_browserTabIndex; + }; + +} // namespace + +#endif // __EVENT_BROWSER_TAB_DELETE_IN_GUI_H__ diff --git a/src/GuiQt/EventBrowserTabNewInGUI.cxx b/src/GuiQt/EventBrowserTabNewInGUI.cxx new file mode 100644 index 000000000..2243f8cda --- /dev/null +++ b/src/GuiQt/EventBrowserTabNewInGUI.cxx @@ -0,0 +1,69 @@ +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "EventBrowserTabNewInGUI.h" + +using namespace caret; + +/** + * Constructor. + */ +EventBrowserTabNewInGUI::EventBrowserTabNewInGUI() +: Event(EventTypeEnum::EVENT_BROWSER_TAB_NEW_IN_GUI) +{ + this->browserTab = NULL; +} + +/** + * Destructor. + */ +EventBrowserTabNewInGUI::~EventBrowserTabNewInGUI() +{ + +} + +/** + * Get the browser tab that was created. + * + * @return + * Pointer to browser tab that was created or + * NULL if a browser tab could not be created. + */ +BrowserTabContent* +EventBrowserTabNewInGUI::getBrowserTab() +{ + return this->browserTab; +} + +/** + * Set the created browser tab. + * + * @param browserTab + * Browser tab that was created. + */ +void +EventBrowserTabNewInGUI::setBrowserTab(BrowserTabContent* browserTab) +{ + this->browserTab = browserTab; +} + + diff --git a/src/GuiQt/EventBrowserTabNewInGUI.h b/src/GuiQt/EventBrowserTabNewInGUI.h new file mode 100644 index 000000000..269ca55b9 --- /dev/null +++ b/src/GuiQt/EventBrowserTabNewInGUI.h @@ -0,0 +1,54 @@ +#ifndef __EVENT_BROWSER_TAB_NEW_IN_GUI_H__ +#define __EVENT_BROWSER_TAB_NEW_IN_GUI_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2014 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include "Event.h" + +namespace caret { + + class BrowserTabContent; + + /// Event for creating a new browser tab + class EventBrowserTabNewInGUI : public Event { + + public: + EventBrowserTabNewInGUI(); + + virtual ~EventBrowserTabNewInGUI(); + + BrowserTabContent* getBrowserTab(); + + void setBrowserTab(BrowserTabContent* browserTab); + + private: + EventBrowserTabNewInGUI(const EventBrowserTabNewInGUI&); + + EventBrowserTabNewInGUI& operator=(const EventBrowserTabNewInGUI&); + + BrowserTabContent* browserTab; + }; + +} // namespace + +#endif // __EVENT_BROWSER_TAB_NEW_IN_GUI_H__ diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index d0bd6743d..2c697db8c 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -53,6 +53,8 @@ #include "CaretLogger.h" #include "CaretPreferences.h" #include "EnumComboBoxTemplate.h" +#include "EventBrowserTabDeleteInGUI.h" +#include "EventBrowserTabNewInGUI.h" #include "EventBrowserWindowGraphicsRedrawn.h" #include "EventGraphicsUpdateOneWindow.h" #include "EventHelpViewerDisplay.h" @@ -444,19 +446,92 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() std::vector allTabContent; getBrowserWindow()->getAllTabContent(allTabContent); - const int32_t numBrowserTabs = static_cast(allTabContent.size()); + int32_t numBrowserTabs = static_cast(allTabContent.size()); - const int numMissingTabs = numBrowserTabs - numConfigTabs; - if (numMissingTabs > 0) { - const QString msg("User configuration \"" - + userManualConfig->getName() - + "\" contains fewer tabs than in window. The last " - + AString::number(numMissingTabs) - + " will not change position."); - if ( ! WuQMessageBox::warningOkCancel(m_loadConfigurationPushButton, msg)) { - return; + if (numBrowserTabs == numConfigTabs) { + /* OK */ + } + else { + AString msg("The are " + + AString::number(numBrowserTabs) + + " tabs in the window but the layout has space for " + + AString::number(numConfigTabs) + + " tabs.

"); + if (numBrowserTabs < numConfigTabs) { + msg.append("Do you want to add tabs to available spaces in the layout?"); + switch (WuQMessageBox::warningYesNoCancel(m_loadConfigurationPushButton, msg, "")) { + case WuQMessageBox::RESULT_CANCEL: + return; + break; + case WuQMessageBox::RESULT_NO: + break; + case WuQMessageBox::RESULT_YES: + { + const int32_t numTabsToAdd = numConfigTabs - numBrowserTabs; + for (int32_t i = 0; i < numTabsToAdd; i++) { + EventBrowserTabNewInGUI newTabEvent; + EventManager::get()->sendEvent(newTabEvent.getPointer()); + updateGraphicsWindow(); + } + } + break; + } + } + else { + msg.append("Do you want to:"); + + WuQDataEntryDialog dialog("New Configuration", + m_loadConfigurationPushButton, + WuQDialogNonModal::SCROLL_AREA_NEVER); + dialog.setTextAtTop(msg, true); + QRadioButton* closeTabsRadioButton = dialog.addRadioButton("Close extra tabs"); + QRadioButton* expandLayoutRadioButton = dialog.addRadioButton("Expand layout to include tabs"); + expandLayoutRadioButton->setChecked(true); + if (dialog.exec() == WuQDataEntryDialog::Accepted) { + if (closeTabsRadioButton->isChecked()) { + const int32_t numTabsToDelete = numBrowserTabs - numConfigTabs; + int32_t deleteIndex = numBrowserTabs - 1; + for (int32_t i = 0; i < numTabsToDelete; i++) { + CaretAssertVectorIndex(allTabContent, deleteIndex); + EventBrowserTabDeleteInGUI deleteTabEvent(allTabContent[deleteIndex], + allTabContent[deleteIndex]->getTabNumber()); + EventManager::get()->sendEvent(deleteTabEvent.getPointer()); + updateGraphicsWindow(); + deleteIndex--; + } + } + else if (expandLayoutRadioButton->isChecked()) { + /* Position and size from within tab will be used */ + } + else { + CaretAssert(0); + } + } + else { + return; + } } } + + /* + * Get the tabs again since the number of tabs may have changed + */ + allTabContent.clear(); + getBrowserWindow()->getAllTabContent(allTabContent); + numBrowserTabs = static_cast(allTabContent.size()); + + +// const int32_t numMissingTabs = numBrowserTabs - numConfigTabs; +// if (numMissingTabs > 0) { +// const QString msg("User configuration \"" +// + userManualConfig->getName() +// + "\" contains fewer tabs than in window. The last " +// + AString::number(numMissingTabs) +// + " will not change position."); +// if ( ! WuQMessageBox::warningOkCancel(m_loadConfigurationPushButton, msg)) { +// return; +// } +// } std::vector tabViewports; getBrowserWindow()->getAllBrainOpenGLViewportContent(tabViewports); @@ -481,12 +556,21 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() */ const BrainOpenGLViewportContent* tabViewportContent = getViewportContentForTab(allTabContent[i]->getTabNumber()); if (tabViewportContent != NULL) { + int32_t tabViewport[4]; + tabViewportContent->getTabViewportBeforeApplyingMargins(tabViewport); int32_t windowViewport[4]; tabViewportContent->getWindowViewport(windowViewport); - const float minX(windowViewport[0]); - const float maxX(minX + windowViewport[2]); - const float minY(windowViewport[1]); - const float maxY(minY + windowViewport[3]); + const float tabX(tabViewport[0]); + const float tabY(tabViewport[1]); + const float tabWidth(tabViewport[2]); + const float tabHeight(tabViewport[3]); + const float windowWidth(windowViewport[2]); + const float windowHeight(windowViewport[3]); + tabViewportContent->getWindowViewport(windowViewport); + const float minX((tabX / windowWidth) * 100.0); + const float maxX(((tabX + tabWidth) / windowWidth) * 100.0); + const float minY((tabY / windowHeight) * 100.0); + const float maxY(((tabY + tabHeight) / windowHeight) * 100.0); browserTabAnnotation->setBounds2D(minX, maxX, minY, maxY); } @@ -503,8 +587,10 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() break; } - updateGridStretchFactors(); - updateManualGeometryEditorWidget(); + updateDialog(); +// updateGridStretchFactors(); +// updateManualGeometryEditorWidget(); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); updateGraphicsWindow(); } -- GitLab From 36512f1edae0d91460432feaf362d0de60923f45 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 21 Aug 2019 16:27:29 -0500 Subject: [PATCH 012/584] WB-859 Manual Tile Tabs Layout System: Annotations mode processing has been updated to also process editing of manual tab layouts. Toolbar also updated. Separate undo system used for manual tabs vs annotations. --- src/Brain/AnnotationArrangerExecutor.cxx | 13 +- src/Brain/AnnotationArrangerExecutor.h | 5 +- src/Brain/AnnotationManager.cxx | 89 +++++-- src/Brain/AnnotationManager.h | 28 +- ...inOpenGLAnnotationDrawingFixedPipeline.cxx | 87 +++++-- ...rainOpenGLAnnotationDrawingFixedPipeline.h | 9 +- src/Brain/BrainOpenGLFixedPipeline.cxx | 24 +- .../BrainOpenGLVolumeObliqueSliceDrawing.cxx | 4 +- src/Brain/BrainOpenGLVolumeSliceDrawing.cxx | 4 +- .../BrainOpenGLVolumeTextureSliceDrawing.cxx | 4 +- src/Brain/UserInputModeEnum.cxx | 6 +- src/Brain/UserInputModeEnum.h | 2 + src/GuiQt/AnnotationColorWidget.cxx | 9 +- .../AnnotationCoordinateSelectionWidget.cxx | 23 +- src/GuiQt/AnnotationCoordinateWidget.cxx | 8 +- src/GuiQt/AnnotationCoordinateWidget.h | 6 +- src/GuiQt/AnnotationCreateDialog.cxx | 24 +- src/GuiQt/AnnotationDeleteWidget.cxx | 23 +- src/GuiQt/AnnotationFontWidget.cxx | 18 +- src/GuiQt/AnnotationFormatWidget.cxx | 11 +- src/GuiQt/AnnotationFormatWidget.h | 7 +- src/GuiQt/AnnotationLineArrowTipsWidget.cxx | 6 +- src/GuiQt/AnnotationMenuArrange.cxx | 15 +- src/GuiQt/AnnotationMenuArrange.h | 7 +- src/GuiQt/AnnotationPasteDialog.cxx | 42 ++- src/GuiQt/AnnotationRedoUndoWidget.cxx | 17 +- src/GuiQt/AnnotationRedoUndoWidget.h | 7 +- src/GuiQt/AnnotationRotationWidget.cxx | 7 +- src/GuiQt/AnnotationRotationWidget.h | 7 +- .../AnnotationSelectionViewController.cxx | 1 - src/GuiQt/AnnotationTextAlignmentWidget.cxx | 6 +- src/GuiQt/AnnotationTextEditorDialog.cxx | 3 +- src/GuiQt/AnnotationTextEditorWidget.cxx | 7 +- src/GuiQt/AnnotationTextOrientationWidget.cxx | 3 +- ...notationTextSubstitutionViewController.cxx | 42 --- src/GuiQt/AnnotationWidthHeightWidget.cxx | 11 +- src/GuiQt/AnnotationWidthHeightWidget.h | 6 +- .../BrainBrowserWindowOrientedToolBox.cxx | 2 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 33 ++- src/GuiQt/BrainBrowserWindowToolBar.h | 1 + src/GuiQt/BrainOpenGLWidget.cxx | 6 + src/GuiQt/BrainOpenGLWidget.h | 2 + src/GuiQt/CMakeLists.txt | 2 + src/GuiQt/UserInputModeAnnotations.cxx | 59 ++++- src/GuiQt/UserInputModeAnnotations.h | 4 + .../UserInputModeAnnotationsContextMenu.cxx | 11 +- src/GuiQt/UserInputModeAnnotationsWidget.cxx | 242 ++++++++++++------ src/GuiQt/UserInputModeAnnotationsWidget.h | 38 +-- .../UserInputModeTileTabsManualLayout.cxx | 56 ++++ src/GuiQt/UserInputModeTileTabsManualLayout.h | 58 +++++ 50 files changed, 828 insertions(+), 277 deletions(-) create mode 100644 src/GuiQt/UserInputModeTileTabsManualLayout.cxx create mode 100644 src/GuiQt/UserInputModeTileTabsManualLayout.h diff --git a/src/Brain/AnnotationArrangerExecutor.cxx b/src/Brain/AnnotationArrangerExecutor.cxx index aead692c6..c481f1473 100644 --- a/src/Brain/AnnotationArrangerExecutor.cxx +++ b/src/Brain/AnnotationArrangerExecutor.cxx @@ -54,8 +54,9 @@ using namespace caret; /** * Constructor. */ -AnnotationArrangerExecutor::AnnotationArrangerExecutor() +AnnotationArrangerExecutor::AnnotationArrangerExecutor(const UserInputModeEnum::Enum userInputMode) : CaretObject(), +m_userInputMode(userInputMode), m_mode(MODE_NONE), m_annotationManager(NULL), m_alignment(AnnotationAlignmentEnum::ALIGN_BOTTOM), @@ -75,6 +76,8 @@ AnnotationArrangerExecutor::~AnnotationArrangerExecutor() /** * Apply alignment modification to selected annotations * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param annotationManager * The annotation manager. * @param arrangerInputs @@ -115,6 +118,8 @@ AnnotationArrangerExecutor::alignAnnotations(AnnotationManager* annotationManage /** * Apply distribute modification to selected annotations * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param annotationManager * The annotation manager. * @param arrangerInputs @@ -342,7 +347,8 @@ AnnotationArrangerExecutor::distributeAnnotationsPrivate(const AnnotationArrange afterMoving); undoCommand->setDescription(AnnotationDistributeEnum::toGuiName(m_distribute)); - validFlag = m_annotationManager->applyCommand(undoCommand, + validFlag = m_annotationManager->applyCommand(m_userInputMode, + undoCommand, errorMessage); } @@ -452,7 +458,8 @@ AnnotationArrangerExecutor::alignAnnotationsPrivate(const AnnotationArrangerInpu afterMoving); undoCommand->setDescription(AnnotationAlignmentEnum::toGuiName(m_alignment)); - validFlag = m_annotationManager->applyCommand(undoCommand, + validFlag = m_annotationManager->applyCommand(m_userInputMode, + undoCommand, errorMessage); } diff --git a/src/Brain/AnnotationArrangerExecutor.h b/src/Brain/AnnotationArrangerExecutor.h index 2d11250b4..2fc4b8fc5 100644 --- a/src/Brain/AnnotationArrangerExecutor.h +++ b/src/Brain/AnnotationArrangerExecutor.h @@ -28,6 +28,7 @@ #include "BoundingBox.h" #include "CaretObject.h" #include "SpacerTabIndex.h" +#include "UserInputModeEnum.h" namespace caret { @@ -38,7 +39,7 @@ namespace caret { class AnnotationArrangerExecutor : public CaretObject { public: - AnnotationArrangerExecutor(); + AnnotationArrangerExecutor(const UserInputModeEnum::Enum userInputMode); virtual ~AnnotationArrangerExecutor(); @@ -138,6 +139,8 @@ namespace caret { void printAnnotationInfo(const QString& title); + const UserInputModeEnum::Enum m_userInputMode; + Mode m_mode; AnnotationManager* m_annotationManager; diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 85f176a97..638cae7c8 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -71,8 +71,11 @@ m_brain(brain) m_clipboardAnnotationFile = NULL; m_clipboardAnnotation.grabNew(NULL); - m_annotationRedoUndoStack.grabNew(new CaretUndoStack()); - m_annotationRedoUndoStack->setUndoLimit(500); + m_annotationsExceptBrowserTabsRedoUndoStack.grabNew(new CaretUndoStack()); + m_annotationsExceptBrowserTabsRedoUndoStack->setUndoLimit(500); + + m_browserTabAnnotationsRedoUndoStack.grabNew(new CaretUndoStack()); + m_browserTabAnnotationsRedoUndoStack->setUndoLimit(100); for (int32_t i = 0; i < BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS; i++) { m_annotationBeingDrawnInWindow[i] = NULL; @@ -97,7 +100,8 @@ AnnotationManager::~AnnotationManager() delete m_selectionInformation[i]; } - m_annotationRedoUndoStack->clear(); + m_annotationsExceptBrowserTabsRedoUndoStack->clear(); + m_browserTabAnnotationsRedoUndoStack->clear(); delete m_sceneAssistant; } @@ -108,7 +112,8 @@ AnnotationManager::~AnnotationManager() void AnnotationManager::reset() { - m_annotationRedoUndoStack->clear(); + m_annotationsExceptBrowserTabsRedoUndoStack->clear(); + m_browserTabAnnotationsRedoUndoStack->clear(); } /** @@ -116,16 +121,22 @@ AnnotationManager::reset() * the command, the command is placed on the undo stack so that the * user can undo or redo the command. * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param command * Command that will be applied to the selected annotations. * Annotation manager will take ownership of the command and * destroy it at the appropriate time. + * @param errorMessageOut + * Output with error information if command fails. */ bool -AnnotationManager::applyCommand(AnnotationRedoUndoCommand* command, +AnnotationManager::applyCommand(const UserInputModeEnum::Enum userInputMode, + AnnotationRedoUndoCommand* command, AString& errorMessageOut) { - return applyCommandInWindow(command, + return applyCommandInWindow(userInputMode, + command, -1, errorMessageOut); } @@ -135,15 +146,20 @@ AnnotationManager::applyCommand(AnnotationRedoUndoCommand* command, * the command, the command is placed on the undo stack so that the * user can undo or redo the command. * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param command * Command that will be applied to the selected annotations. * Annotation manager will take ownership of the command and * destroy it at the appropriate time. * @param windowIndex * Index of window in which command was requested. + * @param errorMessageOut + * Output with error information if command fails. */ bool -AnnotationManager::applyCommandInWindow(AnnotationRedoUndoCommand* command, +AnnotationManager::applyCommandInWindow(const UserInputModeEnum::Enum userInputMode, + AnnotationRedoUndoCommand* command, const int32_t windowIndex, AString& errorMessageOut) { @@ -163,9 +179,9 @@ AnnotationManager::applyCommandInWindow(AnnotationRedoUndoCommand* command, /* * "Redo" the command and add it to the undo stack */ - const bool result = m_annotationRedoUndoStack->pushAndRedo(command, - windowIndex, - errorMessageOut); + const bool result = getCommandRedoUndoStack(userInputMode)->pushAndRedo(command, + windowIndex, + errorMessageOut); return result; } @@ -622,6 +638,8 @@ AnnotationManager::getAnnotationsSelectedForEditingIncludingLabels(const int32_t /** * Align annotations. * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param arrangerInputs * Inputs to algorithm that aligns the annotations. * @param errorMessageOut @@ -630,11 +648,12 @@ AnnotationManager::getAnnotationsSelectedForEditingIncludingLabels(const int32_t * True if successful, false if error. */ bool -AnnotationManager::alignAnnotations(const AnnotationArrangerInputs& arrangerInputs, +AnnotationManager::alignAnnotations(const UserInputModeEnum::Enum userInputMode, + const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut) { - AnnotationArrangerExecutor arranger; + AnnotationArrangerExecutor arranger(userInputMode); return arranger.alignAnnotations(this, arrangerInputs, @@ -645,6 +664,8 @@ AnnotationManager::alignAnnotations(const AnnotationArrangerInputs& arrangerInpu /** * Align annotations. * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param arrangerInputs * Inputs to algorithm that aligns the annotations. * @param errorMessageOut @@ -653,11 +674,12 @@ AnnotationManager::alignAnnotations(const AnnotationArrangerInputs& arrangerInpu * True if successful, false if error. */ bool -AnnotationManager::distributeAnnotations(const AnnotationArrangerInputs& arrangerInputs, +AnnotationManager::distributeAnnotations(const UserInputModeEnum::Enum userInputMode, + const AnnotationArrangerInputs& arrangerInputs, const AnnotationDistributeEnum::Enum distribute, AString& errorMessageOut) { - AnnotationArrangerExecutor arranger; + AnnotationArrangerExecutor arranger(userInputMode); return arranger.distributeAnnotations(this, arrangerInputs, @@ -668,6 +690,8 @@ AnnotationManager::distributeAnnotations(const AnnotationArrangerInputs& arrange /** * Apply given grouping mode valid in the given window. * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING * @param windowIndex * Index of the window. * @param groupingMode @@ -678,7 +702,8 @@ AnnotationManager::distributeAnnotations(const AnnotationArrangerInputs& arrange * True if successful, else false. */ bool -AnnotationManager::applyGroupingMode(const int32_t windowIndex, +AnnotationManager::applyGroupingMode(const UserInputModeEnum::Enum userInputMode, + const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode, AString& errorMessageOut) { @@ -717,7 +742,8 @@ AnnotationManager::applyGroupingMode(const int32_t windowIndex, AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingGroupAnnotations(annotationGroupKey, annotations); - validFlag = applyCommandInWindow(command, + validFlag = applyCommandInWindow(userInputMode, + command, windowIndex, errorMessageOut); } @@ -737,7 +763,8 @@ AnnotationManager::applyGroupingMode(const int32_t windowIndex, AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingRegroupAnnotations(annotationGroupKey); - validFlag = applyCommandInWindow(command, + validFlag = applyCommandInWindow(userInputMode, + command, windowIndex, errorMessageOut); } @@ -758,7 +785,8 @@ AnnotationManager::applyGroupingMode(const int32_t windowIndex, AnnotationRedoUndoCommand* command = new AnnotationRedoUndoCommand(); command->setModeGroupingUngroupAnnotations(annotationGroupKey); - validFlag = applyCommandInWindow(command, + validFlag = applyCommandInWindow(userInputMode, + command, windowIndex, errorMessageOut); } @@ -979,11 +1007,32 @@ AnnotationManager::getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displ /** * @return Pointer to the command redo undo stack + * + * @param userInputMode + * The current user input mode which MUST be ANNOTATIONS or TILE_TABS_MANUAL_LAYOUT_EDITING */ CaretUndoStack* -AnnotationManager::getCommandRedoUndoStack() +AnnotationManager::getCommandRedoUndoStack(const UserInputModeEnum::Enum userInputMode) { - return m_annotationRedoUndoStack; + CaretUndoStack* undoStackOut(NULL); + switch (userInputMode) { + case UserInputModeEnum::ANNOTATIONS: + undoStackOut = m_annotationsExceptBrowserTabsRedoUndoStack; + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + undoStackOut = m_browserTabAnnotationsRedoUndoStack; + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + case UserInputModeEnum::VIEW: + case UserInputModeEnum::VOLUME_EDIT: + CaretAssert(0); + break; + } + + return undoStackOut; } /** diff --git a/src/Brain/AnnotationManager.h b/src/Brain/AnnotationManager.h index 779aeba83..b576acbd0 100644 --- a/src/Brain/AnnotationManager.h +++ b/src/Brain/AnnotationManager.h @@ -31,7 +31,7 @@ #include "CaretPointer.h" #include "EventListenerInterface.h" #include "SceneableInterface.h" - +#include "UserInputModeEnum.h" namespace caret { class Annotation; @@ -70,10 +70,12 @@ namespace caret { virtual ~AnnotationManager(); - bool applyCommand(AnnotationRedoUndoCommand* command, + bool applyCommand(const UserInputModeEnum::Enum userInputMode, + AnnotationRedoUndoCommand* command, AString& errorMessageOut); - bool applyCommandInWindow(AnnotationRedoUndoCommand* command, + bool applyCommandInWindow(const UserInputModeEnum::Enum userInputMode, + AnnotationRedoUndoCommand* command, const int32_t windowIndex, AString& errorMessageOut); @@ -122,20 +124,23 @@ namespace caret { void setAnnotationBeingDrawnInWindow(const int32_t windowIndex, const Annotation* annotation); - CaretUndoStack* getCommandRedoUndoStack(); + CaretUndoStack* getCommandRedoUndoStack(const UserInputModeEnum::Enum userInputMode); void getDisplayedAnnotationFiles(EventGetDisplayedDataFiles* displayedFilesEvent, std::vector& displayedAnnotationFilesOut) const; - bool alignAnnotations(const AnnotationArrangerInputs& arrangerInputs, + bool alignAnnotations(const UserInputModeEnum::Enum userInputMode, + const AnnotationArrangerInputs& arrangerInputs, const AnnotationAlignmentEnum::Enum alignment, AString& errorMessageOut); - bool distributeAnnotations(const AnnotationArrangerInputs& arrangerInputs, - const AnnotationDistributeEnum::Enum distribute, - AString& errorMessageOut); - - bool applyGroupingMode(const int32_t windowIndex, + bool distributeAnnotations(const UserInputModeEnum::Enum userInputMode, + const AnnotationArrangerInputs& arrangerInputs, + const AnnotationDistributeEnum::Enum distribute, + AString& errorMessageOut); + + bool applyGroupingMode(const UserInputModeEnum::Enum userInputMode, + const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode, AString& errorMessageOut); @@ -204,8 +209,9 @@ namespace caret { CaretPointer m_clipboardAnnotation; - CaretPointer m_annotationRedoUndoStack; + CaretPointer m_annotationsExceptBrowserTabsRedoUndoStack; + CaretPointer m_browserTabAnnotationsRedoUndoStack; // ADD_NEW_MEMBERS_HERE }; diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 8e1e2a3b4..73df81be5 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1568,7 +1568,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBox(AnnotationFile* annotationFil bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -1681,7 +1682,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBoxSurfaceTangentOffset(Annotatio float lineThickness = ((box->getLineWidthPercentage() / 100.0) * surfaceExtentZ); - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } @@ -1698,7 +1700,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBoxSurfaceTangentOffset(Annotatio bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -1831,7 +1834,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBrowserTab(AnnotationFile* annota bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_tileTabsManualLayoutUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -2093,7 +2097,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawColorBar(AnnotationFile* annotati const bool drawBackgroundFlag = (backgroundRGBA[3] > 0.0f); - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -2762,7 +2767,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOval(AnnotationFile* annotationFi glRotatef(-rotationAngle, 0.0f, 0.0f, 1.0f); } - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -2869,7 +2875,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOvalSurfaceTangentOffset(Annotati float lineThickness = ((oval->getLineWidthPercentage() / 100.0) * surfaceExtentZ); - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } @@ -2889,7 +2896,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawOvalSurfaceTangentOffset(Annotati const float minorAxis = ((oval->getHeight() / 100.0f) * surfaceExtentZ); if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -3282,7 +3290,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawTextSurfaceTangentOffset(Annotati underlineStart, underlineEnd); bool textDrawnFlag = false; - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4] = { 0, 0, 0, 0 }; getIdentificationColor(selectionColorRGBA); GraphicsPrimitiveV3fN3f primitive(GraphicsPrimitive::PrimitiveType::OPENGL_TRIANGLE_STRIP, @@ -3437,7 +3446,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawText(AnnotationFile* annotationFi bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -3641,7 +3651,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImage(AnnotationFile* annotationF bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, bottomRight, topRight, topLeft, @@ -3742,7 +3753,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImageSurfaceTangentOffset(Annotat float lineThickness = ((image->getLineWidthPercentage() / 100.0) * surfaceExtentZ); - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } @@ -3758,7 +3770,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawImageSurfaceTangentOffset(Annotat bool drawnFlag = false; if (drawAnnotationFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -4019,7 +4032,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLine(AnnotationFile* annotationFi bool drawnFlag = false; if (drawForegroundFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -4153,7 +4167,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(Annotati float lineThickness = ((line->getLineWidthPercentage() / 100.0) * surfaceExtentZ); lineThickness *= m_surfaceViewScaling; - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { lineThickness = std::max(lineThickness, s_selectionLineMinimumPixelWidth); } @@ -4179,7 +4194,8 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawLineSurfaceTextureOffset(Annotati const bool drawForegroundFlag = (foregroundRGBA[3] > 0.0f); if (drawForegroundFlag) { - if (m_selectionModeFlag) { + if (m_selectionModeFlag + && m_inputs->m_annotationUserInputModeFlag) { uint8_t selectionColorRGBA[4]; getIdentificationColor(selectionColorRGBA); @@ -4340,7 +4356,24 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawSizingHandle(const AnnotationSizi drawSquareFlag = true; } + bool selectionFlag(false); if (m_selectionModeFlag) { + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + case AnnotationTypeEnum::COLOR_BAR: + case AnnotationTypeEnum::IMAGE: + case AnnotationTypeEnum::LINE: + case AnnotationTypeEnum::OVAL: + case AnnotationTypeEnum::TEXT: + selectionFlag = m_inputs->m_annotationUserInputModeFlag; + break; + case AnnotationTypeEnum::BROWSER_TAB: + selectionFlag = m_inputs->m_tileTabsManualLayoutUserInputModeFlag; + break; + } + } + + if (selectionFlag) { uint8_t identificationRGBA[4]; getIdentificationColor(identificationRGBA); GraphicsShape::drawBoxFilledByteColor(bottomLeft, @@ -4521,11 +4554,27 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawAnnotationTwoDimSizingHandles(Ann const float lineThickness, const float rotationAngle) { - if ( ! m_inputs->m_annotationUserInputModeFlag) { - return; - } CaretAssert(annotation); + + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + case AnnotationTypeEnum::COLOR_BAR: + case AnnotationTypeEnum::IMAGE: + case AnnotationTypeEnum::LINE: + case AnnotationTypeEnum::OVAL: + case AnnotationTypeEnum::TEXT: + if ( ! m_inputs->m_annotationUserInputModeFlag) { + return; + } + break; + case AnnotationTypeEnum::BROWSER_TAB: + if ( ! m_inputs->m_tileTabsManualLayoutUserInputModeFlag) { + return; + } + break; + } + AnnotationText* textAnn = dynamic_cast(annotation); const bool modelSpaceTangentTextFlag = annotation->isInSurfaceSpaceWithTangentOffset(); diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h index 41f2c3940..e77e727ef 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.h @@ -71,7 +71,8 @@ namespace caret { const int32_t tabIndex, const SpacerTabIndex &spacerTabIndex, const WindowDrawingMode windowDrawingMode, - const bool annotationUserInputModeFlag) + const bool annotationUserInputModeFlag, + const bool tileTabsManualLayoutUserInputModeFlag) : m_brain(brain), m_drawingMode(drawingMode), m_centerToEyeDistance(centerToEyeDistance), @@ -79,8 +80,9 @@ namespace caret { m_tabIndex(tabIndex), m_spacerTabIndex(spacerTabIndex), m_windowDrawingMode(windowDrawingMode), - m_annotationUserInputModeFlag(annotationUserInputModeFlag) { - } + m_annotationUserInputModeFlag(annotationUserInputModeFlag), + m_tileTabsManualLayoutUserInputModeFlag(tileTabsManualLayoutUserInputModeFlag) + { } Brain* m_brain; const BrainOpenGLFixedPipeline::Mode m_drawingMode; @@ -90,6 +92,7 @@ namespace caret { const SpacerTabIndex m_spacerTabIndex; const WindowDrawingMode m_windowDrawingMode; const bool m_annotationUserInputModeFlag; + const bool m_tileTabsManualLayoutUserInputModeFlag; }; BrainOpenGLAnnotationDrawingFixedPipeline(BrainOpenGLFixedPipeline* brainOpenGLFixedPipeline); diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index 749c7e995..c0ee3257e 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -1004,6 +1004,7 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLV * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -1011,7 +1012,8 @@ BrainOpenGLFixedPipeline::drawChartCoordinateSpaceAnnotations(const BrainOpenGLV this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, @@ -1071,6 +1073,7 @@ BrainOpenGLFixedPipeline::drawSpacerAnnotations(const BrainOpenGLViewportContent spacerTabIndex = spacerTabContent->getSpacerTabIndex(); const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -1078,7 +1081,8 @@ BrainOpenGLFixedPipeline::drawSpacerAnnotations(const BrainOpenGLViewportContent this->windowTabIndex, spacerTabIndex, BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::SPACER, m_annotationColorBarsForDrawing, @@ -1127,6 +1131,7 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* t this->windowTabIndex = this->browserTabContent->getTabNumber(); const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -1134,7 +1139,8 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* t this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); m_annotationDrawing->drawAnnotations(&inputs, AnnotationCoordinateSpaceEnum::TAB, m_annotationColorBarsForDrawing, @@ -1190,6 +1196,7 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) this->windowTabIndex = -1; const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -1197,7 +1204,8 @@ BrainOpenGLFixedPipeline::drawWindowAnnotations(const int windowViewport[4]) this->windowTabIndex, SpacerTabIndex(), windowDrawingMode, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); std::vector notInFileAnnotations; notInFileAnnotations.insert(notInFileAnnotations.end(), @@ -2170,6 +2178,7 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -2177,7 +2186,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; @@ -2225,6 +2235,7 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, * the model annotations. */ const bool annotationModeFlag = (m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, this->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -2232,7 +2243,8 @@ BrainOpenGLFixedPipeline::drawSurface(Surface* surface, this->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); std::vector emptyColorBars; std::vector emptyViewportAnnotations; m_annotationDrawing->drawAnnotations(&inputs, diff --git a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx index 084a56835..78e4f1fcf 100644 --- a/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeObliqueSliceDrawing.cxx @@ -848,6 +848,7 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewProjection(const BrainO } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -855,7 +856,8 @@ BrainOpenGLVolumeObliqueSliceDrawing::drawVolumeSliceViewProjection(const BrainO m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); diff --git a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx index 93bb46fc2..1b5f7c0b5 100644 --- a/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeSliceDrawing.cxx @@ -882,6 +882,7 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewProjection(const AllSliceViewM } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -889,7 +890,8 @@ BrainOpenGLVolumeSliceDrawing::drawVolumeSliceViewProjection(const AllSliceViewM m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); diff --git a/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx index 1a10b7d4e..a40a39676 100644 --- a/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx +++ b/src/Brain/BrainOpenGLVolumeTextureSliceDrawing.cxx @@ -895,6 +895,7 @@ BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewProjection(const BrainO } } const bool annotationModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::ANNOTATIONS); + const bool tileTabsEditModeFlag = (m_fixedPipelineDrawing->m_windowUserInputMode == UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING); BrainOpenGLAnnotationDrawingFixedPipeline::Inputs inputs(this->m_brain, m_fixedPipelineDrawing->mode, BrainOpenGLFixedPipeline::s_gluLookAtCenterFromEyeOffsetDistance, @@ -902,7 +903,8 @@ BrainOpenGLVolumeTextureSliceDrawing::drawVolumeSliceViewProjection(const BrainO m_fixedPipelineDrawing->windowTabIndex, SpacerTabIndex(), BrainOpenGLAnnotationDrawingFixedPipeline::Inputs::WINDOW_DRAWING_NO, - annotationModeFlag); + annotationModeFlag, + tileTabsEditModeFlag); m_fixedPipelineDrawing->m_annotationDrawing->drawModelSpaceAnnotationsOnVolumeSlice(&inputs, slicePlane, sliceThickness); diff --git a/src/Brain/UserInputModeEnum.cxx b/src/Brain/UserInputModeEnum.cxx index 9a9749fea..78d090d72 100644 --- a/src/Brain/UserInputModeEnum.cxx +++ b/src/Brain/UserInputModeEnum.cxx @@ -126,7 +126,11 @@ UserInputModeEnum::initialize() "IMAGE", "Image")); - enumData.push_back(UserInputModeEnum(VIEW, + enumData.push_back(UserInputModeEnum(TILE_TABS_MANUAL_LAYOUT_EDITING, + "TILE_TABS_MANUAL_LAYOUT_EDITING", + "Tile Tabs Manual Layout Editing")); + + enumData.push_back(UserInputModeEnum(VIEW, "VIEW", "View")); diff --git a/src/Brain/UserInputModeEnum.h b/src/Brain/UserInputModeEnum.h index 564e4c488..6d0c1b07f 100644 --- a/src/Brain/UserInputModeEnum.h +++ b/src/Brain/UserInputModeEnum.h @@ -45,6 +45,8 @@ public: FOCI, /** Image */ IMAGE, + /** Tile tabs manual layouot editing */ + TILE_TABS_MANUAL_LAYOUT_EDITING, /** View */ VIEW, /** Volume Edit */ diff --git a/src/GuiQt/AnnotationColorWidget.cxx b/src/GuiQt/AnnotationColorWidget.cxx index cae142d8c..cb7a57dcc 100644 --- a/src/GuiQt/AnnotationColorWidget.cxx +++ b/src/GuiQt/AnnotationColorWidget.cxx @@ -308,7 +308,8 @@ AnnotationColorWidget::backgroundColorSelected(const CaretColorEnum::Enum caretC AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -579,7 +580,8 @@ AnnotationColorWidget::lineColorSelected(const CaretColorEnum::Enum caretColor) AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -680,7 +682,8 @@ AnnotationColorWidget::lineThicknessSpinBoxValueChanged(double value) AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx index fb0812692..df2b9de40 100644 --- a/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateSelectionWidget.cxx @@ -755,9 +755,28 @@ AnnotationCoordinateSelectionWidget::changeAnnotationCoordinate(Annotation* anno command->setDescription("Change Coordinate"); AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); + switch (m_annotationType) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssert(0); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + AString errorMessage; - if ( ! annotationManager->applyCommand(command, - errorMessage)) { + if ( ! annotationManager->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, + errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index e6069e8f3..702540e4c 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -80,11 +80,13 @@ using namespace caret; * @param parent * Parent widget */ -AnnotationCoordinateWidget::AnnotationCoordinateWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, +AnnotationCoordinateWidget::AnnotationCoordinateWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, const WhichCoordinate whichCoordinate, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), +m_userInputMode(userInputMode), m_parentWidgetType(parentWidgetType), m_whichCoordinate(whichCoordinate), m_browserWindowIndex(browserWindowIndex) @@ -655,10 +657,12 @@ AnnotationCoordinateWidget::valueChanged() selectedAnnotations); break; } + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationCoordinateWidget.h b/src/GuiQt/AnnotationCoordinateWidget.h index e5822eba3..fd0808ff0 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.h +++ b/src/GuiQt/AnnotationCoordinateWidget.h @@ -26,6 +26,7 @@ #include "AnnotationCoordinateSpaceEnum.h" #include "AnnotationWidgetParentEnum.h" +#include "UserInputModeEnum.h" class QDoubleSpinBox; class QSpinBox; @@ -47,7 +48,8 @@ namespace caret { COORDINATE_TWO }; - AnnotationCoordinateWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, + AnnotationCoordinateWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, const WhichCoordinate whichCoordinate, const int32_t browserWindowIndex, QWidget* parent = 0); @@ -80,6 +82,8 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + const UserInputModeEnum::Enum m_userInputMode; + const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const WhichCoordinate m_whichCoordinate; diff --git a/src/GuiQt/AnnotationCreateDialog.cxx b/src/GuiQt/AnnotationCreateDialog.cxx index 8727779ed..97e09ca21 100644 --- a/src/GuiQt/AnnotationCreateDialog.cxx +++ b/src/GuiQt/AnnotationCreateDialog.cxx @@ -793,9 +793,29 @@ AnnotationCreateDialog::finishAnnotationCreation(AnnotationFile* annotationFile, undoCommand->setModeCreateAnnotation(annotationFile, annotation); + CaretAssert(annotation); + UserInputModeEnum::Enum inputMode = UserInputModeEnum::ANNOTATIONS; + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + inputMode = UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING; + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, - errorMessage)) { + if ( ! annotationManager->applyCommand(inputMode, + undoCommand, + errorMessage)) { WuQMessageBox::errorOk(GuiManager::get()->getBrowserWindowByWindowIndex(browswerWindowIndex), errorMessage); } diff --git a/src/GuiQt/AnnotationDeleteWidget.cxx b/src/GuiQt/AnnotationDeleteWidget.cxx index a6dd38cd0..8d1d92800 100644 --- a/src/GuiQt/AnnotationDeleteWidget.cxx +++ b/src/GuiQt/AnnotationDeleteWidget.cxx @@ -152,6 +152,24 @@ AnnotationDeleteWidget::deleteActionTriggered() std::vector deleteAnnotations; for (auto a : selectedAnnotations) { if (a->testProperty(Annotation::Property::DELETION)) { + switch (a->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssert(0); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + deleteAnnotations.push_back(a); } } @@ -161,8 +179,9 @@ AnnotationDeleteWidget::deleteActionTriggered() undoCommand->setModeDeleteAnnotations(deleteAnnotations); AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, - errorMessage)) { + if ( ! annotationManager->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, + errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } diff --git a/src/GuiQt/AnnotationFontWidget.cxx b/src/GuiQt/AnnotationFontWidget.cxx index 69265393f..f2c2b0d50 100644 --- a/src/GuiQt/AnnotationFontWidget.cxx +++ b/src/GuiQt/AnnotationFontWidget.cxx @@ -606,7 +606,8 @@ AnnotationFontWidget::textColorSelected(const CaretColorEnum::Enum caretColor) convertToAnnotations(m_annotationsFontColor)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -726,7 +727,8 @@ AnnotationFontWidget::fontBoldChanged() convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(command, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -754,7 +756,8 @@ AnnotationFontWidget::fontItalicChanged() convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(command, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -784,7 +787,8 @@ AnnotationFontWidget::fontNameChanged() convertToAnnotations(m_annotationsFontName)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(command, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -817,7 +821,8 @@ AnnotationFontWidget::fontSizeChanged() getSurfaceMontageRowCount()); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(command, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -877,7 +882,8 @@ AnnotationFontWidget::fontUnderlineChanged() convertToAnnotations(m_annotationsFontStyle)); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(command, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + command, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationFormatWidget.cxx b/src/GuiQt/AnnotationFormatWidget.cxx index 908a5cd06..0c3a2d759 100644 --- a/src/GuiQt/AnnotationFormatWidget.cxx +++ b/src/GuiQt/AnnotationFormatWidget.cxx @@ -42,14 +42,18 @@ using namespace caret; /** * Constructor. * + * @param userInputMode + * The user input mode * @param browserWindowIndex * Index of the browser window. * @param parent * Parent of this widget. */ -AnnotationFormatWidget::AnnotationFormatWidget(const int32_t browserWindowIndex, - QWidget* parent) +AnnotationFormatWidget::AnnotationFormatWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, + QWidget* parent) : QWidget(parent), +m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { QLabel* formatLabel = new QLabel("Format"); @@ -89,7 +93,8 @@ AnnotationFormatWidget::updateContent(Annotation* /*annotation*/) QWidget* AnnotationFormatWidget::createArrangeMenuToolButton() { - AnnotationMenuArrange* arrangeMenu = new AnnotationMenuArrange(m_browserWindowIndex); + AnnotationMenuArrange* arrangeMenu = new AnnotationMenuArrange(m_userInputMode, + m_browserWindowIndex); QAction* arrangeAction = new QAction("Arrange", this); diff --git a/src/GuiQt/AnnotationFormatWidget.h b/src/GuiQt/AnnotationFormatWidget.h index 52b08cbcf..ae106ddd2 100644 --- a/src/GuiQt/AnnotationFormatWidget.h +++ b/src/GuiQt/AnnotationFormatWidget.h @@ -25,6 +25,8 @@ #include +#include "UserInputModeEnum.h" + namespace caret { class Annotation; @@ -34,7 +36,8 @@ namespace caret { Q_OBJECT public: - AnnotationFormatWidget(const int32_t browserWindowIndex, + AnnotationFormatWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationFormatWidget(); @@ -51,6 +54,8 @@ namespace caret { QWidget* createArrangeMenuToolButton(); + const UserInputModeEnum::Enum m_userInputMode; + const int32_t m_browserWindowIndex; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx index 8a9a4a252..a20381761 100644 --- a/src/GuiQt/AnnotationLineArrowTipsWidget.cxx +++ b/src/GuiQt/AnnotationLineArrowTipsWidget.cxx @@ -163,7 +163,8 @@ AnnotationLineArrowTipsWidget::startArrowTipActionToggled() AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -186,7 +187,8 @@ AnnotationLineArrowTipsWidget::endArrowTipActionToggled() AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index 33583be3f..ce530b4aa 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -53,14 +53,18 @@ using namespace caret; /** * Constructor. * + * @param userInputMode + * The user input mode * @param parent * The parent widget. * @param browserWindowIndex * Index of the browser window. */ -AnnotationMenuArrange::AnnotationMenuArrange(const int32_t browserWindowIndex, +AnnotationMenuArrange::AnnotationMenuArrange(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent) : QMenu(parent), +m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { addAlignmentSelections(); @@ -266,7 +270,8 @@ AnnotationMenuArrange::applyAlignment(const AnnotationAlignmentEnum::Enum alignm AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->alignAnnotations(alignMod, + if ( ! annMan->alignAnnotations(m_userInputMode, + alignMod, alignment, errorMessage)) { WuQMessageBox::errorOk(this, @@ -304,7 +309,8 @@ AnnotationMenuArrange::applyDistribute(const AnnotationDistributeEnum::Enum dist AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->distributeAnnotations(distributeMod, + if ( ! annMan->distributeAnnotations(m_userInputMode, + distributeMod, distribute, errorMessage)) { WuQMessageBox::errorOk(this, @@ -327,7 +333,8 @@ AnnotationMenuArrange::applyGrouping(const AnnotationGroupingModeEnum::Enum grou AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyGroupingMode(m_browserWindowIndex, + if ( ! annMan->applyGroupingMode(m_userInputMode, + m_browserWindowIndex, grouping, errorMessage)) { WuQMessageBox::errorOk(this, diff --git a/src/GuiQt/AnnotationMenuArrange.h b/src/GuiQt/AnnotationMenuArrange.h index 98adf6c55..1a5ea226f 100644 --- a/src/GuiQt/AnnotationMenuArrange.h +++ b/src/GuiQt/AnnotationMenuArrange.h @@ -29,7 +29,7 @@ #include "AnnotationAlignmentEnum.h" #include "AnnotationDistributeEnum.h" #include "AnnotationGroupingModeEnum.h" - +#include "UserInputModeEnum.h" namespace caret { @@ -38,7 +38,8 @@ namespace caret { Q_OBJECT public: - AnnotationMenuArrange(const int32_t browserWindowIndex, + AnnotationMenuArrange(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationMenuArrange(); @@ -88,6 +89,8 @@ namespace caret { const qreal x, const qreal y); + const UserInputModeEnum::Enum m_userInputMode; + const int32_t m_browserWindowIndex; QAction* m_groupAction; diff --git a/src/GuiQt/AnnotationPasteDialog.cxx b/src/GuiQt/AnnotationPasteDialog.cxx index e6d7e2db2..09bff33cb 100644 --- a/src/GuiQt/AnnotationPasteDialog.cxx +++ b/src/GuiQt/AnnotationPasteDialog.cxx @@ -116,8 +116,26 @@ AnnotationPasteDialog::pasteAnnotationOnClipboard(const MouseEvent& mouseEvent, AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModePasteAnnotation(annotationFile, annotation); + switch (annotation->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssert(0); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, + if ( ! annotationManager->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(mouseEvent.getOpenGLWidget(), errorMessage); @@ -438,8 +456,26 @@ AnnotationPasteDialog::okButtonClicked() AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModePasteAnnotation(m_annotationFile, annotationPointer); - if ( ! annotationManager->applyCommand(undoCommand, - errorMessage)) { + switch (annotationPointer->getType()) { + case AnnotationTypeEnum::BOX: + break; + case AnnotationTypeEnum::BROWSER_TAB: + CaretAssert(0); + break; + case AnnotationTypeEnum::COLOR_BAR: + break; + case AnnotationTypeEnum::IMAGE: + break; + case AnnotationTypeEnum::LINE: + break; + case AnnotationTypeEnum::OVAL: + break; + case AnnotationTypeEnum::TEXT: + break; + } + if ( ! annotationManager->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, + errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } diff --git a/src/GuiQt/AnnotationRedoUndoWidget.cxx b/src/GuiQt/AnnotationRedoUndoWidget.cxx index 3b7519b67..5fa27f400 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.cxx +++ b/src/GuiQt/AnnotationRedoUndoWidget.cxx @@ -50,10 +50,19 @@ using namespace caret; /** * Constructor. + * + * @param userInputMode + * The user input mode + * @param browserWindowIndex + * The browser window index + * @param parent + * The parent widget. */ -AnnotationRedoUndoWidget::AnnotationRedoUndoWidget(const int32_t browserWindowIndex, +AnnotationRedoUndoWidget::AnnotationRedoUndoWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), +m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { QLabel* titleLabel = new QLabel("Edit"); @@ -106,7 +115,7 @@ void AnnotationRedoUndoWidget::updateContent() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); + CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(m_userInputMode); m_redoAction->setEnabled(undoStack->canRedo()); m_redoAction->setToolTip(undoStack->redoText()); @@ -123,7 +132,7 @@ void AnnotationRedoUndoWidget::redoActionTriggered() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); + CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(m_userInputMode); AString errorMessage; if ( ! undoStack->redoInWindow(m_browserWindowIndex, @@ -143,7 +152,7 @@ void AnnotationRedoUndoWidget::undoActionTriggered() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); + CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(m_userInputMode); AString errorMessage; if ( ! undoStack->undoInWindow(m_browserWindowIndex, diff --git a/src/GuiQt/AnnotationRedoUndoWidget.h b/src/GuiQt/AnnotationRedoUndoWidget.h index 58af270dd..34a94c020 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.h +++ b/src/GuiQt/AnnotationRedoUndoWidget.h @@ -26,7 +26,7 @@ #include - +#include "UserInputModeEnum.h" namespace caret { @@ -35,7 +35,8 @@ namespace caret { Q_OBJECT public: - AnnotationRedoUndoWidget(const int32_t browserWindowIndex, + AnnotationRedoUndoWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationRedoUndoWidget(); @@ -55,6 +56,8 @@ namespace caret { AnnotationRedoUndoWidget& operator=(const AnnotationRedoUndoWidget&); + const UserInputModeEnum::Enum m_userInputMode; + const int32_t m_browserWindowIndex; QAction* m_redoAction; diff --git a/src/GuiQt/AnnotationRotationWidget.cxx b/src/GuiQt/AnnotationRotationWidget.cxx index 0e2d17bd4..4140aef8d 100644 --- a/src/GuiQt/AnnotationRotationWidget.cxx +++ b/src/GuiQt/AnnotationRotationWidget.cxx @@ -64,9 +64,11 @@ using namespace caret; * @param parent * Parent of this widget. */ -AnnotationRotationWidget::AnnotationRotationWidget(const int32_t browserWindowIndex, +AnnotationRotationWidget::AnnotationRotationWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), +m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { QLabel* rotationLabel = new QLabel(" R:"); @@ -273,7 +275,8 @@ AnnotationRotationWidget::rotationValueChanged(double value) m_annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationRotationWidget.h b/src/GuiQt/AnnotationRotationWidget.h index 6fb7419a6..72c17ee74 100644 --- a/src/GuiQt/AnnotationRotationWidget.h +++ b/src/GuiQt/AnnotationRotationWidget.h @@ -26,6 +26,8 @@ #include #include +#include "UserInputModeEnum.h" + class QDoubleSpinBox; @@ -38,7 +40,8 @@ namespace caret { Q_OBJECT public: - AnnotationRotationWidget(const int32_t browserWindowIndex, + AnnotationRotationWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, QWidget* parent = 0); virtual ~AnnotationRotationWidget(); @@ -60,6 +63,8 @@ namespace caret { std::vector m_annotations; + const UserInputModeEnum::Enum m_userInputMode; + const int32_t m_browserWindowIndex; QDoubleSpinBox* m_rotationSpinBox; diff --git a/src/GuiQt/AnnotationSelectionViewController.cxx b/src/GuiQt/AnnotationSelectionViewController.cxx index 3fc754f3b..3f1792c7b 100644 --- a/src/GuiQt/AnnotationSelectionViewController.cxx +++ b/src/GuiQt/AnnotationSelectionViewController.cxx @@ -34,7 +34,6 @@ #include "DisplayGroupAndTabItemViewController.h" #include "DisplayGroupEnumComboBox.h" #include "DisplayPropertiesAnnotation.h" -#include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" diff --git a/src/GuiQt/AnnotationTextAlignmentWidget.cxx b/src/GuiQt/AnnotationTextAlignmentWidget.cxx index 8e5398dfc..90182eccb 100644 --- a/src/GuiQt/AnnotationTextAlignmentWidget.cxx +++ b/src/GuiQt/AnnotationTextAlignmentWidget.cxx @@ -305,7 +305,8 @@ AnnotationTextAlignmentWidget::horizontalAlignmentActionSelected(QAction* action annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -339,7 +340,8 @@ AnnotationTextAlignmentWidget::verticalAlignmentActionSelected(QAction* action) annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationTextEditorDialog.cxx b/src/GuiQt/AnnotationTextEditorDialog.cxx index a1c28fb27..19fc18bb5 100644 --- a/src/GuiQt/AnnotationTextEditorDialog.cxx +++ b/src/GuiQt/AnnotationTextEditorDialog.cxx @@ -133,7 +133,8 @@ AnnotationTextEditorDialog::textWasEdited() undoCommand->setModeTextCharacters(text, annotationVector); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationTextEditorWidget.cxx b/src/GuiQt/AnnotationTextEditorWidget.cxx index 22e774eb1..7e41e9d8b 100644 --- a/src/GuiQt/AnnotationTextEditorWidget.cxx +++ b/src/GuiQt/AnnotationTextEditorWidget.cxx @@ -38,6 +38,7 @@ #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" #include "GuiManager.h" +#include "UserInputModeEnum.h" #include "WuQDataEntryDialog.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -196,7 +197,8 @@ AnnotationTextEditorWidget::annotationTextChanged() undoCommand->setModeTextCharacters(s, selectedAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -241,7 +243,8 @@ AnnotationTextEditorWidget::annotationTextConnectTypeEnumComboBoxItemActivated() selectedAnnotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationTextOrientationWidget.cxx b/src/GuiQt/AnnotationTextOrientationWidget.cxx index 3dbe7064a..4bd8e80f2 100644 --- a/src/GuiQt/AnnotationTextOrientationWidget.cxx +++ b/src/GuiQt/AnnotationTextOrientationWidget.cxx @@ -189,7 +189,8 @@ AnnotationTextOrientationWidget::orientationActionSelected(QAction* action) annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(UserInputModeEnum::ANNOTATIONS, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationTextSubstitutionViewController.cxx b/src/GuiQt/AnnotationTextSubstitutionViewController.cxx index 0a3c71c31..c77bcd233 100644 --- a/src/GuiQt/AnnotationTextSubstitutionViewController.cxx +++ b/src/GuiQt/AnnotationTextSubstitutionViewController.cxx @@ -39,7 +39,6 @@ #include "BrowserTabContent.h" #include "CaretAssert.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" -#include "EventGetOrSetUserInputModeProcessor.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventMapYokingSelectMap.h" #include "EventSurfaceColoringInvalidate.h" @@ -365,47 +364,6 @@ AnnotationTextSubstitutionViewController::updateSelections() fgc->m_valueIndexSpinBox->setVisible(visibleFlag); fgc->m_fileNameLabel->setVisible(visibleFlag); } - - - - -// const DisplayPropertiesAnnotation* dpa = GuiManager::get()->getBrain()->getDisplayPropertiesAnnotation(); -// -// BrowserTabContent* browserTabContent = -// GuiManager::get()->getBrowserTabContentForBrowserWindow(m_browserWindowIndex, true); -// if (browserTabContent == NULL) { -// return; -// } -// const int32_t browserTabIndex = browserTabContent->getTabNumber(); -// -// m_displayAnnotationsCheckBox->setChecked(dpa->isDisplayAnnotations()); -// m_displayTextAnnotationsCheckBox->setChecked(dpa->isDisplayTextAnnotations()); -// m_displayWindowAnnotationInSingleTabViewsCheckBox->setChecked(dpa->isDisplayWindowAnnotationsInSingleTabViews(m_browserWindowIndex)); -// -// Brain* brain = GuiManager::get()->getBrain(); -// std::vector annotationFiles; -// brain->getAllAnnotationFilesIncludingSceneAnnotationFile(annotationFiles); -// -// std::vector fileItems; -// for (std::vector::iterator fileIter = annotationFiles.begin(); -// fileIter != annotationFiles.end(); -// fileIter++) { -// AnnotationFile* annFile = *fileIter; -// fileItems.push_back(annFile); -// } -// -// const DisplayGroupEnum::Enum displayGroup = dpa->getDisplayGroupForTab(browserTabIndex); -// m_displayGroupComboBox->setSelectedDisplayGroup(displayGroup); -// -// EventGetOrSetUserInputModeProcessor inputModeEvent(m_browserWindowIndex); -// EventManager::get()->sendEvent(inputModeEvent.getPointer()); -// UserInputModeAbstract::UserInputMode mode = inputModeEvent.getUserInputMode(); -// const bool annotationsValidFlag = (mode == UserInputModeAbstract::ANNOTATIONS); -// -// m_selectionViewController->updateContent(fileItems, -// displayGroup, -// browserTabIndex, -// annotationsValidFlag); } diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index 0896ca317..5d0df2114 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -60,10 +60,12 @@ using namespace caret; * @param parent * Parent of this widget. */ -AnnotationWidthHeightWidget::AnnotationWidthHeightWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, +AnnotationWidthHeightWidget::AnnotationWidthHeightWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent) : QWidget(parent), +m_userInputMode(userInputMode), m_parentWidgetType(parentWidgetType), m_browserWindowIndex(browserWindowIndex) { @@ -223,7 +225,8 @@ AnnotationWidthHeightWidget::heightValueChanged(double value) annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -255,12 +258,14 @@ AnnotationWidthHeightWidget::widthValueChanged(double value) { std::vector annotations(m_annotations2D.begin(), m_annotations2D.end()); + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeTwoDimWidth(value, annotations); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); diff --git a/src/GuiQt/AnnotationWidthHeightWidget.h b/src/GuiQt/AnnotationWidthHeightWidget.h index 37c73b01b..7ec1d0e18 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.h +++ b/src/GuiQt/AnnotationWidthHeightWidget.h @@ -27,6 +27,7 @@ #include #include "AnnotationWidgetParentEnum.h" +#include "UserInputModeEnum.h" class QDoubleSpinBox; @@ -39,7 +40,8 @@ namespace caret { Q_OBJECT public: - AnnotationWidthHeightWidget(const AnnotationWidgetParentEnum::Enum parentWidgetType, + AnnotationWidthHeightWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, QWidget* parent = 0); @@ -62,6 +64,8 @@ namespace caret { // ADD_NEW_MEMBERS_HERE + const UserInputModeEnum::Enum m_userInputMode; + const AnnotationWidgetParentEnum::Enum m_parentWidgetType; const int32_t m_browserWindowIndex; diff --git a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx index f7ee1e2c7..b7829c8fd 100644 --- a/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx +++ b/src/GuiQt/BrainBrowserWindowOrientedToolBox.cxx @@ -847,6 +847,8 @@ BrainBrowserWindowOrientedToolBox::receiveEvent(Event* event) break; case UserInputModeEnum::INVALID: break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + break; case UserInputModeEnum::VIEW: break; case UserInputModeEnum::VOLUME_EDIT: diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 33771ead2..e7a9e1bd3 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -2980,6 +2980,19 @@ BrainBrowserWindowToolBar::createModeWidget() + ":Mode:Image"); } + /* + * Tile tabs manual layout editing + */ + this->modeInputModeTileTabsManualLayoutAction = WuQtUtilities::createAction("Tile", + "Edit Tile Tabs Manual Layout", + this); + this->modeInputModeTileTabsManualLayoutAction->setCheckable(true); + QToolButton* inputModeTileTabsManualLayoutButton = new QToolButton(); + inputModeTileTabsManualLayoutButton->setDefaultAction(this->modeInputModeTileTabsManualLayoutAction); + WuQtUtilities::setToolButtonStyleForQt5Mac(inputModeTileTabsManualLayoutButton); + this->modeInputModeTileTabsManualLayoutAction->setObjectName(m_objectNamePrefix + + "Mode:TileTabsManualLayout"); + /* * Volume Edit */ @@ -3024,8 +3037,6 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeBordersToolButton, inputModeViewToolButton, inputModeVolumeEditButton); - inputModeFociToolButton->setSizePolicy(QSizePolicy::Preferred, - inputModeFociToolButton->sizePolicy().verticalPolicy()); if (inputModeImageToolButton != NULL) { inputModeImageToolButton->setSizePolicy(QSizePolicy::Preferred, inputModeImageToolButton->sizePolicy().verticalPolicy()); @@ -3043,11 +3054,18 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeLayout->addWidget(inputModeBordersToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); modeRow++; if (inputModeImageToolButton != NULL) { + CaretAssertMessage(0, "Layout will need to be updated for location of image button and to show Tile button."); inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); inputModeLayout->addWidget(inputModeImageToolButton, modeRow, 1); } else { - inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); + inputModeFociToolButton->setSizePolicy(QSizePolicy::Preferred, + inputModeFociToolButton->sizePolicy().verticalPolicy()); + inputModeTileTabsManualLayoutButton->setSizePolicy(QSizePolicy::Preferred, + inputModeFociToolButton->sizePolicy().verticalPolicy()); + inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); + inputModeLayout->addWidget(inputModeTileTabsManualLayoutButton, modeRow, 1); +// inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); } modeRow++; inputModeLayout->addWidget(inputModeViewToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); @@ -3063,6 +3081,7 @@ BrainBrowserWindowToolBar::createModeWidget() this->modeInputModeActionGroup->addAction(this->modeInputModeImageAction); } this->modeInputModeActionGroup->addAction(this->modeInputModeViewAction); + this->modeInputModeActionGroup->addAction(this->modeInputModeTileTabsManualLayoutAction); this->modeInputModeActionGroup->addAction(this->modeInputVolumeEditAction); QObject::connect(this->modeInputModeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(modeInputModeActionTriggered(QAction*))); @@ -3078,6 +3097,8 @@ BrainBrowserWindowToolBar::createModeWidget() WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeImageAction, "Select image mode"); } + WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeTileTabsManualLayoutAction, + "Select Tile Tabs Manual Layout Editing"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputModeViewAction, "Select view mode"); WuQMacroManager::instance()->addMacroSupportToObject(this->modeInputVolumeEditAction, @@ -3158,6 +3179,9 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) && (this->modeInputModeImageAction != NULL)) { inputMode = UserInputModeEnum::IMAGE; } + else if (action == this->modeInputModeTileTabsManualLayoutAction) { + inputMode = UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING; + } else if (action == this->modeInputVolumeEditAction) { inputMode = UserInputModeEnum::VOLUME_EDIT; } @@ -3212,6 +3236,9 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte this->modeInputModeImageAction->setChecked(true); } break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + this->modeInputModeTileTabsManualLayoutAction->setChecked(true); + break; case UserInputModeEnum::VOLUME_EDIT: this->modeInputVolumeEditAction->setChecked(true); break; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 64ec3bd3e..360868272 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -429,6 +429,7 @@ namespace caret { QAction* modeInputModeFociAction; QAction* modeInputModeImageAction; QAction* modeInputModeViewAction; + QAction* modeInputModeTileTabsManualLayoutAction; QAction* modeInputVolumeEditAction; private: diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index bfc436d2f..504412437 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -89,6 +89,7 @@ #include "UserInputModeBorders.h" #include "UserInputModeFoci.h" #include "UserInputModeImage.h" +#include "UserInputModeTileTabsManualLayout.h" #include "UserInputModeView.h" #include "UserInputModeVolumeEdit.h" #include "WuQMacroManager.h" @@ -153,6 +154,7 @@ windowIndex(windowIndex) this->userInputFociModeProcessor = new UserInputModeFoci(windowIndex); this->userInputImageModeProcessor = new UserInputModeImage(windowIndex); this->userInputVolumeEditModeProcessor = new UserInputModeVolumeEdit(windowIndex); + this->userInputTileTabsManualLayoutProcessor = new UserInputModeTileTabsManualLayout(windowIndex); this->userInputViewModeProcessor = new UserInputModeView(); this->selectedUserInputProcessor = this->userInputViewModeProcessor; this->selectedUserInputProcessor->initialize(); @@ -232,6 +234,7 @@ BrainOpenGLWidget::~BrainOpenGLWidget() delete this->userInputBordersModeProcessor; delete this->userInputFociModeProcessor; delete this->userInputImageModeProcessor; + delete this->userInputTileTabsManualLayoutProcessor; delete this->userInputVolumeEditModeProcessor; this->selectedUserInputProcessor = NULL; /* DO NOT DELETE since it does not own the object to which it points */ @@ -1756,6 +1759,9 @@ BrainOpenGLWidget::receiveEvent(Event* event) case UserInputModeEnum::IMAGE: newUserInputProcessor = this->userInputImageModeProcessor; break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + newUserInputProcessor = this->userInputTileTabsManualLayoutProcessor; + break; case UserInputModeEnum::VOLUME_EDIT: newUserInputProcessor = this->userInputVolumeEditModeProcessor; break; diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 5f5942eee..3e70aa2a9 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -66,6 +66,7 @@ namespace caret { class UserInputModeBorders; class UserInputModeFoci; class UserInputModeImage; + class UserInputModeTileTabsManualLayout; class UserInputModeView; class UserInputModeVolumeEdit; class UserInputModeAbstract; @@ -201,6 +202,7 @@ namespace caret { UserInputModeBorders* userInputBordersModeProcessor; UserInputModeFoci* userInputFociModeProcessor; UserInputModeImage* userInputImageModeProcessor; + UserInputModeTileTabsManualLayout* userInputTileTabsManualLayoutProcessor; UserInputModeVolumeEdit* userInputVolumeEditModeProcessor; Border* borderBeingDrawn; diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index b2ea91e99..2ab6985c0 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -463,6 +463,7 @@ UserInputModeFociWidget.h UserInputModeFoci.h UserInputModeImageWidget.h UserInputModeImage.h +UserInputModeTileTabsManualLayout.h UserInputModeView.h UserInputModeViewContextMenu.h UserInputModeVolumeEdit.h @@ -740,6 +741,7 @@ UserInputModeFoci.cxx UserInputModeFociWidget.cxx UserInputModeImage.cxx UserInputModeImageWidget.cxx +UserInputModeTileTabsManualLayout.cxx UserInputModeView.cxx UserInputModeViewContextMenu.cxx UserInputModeVolumeEdit.cxx diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index 91e649bdb..a1b8e1654 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -82,9 +82,48 @@ using namespace caret; /** * Constructor. + * + * @param windowIndex + * Index of window */ UserInputModeAnnotations::UserInputModeAnnotations(const int32_t windowIndex) -: UserInputModeView(UserInputModeEnum::ANNOTATIONS), +: UserInputModeAnnotations(UserInputModeEnum::ANNOTATIONS, + windowIndex) +{ + +} +//: UserInputModeView(UserInputModeEnum::ANNOTATIONS), +//m_browserWindowIndex(windowIndex), +//m_annotationUnderMouse(NULL), +//m_annotationBeingDragged(NULL) +//{ +// m_allowMultipleSelectionModeFlag = true; +// m_mode = MODE_SELECT; +// m_annotationUnderMouseSizeHandleType = AnnotationSizingHandleTypeEnum::ANNOTATION_SIZING_HANDLE_NONE; +// +// m_modeNewAnnotationFileSpaceAndType.grabNew(new NewAnnotationFileSpaceAndType(NULL, +// AnnotationCoordinateSpaceEnum::VIEWPORT, +// AnnotationTypeEnum::LINE)); +// m_newAnnotationCreatingWithMouseDrag.grabNew(NULL); +// +// m_annotationToolsWidget = new UserInputModeAnnotationsWidget(this, +// m_browserWindowIndex); +// setWidgetForToolBar(m_annotationToolsWidget); +// +// EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE); +//} + +/** + * Constructor. + * + * @param userInputMode + * Input + * @param windowIndex + * Index of window + */ +UserInputModeAnnotations::UserInputModeAnnotations(const UserInputModeEnum::Enum userInputMode, + const int32_t windowIndex) +: UserInputModeView(userInputMode), m_browserWindowIndex(windowIndex), m_annotationUnderMouse(NULL), m_annotationBeingDragged(NULL) @@ -305,7 +344,8 @@ UserInputModeAnnotations::deleteSelectedAnnotations() AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDeleteAnnotations(selectedAnnotations); AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, + if ( ! annotationManager->applyCommand(getUserInputMode(), + undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); @@ -542,7 +582,8 @@ UserInputModeAnnotations::keyPressEvent(const KeyEvent& keyEvent) AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyCommand(undoCommand, + if ( ! annMan->applyCommand(getUserInputMode(), + undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); @@ -855,7 +896,8 @@ UserInputModeAnnotations::mouseLeftDrag(const MouseEvent& mouseEvent) } AString errorMessage; - if ( ! annotationManager->applyCommand(command, + if ( ! annotationManager->applyCommand(getUserInputMode(), + command, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); @@ -1493,7 +1535,8 @@ UserInputModeAnnotations::cutAnnotation() AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeCutAnnotations(annotationVector); AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, + if ( ! annotationManager->applyCommand(getUserInputMode(), + undoCommand, errorMessage)) { WuQMessageBox::errorOk(m_annotationToolsWidget, errorMessage); @@ -1566,7 +1609,7 @@ UserInputModeAnnotations::processEditMenuItemSelection(const BrainBrowserWindowE case BrainBrowserWindowEditMenuItemEnum::REDO: { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); + CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(getUserInputMode()); AString errorMessage; if ( ! undoStack->redo(errorMessage)) { @@ -1584,7 +1627,7 @@ UserInputModeAnnotations::processEditMenuItemSelection(const BrainBrowserWindowE case BrainBrowserWindowEditMenuItemEnum::UNDO: { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(); + CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(getUserInputMode()); AString errorMessage; if ( ! undoStack->undo(errorMessage)) { @@ -1706,7 +1749,7 @@ UserInputModeAnnotations::getEnabledEditMenuItems(std::vectorgetCommandRedoUndoStack(); + CaretUndoStack* undoStack = annotationManager->getCommandRedoUndoStack(getUserInputMode()); if (undoStack->canRedo()) { enabledEditMenuItemsOut.push_back(BrainBrowserWindowEditMenuItemEnum::REDO); diff --git a/src/GuiQt/UserInputModeAnnotations.h b/src/GuiQt/UserInputModeAnnotations.h index 2aa73142a..480dce88d 100644 --- a/src/GuiQt/UserInputModeAnnotations.h +++ b/src/GuiQt/UserInputModeAnnotations.h @@ -124,6 +124,10 @@ namespace caret { // ADD_NEW_METHODS_HERE + protected: + UserInputModeAnnotations(const UserInputModeEnum::Enum userInputMode, + const int32_t windowIndex); + private: class NewMouseDragCreateAnnotation { public: diff --git a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx index 8a6d89e61..bb27bb253 100644 --- a/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx +++ b/src/GuiQt/UserInputModeAnnotationsContextMenu.cxx @@ -349,8 +349,9 @@ UserInputModeAnnotationsContextMenu::deleteAnnotations() AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); undoCommand->setModeDeleteAnnotations(selectedAnnotations); AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, - errorMessage)) { + if ( ! annotationManager->applyCommand(m_userInputModeAnnotations->getUserInputMode(), + undoCommand, + errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); } @@ -581,7 +582,8 @@ UserInputModeAnnotationsContextMenu::duplicateAnnotationSelected(QAction* action undoCommand->setModeDuplicateAnnotation(m_annotationFile, annCopy); AString errorMessage; - if ( ! annotationManager->applyCommand(undoCommand, + if ( ! annotationManager->applyCommand(m_userInputModeAnnotations->getUserInputMode(), + undoCommand, errorMessage)) { WuQMessageBox::errorOk(this, errorMessage); @@ -634,7 +636,8 @@ UserInputModeAnnotationsContextMenu::applyGrouping(const AnnotationGroupingModeE AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); AString errorMessage; - if ( ! annMan->applyGroupingMode(m_mouseEvent.getBrowserWindowIndex(), + if ( ! annMan->applyGroupingMode(m_userInputModeAnnotations->getUserInputMode(), + m_mouseEvent.getBrowserWindowIndex(), grouping, errorMessage)) { WuQMessageBox::errorOk(this, diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index 62ab2a206..f492b174c 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -82,6 +82,134 @@ m_inputModeAnnotations(inputModeAnnotations) { CaretAssert(inputModeAnnotations); + switch (inputModeAnnotations->getUserInputMode()) { + case UserInputModeEnum::ANNOTATIONS: + createAnnotationWidget(); + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + createTileTabsEditingWidget(); + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + case UserInputModeEnum::VIEW: + case UserInputModeEnum::VOLUME_EDIT: + CaretAssert(0); + return; + break; + } + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + + setFixedHeight(sizeHint().height()); +} + +/** + * Destructor. + */ +UserInputModeAnnotationsWidget::~UserInputModeAnnotationsWidget() +{ + EventManager::get()->removeAllEventsFromListener(this); +} + +/** + * Receive an event. + * + * @param event + * The event that the receive can respond to. + */ +void +UserInputModeAnnotationsWidget::receiveEvent(Event* event) +{ + bool updateAnnotationWidgetsFlag = false; + + if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { + EventBrainReset* brainEvent = dynamic_cast(event); + CaretAssert(brainEvent); + + updateAnnotationWidgetsFlag = true; + + brainEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE) { + EventAnnotationCreateNewType* annotationEvent = dynamic_cast(event); + CaretAssert(annotationEvent); + updateAnnotationWidgetsFlag = true; + annotationEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { + EventUserInterfaceUpdate* updateEvent = dynamic_cast(event); + CaretAssert(updateEvent); + updateAnnotationWidgetsFlag = true; + updateEvent->setEventProcessed(); + } + else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE) { + updateAnnotationWidgetsFlag = true; + } + else { + return; + } + + if (! updateAnnotationWidgetsFlag) { + return; + } + + updateWidget(); + +} + +/** + * Create annotation mode widget + */ +void +UserInputModeAnnotationsWidget::createTileTabsEditingWidget() +{ + m_coordinateOneWidget = new AnnotationCoordinateWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + AnnotationCoordinateWidget::COORDINATE_ONE, + m_browserWindowIndex); + + m_widthHeightWidget = new AnnotationWidthHeightWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + m_browserWindowIndex); + + m_formatWidget = new AnnotationFormatWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); + + m_redoUndoWidget = new AnnotationRedoUndoWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); + + /* + * Connect signals for setting a coordinate with the mouse. + */ + QObject::connect(m_coordinateOneWidget, SIGNAL(signalSelectCoordinateWithMouse()), + this, SLOT(selectCoordinateOneWithMouse())); + + /* + * Layout of widgets + */ + QHBoxLayout* layout = new QHBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); + layout->addWidget(m_coordinateOneWidget); + layout->addWidget(WuQtUtilities::createVerticalLineWidget()); + layout->addWidget(m_widthHeightWidget); + layout->addWidget(WuQtUtilities::createVerticalLineWidget()); + layout->addWidget(m_formatWidget); + layout->addWidget(WuQtUtilities::createVerticalLineWidget()); + layout->addWidget(m_redoUndoWidget); + layout->addStretch(); +} + +/* + * Create tile tabs mode widget + */ +void +UserInputModeAnnotationsWidget::createAnnotationWidget() +{ m_textEditorWidget = new AnnotationTextEditorWidget(m_browserWindowIndex); m_lineArrowTipsWidget = new AnnotationLineArrowTipsWidget(m_browserWindowIndex); @@ -98,26 +226,32 @@ m_inputModeAnnotations(inputModeAnnotations) m_coordinateSpaceWidget = new AnnotationCoordinateSpaceWidget(m_browserWindowIndex); - m_coordinateOneWidget = new AnnotationCoordinateWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + m_coordinateOneWidget = new AnnotationCoordinateWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, AnnotationCoordinateWidget::COORDINATE_ONE, m_browserWindowIndex); - m_coordinateTwoWidget = new AnnotationCoordinateWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + m_coordinateTwoWidget = new AnnotationCoordinateWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, AnnotationCoordinateWidget::COORDINATE_TWO, m_browserWindowIndex); - m_widthHeightWidget = new AnnotationWidthHeightWidget(AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + m_widthHeightWidget = new AnnotationWidthHeightWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); - m_rotationWidget = new AnnotationRotationWidget(m_browserWindowIndex); + m_rotationWidget = new AnnotationRotationWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); - m_formatWidget = new AnnotationFormatWidget(m_browserWindowIndex); + m_formatWidget = new AnnotationFormatWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); m_insertDeleteWidget = new AnnotationInsertNewWidget(m_browserWindowIndex); m_deleteWidget = new AnnotationDeleteWidget(m_browserWindowIndex); - m_redoUndoWidget = new AnnotationRedoUndoWidget(m_browserWindowIndex); + m_redoUndoWidget = new AnnotationRedoUndoWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); /* * Connect signals for setting a coordinate with the mouse. @@ -177,67 +311,6 @@ m_inputModeAnnotations(inputModeAnnotations) layout->addWidget(topRowWidget); layout->addWidget(WuQtUtilities::createHorizontalLineWidget()); layout->addLayout(bottomRowLayout); - - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BRAIN_RESET); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); - - setFixedHeight(sizeHint().height()); -} - -/** - * Destructor. - */ -UserInputModeAnnotationsWidget::~UserInputModeAnnotationsWidget() -{ - EventManager::get()->removeAllEventsFromListener(this); -} - -/** - * Receive an event. - * - * @param event - * The event that the receive can respond to. - */ -void -UserInputModeAnnotationsWidget::receiveEvent(Event* event) -{ - bool updateAnnotationWidgetsFlag = false; - - if (event->getEventType() == EventTypeEnum::EVENT_BRAIN_RESET) { - EventBrainReset* brainEvent = dynamic_cast(event); - CaretAssert(brainEvent); - - updateAnnotationWidgetsFlag = true; - - brainEvent->setEventProcessed(); - } - else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_CREATE_NEW_TYPE) { - EventAnnotationCreateNewType* annotationEvent = dynamic_cast(event); - CaretAssert(annotationEvent); - updateAnnotationWidgetsFlag = true; - annotationEvent->setEventProcessed(); - } - else if (event->getEventType() == EventTypeEnum::EVENT_USER_INTERFACE_UPDATE) { - EventUserInterfaceUpdate* updateEvent = dynamic_cast(event); - CaretAssert(updateEvent); - updateAnnotationWidgetsFlag = true; - updateEvent->setEventProcessed(); - } - else if (event->getEventType() == EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE) { - updateAnnotationWidgetsFlag = true; - } - else { - return; - } - - if (! updateAnnotationWidgetsFlag) { - return; - } - - updateWidget(); - } /** @@ -328,17 +401,20 @@ UserInputModeAnnotationsWidget::updateWidget() } } - m_coordinateSpaceWidget->updateContent(selectedAnnotations); - m_fontWidget->updateContent(fontStyleAnnotations); - m_textEditorWidget->updateContent(textAnnotations); - m_colorWidget->updateContent(selectedAnnotations); - m_lineArrowTipsWidget->updateContent(lineAnnotations); - m_textAlignmentWidget->updateContent(textAnnotations); - m_textOrientationWidget->updateContent(textAnnotations); - m_widthHeightWidget->updateContent(twoDimAnnotations); - m_rotationWidget->updateContent(selectedAnnotations); //twoDimAnnotations); - m_insertDeleteWidget->updateContent(); - m_deleteWidget->updateContent(); + /* + * Note: pointers are initialized to NULL in the header file + */ + if (m_coordinateSpaceWidget != NULL) m_coordinateSpaceWidget->updateContent(selectedAnnotations); + if (m_fontWidget != NULL) m_fontWidget->updateContent(fontStyleAnnotations); + if (m_textEditorWidget != NULL) m_textEditorWidget->updateContent(textAnnotations); + if (m_colorWidget != NULL) m_colorWidget->updateContent(selectedAnnotations); + if (m_lineArrowTipsWidget != NULL) m_lineArrowTipsWidget->updateContent(lineAnnotations); + if (m_textAlignmentWidget != NULL) m_textAlignmentWidget->updateContent(textAnnotations); + if (m_textOrientationWidget != NULL) m_textOrientationWidget->updateContent(textAnnotations); + if (m_widthHeightWidget != NULL) m_widthHeightWidget->updateContent(twoDimAnnotations); + if (m_rotationWidget != NULL) m_rotationWidget->updateContent(selectedAnnotations); //twoDimAnnotations); + if (m_insertDeleteWidget != NULL) m_insertDeleteWidget->updateContent(); + if (m_deleteWidget != NULL) m_deleteWidget->updateContent(); Annotation* coordEditAnnotation = NULL; AnnotationOneDimensionalShape* coordEditOneDimAnnotation = NULL; @@ -346,16 +422,16 @@ UserInputModeAnnotationsWidget::updateWidget() coordEditAnnotation = selectedAnnotations[0]; coordEditOneDimAnnotation = dynamic_cast(coordEditAnnotation); } - m_coordinateOneWidget->updateContent(coordEditAnnotation); + if (m_coordinateOneWidget != NULL) m_coordinateOneWidget->updateContent(coordEditAnnotation); if (coordEditOneDimAnnotation != NULL) { - m_coordinateTwoWidget->updateContent(coordEditOneDimAnnotation); - m_coordinateTwoWidget->setVisible(true); + if (m_coordinateTwoWidget != NULL) m_coordinateTwoWidget->updateContent(coordEditOneDimAnnotation); + if (m_coordinateTwoWidget != NULL) m_coordinateTwoWidget->setVisible(true); } else { - m_coordinateTwoWidget->setVisible(false); + if (m_coordinateTwoWidget != NULL) m_coordinateTwoWidget->setVisible(false); } - m_redoUndoWidget->updateContent(); + if (m_redoUndoWidget != NULL) m_redoUndoWidget->updateContent(); } diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.h b/src/GuiQt/UserInputModeAnnotationsWidget.h index 581c55184..5a9fa7cc6 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.h +++ b/src/GuiQt/UserInputModeAnnotationsWidget.h @@ -75,43 +75,47 @@ namespace caret { UserInputModeAnnotationsWidget& operator=(const UserInputModeAnnotationsWidget&); + void createAnnotationWidget(); + + void createTileTabsEditingWidget(); + QWidget* createInsertMenuToolButton(); QWidget* createTextEditorWidget(); - const int32_t m_browserWindowIndex; + const int32_t m_browserWindowIndex = -1; - UserInputModeAnnotations* m_inputModeAnnotations; + UserInputModeAnnotations* m_inputModeAnnotations = NULL; - AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget; + AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget = NULL; - AnnotationCoordinateWidget* m_coordinateOneWidget; + AnnotationCoordinateWidget* m_coordinateOneWidget = NULL; - AnnotationCoordinateWidget* m_coordinateTwoWidget; + AnnotationCoordinateWidget* m_coordinateTwoWidget = NULL; - AnnotationWidthHeightWidget* m_widthHeightWidget; + AnnotationWidthHeightWidget* m_widthHeightWidget = NULL; - AnnotationRotationWidget* m_rotationWidget; + AnnotationRotationWidget* m_rotationWidget = NULL; - AnnotationLineArrowTipsWidget* m_lineArrowTipsWidget; + AnnotationLineArrowTipsWidget* m_lineArrowTipsWidget = NULL; - AnnotationFontWidget* m_fontWidget; + AnnotationFontWidget* m_fontWidget = NULL; - AnnotationColorWidget* m_colorWidget; + AnnotationColorWidget* m_colorWidget = NULL; - AnnotationTextAlignmentWidget* m_textAlignmentWidget; + AnnotationTextAlignmentWidget* m_textAlignmentWidget = NULL; - AnnotationFormatWidget* m_formatWidget; + AnnotationFormatWidget* m_formatWidget = NULL; - AnnotationTextEditorWidget* m_textEditorWidget; + AnnotationTextEditorWidget* m_textEditorWidget = NULL; - AnnotationTextOrientationWidget* m_textOrientationWidget; + AnnotationTextOrientationWidget* m_textOrientationWidget = NULL; - AnnotationInsertNewWidget* m_insertDeleteWidget; + AnnotationInsertNewWidget* m_insertDeleteWidget = NULL; - AnnotationDeleteWidget* m_deleteWidget; + AnnotationDeleteWidget* m_deleteWidget = NULL; - AnnotationRedoUndoWidget* m_redoUndoWidget; + AnnotationRedoUndoWidget* m_redoUndoWidget = NULL; // ADD_NEW_MEMBERS_HERE diff --git a/src/GuiQt/UserInputModeTileTabsManualLayout.cxx b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx new file mode 100644 index 000000000..7082ca681 --- /dev/null +++ b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx @@ -0,0 +1,56 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_DECLARE__ +#include "UserInputModeTileTabsManualLayout.h" +#undef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_DECLARE__ + +#include "CaretAssert.h" +using namespace caret; + + + +/** + * \class caret::UserInputModeTileTabsManualLayout + * \brief User Input mode for editing manual tile tabs layout + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param windowIndex + * Index of window + */ +UserInputModeTileTabsManualLayout::UserInputModeTileTabsManualLayout(const int32_t windowIndex) +: UserInputModeAnnotations(UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING, + windowIndex) +{ + +} + +/** + * Destructor. + */ +UserInputModeTileTabsManualLayout::~UserInputModeTileTabsManualLayout() +{ +} + diff --git a/src/GuiQt/UserInputModeTileTabsManualLayout.h b/src/GuiQt/UserInputModeTileTabsManualLayout.h new file mode 100644 index 000000000..e786eae86 --- /dev/null +++ b/src/GuiQt/UserInputModeTileTabsManualLayout.h @@ -0,0 +1,58 @@ +#ifndef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_H__ +#define __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2019 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + + +#include + +#include "UserInputModeAnnotations.h" + + + +namespace caret { + + class UserInputModeTileTabsManualLayout : public UserInputModeAnnotations { + + public: + UserInputModeTileTabsManualLayout(const int32_t windowIndex); + + virtual ~UserInputModeTileTabsManualLayout(); + + UserInputModeTileTabsManualLayout(const UserInputModeTileTabsManualLayout&) = delete; + + UserInputModeTileTabsManualLayout& operator=(const UserInputModeTileTabsManualLayout&) = delete; + + + // ADD_NEW_METHODS_HERE + + private: + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_DECLARE__ + // +#endif // __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_DECLARE__ + +} // namespace +#endif //__USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_H__ -- GitLab From 8d034aed698e587548df4508a19e3adc4e08c3d8 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 22 Aug 2019 15:47:34 -0500 Subject: [PATCH 013/584] WB-859 Manual Tile Tabs Layout System: When editing tile tabs manual layout, use special version of Annotation Toolbar that shows only widgets valid for tile tabs editing. Add new widget for setting bounds of tile tags to the annotation toolbar. Update Redo/Undo for new bounds 2D. --- src/Annotations/AnnotationRedoUndoCommand.cxx | 148 +++++++++ src/Annotations/AnnotationRedoUndoCommand.h | 26 ++ .../AnnotationRedoUndoCommandModeEnum.cxx | 4 + .../AnnotationRedoUndoCommandModeEnum.h | 2 + src/GuiQt/AnnotationBoundsWidget.cxx | 294 ++++++++++++++++++ src/GuiQt/AnnotationBoundsWidget.h | 97 ++++++ src/GuiQt/AnnotationWidthHeightWidget.cxx | 30 +- src/GuiQt/AnnotationWidthHeightWidget.h | 1 + src/GuiQt/BrainBrowserWindowToolBar.cxx | 22 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/UserInputModeAnnotationsWidget.cxx | 64 ++-- src/GuiQt/UserInputModeAnnotationsWidget.h | 3 + 12 files changed, 661 insertions(+), 33 deletions(-) create mode 100644 src/GuiQt/AnnotationBoundsWidget.cxx create mode 100644 src/GuiQt/AnnotationBoundsWidget.h diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index a65e8e89e..f2565e2e4 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -25,6 +25,7 @@ #include +#include "AnnotationBrowserTab.h" #include "AnnotationFontAttributesInterface.h" #include "AnnotationLine.h" #include "AnnotationPercentSizeText.h" @@ -93,6 +94,21 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, switch (m_mode) { case AnnotationRedoUndoCommandModeEnum::INVALID: break; + case AnnotationRedoUndoCommandModeEnum::BOUNDS_2D: + { + CaretAssert(annotation); + CaretAssert(annotationValue); + + AnnotationBrowserTab* annotationBrowserTab = dynamic_cast(annotation); + const AnnotationBrowserTab* annotationBrowserTabValue = dynamic_cast(annotationValue); + CaretAssert(annotationBrowserTab); + CaretAssert(annotationBrowserTabValue); + + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + annotationBrowserTabValue->getBounds2D(minX, maxX, minY, maxY); + annotationBrowserTab->setBounds2D(minX, maxX, minY, maxY); + } + break; case AnnotationRedoUndoCommandModeEnum::COLOR_BACKGROUND: { CaretAssert(annotationValue); @@ -791,6 +807,138 @@ AnnotationRedoUndoCommand::mergeWith(const CaretUndoCommand* command) return true; } +/** + * Set them mode to x-minimum and create the redo/undo instances. + * + * @param newMinX + * New minimum x-value of the annotation + * @param annotations + * Annotations that receive this new bounds (browser tabs only). + */ +void +AnnotationRedoUndoCommand::setBoundsMinX2D(const float newMinX, + const std::vector& annotations) +{ + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + setDescription("Bounds 2D X-Min"); + setBounds2DHelper(BoundsType2D::MIN_X, + newMinX, + annotations); +} + +/** + * Set them mode to x-maximum and create the redo/undo instances. + * + * @param newMaxX + * New minimum x-value of the annotation + * @param annotations + * Annotations that receive this new bounds (browser tabs only). + */ +void +AnnotationRedoUndoCommand::setBoundsMaxX2D(const float newMaxX, + const std::vector& annotations) +{ + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + setDescription("Bounds 2D X-Max"); + setBounds2DHelper(BoundsType2D::MAX_X, + newMaxX, + annotations); +} + +/** + * Set them mode to y-minimum and create the redo/undo instances. + * + * @param newMinY + * New minimum y-value of the annotation + * @param annotations + * Annotations that receive this new bounds (browser tabs only). + */ +void +AnnotationRedoUndoCommand::setBoundsMinY2D(const float newMinY, + const std::vector& annotations) +{ + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + setDescription("Bounds 2D Y-Min"); + setBounds2DHelper(BoundsType2D::MIN_Y, + newMinY, + annotations); +} + +/** + * Set them mode to y-maximum and create the redo/undo instances. + * + * @param newMaxY + * New maximum y-value of the annotation + * @param annotations + * Annotations that receive this new bounds (browser tabs only). + */ +void +AnnotationRedoUndoCommand::setBoundsMaxY2D(const float newMaxY, + const std::vector& annotations) +{ + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + setDescription("Bounds 2D Y-Max"); + setBounds2DHelper(BoundsType2D::MAX_Y, + newMaxY, + annotations); +} + +/** + * Helper for bounds 2D + * + * @param boundsType + * The bounds value bing set + * @param value + * New value + * @param annotation + * Annotations that have bounds changed. + */ +void +AnnotationRedoUndoCommand::setBounds2DHelper(const BoundsType2D boundsType, + const float value, + const std::vector& annotations) +{ + for (std::vector::const_iterator iter = annotations.begin(); + iter != annotations.end(); + iter++) { + Annotation* annotation = *iter; + CaretAssert(annotation); + + AnnotationBrowserTab* browserTabAnnotation = dynamic_cast(annotation); + if (browserTabAnnotation != NULL) { + AnnotationBrowserTab* redoAnnotation = dynamic_cast(browserTabAnnotation->clone()); + CaretAssert(redoAnnotation); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + redoAnnotation->getBounds2D(minX, maxX, minY, maxY); + + switch (boundsType) { + case BoundsType2D::MIN_X: + minX = value; + break; + case BoundsType2D::MAX_X: + maxX = value; + break; + case BoundsType2D::MIN_Y: + minY = value; + break; + case BoundsType2D::MAX_Y: + maxY = value; + break; + } + + redoAnnotation->setBounds2D(minX, maxX, minY, maxY); + + Annotation* undoAnnotation = browserTabAnnotation->clone(); + AnnotationMemento* am = new AnnotationMemento(annotation, + redoAnnotation, + undoAnnotation); + m_annotationMementos.push_back(am); + } + else { + CaretLogWarning("Annotation for bounds setting must be a Browser Tab Annotation"); + } + } +} /** * Set them mode to first coordinate and create the redo/undo instances. diff --git a/src/Annotations/AnnotationRedoUndoCommand.h b/src/Annotations/AnnotationRedoUndoCommand.h index c15773d46..008547267 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.h +++ b/src/Annotations/AnnotationRedoUndoCommand.h @@ -49,6 +49,18 @@ namespace caret { virtual bool mergeWith(const CaretUndoCommand* command); + void setBoundsMinX2D(const float minX, + const std::vector& annotations); + + void setBoundsMaxX2D(const float maxX, + const std::vector& annotations); + + void setBoundsMinY2D(const float minY, + const std::vector& annotations); + + void setBoundsMaxY2D(const float maxY, + const std::vector& annotations); + void setModeCoordinateOne(const AnnotationCoordinate& coordinate, const std::vector& annotations); @@ -152,6 +164,16 @@ namespace caret { // ADD_NEW_METHODS_HERE private: + /** + * Used with bounds 2D helper + */ + enum class BoundsType2D { + MIN_X, + MAX_X, + MIN_Y, + MAX_Y + }; + /** * The annotation memento contains copies of the * annotation before and after its modification. @@ -247,6 +269,10 @@ namespace caret { static bool lessThanAnnotationMemento(const AnnotationMemento* am1, const AnnotationMemento* am2); + void setBounds2DHelper(const BoundsType2D boundsType, + const float value, + const std::vector& annotations); + AnnotationRedoUndoCommandModeEnum::Enum m_mode; mutable std::vector m_annotationMementos; diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx index 8ec48ec93..7fc489032 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx @@ -110,6 +110,10 @@ AnnotationRedoUndoCommandModeEnum::initialize() "INVALID", "Invalid")); + enumData.push_back(AnnotationRedoUndoCommandModeEnum(BOUNDS_2D, + "BOUNDS_2D", + "Bounds 2D")); + enumData.push_back(AnnotationRedoUndoCommandModeEnum(COLOR_BACKGROUND, "COLOR_BACKGROUND", "Color - Background")); diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h index 3b8d2c84f..447613d38 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h @@ -37,6 +37,8 @@ public: enum Enum { /** Invalid mode */ INVALID, + /** Set the bounds in 2D */ + BOUNDS_2D, /** Color - Background */ COLOR_BACKGROUND, /** Color - Foreground */ diff --git a/src/GuiQt/AnnotationBoundsWidget.cxx b/src/GuiQt/AnnotationBoundsWidget.cxx new file mode 100644 index 000000000..6a5aeb3e0 --- /dev/null +++ b/src/GuiQt/AnnotationBoundsWidget.cxx @@ -0,0 +1,294 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __ANNOTATION_COORDINATE_WIDGET_DECLARE__ +#include "AnnotationBoundsWidget.h" +#undef __ANNOTATION_COORDINATE_WIDGET_DECLARE__ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "AnnotationBrowserTab.h" +#include "AnnotationManager.h" +#include "AnnotationRedoUndoCommand.h" +#include "Brain.h" +#include "CaretAssert.h" +#include "EventBrowserWindowContent.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventUserInterfaceUpdate.h" +#include "EventManager.h" +#include "GuiManager.h" +#include "MathFunctions.h" +#include "WuQFactory.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::AnnotationBoundsWidget + * \brief Widget for editing annotation coordinate + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param + * @param whichCoordinate + * Which coordinate, one (or only), or two + * @param browserWindowIndex + * Index of browser window + * @param parent + * Parent widget + */ +AnnotationBoundsWidget::AnnotationBoundsWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, + const int32_t browserWindowIndex, + QWidget* parent) +: QWidget(parent), +m_userInputMode(userInputMode), +m_parentWidgetType(parentWidgetType), +m_browserWindowIndex(browserWindowIndex) +{ + + m_annotationBrowserTab = NULL; + + QString colonString; + switch (m_parentWidgetType) { + case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: + colonString = ":"; + break; + case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: + CaretAssert(0); + break; + } + + + QLabel* xMinCoordLabel = new QLabel("Min X" + colonString); + m_xMinCoordSpinBox = createSpinBox(); + QObject::connect(m_xMinCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationBoundsWidget::xMinValueChanged); + + QLabel* xMaxCoordLabel = new QLabel(" Max X" + colonString); + m_xMaxCoordSpinBox = createSpinBox(); + QObject::connect(m_xMaxCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationBoundsWidget::xMaxValueChanged); + + QLabel* yMinCoordLabel = new QLabel("Min Y" + colonString); + m_yMinCoordSpinBox = createSpinBox(); + QObject::connect(m_yMinCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationBoundsWidget::yMinValueChanged); + + QLabel* yMaxCoordLabel = new QLabel(" Max Y" + colonString); + m_yMaxCoordSpinBox = createSpinBox(); + QObject::connect(m_yMaxCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationBoundsWidget::yMaxValueChanged); + + QHBoxLayout* coordinateLayout = new QHBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(coordinateLayout, 2, 0); + coordinateLayout->addWidget(xMinCoordLabel); + coordinateLayout->addWidget(m_xMinCoordSpinBox); + coordinateLayout->addWidget(xMaxCoordLabel); + coordinateLayout->addWidget(m_xMaxCoordSpinBox); + coordinateLayout->addWidget(yMinCoordLabel); + coordinateLayout->addWidget(m_yMinCoordSpinBox); + coordinateLayout->addWidget(yMaxCoordLabel); + coordinateLayout->addWidget(m_yMaxCoordSpinBox); + + setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); +} + +QDoubleSpinBox* +AnnotationBoundsWidget::createSpinBox() +{ + QDoubleSpinBox* spinBox = new QDoubleSpinBox(); + spinBox->setMinimum(-100.0); + spinBox->setMaximum( 200.0); + spinBox->setSingleStep(0.1); + spinBox->setDecimals(1); + spinBox->setToolTip("0.0% => Bottom of window\n" + "100.0% => Top of window"); + return spinBox; +} + + +/** + * Destructor. + */ +AnnotationBoundsWidget::~AnnotationBoundsWidget() +{ +} + +/** + * Update with the given annotation coordinate. + * + * @param annotationBrowserTabs. + */ +void +AnnotationBoundsWidget::updateContent(std::vector& annotationBrowserTabs) +{ + m_annotationBrowserTab = NULL; + if ( ! annotationBrowserTabs.empty()) { + CaretAssertVectorIndex(annotationBrowserTabs, 0); + m_annotationBrowserTab = annotationBrowserTabs[0]; + } + + if (m_annotationBrowserTab != NULL) { + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + m_annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); + + m_xMinCoordSpinBox->blockSignals(true); + m_xMinCoordSpinBox->setValue(minX); + m_xMinCoordSpinBox->blockSignals(false); + + m_xMaxCoordSpinBox->blockSignals(true); + m_xMaxCoordSpinBox->setValue(maxX); + m_xMaxCoordSpinBox->blockSignals(false); + + m_yMinCoordSpinBox->blockSignals(true); + m_yMinCoordSpinBox->setValue(minY); + m_yMinCoordSpinBox->blockSignals(false); + + m_yMaxCoordSpinBox->blockSignals(true); + m_yMaxCoordSpinBox->setValue(maxY); + m_yMaxCoordSpinBox->blockSignals(false); + + setEnabled(true); + } + else { + setEnabled(false); + } +} + +/** + * Gets called when x-min value is changed. + * + * @param value + */ +void +AnnotationBoundsWidget::xMinValueChanged(const double value) +{ + valueChangedHelper(m_xMinCoordSpinBox, + value); +} + +/** + * Gets called when x-max value is changed. + * + * @param value + */ +void +AnnotationBoundsWidget::xMaxValueChanged(const double value) +{ + valueChangedHelper(m_xMaxCoordSpinBox, + value); +} + +/** + * Gets called when y-min value is changed. + * + * @param value + */ +void +AnnotationBoundsWidget::yMinValueChanged(const double value) +{ + valueChangedHelper(m_yMinCoordSpinBox, + value); +} + +/** + * Gets called when y-max value is changed. + * + * @param value + */ +void +AnnotationBoundsWidget::yMaxValueChanged(const double value) +{ + valueChangedHelper(m_yMaxCoordSpinBox, + value); +} + +/** + * Helper for bounds value changed + * + * @param spinBox + * Spin box that had value changed + * @param value + * New value + */ +void +AnnotationBoundsWidget::valueChangedHelper(QDoubleSpinBox* spinBox, + float value) +{ + if (m_annotationBrowserTab != NULL) { + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + std::vector annotations { m_annotationBrowserTab }; + + if (spinBox == m_xMinCoordSpinBox) { + undoCommand->setBoundsMinX2D(value, annotations); + } + else if (spinBox == m_xMaxCoordSpinBox) { + undoCommand->setBoundsMaxX2D(value, annotations); + } + else if (spinBox == m_yMinCoordSpinBox) { + undoCommand->setBoundsMinY2D(value, annotations); + } + else if (spinBox == m_yMaxCoordSpinBox) { + undoCommand->setBoundsMaxY2D(value, annotations); + } + else { + delete undoCommand; + CaretAssertToDoFatal(); + return; + } + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + + AString errorMessage; + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + } + + /* + * Update as annotation might adjust/limit coordinates + */ + std::vector annTabs { m_annotationBrowserTab }; + updateContent(annTabs); + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + } +} diff --git a/src/GuiQt/AnnotationBoundsWidget.h b/src/GuiQt/AnnotationBoundsWidget.h new file mode 100644 index 000000000..f3f5c4b0e --- /dev/null +++ b/src/GuiQt/AnnotationBoundsWidget.h @@ -0,0 +1,97 @@ +#ifndef __ANNOTATION_BOUNDS_WIDGET_H__ +#define __ANNOTATION_BOUNDS_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include "AnnotationWidgetParentEnum.h" +#include "UserInputModeEnum.h" + +class QDoubleSpinBox; + +namespace caret { + + class AnnotationBrowserTab; + + class AnnotationBoundsWidget : public QWidget { + + Q_OBJECT + + public: + AnnotationBoundsWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, + const int32_t browserWindowIndex, + QWidget* parent = 0); + + virtual ~AnnotationBoundsWidget(); + + + // ADD_NEW_METHODS_HERE + + void updateContent(std::vector& annotationBrowserTabs); + + private slots: + void xMinValueChanged(const double value); + + void xMaxValueChanged(const double value); + + void yMinValueChanged(const double value); + + void yMaxValueChanged(const double value); + + private: + AnnotationBoundsWidget(const AnnotationBoundsWidget&); + + AnnotationBoundsWidget& operator=(const AnnotationBoundsWidget&); + + QDoubleSpinBox* createSpinBox(); + + void valueChangedHelper(QDoubleSpinBox* spinBox, + float value); + + // ADD_NEW_MEMBERS_HERE + + const UserInputModeEnum::Enum m_userInputMode; + + const AnnotationWidgetParentEnum::Enum m_parentWidgetType; + + const int32_t m_browserWindowIndex; + + QDoubleSpinBox* m_xMinCoordSpinBox; + + QDoubleSpinBox* m_xMaxCoordSpinBox; + + QDoubleSpinBox* m_yMinCoordSpinBox; + + QDoubleSpinBox* m_yMaxCoordSpinBox; + + AnnotationBrowserTab* m_annotationBrowserTab; + + }; + +#ifdef __ANNOTATION_BOUNDS_WIDGET_DECLARE__ + // +#endif // __ANNOTATION_BOUNDS_WIDGET_DECLARE__ + +} // namespace +#endif //__ANNOTATION_BOUNDS_WIDGET_H__ diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index 5d0df2114..8f909007a 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -24,6 +24,7 @@ #undef __ANNOTATION_WIDTH_HEIGHT_WIDGET_DECLARE__ #include +#include #include #include @@ -63,6 +64,7 @@ using namespace caret; AnnotationWidthHeightWidget::AnnotationWidthHeightWidget(const UserInputModeEnum::Enum userInputMode, const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, + const Qt::Orientation orientation, QWidget* parent) : QWidget(parent), m_userInputMode(userInputMode), @@ -94,12 +96,28 @@ m_browserWindowIndex(browserWindowIndex) WuQtUtilities::setWordWrappedToolTip(m_heightSpinBox, "Percentage height of 2D Shapes (Box, Image, Oval)"); - QHBoxLayout* layout = new QHBoxLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); - layout->addWidget(widthLabel); - layout->addWidget(m_widthSpinBox); - layout->addWidget(heightLabel); - layout->addWidget(m_heightSpinBox); + switch (orientation) { + case Qt::Horizontal: + { + QHBoxLayout* layout = new QHBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); + layout->addWidget(widthLabel); + layout->addWidget(m_widthSpinBox); + layout->addWidget(heightLabel); + layout->addWidget(m_heightSpinBox); + } + break; + case Qt::Vertical: + { + QGridLayout* layout = new QGridLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); + layout->addWidget(widthLabel, 0, 0); + layout->addWidget(m_widthSpinBox, 0, 1); + layout->addWidget(heightLabel, 1, 0); + layout->addWidget(m_heightSpinBox, 1, 1); + } + break; + } setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); diff --git a/src/GuiQt/AnnotationWidthHeightWidget.h b/src/GuiQt/AnnotationWidthHeightWidget.h index 7ec1d0e18..5929a2052 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.h +++ b/src/GuiQt/AnnotationWidthHeightWidget.h @@ -43,6 +43,7 @@ namespace caret { AnnotationWidthHeightWidget(const UserInputModeEnum::Enum userInputMode, const AnnotationWidgetParentEnum::Enum parentWidgetType, const int32_t browserWindowIndex, + const Qt::Orientation orientation, QWidget* parent = 0); virtual ~AnnotationWidthHeightWidget(); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index e7a9e1bd3..f2d3792b5 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -3308,12 +3308,22 @@ BrainBrowserWindowToolBar::updateDisplayedModeUserInputWidget() } } - if (userInputProcessor->getUserInputMode() != UserInputModeEnum::ANNOTATIONS) { - /* - * Delete all selected annotations and update graphics and UI. - */ - AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); - annotationManager->deselectAllAnnotationsForEditing(this->browserWindowIndex); + switch (userInputProcessor->getUserInputMode()) { + case UserInputModeEnum::ANNOTATIONS: + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + case UserInputModeEnum::VIEW: + case UserInputModeEnum::VOLUME_EDIT: + /* + * Delete all selected annotations and update graphics and UI. + */ + AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); + annotationManager->deselectAllAnnotationsForEditing(this->browserWindowIndex); + break; } } diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 2ab6985c0..2aea5af60 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -44,6 +44,7 @@ ELSE() SET(MOC_INPUT_HEADER_FILES AboutWorkbenchDialog.h + AnnotationBoundsWidget.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h AnnotationCoordinateSelectionWidget.h @@ -264,6 +265,7 @@ ENDIF() # SET(SOURCE_FILES AboutWorkbenchDialog.h +AnnotationBoundsWidget.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h AnnotationCoordinateInformation.h @@ -543,6 +545,7 @@ WuQtUtilities.h ZipSceneFileDialog.h AboutWorkbenchDialog.cxx +AnnotationBoundsWidget.cxx AnnotationChangeCoordinateDialog.cxx AnnotationColorWidget.cxx AnnotationCoordinateInformation.cxx diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index f492b174c..84893af71 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -30,6 +30,8 @@ #include #include +#include "AnnotationBoundsWidget.h" +#include "AnnotationBrowserTab.h" #include "AnnotationCoordinateSpaceWidget.h" #include "AnnotationCoordinateWidget.h" #include "AnnotationColorWidget.h" @@ -168,6 +170,10 @@ UserInputModeAnnotationsWidget::receiveEvent(Event* event) void UserInputModeAnnotationsWidget::createTileTabsEditingWidget() { + m_boundsWidget = new AnnotationBoundsWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + m_browserWindowIndex); + m_coordinateOneWidget = new AnnotationCoordinateWidget(m_inputModeAnnotations->getUserInputMode(), AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, AnnotationCoordinateWidget::COORDINATE_ONE, @@ -175,7 +181,8 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() m_widthHeightWidget = new AnnotationWidthHeightWidget(m_inputModeAnnotations->getUserInputMode(), AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, - m_browserWindowIndex); + m_browserWindowIndex, + Qt::Vertical); m_formatWidget = new AnnotationFormatWidget(m_inputModeAnnotations->getUserInputMode(), m_browserWindowIndex); @@ -183,25 +190,30 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() m_redoUndoWidget = new AnnotationRedoUndoWidget(m_inputModeAnnotations->getUserInputMode(), m_browserWindowIndex); - /* - * Connect signals for setting a coordinate with the mouse. - */ - QObject::connect(m_coordinateOneWidget, SIGNAL(signalSelectCoordinateWithMouse()), - this, SLOT(selectCoordinateOneWithMouse())); - - /* - * Layout of widgets - */ - QHBoxLayout* layout = new QHBoxLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); - layout->addWidget(m_coordinateOneWidget); - layout->addWidget(WuQtUtilities::createVerticalLineWidget()); - layout->addWidget(m_widthHeightWidget); - layout->addWidget(WuQtUtilities::createVerticalLineWidget()); - layout->addWidget(m_formatWidget); - layout->addWidget(WuQtUtilities::createVerticalLineWidget()); - layout->addWidget(m_redoUndoWidget); - layout->addStretch(); + QGridLayout* gridLayout = new QGridLayout(this); + gridLayout->setContentsMargins(2, 2, 2, 2); + gridLayout->setVerticalSpacing(0); + int column = 0; + gridLayout->addWidget(m_boundsWidget, 0, column); + gridLayout->addWidget(m_coordinateOneWidget, 1, column); + column++; + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); + column++; + gridLayout->addWidget(m_widthHeightWidget, 0, column, 2, 1, Qt::AlignTop); + column++; + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); + column++; + gridLayout->addWidget(m_formatWidget, 0, column, 2, 1, Qt::AlignTop); + column++; + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); + column++; + gridLayout->addWidget(m_redoUndoWidget, 0, column, 2, 1, Qt::AlignTop); + column++; + + for (int32_t iCol = 0; iCol < column; iCol++) { + gridLayout->setColumnStretch(iCol, 0); + } + gridLayout->setColumnStretch(column, 100); } /* @@ -238,7 +250,8 @@ UserInputModeAnnotationsWidget::createAnnotationWidget() m_widthHeightWidget = new AnnotationWidthHeightWidget(m_inputModeAnnotations->getUserInputMode(), AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, - m_browserWindowIndex); + m_browserWindowIndex, + Qt::Horizontal); m_rotationWidget = new AnnotationRotationWidget(m_inputModeAnnotations->getUserInputMode(), m_browserWindowIndex); @@ -363,6 +376,7 @@ UserInputModeAnnotationsWidget::updateWidget() std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(m_browserWindowIndex); + std::vector browserTabAnnotations; std::vector lineAnnotations; std::vector textAnnotations; std::vector fontStyleAnnotations; @@ -375,6 +389,13 @@ UserInputModeAnnotationsWidget::updateWidget() Annotation* ann = *iter; CaretAssert(ann); + if (ann->getType() == AnnotationTypeEnum::BROWSER_TAB) { + AnnotationBrowserTab* abt = dynamic_cast(ann); + if (abt != NULL) { + browserTabAnnotations.push_back(abt); + } + } + AnnotationText* annText = dynamic_cast(ann); if (annText != NULL) { textAnnotations.push_back(annText); @@ -404,6 +425,7 @@ UserInputModeAnnotationsWidget::updateWidget() /* * Note: pointers are initialized to NULL in the header file */ + if (m_boundsWidget != NULL) m_boundsWidget->updateContent(browserTabAnnotations); if (m_coordinateSpaceWidget != NULL) m_coordinateSpaceWidget->updateContent(selectedAnnotations); if (m_fontWidget != NULL) m_fontWidget->updateContent(fontStyleAnnotations); if (m_textEditorWidget != NULL) m_textEditorWidget->updateContent(textAnnotations); diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.h b/src/GuiQt/UserInputModeAnnotationsWidget.h index 5a9fa7cc6..acccc4471 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.h +++ b/src/GuiQt/UserInputModeAnnotationsWidget.h @@ -32,6 +32,7 @@ class QComboBox; namespace caret { class Annotation; + class AnnotationBoundsWidget; class AnnotationColorWidget; class AnnotationCoordinateSpaceWidget; class AnnotationCoordinateWidget; @@ -87,6 +88,8 @@ namespace caret { UserInputModeAnnotations* m_inputModeAnnotations = NULL; + AnnotationBoundsWidget* m_boundsWidget = NULL; + AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget = NULL; AnnotationCoordinateWidget* m_coordinateOneWidget = NULL; -- GitLab From 5dcabaa860d928614140f3df6feb7bc3c4ac7d00 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Aug 2019 14:26:05 -0500 Subject: [PATCH 014/584] WB-859 Manual Tile Tabs Layout System: Add checkbox to manual tab layouts in Tile Tabs Dialog so that tabs in a manual configuration can be displayed/hidden. Improved dialogs that pop-up when the number of tabs in the current configuration is different than the number of tabs in a manual layout loaded from the user configurations. --- src/Annotations/AnnotationBrowserTab.cxx | 25 ++++- src/Annotations/AnnotationBrowserTab.h | 7 ++ src/Brain/BrainOpenGLViewportContent.cxx | 6 +- src/Common/TileTabsBrowserTabGeometry.cxx | 35 ++++-- src/Common/TileTabsBrowserTabGeometry.h | 9 +- .../TileTabsLayoutManualConfiguration.cxx | 9 ++ .../TileTabsLayoutManualConfiguration.h | 2 + src/GuiQt/TileTabsConfigurationDialog.cxx | 100 +++++++++++++++--- src/GuiQt/TileTabsManualTabGeometryWidget.cxx | 25 +++++ src/GuiQt/TileTabsManualTabGeometryWidget.h | 5 + .../TileTabsBrowserTabGeometrySceneHelper.cxx | 8 +- 11 files changed, 206 insertions(+), 25 deletions(-) diff --git a/src/Annotations/AnnotationBrowserTab.cxx b/src/Annotations/AnnotationBrowserTab.cxx index d42d05724..81d00beb4 100644 --- a/src/Annotations/AnnotationBrowserTab.cxx +++ b/src/Annotations/AnnotationBrowserTab.cxx @@ -201,6 +201,26 @@ AnnotationBrowserTab::getTabIndex() const return m_tabIndex; } +/** + * @return Display status of tab + */ +bool +AnnotationBrowserTab::isBrowserTabDisplayed() const +{ + return m_displayStatus; +} + +/** + * Set the display status of this tab + * + * @param status + * New display status for this tab + */ +void +AnnotationBrowserTab::setBrowserTabDisplayed(const bool status) +{ + m_displayStatus = status; +} /** * Set the browser tab annotation dimensions using the tile tabs geometry @@ -216,7 +236,8 @@ AnnotationBrowserTab::setFromTileTabsGeometry(const TileTabsBrowserTabGeometry* geometry->getMaxX(), geometry->getMinY(), geometry->getMaxY()); - m_stackingOrder = geometry->getStackingOrder(); + m_displayStatus = geometry->isDisplayed(); + m_stackingOrder = geometry->getStackingOrder(); m_backgroundType = geometry->getBackgroundType(); } @@ -235,6 +256,7 @@ AnnotationBrowserTab::getTileTabsGeometry(TileTabsBrowserTabGeometry* geometryOu getBounds2D(minX, maxX, minY, maxY); geometryOut->setBounds(minX, maxX, minY, maxY); + geometryOut->setDisplayed(m_displayStatus); geometryOut->setStackingOrder(m_stackingOrder); geometryOut->setBackgroundType(m_backgroundType); } @@ -340,6 +362,7 @@ AnnotationBrowserTab::setBackgroundType(const TileTabsLayoutBackgroundTypeEnum:: * @return true if this and the given geometry intersect. * NOTE: if 'other' is 'this' true is returned (overlaps self) but this * could change so it is best to avoid testing overlap of self. + * NOTE: Display status is ignored * * @param other * Other geometry for intersection test diff --git a/src/Annotations/AnnotationBrowserTab.h b/src/Annotations/AnnotationBrowserTab.h index 252d8c6b9..53b33902f 100644 --- a/src/Annotations/AnnotationBrowserTab.h +++ b/src/Annotations/AnnotationBrowserTab.h @@ -53,6 +53,10 @@ namespace caret { const BrowserTabContent* getBrowserTabContent() const; + bool isBrowserTabDisplayed() const; + + void setBrowserTabDisplayed(const bool status); + int32_t getTabIndex() const; int32_t getStackingOrder() const; @@ -99,6 +103,9 @@ namespace caret { /** Browser tab that owns this annotation DO NOT DELETE */ BrowserTabContent* m_browserTabContent = NULL; + /** Display status of browser tab */ + bool m_displayStatus = true; + /** Index of browser tab that owns this annotation */ int32_t m_tabIndex = -1; diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 798cd51fc..744a00827 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -1024,10 +1024,14 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vectorgetManualLayoutBrowserTabAnnotation(); + if ( ! tabAnnotation->isBrowserTabDisplayed()) { + continue; + } + /* * Tab Geometry is in percentages ranging [0.0, 100.0] */ - const AnnotationBrowserTab* tabAnnotation = tab->getManualLayoutBrowserTabAnnotation(); float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); tabAnnotation->getBounds2D(minX, maxX, minY, maxY); const float tabAnnWidth(maxX - minX); diff --git a/src/Common/TileTabsBrowserTabGeometry.cxx b/src/Common/TileTabsBrowserTabGeometry.cxx index 5e3900676..29295190b 100644 --- a/src/Common/TileTabsBrowserTabGeometry.cxx +++ b/src/Common/TileTabsBrowserTabGeometry.cxx @@ -102,11 +102,12 @@ TileTabsBrowserTabGeometry::operator=(const TileTabsBrowserTabGeometry& obj) void TileTabsBrowserTabGeometry::copyHelperTileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj) { - m_tabIndex = obj.m_tabIndex; - m_minX = obj.m_minX; - m_maxX = obj.m_maxX; - m_minY = obj.m_minY; - m_maxY = obj.m_maxY; + m_displayFlag = obj.m_displayFlag; + m_tabIndex = obj.m_tabIndex; + m_minX = obj.m_minX; + m_maxX = obj.m_maxX; + m_minY = obj.m_minY; + m_maxY = obj.m_maxY; m_stackingOrder = obj.m_stackingOrder; m_backgroundType = obj.m_backgroundType; } @@ -143,7 +144,8 @@ TileTabsBrowserTabGeometry::toString() const QTextStream ts(&str); ts << "TileTabsBrowserTabGeometry: " - << "m_tabIndex=" << m_tabIndex + << "m_displayFlag=" << AString::fromBool(m_displayFlag) + << " m_tabIndex=" << m_tabIndex << " m_minX=" << m_minX << " m_maxX=" << m_maxX << " m_minY=" << m_minY @@ -154,6 +156,27 @@ TileTabsBrowserTabGeometry::toString() const return str; } +/** + * @return The display status + */ +bool +TileTabsBrowserTabGeometry::isDisplayed() const +{ + return m_displayFlag; +} + +/** + * Set the display status + * + * @param status + * New display status + */ +void +TileTabsBrowserTabGeometry::setDisplayed(const bool status) +{ + m_displayFlag = status; +} + /** * Set the bounds * diff --git a/src/Common/TileTabsBrowserTabGeometry.h b/src/Common/TileTabsBrowserTabGeometry.h index 94756b6aa..0a394aded 100644 --- a/src/Common/TileTabsBrowserTabGeometry.h +++ b/src/Common/TileTabsBrowserTabGeometry.h @@ -46,6 +46,10 @@ namespace caret { int32_t getTabIndex() const; + bool isDisplayed() const; + + void setDisplayed(const bool status); + void setBounds(const float minX, const float maxX, const float minY, @@ -109,8 +113,11 @@ namespace caret { private: void copyHelperTileTabsBrowserTabGeometry(const TileTabsBrowserTabGeometry& obj); + /** display status of tab */ + bool m_displayFlag = true; + /** index of tab */ - int32_t m_tabIndex; + int32_t m_tabIndex = -1; /** left as percentage*/ float m_minX = 10.0; diff --git a/src/Common/TileTabsLayoutManualConfiguration.cxx b/src/Common/TileTabsLayoutManualConfiguration.cxx index 7ec3c798c..845d672fd 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.cxx +++ b/src/Common/TileTabsLayoutManualConfiguration.cxx @@ -333,6 +333,8 @@ TileTabsLayoutManualConfiguration::encodeInXMLString(AString& xmlTextOut) const for (const auto& tabInfo : m_tabInfo) { writer.writeStartElement(s_tabInfoElementName); + writer.writeAttribute(s_tabInfoAttributeDisplayStatus, + AString::fromBool(tabInfo->isDisplayed())); writer.writeAttribute(s_tabInfoAttributeTabIndex, AString::number(tabInfo->getTabIndex())); writer.writeAttribute(s_tabInfoAttributeMinX, @@ -429,6 +431,7 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, bool maxYValid(false); bool stackingValid(false); const QXmlStreamAttributes atts = xml.attributes(); + AString displayStatusText = atts.value(s_tabInfoAttributeDisplayStatus).toString(); const int32_t tabIndex = atts.value(s_tabInfoAttributeTabIndex).toInt(&tabIndexValid); const float minX = atts.value(s_tabInfoAttributeMinX).toFloat(&minXValid); const float maxX = atts.value(s_tabInfoAttributeMaxX).toFloat(&maxXValid); @@ -438,6 +441,11 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, const QString backStr = atts.value(s_tabInfoAttributeBackground).toString(); const TileTabsLayoutBackgroundTypeEnum::Enum backType = TileTabsLayoutBackgroundTypeEnum::fromName(backStr, NULL); + if (displayStatusText.isEmpty()) { + displayStatusText = "true"; + } + const bool displayStatus = displayStatusText.toBool(); + if (tabIndexValid && minXValid && maxXValid @@ -449,6 +457,7 @@ TileTabsLayoutManualConfiguration::decodeFromXMLString(QXmlStreamReader& xml, tabInfo->setMaxX(maxX); tabInfo->setMinY(minY); tabInfo->setMaxY(maxY); + tabInfo->setDisplayed(displayStatus); tabInfo->setStackingOrder(stacking); tabInfo->setBackgroundType(backType); diff --git a/src/Common/TileTabsLayoutManualConfiguration.h b/src/Common/TileTabsLayoutManualConfiguration.h index ee0bc1db6..68fd94330 100644 --- a/src/Common/TileTabsLayoutManualConfiguration.h +++ b/src/Common/TileTabsLayoutManualConfiguration.h @@ -91,6 +91,7 @@ namespace caret { static const AString s_rootElementAttributeValueVersionOne; static const AString s_tabInfoElementName; + static const AString s_tabInfoAttributeDisplayStatus; static const AString s_tabInfoAttributeTabIndex; static const AString s_tabInfoAttributeMinX; static const AString s_tabInfoAttributeMaxX; @@ -111,6 +112,7 @@ namespace caret { const AString TileTabsLayoutManualConfiguration::s_rootElementAttributeValueVersionOne = "1"; const AString TileTabsLayoutManualConfiguration::s_tabInfoElementName = "TabInfo"; + const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeDisplayStatus = "DisplayStatus"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeTabIndex = "TabIndex"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMinX = "MinX"; const AString TileTabsLayoutManualConfiguration::s_tabInfoAttributeMaxX = "MaxX"; diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 2c697db8c..7aff7360d 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -448,39 +448,100 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() getBrowserWindow()->getAllTabContent(allTabContent); int32_t numBrowserTabs = static_cast(allTabContent.size()); + /* + * Display status of tabs must be set after + * configuration is copied from User Configurations + */ + std::set tabsWithDisplayStatusOn; + std::set tabsWithDisplayStatusOff; + if (numBrowserTabs == numConfigTabs) { /* OK */ } else { - AString msg("The are " + AString msg("" + "The Window contains " + AString::number(numBrowserTabs) - + " tabs in the window but the layout has space for " + + " tabs.
" + "The Layout has space for " + AString::number(numConfigTabs) - + " tabs.

"); + + " tabs" + "

"); if (numBrowserTabs < numConfigTabs) { - msg.append("Do you want to add tabs to available spaces in the layout?"); - switch (WuQMessageBox::warningYesNoCancel(m_loadConfigurationPushButton, msg, "")) { - case WuQMessageBox::RESULT_CANCEL: - return; - break; - case WuQMessageBox::RESULT_NO: - break; - case WuQMessageBox::RESULT_YES: - { + msg.append("Do you want to add tabs to fill layout?:"); + WuQDataEntryDialog dialog("Load Configuration", + m_loadConfigurationPushButton, + WuQDialogNonModal::SCROLL_AREA_NEVER); + dialog.setTextAtTop(msg, true); + QRadioButton* yesRadioButton = dialog.addRadioButton("Yes, add tabs to fill layout"); + QRadioButton* yesDisableDisplayRadioButton = dialog.addRadioButton("Yes, add tabs but disable display of them"); + QRadioButton* noRadioButton = dialog.addRadioButton("No, discard extra spaces in layout"); + yesDisableDisplayRadioButton->setChecked(true); + if (dialog.exec() == WuQDataEntryDialog::Accepted) { + bool addTabsFlag(false); + bool showTabsFlag(false); + if (yesRadioButton->isChecked()) { + addTabsFlag = true; + showTabsFlag = true; + } + else if (yesDisableDisplayRadioButton->isChecked()) { + addTabsFlag = true; + } + else if (noRadioButton->isChecked()) { + /* No action needed */ + } + else { + CaretAssert(0); + } + + if (addTabsFlag) { const int32_t numTabsToAdd = numConfigTabs - numBrowserTabs; for (int32_t i = 0; i < numTabsToAdd; i++) { EventBrowserTabNewInGUI newTabEvent; EventManager::get()->sendEvent(newTabEvent.getPointer()); + BrowserTabContent* btc = newTabEvent.getBrowserTab(); +// if (btc != NULL) { +// btc->getManualLayoutBrowserTabAnnotation()->setBrowserTabDisplayed(showTabsFlag); +// } updateGraphicsWindow(); + if (btc != NULL) { + if (showTabsFlag) { + tabsWithDisplayStatusOn.insert(btc); + } + else { + tabsWithDisplayStatusOff.insert(btc); + } +// btc->getManualLayoutBrowserTabAnnotation()->setBrowserTabDisplayed(showTabsFlag); + } } } - break; } + else { + return; + } +// msg.append("Do you want to add tabs to available spaces in the layout?"); +// switch (WuQMessageBox::warningYesNoCancel(m_loadConfigurationPushButton, msg, "")) { +// case WuQMessageBox::RESULT_CANCEL: +// return; +// break; +// case WuQMessageBox::RESULT_NO: +// break; +// case WuQMessageBox::RESULT_YES: +// { +// const int32_t numTabsToAdd = numConfigTabs - numBrowserTabs; +// for (int32_t i = 0; i < numTabsToAdd; i++) { +// EventBrowserTabNewInGUI newTabEvent; +// EventManager::get()->sendEvent(newTabEvent.getPointer()); +// updateGraphicsWindow(); +// } +// } +// break; +// } } else { msg.append("Do you want to:"); - WuQDataEntryDialog dialog("New Configuration", + WuQDataEntryDialog dialog("Load Configuration", m_loadConfigurationPushButton, WuQDialogNonModal::SCROLL_AREA_NEVER); dialog.setTextAtTop(msg, true); @@ -547,6 +608,14 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() CaretAssert(configGeometry); browserTabAnnotation->setFromTileTabsGeometry(configGeometry); + + BrowserTabContent* btc = browserTabAnnotation->getBrowserTabContent(); + if (tabsWithDisplayStatusOn.find(btc) != tabsWithDisplayStatusOn.end()) { + browserTabAnnotation->setBrowserTabDisplayed(true); + } + else if (tabsWithDisplayStatusOff.find(btc) != tabsWithDisplayStatusOff.end()) { + browserTabAnnotation->setBrowserTabDisplayed(false); + } } else { if (i < numViewportContent) { @@ -1067,7 +1136,8 @@ TileTabsConfigurationDialog::addManualGeometryWidget(QGridLayout* gridLayout, int32_t rowIndex = gridLayout->rowCount(); gridLayout->setHorizontalSpacing(8); - gridLayout->addWidget(new QLabel("Tab"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Show"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Name"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Left"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Right"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Bottom"), rowIndex, columnIndex++, Qt::AlignLeft); diff --git a/src/GuiQt/TileTabsManualTabGeometryWidget.cxx b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx index 71a951a6b..8e414419e 100644 --- a/src/GuiQt/TileTabsManualTabGeometryWidget.cxx +++ b/src/GuiQt/TileTabsManualTabGeometryWidget.cxx @@ -23,6 +23,7 @@ #include "TileTabsManualTabGeometryWidget.h" #undef __TILE_TABS_MANUAL_TAB_GEOMETRY_WIDGET_DECLARE__ +#include #include #include #include @@ -67,6 +68,10 @@ m_index(index) CaretAssert(tileTabsConfigurationDialog); CaretAssert(gridLayout); + m_showTabCheckBox = new QCheckBox(""); + QObject::connect(m_showTabCheckBox, &QCheckBox::clicked, + this, &TileTabsManualTabGeometryWidget::showCheckBoxClicked); + m_tabNumberLabel = new QLabel(" "); m_tabNumberLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -105,6 +110,7 @@ m_index(index) m_gridLayoutGroup = new WuQGridLayoutGroup(gridLayout); const int32_t rowIndex(gridLayout->rowCount()); int32_t columnIndex(0); + m_gridLayoutGroup->addWidget(m_showTabCheckBox, rowIndex, columnIndex++, Qt::AlignHCenter); m_gridLayoutGroup->addWidget(m_tabNumberLabel, rowIndex, columnIndex++, Qt::AlignLeft); m_gridLayoutGroup->addWidget(m_xMinSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); m_gridLayoutGroup->addWidget(m_xMaxSpinBox, rowIndex, columnIndex++, Qt::AlignHCenter); @@ -144,6 +150,7 @@ TileTabsManualTabGeometryWidget::updateContent(BrowserTabContent* browserTabCont updatePercentSpinBox(m_yMinSpinBox, minY); updatePercentSpinBox(m_yMaxSpinBox, maxY); + m_showTabCheckBox->setChecked(annotationBrowserTab->isBrowserTabDisplayed()); const TileTabsLayoutBackgroundTypeEnum::Enum background = annotationBrowserTab->getBackgroundType(); m_TileTabsLayoutBackgroundTypeEnumComboBox->setSelectedItem(background); @@ -213,6 +220,24 @@ TileTabsManualTabGeometryWidget::createPercentSpinBox(const QString& toolTip, return dsb; } +/** + * Called when show checkbox is clicked + * + * @param status + * New checked status + */ +void +TileTabsManualTabGeometryWidget::showCheckBoxClicked(bool status) +{ + CaretAssert(m_browserTabContent); + if (m_browserTabContent != NULL) { + AnnotationBrowserTab* annotationBrowserTab = m_browserTabContent->getManualLayoutBrowserTabAnnotation(); + CaretAssert(annotationBrowserTab); + annotationBrowserTab->setBrowserTabDisplayed(status); + emit itemChanged(); + } +} + /** * Called when x-min value is changed * diff --git a/src/GuiQt/TileTabsManualTabGeometryWidget.h b/src/GuiQt/TileTabsManualTabGeometryWidget.h index 5d75d854c..17320dac6 100644 --- a/src/GuiQt/TileTabsManualTabGeometryWidget.h +++ b/src/GuiQt/TileTabsManualTabGeometryWidget.h @@ -27,6 +27,7 @@ #include +class QCheckBox; class QGridLayout; class QLabel; class QDoubleSpinBox; @@ -63,6 +64,8 @@ namespace caret { void itemChanged(); private slots: + void showCheckBoxClicked(bool status); + void xMinSpinBoxValueChanged(double value); void xMaxSpinBoxValueChanged(double value); @@ -89,6 +92,8 @@ namespace caret { BrowserTabContent* m_browserTabContent = NULL; + QCheckBox* m_showTabCheckBox; + QLabel* m_tabNumberLabel; QDoubleSpinBox* m_xMinSpinBox; diff --git a/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx index 8b3dd3f09..9610688b1 100644 --- a/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx +++ b/src/Scenes/TileTabsBrowserTabGeometrySceneHelper.cxx @@ -51,6 +51,8 @@ m_geometry(geometry) CaretAssert(m_geometry); m_sceneAssistant = std::unique_ptr(new SceneClassAssistant()); + m_sceneAssistant->add("m_displayFlag", + &m_geometry->m_displayFlag); m_sceneAssistant->add("m_tabIndex", &m_geometry->m_tabIndex); m_sceneAssistant->add("m_minX", @@ -132,7 +134,11 @@ TileTabsBrowserTabGeometrySceneHelper::restoreFromScene(const SceneAttributes* s } m_sceneAssistant->restoreMembers(sceneAttributes, - sceneClass); + sceneClass); + + if ( ! sceneClass->getPrimitive("m_displayFlag")) { + m_geometry->m_displayFlag = true; + } //Uncomment if sub-classes must restore from scene //restoreSubClassDataFromScene(sceneAttributes, -- GitLab From efa9194fcce1310845e2ded71ae706b7a9a761fc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Aug 2019 14:43:56 -0500 Subject: [PATCH 015/584] WB-859 Manual Tile Tabs Layout System: Clean up unused member in BrowserTabContent. --- src/Brain/BrowserTabContent.cxx | 11 ++++++----- src/Brain/BrowserTabContent.h | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Brain/BrowserTabContent.cxx b/src/Brain/BrowserTabContent.cxx index ba116361a..3e4dd52e9 100644 --- a/src/Brain/BrowserTabContent.cxx +++ b/src/Brain/BrowserTabContent.cxx @@ -159,7 +159,6 @@ BrowserTabContent::BrowserTabContent(const int32_t tabNumber) m_manualLayoutBrowserTabAnnotation.reset(new AnnotationBrowserTab(AnnotationAttributesDefaultTypeEnum::NORMAL)); //;m_tabNumber)); m_manualLayoutBrowserTabAnnotation->setBrowserTabContent(this, m_tabNumber); - m_manualLayoutTabGeometry.reset(new TileTabsBrowserTabGeometry(m_tabNumber)); m_sceneClassAssistant = new SceneClassAssistant(); m_sceneClassAssistant->add("m_tabNumber", @@ -3594,8 +3593,9 @@ BrowserTabContent::saveToScene(const SceneAttributes* sceneAttributes, m_obliqueVolumeRotationMatrix->getMatrixForOpenGL(obliqueMatrix); sceneClass->addFloatArray("m_obliqueVolumeRotationMatrix", obliqueMatrix, 16); - m_manualLayoutBrowserTabAnnotation->getTileTabsGeometry(m_manualLayoutTabGeometry.get()); - TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); + TileTabsBrowserTabGeometry manualLayoutTabGeometry(m_tabNumber); + m_manualLayoutBrowserTabAnnotation->getTileTabsGeometry(&manualLayoutTabGeometry); + TileTabsBrowserTabGeometrySceneHelper geometryHelper(&manualLayoutTabGeometry); sceneClass->addClass(geometryHelper.saveToScene(sceneAttributes, "m_manualLayoutTabGeometry")); @@ -3628,10 +3628,11 @@ BrowserTabContent::restoreFromScene(const SceneAttributes* sceneAttributes, m_brainModelYokingGroup = YokingGroupEnum::YOKING_GROUP_A; m_chartModelYokingGroup = YokingGroupEnum::YOKING_GROUP_OFF; - TileTabsBrowserTabGeometrySceneHelper geometryHelper(m_manualLayoutTabGeometry.get()); + TileTabsBrowserTabGeometry manualLayoutTabGeometry(m_tabNumber); + TileTabsBrowserTabGeometrySceneHelper geometryHelper(&manualLayoutTabGeometry); geometryHelper.restoreFromScene(sceneAttributes, sceneClass->getClass("m_manualLayoutTabGeometry")); - m_manualLayoutBrowserTabAnnotation->setFromTileTabsGeometry(m_manualLayoutTabGeometry.get()); + m_manualLayoutBrowserTabAnnotation->setFromTileTabsGeometry(&manualLayoutTabGeometry); m_sceneClassAssistant->restoreMembers(sceneAttributes, sceneClass); diff --git a/src/Brain/BrowserTabContent.h b/src/Brain/BrowserTabContent.h index b42588c17..fd6c9a086 100644 --- a/src/Brain/BrowserTabContent.h +++ b/src/Brain/BrowserTabContent.h @@ -64,7 +64,6 @@ namespace caret { class PlainTextStringBuilder; class SceneClassAssistant; class Surface; - class TileTabsBrowserTabGeometry; class ViewingTransformations; class ViewingTransformationsCerebellum; class ViewingTransformationsVolume; @@ -597,9 +596,6 @@ namespace caret { */ bool isExecutingConstructor; - /** Manual tab layout geometry */ - std::unique_ptr m_manualLayoutTabGeometry; - /** Manual layout brower tab annotation */ std::unique_ptr m_manualLayoutBrowserTabAnnotation; -- GitLab From 536d77ebfd601df0ac0815427757aa06402f7442 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 23 Aug 2019 15:46:54 -0500 Subject: [PATCH 016/584] WB-859 Manual Tile Tabs Layout System: Updated 'wb_command -show-scene' for manual tile tab layouts. Also, replaced a few CaretAssertToDoFatal() assertions with the needed code. --- src/Brain/BrainOpenGLViewportContent.cxx | 2 +- src/Brain/BrowserWindowContent.cxx | 10 +++-- src/Brain/BrowserWindowContent.h | 4 +- src/Common/CaretPreferences.cxx | 11 +++++- src/Common/CaretPreferences.h | 2 +- src/GuiQt/AnnotationBoundsWidget.cxx | 2 +- src/GuiQt/BrainBrowserWindow.cxx | 9 ++++- src/GuiQt/BrainOpenGLWidget.cxx | 2 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 3 +- src/Operations/OperationShowScene.cxx | 45 ++++++++++++++--------- 10 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 744a00827..875624e14 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -618,7 +618,7 @@ BrainOpenGLViewportContent::createViewportContentForTileTabs(std::vectorgetSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsGridConfiguration(); CaretAssert(tileTabsConfiguration); viewportContentsOut = createViewportContentForGridTileTabs(tabContents, browserWindowContent, diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index 703394d5d..308dbb57a 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -215,9 +215,11 @@ BrowserWindowContent::setTileTabsEnabled(const bool tileTabsEnabled) * @return The selected tile tabs configuration. * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. + * Will return NULL if the selected tile tabs configuration is + * neither AUTO nor CUSTOM grid. */ TileTabsLayoutBaseConfiguration* -BrowserWindowContent::getSelectedTileTabsConfiguration() +BrowserWindowContent::getSelectedTileTabsGridConfiguration() { TileTabsLayoutBaseConfiguration* configMode = NULL; @@ -241,9 +243,11 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() * @return The selected tile tabs configuration (const method) * This will be the automatic configuration when automatic is selected, * otherwise it is the custom configuration. + * Will return NULL if the selected tile tabs configuration is + * neither AUTO nor CUSTOM grid. */ const TileTabsLayoutBaseConfiguration* -BrowserWindowContent::getSelectedTileTabsConfiguration() const +BrowserWindowContent::getSelectedTileTabsGridConfiguration() const { TileTabsLayoutBaseConfiguration* configMode = NULL; @@ -255,7 +259,7 @@ BrowserWindowContent::getSelectedTileTabsConfiguration() const configMode = m_customGridTileTabsConfiguration.get(); break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: - CaretAssertToDoFatal(); + return NULL; break; } CaretAssert(configMode); diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index 0e57304c1..f0e0db55f 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -66,9 +66,9 @@ namespace caret { void setTileTabsEnabled(const bool tileTabsEnabled); - TileTabsLayoutBaseConfiguration* getSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* getSelectedTileTabsGridConfiguration(); - const TileTabsLayoutBaseConfiguration* getSelectedTileTabsConfiguration() const; + const TileTabsLayoutBaseConfiguration* getSelectedTileTabsGridConfiguration() const; TileTabsLayoutGridConfiguration* getAutomaticGridTileTabsConfiguration(); diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 4ef29c01a..61c15e82e 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -564,13 +564,22 @@ CaretPreferences::readTileTabsUserConfigurations(const bool performSync) * @return A vector containing pairs of Name and Unique Identifier for each * Tile Tabs configuration. The items are sorted by name with 'first' being * the name, and 'second' being the unique identifier. + * + * @param includeManualConfigurationsFlag + * If true, include manual configurations; if false exclude manual configurations */ std::vector> -CaretPreferences::getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const +CaretPreferences::getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(const bool includeManualConfigurationsFlag) const { std::vector> nameIDs; for (const auto ttc : this->tileTabsConfigurations) { + if (ttc->getLayoutType() == TileTabsLayoutConfigurationTypeEnum::MANUAL) { + if ( ! includeManualConfigurationsFlag) { + continue; + } + } + QString typeString; switch (ttc->getLayoutType()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: diff --git a/src/Common/CaretPreferences.h b/src/Common/CaretPreferences.h index f6de7a89f..8d0fe8a2d 100644 --- a/src/Common/CaretPreferences.h +++ b/src/Common/CaretPreferences.h @@ -138,7 +138,7 @@ namespace caret { void readTileTabsUserConfigurations(const bool performSync = true); - std::vector> getTileTabsUserConfigurationsNamesAndUniqueIdentifiers() const; + std::vector> getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(const bool includeManualConfigurationsFlag) const; std::unique_ptr getCopyOfTileTabsUserConfigurationByUniqueIdentifier(const AString& uniqueIdentifier) const; diff --git a/src/GuiQt/AnnotationBoundsWidget.cxx b/src/GuiQt/AnnotationBoundsWidget.cxx index 6a5aeb3e0..66b79e493 100644 --- a/src/GuiQt/AnnotationBoundsWidget.cxx +++ b/src/GuiQt/AnnotationBoundsWidget.cxx @@ -268,7 +268,7 @@ AnnotationBoundsWidget::valueChangedHelper(QDoubleSpinBox* spinBox, } else { delete undoCommand; - CaretAssertToDoFatal(); + CaretAssert(0); return; } diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index 1b9805a2b..c7f4c8f33 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -2604,8 +2604,9 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow() const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); + const bool includeManualConfigurationsFlag(false); std::vector> nameUniqueIDs = - prefs->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(); + prefs->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(includeManualConfigurationsFlag); for (const auto nameID : nameUniqueIDs) { /* @@ -2680,7 +2681,11 @@ BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QA } break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: - CaretAssertToDoFatal(); + /* + * The method processViewTileTabsLoadUserConfigurationMenuAboutToShow() + * excludes manual configurations so we should never get here. + */ + CaretAssert(0); break; } diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 504412437..3eba0ef30 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -590,7 +590,7 @@ BrainOpenGLWidget::getDrawingWindowContent(const int32_t windowViewportIn[4], /* * Determine if default configuration for tiles */ - TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsConfiguration(); + TileTabsLayoutBaseConfiguration* tileTabsConfiguration = browserWindowContent->getSelectedTileTabsGridConfiguration(); CaretAssert(tileTabsConfiguration); TileTabsLayoutGridConfiguration* gridConfiguration = tileTabsConfiguration->castToGridConfiguration(); diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 7aff7360d..61fb6a2c1 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -1609,8 +1609,9 @@ TileTabsConfigurationDialog::updateDialog() QSignalBlocker blocker(m_userConfigurationSelectionListWidget); m_userConfigurationSelectionListWidget->clear(); + const bool includeManualConfigurationsFlag(true); std::vector> nameUniqueIDs = - m_caretPreferences->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(); + m_caretPreferences->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(includeManualConfigurationsFlag); for (const auto nameID : nameUniqueIDs) { /* diff --git a/src/Operations/OperationShowScene.cxx b/src/Operations/OperationShowScene.cxx index 62ba3fafe..bdb4eb78d 100644 --- a/src/Operations/OperationShowScene.cxx +++ b/src/Operations/OperationShowScene.cxx @@ -464,13 +464,22 @@ OperationShowScene::useParameters(OperationParameters* myParams, if (restoreToTabTiles) { CaretPointer brainOpenGL(createBrainOpenGL()); - TileTabsLayoutBaseConfiguration* tileTabsConfiguration = bwc->getSelectedTileTabsConfiguration(); - CaretAssert(tileTabsConfiguration); + TileTabsLayoutGridConfiguration* gridConfig = NULL; //tileTabsConfiguration->castToGridConfiguration(); + bool manualFlag(false); + switch (bwc->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + gridConfig = bwc->getCustomGridTileTabsConfiguration(); + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + gridConfig = bwc->getCustomGridTileTabsConfiguration(); + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + manualFlag = true; + break; + } - TileTabsLayoutGridConfiguration* gridConfig = tileTabsConfiguration->castToGridConfiguration(); - TileTabsLayoutManualConfiguration* manualConfig = tileTabsConfiguration->castToManualConfiguration(); - - if (gridConfig != NULL) { + if ((gridConfig != NULL) + || manualFlag) { const std::vector tabIndices = bwc->getSceneTabIndices(); if ( ! tabIndices.empty()) { std::vector allTabContent; @@ -494,15 +503,18 @@ OperationShowScene::useParameters(OperationParameters* myParams, if (numTabContent <= 0) { throw OperationException("Failed to find any tab content"); } - std::vector rowHeights; - std::vector columnWidths; - if ( ! gridConfig->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, - windowHeight, - numTabContent, - bwc->getTileTabsConfigurationMode(), - rowHeights, - columnWidths)) { - throw OperationException("Tile Tabs Row/Column sizing failed !!!"); + + if (gridConfig != NULL) { + std::vector rowHeights; + std::vector columnWidths; + if ( ! gridConfig->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, + numTabContent, + bwc->getTileTabsConfigurationMode(), + rowHeights, + columnWidths)) { + throw OperationException("Tile Tabs Row/Column sizing failed !!!"); + } } const int32_t tabIndexToHighlight = -1; @@ -540,9 +552,6 @@ OperationShowScene::useParameters(OperationParameters* myParams, viewports.clear(); } } - else if (manualConfig != NULL) { - CaretAssertToDoFatal(); - } else { throw OperationException("Tile tabs configuration is neither Grid nor Manual"); } -- GitLab From ff459cb1eb339d0280b5d0640c67893bfd28bea1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Aug 2019 11:02:41 -0500 Subject: [PATCH 017/584] WB-859 Manual Tile Tabs Layout System: Revised saving of tile tab configurations to preferences. Grid and manual configurations are read/written separately so that older versions of wb_view can read the grid configurations while ignoring (and not altering) the manual configurations. --- src/Common/CaretPreferences.cxx | 92 ++++++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/src/Common/CaretPreferences.cxx b/src/Common/CaretPreferences.cxx index 61c15e82e..b8dc6ebaf 100644 --- a/src/Common/CaretPreferences.cxx +++ b/src/Common/CaretPreferences.cxx @@ -459,14 +459,61 @@ CaretPreferences::removeAllTileTabsConfigurations() void CaretPreferences::writeTileTabsUserConfigurations() { + /* + * NOTE: The GRID and MANUAL configurations are written separately. + * Older versions of wb_view will correctly read the GRID configurations + * and ignore the MANUAL configurations (not log error messages). + * Newer versions of wb_view will read both. + */ + + /* + * Write only GRID configurations to "NAME_TILE_TABS_CONFIGURATIONS", + * This allows previous versions of the software to read the configurations + */ this->qSettings->beginWriteArray(NAME_TILE_TABS_CONFIGURATIONS); const int32_t numViews = static_cast(this->tileTabsConfigurations.size()); + int32_t gridConfigCounter(0); for (int32_t i = 0; i < numViews; i++) { - this->qSettings->setArrayIndex(i); - this->qSettings->setValue(AString::number(i), - this->tileTabsConfigurations[i]->encodeInXML()); + CaretAssertVectorIndex(this->tileTabsConfigurations, i); + const TileTabsLayoutBaseConfiguration* config = this->tileTabsConfigurations[i]; + switch (config->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + this->qSettings->setArrayIndex(gridConfigCounter); + this->qSettings->setValue(AString::number(gridConfigCounter), + config->encodeInXML()); + gridConfigCounter++; + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + break; + } + } + this->qSettings->endArray(); + + /* + * Write only MANUAL configurations to "NAME_TILE_TABS_CONFIGURATIONS_TWO", + * Older versions of the software will not try to read these configurations + */ + this->qSettings->beginWriteArray(NAME_TILE_TABS_CONFIGURATIONS_TWO); + int32_t manualConfigCounter(0); + for (int32_t i = 0; i < numViews; i++) { + CaretAssertVectorIndex(this->tileTabsConfigurations, i); + const TileTabsLayoutBaseConfiguration* config = this->tileTabsConfigurations[i]; + switch (config->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + this->qSettings->setArrayIndex(manualConfigCounter); + this->qSettings->setValue(AString::number(manualConfigCounter), + config->encodeInXML()); + manualConfigCounter++; + break; + } } this->qSettings->endArray(); + this->qSettings->sync(); } @@ -489,12 +536,42 @@ CaretPreferences::readTileTabsUserConfigurations(const bool performSync) this->removeAllTileTabsConfigurations(); /* - * Read Configurations + * NOTE: The GRID and MANUAL configurations are written separately. + * Older versions of wb_view will correctly read the GRID configurations + * and ignore the MANUAL configurations (not log error messages). + * Newer versions of wb_view will read both. */ - const int numConfigurations = this->qSettings->beginReadArray(NAME_TILE_TABS_CONFIGURATIONS); - for (int i = 0; i < numConfigurations; i++) { + std::vector configurationStrings; + + /* + * Read GRID Configurations (Array Name: NAME_TILE_TABS_CONFIGURATIONS) + */ + const int numGridConfigs = this->qSettings->beginReadArray(NAME_TILE_TABS_CONFIGURATIONS); + for (int32_t i = 0; i < numGridConfigs; i++) { this->qSettings->setArrayIndex(i); - const AString configString = this->qSettings->value(AString::number(i)).toString(); + const AString str = this->qSettings->value(AString::number(i)).toString(); + configurationStrings.push_back(str); + } + this->qSettings->endArray(); + + /* + * Read MANUAL Configurations (Array Name: NAME_TILE_TABS_CONFIGURATIONS_TWO) + */ + const int numManualConfigs = this->qSettings->beginReadArray(NAME_TILE_TABS_CONFIGURATIONS_TWO); + for (int32_t i = 0; i < numManualConfigs; i++) { + this->qSettings->setArrayIndex(i); + const AString str = this->qSettings->value(AString::number(i)).toString(); + configurationStrings.push_back(str); + } + this->qSettings->endArray(); + + /* + * Read from the configuration strings to create layouts + */ + const int numConfigurations = static_cast(configurationStrings.size()); + for (int i = 0; i < numConfigurations; i++) { + CaretAssertVectorIndex(configurationStrings, i); + const AString configString = configurationStrings[i]; AString errorMessage; TileTabsLayoutBaseConfiguration* ttc = TileTabsLayoutBaseConfiguration::decodeFromXML(configString, errorMessage); @@ -557,7 +634,6 @@ CaretPreferences::readTileTabsUserConfigurations(const bool performSync) std::cout << std::endl; } } - this->qSettings->endArray(); } /** -- GitLab From 562dd5414f9fc868cfe4f531aa805d51d5686e50 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Aug 2019 12:32:20 -0500 Subject: [PATCH 018/584] WB-859 Manual Tile Tabs Layout System: Updates Tile Editing toolbar so that its components are enabled only if in Tile Tabs Manual mode with a tab selected. --- src/Brain/AnnotationManager.cxx | 27 +++++++++++++++++--- src/GuiQt/AnnotationFormatWidget.cxx | 6 +++-- src/GuiQt/AnnotationFormatWidget.h | 2 +- src/GuiQt/AnnotationRedoUndoWidget.cxx | 9 ++++--- src/GuiQt/AnnotationRedoUndoWidget.h | 3 ++- src/GuiQt/BrainBrowserWindowToolBar.cxx | 27 ++++++++++++++++++++ src/GuiQt/UserInputModeAnnotationsWidget.cxx | 3 ++- 7 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 638cae7c8..6d7707de0 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -34,6 +34,7 @@ #include "AnnotationEditingSelectionInformation.h" #include "AnnotationTwoDimensionalShape.h" #include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "Brain.h" #include "CaretAssert.h" #include "CaretLogger.h" @@ -43,6 +44,7 @@ #include "EventAnnotationColorBarGet.h" #include "EventAnnotationGroupGetWithKey.h" #include "EventBrowserTabGetAll.h" +#include "EventBrowserWindowContent.h" #include "EventGetDisplayedDataFiles.h" #include "EventManager.h" #include "SceneClass.h" @@ -501,6 +503,24 @@ AnnotationManager::getAnnotationEditingSelectionInformation(const int32_t window { CaretAssertArrayIndex(m_selectionInformation, BrainConstants::MAXIMUM_NUMBER_OF_BROWSER_WINDOWS, windowIndex); + bool manualTileTabsModeFlag(false); + std::unique_ptr windowContentEvent = EventBrowserWindowContent::getWindowContent(windowIndex); + if (windowContentEvent) { + EventManager::get()->sendEvent(windowContentEvent.get()); + const BrowserWindowContent* windowContent = windowContentEvent->getBrowserWindowContent(); + if (windowContent != NULL) { + switch (windowContent->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + manualTileTabsModeFlag = true; + break; + } + } + } + AnnotationEditingSelectionInformation* asi = m_selectionInformation[windowIndex]; std::vector allAnnotations = getAllAnnotations(); @@ -508,10 +528,11 @@ AnnotationManager::getAnnotationEditingSelectionInformation(const int32_t window for (std::vector::iterator annIter = allAnnotations.begin(); annIter != allAnnotations.end(); annIter++) { - Annotation* annotation = *annIter; - + Annotation* annotation = *annIter; if (annotation->isSelectedForEditing(windowIndex)) { - selectedAnnotations.push_back(annotation); + if (manualTileTabsModeFlag) { + selectedAnnotations.push_back(annotation); + } } } diff --git a/src/GuiQt/AnnotationFormatWidget.cxx b/src/GuiQt/AnnotationFormatWidget.cxx index 0c3a2d759..e625aaf58 100644 --- a/src/GuiQt/AnnotationFormatWidget.cxx +++ b/src/GuiQt/AnnotationFormatWidget.cxx @@ -80,11 +80,13 @@ AnnotationFormatWidget::~AnnotationFormatWidget() /** * Update with the given annotation. * - * @param annotation. + * @param annotations + * The selected annotations */ void -AnnotationFormatWidget::updateContent(Annotation* /*annotation*/) +AnnotationFormatWidget::updateContent(const std::vector& annotations) { + setEnabled( ! annotations.empty()); } /** diff --git a/src/GuiQt/AnnotationFormatWidget.h b/src/GuiQt/AnnotationFormatWidget.h index ae106ddd2..fa15e98dd 100644 --- a/src/GuiQt/AnnotationFormatWidget.h +++ b/src/GuiQt/AnnotationFormatWidget.h @@ -45,7 +45,7 @@ namespace caret { // ADD_NEW_METHODS_HERE - void updateContent(Annotation* annotation); + void updateContent(const std::vector& annotations); private: AnnotationFormatWidget(const AnnotationFormatWidget&); diff --git a/src/GuiQt/AnnotationRedoUndoWidget.cxx b/src/GuiQt/AnnotationRedoUndoWidget.cxx index 5fa27f400..bf693a749 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.cxx +++ b/src/GuiQt/AnnotationRedoUndoWidget.cxx @@ -107,12 +107,13 @@ AnnotationRedoUndoWidget::~AnnotationRedoUndoWidget() } /** - * Update with the given line annotation. + * Update with the selected annotations. * - * @param annotationLine + * @param annotations + * The selected annotations */ void -AnnotationRedoUndoWidget::updateContent() +AnnotationRedoUndoWidget::updateContent(const std::vector& annotations) { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); CaretUndoStack* undoStack = annMan->getCommandRedoUndoStack(m_userInputMode); @@ -122,6 +123,8 @@ AnnotationRedoUndoWidget::updateContent() m_undoAction->setEnabled(undoStack->canUndo()); m_undoAction->setToolTip(undoStack->undoText()); + + setEnabled( ! annotations.empty()); } diff --git a/src/GuiQt/AnnotationRedoUndoWidget.h b/src/GuiQt/AnnotationRedoUndoWidget.h index 34a94c020..aaa54da3e 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.h +++ b/src/GuiQt/AnnotationRedoUndoWidget.h @@ -29,6 +29,7 @@ #include "UserInputModeEnum.h" namespace caret { + class Annotation; class AnnotationRedoUndoWidget : public QWidget { @@ -41,7 +42,7 @@ namespace caret { virtual ~AnnotationRedoUndoWidget(); - void updateContent(); + void updateContent(const std::vector& annotations); private slots: void redoActionTriggered(); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index f2d3792b5..977cb538b 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -3246,7 +3246,34 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte this->modeInputModeViewAction->setChecked(true); break; } + + BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); + CaretAssert(browserWindow); + BrowserWindowContent* browserWindowContent = browserWindow->getBrowerWindowContent(); + CaretAssert(browserWindowContent); + + /* + * Enable "Tile" button only if Tile Tabs enabled and + * Manual Configuration is selected + */ + bool tileModeValidFlag(false); + if (browserWindowContent->isTileTabsEnabled()) { + /* + * Automatic configuration and manual configuration always show all tabs + */ + switch (browserWindowContent->getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + tileModeValidFlag = true; + break; + } + } + this->modeInputModeTileTabsManualLayoutAction->setEnabled(tileModeValidFlag); + this->modeWidgetGroup->blockAllSignals(false); this->updateDisplayedModeUserInputWidget(); diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index 84893af71..6cb4b1ca1 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -453,7 +453,8 @@ UserInputModeAnnotationsWidget::updateWidget() if (m_coordinateTwoWidget != NULL) m_coordinateTwoWidget->setVisible(false); } - if (m_redoUndoWidget != NULL) m_redoUndoWidget->updateContent(); + if (m_formatWidget != NULL) m_formatWidget->updateContent(selectedAnnotations); + if (m_redoUndoWidget != NULL) m_redoUndoWidget->updateContent(selectedAnnotations); } -- GitLab From 26b7e4163e10a32ec85657b2867d8933c3ad489f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Aug 2019 14:34:53 -0500 Subject: [PATCH 019/584] WB-859 Manual Tile Tabs Layout System: For Tile Tabs editing toolbar, added a widget that shows name of selected tab. Also add percentage symbols to widget for editing selected tab's bounds in toolbar. --- src/GuiQt/AnnotationBoundsWidget.cxx | 4 +- src/GuiQt/AnnotationNameWidget.cxx | 104 +++++++++++++++++++ src/GuiQt/AnnotationNameWidget.h | 72 +++++++++++++ src/GuiQt/CMakeLists.txt | 5 +- src/GuiQt/UserInputModeAnnotationsWidget.cxx | 9 ++ src/GuiQt/UserInputModeAnnotationsWidget.h | 3 + 6 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/GuiQt/AnnotationNameWidget.cxx create mode 100644 src/GuiQt/AnnotationNameWidget.h diff --git a/src/GuiQt/AnnotationBoundsWidget.cxx b/src/GuiQt/AnnotationBoundsWidget.cxx index 66b79e493..dc1c8c831 100644 --- a/src/GuiQt/AnnotationBoundsWidget.cxx +++ b/src/GuiQt/AnnotationBoundsWidget.cxx @@ -138,6 +138,8 @@ AnnotationBoundsWidget::createSpinBox() spinBox->setDecimals(1); spinBox->setToolTip("0.0% => Bottom of window\n" "100.0% => Top of window"); + spinBox->setSuffix("%"); + return spinBox; } @@ -158,7 +160,7 @@ void AnnotationBoundsWidget::updateContent(std::vector& annotationBrowserTabs) { m_annotationBrowserTab = NULL; - if ( ! annotationBrowserTabs.empty()) { + if (annotationBrowserTabs.size() == 1) { CaretAssertVectorIndex(annotationBrowserTabs, 0); m_annotationBrowserTab = annotationBrowserTabs[0]; } diff --git a/src/GuiQt/AnnotationNameWidget.cxx b/src/GuiQt/AnnotationNameWidget.cxx new file mode 100644 index 000000000..4e28bc567 --- /dev/null +++ b/src/GuiQt/AnnotationNameWidget.cxx @@ -0,0 +1,104 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __ANNOTATION_NAME_WIDGET_DECLARE__ +#include "AnnotationNameWidget.h" +#undef __ANNOTATION_NAME_WIDGET_DECLARE__ + +#include +#include + +#include "AnnotationBrowserTab.h" +#include "AnnotationMenuArrange.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "WuQtUtilities.h" + +using namespace caret; + +/** + * \class caret::AnnotationNameWidget + * \brief Widget for formatting annotations. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param userInputMode + * The user input mode + * @param browserWindowIndex + * Index of the browser window. + * @param parent + * Parent of this widget. + */ +AnnotationNameWidget::AnnotationNameWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, + QWidget* parent) +: QWidget(parent), +m_userInputMode(userInputMode), +m_browserWindowIndex(browserWindowIndex) +{ + m_nameLabel = new QLabel(); + QHBoxLayout* layout = new QHBoxLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); + layout->addWidget(m_nameLabel, 100, Qt::AlignVCenter); + + setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +AnnotationNameWidget::~AnnotationNameWidget() +{ +} + +/** + * Update with the given annotation. + * + * @param annotations + * The selected annotations + */ +void +AnnotationNameWidget::updateContent(const std::vector& annotations) +{ + AString name; + const int32_t numSelected = static_cast(annotations.size()); + if (numSelected > 1) { + name = "+"; + } + else if (numSelected == 1) { + CaretAssertVectorIndex(annotations, 0); + AnnotationBrowserTab* browserTabAnnotation = dynamic_cast(annotations[0]); + if (browserTabAnnotation != NULL) { + const BrowserTabContent* tabContent = browserTabAnnotation->getBrowserTabContent(); + if (tabContent != NULL) { + name = tabContent->getTabName(); + } + } + } + + setEnabled(numSelected > 0); + m_nameLabel->setText(name); +} + diff --git a/src/GuiQt/AnnotationNameWidget.h b/src/GuiQt/AnnotationNameWidget.h new file mode 100644 index 000000000..fbef0d1ac --- /dev/null +++ b/src/GuiQt/AnnotationNameWidget.h @@ -0,0 +1,72 @@ +#ifndef __ANNOTATION_NAME_WIDGET_H__ +#define __ANNOTATION_NAME_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#include + +#include + +#include "UserInputModeEnum.h" + +class QLabel; + +namespace caret { + + class Annotation; + + class AnnotationNameWidget : public QWidget { + + Q_OBJECT + + public: + AnnotationNameWidget(const UserInputModeEnum::Enum userInputMode, + const int32_t browserWindowIndex, + QWidget* parent = 0); + + virtual ~AnnotationNameWidget(); + + + // ADD_NEW_METHODS_HERE + + void updateContent(const std::vector& annotations); + + private: + AnnotationNameWidget(const AnnotationNameWidget&); + + AnnotationNameWidget& operator=(const AnnotationNameWidget&); + + const UserInputModeEnum::Enum m_userInputMode; + + const int32_t m_browserWindowIndex; + + QLabel* m_nameLabel; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __ANNOTATION_NAME_WIDGET_DECLARE__ + // +#endif // __ANNOTATION_NAME_WIDGET_DECLARE__ + +} // namespace +#endif //__ANNOTATION_NAME_WIDGET_H__ diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 2aea5af60..954980a63 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -58,10 +58,11 @@ ELSE() AnnotationLineArrowTipsWidget.h AnnotationMenuArrange.h AnnotationMenuFileSelection.h + AnnotationNameWidget.h + AnnotationPasteDialog.h AnnotationRedoUndoWidget.h AnnotationRotationWidget.h AnnotationSelectionViewController.h - AnnotationPasteDialog.h AnnotationTextAlignmentWidget.h AnnotationTextEditorDialog.h AnnotationTextEditorWidget.h @@ -280,6 +281,7 @@ AnnotationInsertNewWidget.h AnnotationLineArrowTipsWidget.h AnnotationMenuArrange.h AnnotationMenuFileSelection.h +AnnotationNameWidget.h AnnotationPasteDialog.h AnnotationRedoUndoWidget.h AnnotationRotationWidget.h @@ -560,6 +562,7 @@ AnnotationInsertNewWidget.cxx AnnotationLineArrowTipsWidget.cxx AnnotationMenuArrange.cxx AnnotationMenuFileSelection.cxx +AnnotationNameWidget.cxx AnnotationPasteDialog.cxx AnnotationRedoUndoWidget.cxx AnnotationRotationWidget.cxx diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index 6cb4b1ca1..860669c08 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -42,6 +42,7 @@ #include "AnnotationLine.h" #include "AnnotationLineArrowTipsWidget.h" #include "AnnotationManager.h" +#include "AnnotationNameWidget.h" #include "AnnotationOneDimensionalShape.h" #include "AnnotationRedoUndoWidget.h" #include "AnnotationRotationWidget.h" @@ -170,6 +171,9 @@ UserInputModeAnnotationsWidget::receiveEvent(Event* event) void UserInputModeAnnotationsWidget::createTileTabsEditingWidget() { + m_nameWidget = new AnnotationNameWidget(m_inputModeAnnotations->getUserInputMode(), + m_browserWindowIndex); + m_boundsWidget = new AnnotationBoundsWidget(m_inputModeAnnotations->getUserInputMode(), AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); @@ -194,6 +198,10 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() gridLayout->setContentsMargins(2, 2, 2, 2); gridLayout->setVerticalSpacing(0); int column = 0; + gridLayout->addWidget(m_nameWidget, 0, column, 2, 1); + column++; + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); + column++; gridLayout->addWidget(m_boundsWidget, 0, column); gridLayout->addWidget(m_coordinateOneWidget, 1, column); column++; @@ -425,6 +433,7 @@ UserInputModeAnnotationsWidget::updateWidget() /* * Note: pointers are initialized to NULL in the header file */ + if (m_nameWidget != NULL) m_nameWidget->updateContent(selectedAnnotations); if (m_boundsWidget != NULL) m_boundsWidget->updateContent(browserTabAnnotations); if (m_coordinateSpaceWidget != NULL) m_coordinateSpaceWidget->updateContent(selectedAnnotations); if (m_fontWidget != NULL) m_fontWidget->updateContent(fontStyleAnnotations); diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.h b/src/GuiQt/UserInputModeAnnotationsWidget.h index acccc4471..1bc1254c5 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.h +++ b/src/GuiQt/UserInputModeAnnotationsWidget.h @@ -41,6 +41,7 @@ namespace caret { class AnnotationFormatWidget; class AnnotationInsertNewWidget; class AnnotationLineArrowTipsWidget; + class AnnotationNameWidget; class AnnotationRedoUndoWidget; class AnnotationRotationWidget; class AnnotationTextAlignmentWidget; @@ -88,6 +89,8 @@ namespace caret { UserInputModeAnnotations* m_inputModeAnnotations = NULL; + AnnotationNameWidget* m_nameWidget = NULL; + AnnotationBoundsWidget* m_boundsWidget = NULL; AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget = NULL; -- GitLab From 8dcc9aa109d089214b1de4c5fb2d07007098fb76 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 26 Aug 2019 15:42:24 -0500 Subject: [PATCH 020/584] WB-859 Manual Tile Tabs Layout System: Fix View Menu->Select All for both annotations and tiles. --- src/GuiQt/BrainOpenGLWidget.cxx | 7 ++- src/GuiQt/EventGraphicsUpdateOneWindow.cxx | 21 ++++++++- src/GuiQt/EventGraphicsUpdateOneWindow.h | 7 ++- src/GuiQt/GuiManager.cxx | 4 +- src/GuiQt/UserInputModeAnnotations.cxx | 53 ++++++++++++++++++++-- 5 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 3eba0ef30..4be5f222c 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1713,7 +1713,12 @@ BrainOpenGLWidget::receiveEvent(Event* event) if (updateOneEvent->getWindowIndex() == this->windowIndex) { updateOneEvent->setEventProcessed(); - doUpdateGraphicsFlag = true; + if (updateOneEvent->isRepaint()) { + doRepaintGraphicsFlag = true; + } + else { + doUpdateGraphicsFlag = true; + } } else { /* diff --git a/src/GuiQt/EventGraphicsUpdateOneWindow.cxx b/src/GuiQt/EventGraphicsUpdateOneWindow.cxx index 42de9a8b3..62b49b846 100644 --- a/src/GuiQt/EventGraphicsUpdateOneWindow.cxx +++ b/src/GuiQt/EventGraphicsUpdateOneWindow.cxx @@ -30,11 +30,18 @@ using namespace caret; /** * Constructor. + * + * @param windowIndex + * Index of window + * @param doRepaint + * if true, do a repaint instead of update */ -EventGraphicsUpdateOneWindow::EventGraphicsUpdateOneWindow(const int32_t windowIndex) +EventGraphicsUpdateOneWindow::EventGraphicsUpdateOneWindow(const int32_t windowIndex, + const bool doRepaint) : Event(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ONE_WINDOW) { - this->windowIndex = windowIndex; + this->windowIndex = windowIndex; + this->m_doRepaintFlag = doRepaint; } /* @@ -45,3 +52,13 @@ EventGraphicsUpdateOneWindow::~EventGraphicsUpdateOneWindow() } +/** + * @return Indicates a repaint (instead of updates) is + * to be performed. + */ +bool +EventGraphicsUpdateOneWindow::isRepaint() const +{ + return m_doRepaintFlag; +} + diff --git a/src/GuiQt/EventGraphicsUpdateOneWindow.h b/src/GuiQt/EventGraphicsUpdateOneWindow.h index ca67473ab..09cc076b5 100644 --- a/src/GuiQt/EventGraphicsUpdateOneWindow.h +++ b/src/GuiQt/EventGraphicsUpdateOneWindow.h @@ -30,13 +30,16 @@ namespace caret { class EventGraphicsUpdateOneWindow : public Event { public: - EventGraphicsUpdateOneWindow(const int32_t windowIndex); + EventGraphicsUpdateOneWindow(const int32_t windowIndex, + const bool doRepaint = false); virtual ~EventGraphicsUpdateOneWindow(); /// get the index of the window that is to be updated. int32_t getWindowIndex() const { return this->windowIndex; } + bool isRepaint() const; + private: EventGraphicsUpdateOneWindow(const EventGraphicsUpdateOneWindow&); @@ -44,6 +47,8 @@ namespace caret { /** index of window for update */ int32_t windowIndex; + + bool m_doRepaintFlag = false; }; } // namespace diff --git a/src/GuiQt/GuiManager.cxx b/src/GuiQt/GuiManager.cxx index c6396783b..15d229aef 100644 --- a/src/GuiQt/GuiManager.cxx +++ b/src/GuiQt/GuiManager.cxx @@ -1368,7 +1368,9 @@ GuiManager::receiveEvent(Event* event) /* * Draw the given window */ - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex).getPointer()); + const bool doRepaintFlag(true); + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(windowIndex, + doRepaintFlag).getPointer()); /* * Find annotations that were drawn in the given window. diff --git a/src/GuiQt/UserInputModeAnnotations.cxx b/src/GuiQt/UserInputModeAnnotations.cxx index a1b8e1654..a4d628c9b 100644 --- a/src/GuiQt/UserInputModeAnnotations.cxx +++ b/src/GuiQt/UserInputModeAnnotations.cxx @@ -25,6 +25,7 @@ #include +#include "AnnotationBrowserTab.h" #include "AnnotationChangeCoordinateDialog.h" #include "AnnotationCreateDialog.h" #include "AnnotationColorBar.h" @@ -40,6 +41,7 @@ #include "AnnotationTextEditorDialog.h" #include "AnnotationTwoDimensionalShape.h" #include "Brain.h" +#include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" #include "BrainOpenGLWidget.h" #include "BrowserTabContent.h" @@ -55,6 +57,7 @@ #include "EventIdentificationRequest.h" #include "EventUserInterfaceUpdate.h" #include "EventManager.h" +#include "EventGraphicsUpdateOneWindow.h" #include "GuiManager.h" #include "IdentificationManager.h" #include "KeyEvent.h" @@ -1651,13 +1654,53 @@ UserInputModeAnnotations::processSelectAllAnnotations() AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); annMan->deselectAllAnnotationsForEditing(m_browserWindowIndex); - EventAnnotationGetDrawnInWindow getDrawnEvent(m_browserWindowIndex); - EventManager::get()->sendEvent(getDrawnEvent.getPointer()); std::vector annotationsSelected; - getDrawnEvent.getAnnotations(annotationsSelected); - annMan->setAnnotationsForEditing(m_browserWindowIndex, - annotationsSelected); + switch (getUserInputMode()) { + case UserInputModeEnum::ANNOTATIONS: + { + EventAnnotationGetDrawnInWindow getDrawnEvent(m_browserWindowIndex); + EventManager::get()->sendEvent(getDrawnEvent.getPointer()); + getDrawnEvent.getAnnotations(annotationsSelected); + annMan->setAnnotationsForEditing(m_browserWindowIndex, + annotationsSelected); + } + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + { + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(bbw); + std::vector allTabContent; + bbw->getAllTabContent(allTabContent); + + std::vector annotations; + for (auto btc : allTabContent) { + AnnotationBrowserTab* bta = btc->getManualLayoutBrowserTabAnnotation(); + if (bta->isBrowserTabDisplayed()) { + annotations.push_back(bta); + } + } + + if ( ! annotations.empty()) { + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + CaretAssert(annMan); + annMan->setAnnotationsForEditing(m_browserWindowIndex, + annotations); + } + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + } + break; + case UserInputModeEnum::VIEW: + break; + case UserInputModeEnum::VOLUME_EDIT: + break; + } + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); -- GitLab From 5868661925da7006dcca6bf4c9eeb5bdb1abc414 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 27 Aug 2019 12:31:03 -0500 Subject: [PATCH 021/584] WB-859 Manual Tile Tabs Layout System: Added item to TIle Tab mode toolbar's Format->Arrange Menu named "Expand to File Empty Space". When in tile tabs editing mode choosing this time while one tab is selected for editing will expand the tab to fill available space (not used by other tabs) in the window. --- src/Annotations/AnnotationBrowserTab.cxx | 238 ++++++++++++++++++ src/Annotations/AnnotationBrowserTab.h | 4 + src/Annotations/AnnotationRedoUndoCommand.cxx | 55 +++- src/Annotations/AnnotationRedoUndoCommand.h | 6 + .../AnnotationRedoUndoCommandModeEnum.cxx | 10 +- .../AnnotationRedoUndoCommandModeEnum.h | 6 +- src/Brain/AnnotationManager.cxx | 62 +++++ src/Brain/AnnotationManager.h | 7 + src/Brain/BrowserWindowContent.cxx | 21 ++ src/Brain/BrowserWindowContent.h | 2 + src/GuiQt/AnnotationMenuArrange.cxx | 116 ++++++++- src/GuiQt/AnnotationMenuArrange.h | 14 +- 12 files changed, 527 insertions(+), 14 deletions(-) diff --git a/src/Annotations/AnnotationBrowserTab.cxx b/src/Annotations/AnnotationBrowserTab.cxx index 81d00beb4..e6e27cec5 100644 --- a/src/Annotations/AnnotationBrowserTab.cxx +++ b/src/Annotations/AnnotationBrowserTab.cxx @@ -25,6 +25,7 @@ #include "AnnotationCoordinate.h" #include "CaretAssert.h" +#include "MathFunctions.h" #include "SceneClass.h" #include "SceneClassAssistant.h" #include "TileTabsBrowserTabGeometry.h" @@ -415,3 +416,240 @@ AnnotationBrowserTab::intersectionTest(const AnnotationBrowserTab* other) const return true; } +/** + * This class is used to find an expandable region + * for a browser tab + */ +class PercentageGrid { +public: + /* + * Constructor with grid size + */ + PercentageGrid(const int32_t minXY, + const int32_t maxXY) + : m_minXY(minXY), + m_maxXY(maxXY), + m_rangeXY((maxXY - minXY) + 1) /* Add 1 since inclusive range */ + { + const int32_t gridSize(m_rangeXY * m_rangeXY); + m_grid.resize(gridSize, 0); + } + + /* + * Test to see of ALL of the grid points with the given bounds + * are off + */ + bool rangeOff(const int32_t minX, + const int32_t maxX, + const int32_t minY, + const int32_t maxY) const { + for (int32_t i = minX; i <= maxX; i++) { + for (int32_t j = minY; j <= maxY; j++) { + const int32_t offset = (m_rangeXY * j) + i; + CaretAssertVectorIndex(m_grid, offset); + if (m_grid[offset] != 0) { + return false; + } + } + } + return true; + } + + /** + * Set grid points on for the given range + */ + void setRange(const int32_t minXIn, + const int32_t maxXIn, + const int32_t minYIn, + const int32_t maxYIn) { + const int32_t minX = MathFunctions::limitRange(static_cast(minXIn), m_minXY, m_maxXY); + const int32_t maxX = MathFunctions::limitRange(static_cast(maxXIn), m_minXY, m_maxXY); + const int32_t minY = MathFunctions::limitRange(static_cast(minYIn), m_minXY, m_maxXY); + const int32_t maxY = MathFunctions::limitRange(static_cast(maxYIn), m_minXY, m_maxXY); + + for (int32_t i = minX; i <= maxX; i++) { + for (int32_t j = minY; j <= maxY; j++) { + const int32_t offset = (m_rangeXY * j) + i; + CaretAssertVectorIndex(m_grid, offset); + m_grid[offset] = 1; + } + } + } + + const int32_t m_minXY; + const int32_t m_maxXY; + const int32_t m_rangeXY; + + std::vector m_grid; +}; + +/** + * Expand the given tab using any available space around it + * + * @param browserTabsInWindow + * Tabs in the window + * @param tabToExpand + * Tab that is expanded to fill empty space + * @param boundsOut + * Output with new bounds + * @return + * True if new bounds are valid + */ +bool +AnnotationBrowserTab::expandTab(const std::vector& browserTabsInWindow, + const AnnotationBrowserTab* tabToExpand, + float boundsOut[4]) +{ + if (tabToExpand == NULL) { + return false; + } + + /* + * Ensure tab for expansion is not in list of other tabs + */ + std::vector tabs; + for (auto bt : browserTabsInWindow) { + if (bt != tabToExpand) { + tabs.push_back(bt); + } + } + + /* + * If no other tabs, fill window + */ + if (tabs.empty()) { + boundsOut[0] = 0.0; + boundsOut[1] = 100.0; + boundsOut[2] = 0.0; + boundsOut[3] = 100.0; + return true; + } + + /* + * Since the percentage coordinates in the window range [0, 100], + * create a grid that is 101 x 101 (grid will add one in constructor) + */ + PercentageGrid grid(0, 100); + + /* + * Fill in grid points that are overlapped by + * all of the tabs + */ + for (auto t : tabs) { + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + t->getBounds2D(minX, maxX, minY, maxY); + grid.setRange(minX, maxX, minY, maxY); + } + + /* + * Get bounds of tab for expansion and clip to grid + */ + float tabMinX(0.0), tabMaxX(0.0), tabMinY(0.0), tabMaxY(0.0); + tabToExpand->getBounds2D(tabMinX, tabMaxX, tabMinY, tabMaxY); + +// grid.setRange(tabMinX, tabMaxX, tabMinY, tabMaxY); + /* + * Shrink by 1 point around edges. If the maximum of a tab + * is the same as a minimum of this tab, it will detect + * overlap and prevent expansion + */ + int32_t x1 = MathFunctions::limitRange(static_cast(tabMinX + 1), 0, 100); + int32_t x2 = MathFunctions::limitRange(static_cast(tabMaxX - 1), 0, 100); + int32_t y1 = MathFunctions::limitRange(static_cast(tabMinY + 1), 0, 100); + int32_t y2 = MathFunctions::limitRange(static_cast(tabMaxY - 1), 0, 100); + grid.setRange(x1, x2, y1, y2); + + bool leftDone(x1 <= 0); + bool rightDone(x2 >= 100); + bool bottomDone(y1 <= 0); + bool topDone(y2 >= 100); + + bool done(leftDone && rightDone && bottomDone && topDone); + while ( ! done) { + /* + * Try to expand at bottom by one row + */ + if ( ! bottomDone) { + if (grid.rangeOff(x1, x2, y1 - 1, y1 - 1)) { + y1--; + } + else { + bottomDone = true; + } + } + + /* + * Try to expand at top by one row + */ + if ( ! topDone) { + if (grid.rangeOff(x1, x2, y2 + 1, y2 + 1)) { + y2++; + } + else { + topDone = true; + } + } + + /* + * Try to expand at left by one column + */ + if ( ! leftDone) { + if (grid.rangeOff(x1 - 1, x1 - 1, y1, y2)) { + x1--; + } + else { + leftDone = true; + } + } + + /* + * Try to expand at right by one column + */ + if ( ! rightDone) { + if (grid.rangeOff(x2 + 1, x2 + 1, y1, y2)) { + x2++; + } + else { + rightDone = true; + } + } + + /* + * Test for any sides that no longer are expandable + */ + if (x1 <= 0) { + leftDone = true; + } + if (x2 >= 100) { + rightDone = true; + } + if (y1 <= 0) { + bottomDone = true; + } + if (y2 >= 100) { + topDone = true; + } + + /* + * Done if no expansion available + */ + done = (leftDone && rightDone && bottomDone && topDone); + } + + /* + * If expansion available, report new bounds + */ + if ((x1 < tabMinX) + || (x2 > tabMaxX) + || (y1 < tabMinY) + || (y2 > tabMaxY)) { + boundsOut[0] = x1; + boundsOut[1] = x2; + boundsOut[2] = y1; + boundsOut[3] = y2; + return true; + } + + return false; +} + diff --git a/src/Annotations/AnnotationBrowserTab.h b/src/Annotations/AnnotationBrowserTab.h index 53b33902f..ce42e69fc 100644 --- a/src/Annotations/AnnotationBrowserTab.h +++ b/src/Annotations/AnnotationBrowserTab.h @@ -79,6 +79,10 @@ namespace caret { const float minY, const float maxY); + static bool expandTab(const std::vector& browserTabsInWindow, + const AnnotationBrowserTab* tabToExpand, + float boundOut[4]); + // ADD_NEW_METHODS_HERE diff --git a/src/Annotations/AnnotationRedoUndoCommand.cxx b/src/Annotations/AnnotationRedoUndoCommand.cxx index f2565e2e4..3580c948f 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.cxx +++ b/src/Annotations/AnnotationRedoUndoCommand.cxx @@ -94,7 +94,8 @@ AnnotationRedoUndoCommand::applyRedoOrUndo(Annotation* annotation, switch (m_mode) { case AnnotationRedoUndoCommandModeEnum::INVALID: break; - case AnnotationRedoUndoCommandModeEnum::BOUNDS_2D: + case AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_ALL: + case AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_SINGLE: { CaretAssert(annotation); CaretAssert(annotationValue); @@ -807,6 +808,50 @@ AnnotationRedoUndoCommand::mergeWith(const CaretUndoCommand* command) return true; } +/** + * Set them mode to all bounds and create the redo/undo instances. + * + * @param minX + * New minimum x-value of the annotation + * @param maxX + * New maximum x-value of the annotation + * @param minY + * New minimum y-value of the annotation + * @param maxY + * New minimum y-value of the annotation + * @param annotation + * Annotation that receive this new bounds (browser tabs only). + */ +void +AnnotationRedoUndoCommand::setBoundsAll(const float minX, + const float maxX, + const float minY, + const float maxY, + Annotation* annotation) +{ + CaretAssert(annotation); + + AnnotationBrowserTab* browserTabAnnotation = dynamic_cast(annotation); + if (browserTabAnnotation != NULL) { + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_ALL; + setDescription("Bounds 2D ALL"); + + AnnotationBrowserTab* redoAnnotation = dynamic_cast(browserTabAnnotation->clone()); + CaretAssert(redoAnnotation); + redoAnnotation->setBounds2D(minX, maxX, minY, maxY); + + Annotation* undoAnnotation = browserTabAnnotation->clone(); + AnnotationMemento* am = new AnnotationMemento(annotation, + redoAnnotation, + undoAnnotation); + m_annotationMementos.push_back(am); + } + else { + CaretLogWarning("Annotation for bounds setting must be a Browser Tab Annotation"); + } +} + + /** * Set them mode to x-minimum and create the redo/undo instances. * @@ -819,7 +864,7 @@ void AnnotationRedoUndoCommand::setBoundsMinX2D(const float newMinX, const std::vector& annotations) { - m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_SINGLE; setDescription("Bounds 2D X-Min"); setBounds2DHelper(BoundsType2D::MIN_X, newMinX, @@ -838,7 +883,7 @@ void AnnotationRedoUndoCommand::setBoundsMaxX2D(const float newMaxX, const std::vector& annotations) { - m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_SINGLE; setDescription("Bounds 2D X-Max"); setBounds2DHelper(BoundsType2D::MAX_X, newMaxX, @@ -857,7 +902,7 @@ void AnnotationRedoUndoCommand::setBoundsMinY2D(const float newMinY, const std::vector& annotations) { - m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_SINGLE; setDescription("Bounds 2D Y-Min"); setBounds2DHelper(BoundsType2D::MIN_Y, newMinY, @@ -876,7 +921,7 @@ void AnnotationRedoUndoCommand::setBoundsMaxY2D(const float newMaxY, const std::vector& annotations) { - m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D; + m_mode = AnnotationRedoUndoCommandModeEnum::BOUNDS_2D_SINGLE; setDescription("Bounds 2D Y-Max"); setBounds2DHelper(BoundsType2D::MAX_Y, newMaxY, diff --git a/src/Annotations/AnnotationRedoUndoCommand.h b/src/Annotations/AnnotationRedoUndoCommand.h index 008547267..9b983baa9 100644 --- a/src/Annotations/AnnotationRedoUndoCommand.h +++ b/src/Annotations/AnnotationRedoUndoCommand.h @@ -49,6 +49,12 @@ namespace caret { virtual bool mergeWith(const CaretUndoCommand* command); + void setBoundsAll(const float minX, + const float maxX, + const float minY, + const float maxY, + Annotation* annotation); + void setBoundsMinX2D(const float minX, const std::vector& annotations); diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx index 7fc489032..ff74ff8fe 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.cxx @@ -110,9 +110,13 @@ AnnotationRedoUndoCommandModeEnum::initialize() "INVALID", "Invalid")); - enumData.push_back(AnnotationRedoUndoCommandModeEnum(BOUNDS_2D, - "BOUNDS_2D", - "Bounds 2D")); + enumData.push_back(AnnotationRedoUndoCommandModeEnum(BOUNDS_2D_ALL, + "BOUNDS_2D_ALL", + "Bounds 2D All")); + + enumData.push_back(AnnotationRedoUndoCommandModeEnum(BOUNDS_2D_SINGLE, + "BOUNDS_2D_SINGLE", + "Bounds 2D Single")); enumData.push_back(AnnotationRedoUndoCommandModeEnum(COLOR_BACKGROUND, "COLOR_BACKGROUND", diff --git a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h index 447613d38..dc4ab40c7 100644 --- a/src/Annotations/AnnotationRedoUndoCommandModeEnum.h +++ b/src/Annotations/AnnotationRedoUndoCommandModeEnum.h @@ -37,8 +37,10 @@ public: enum Enum { /** Invalid mode */ INVALID, - /** Set the bounds in 2D */ - BOUNDS_2D, + /** Set all of the bounds in 2D */ + BOUNDS_2D_ALL, + /** Set one of the bounds in 2D */ + BOUNDS_2D_SINGLE, /** Color - Background */ COLOR_BACKGROUND, /** Color - Foreground */ diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 6d7707de0..5c8c74436 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -1112,3 +1112,65 @@ AnnotationManager::restoreFromScene(const SceneAttributes* sceneAttributes, } +/** + * Expand a browser tab to fill available space in the window. MANUAL MODE ONLY ! + * + * @param tabsInWindow + * Tabs displayed in the window (may or may not include selected tab) + * @param selectedTabAnnotation + * Tab that is expanded + * @param userInputMode + * The current user input mode (browser tab always) + * @param errorMessageOut + * Contains error information if expansion has error (inability to expand is NOT an error) + * @return + * True no error, else false. + */ +bool +AnnotationManager::expandBrowserTabAnnotation(const std::vector& tabsInWindow, + AnnotationBrowserTab* selectedTabAnnotation, + const UserInputModeEnum::Enum userInputMode, + AString& errorMessageOut) +{ + errorMessageOut.clear(); + + CaretAssert(selectedTabAnnotation); + + if (selectedTabAnnotation != NULL) { + std::vector tabAnnotations; + for (auto btc : tabsInWindow) { + const AnnotationBrowserTab* ta = btc->getManualLayoutBrowserTabAnnotation(); + CaretAssert(ta); + if (ta != selectedTabAnnotation) { + tabAnnotations.push_back(ta); + } + } + + + float newBounds[4] { 0, 0, 0, 0 }; + if (AnnotationBrowserTab::expandTab(tabAnnotations, + selectedTabAnnotation, + newBounds)) { + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + undoCommand->setBoundsAll(newBounds[0], + newBounds[1], + newBounds[2], + newBounds[3], + selectedTabAnnotation); + if (applyCommand(userInputMode, + undoCommand, + errorMessageOut)) { + return true; + } + } + else { + errorMessageOut = "Unable to expand tab"; + } + } + else { + errorMessageOut = "Selected annotation must be a browser tab"; + } + + return false; +} + diff --git a/src/Brain/AnnotationManager.h b/src/Brain/AnnotationManager.h index b576acbd0..69e80d0a5 100644 --- a/src/Brain/AnnotationManager.h +++ b/src/Brain/AnnotationManager.h @@ -36,11 +36,13 @@ namespace caret { class Annotation; class AnnotationArrangerInputs; + class AnnotationBrowserTab; class AnnotationFile; class AnnotationGroupKey; class AnnotationRedoUndoCommand; class AnnotationEditingSelectionInformation; class Brain; + class BrowserTabContent; class CaretUndoStack; class EventGetDisplayedDataFiles; class SceneClassAssistant; @@ -147,6 +149,11 @@ namespace caret { bool isGroupingModeValid(const int32_t windowIndex, const AnnotationGroupingModeEnum::Enum groupingMode) const; + bool expandBrowserTabAnnotation(const std::vector& tabsInWindow, + AnnotationBrowserTab* selectedTabAnnotation, + const UserInputModeEnum::Enum userInputMode, + AString& errorMessageOut); + // ADD_NEW_METHODS_HERE virtual AString toString() const; diff --git a/src/Brain/BrowserWindowContent.cxx b/src/Brain/BrowserWindowContent.cxx index 308dbb57a..1132aa0ca 100644 --- a/src/Brain/BrowserWindowContent.cxx +++ b/src/Brain/BrowserWindowContent.cxx @@ -341,6 +341,27 @@ BrowserWindowContent::setTileTabsConfigurationMode(const TileTabsLayoutConfigura m_tileTabsConfigurationMode = configMode; } +/** + * @return True if tile tabs is enabled AND a manual configuration is selected + */ +bool +BrowserWindowContent::isManualModeTileTabsConfigurationEnabled() const +{ + if (isTileTabsEnabled()) { + switch (getTileTabsConfigurationMode()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + return true; + break; + } + } + return false; +} + + /** * @return Width of the graphics region from scene. */ diff --git a/src/Brain/BrowserWindowContent.h b/src/Brain/BrowserWindowContent.h index f0e0db55f..d3d7f8a11 100644 --- a/src/Brain/BrowserWindowContent.h +++ b/src/Brain/BrowserWindowContent.h @@ -84,6 +84,8 @@ namespace caret { void setTileTabsConfigurationMode(const TileTabsLayoutConfigurationTypeEnum::Enum configMode); + bool isManualModeTileTabsConfigurationEnabled() const; + int32_t getSceneGraphicsWidth() const; void setSceneGraphicsWidth(const int32_t width); diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index ce530b4aa..e6a1fc03a 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -27,15 +27,22 @@ #include "Annotation.h" #include "AnnotationArrangerInputs.h" +#include "AnnotationBrowserTab.h" #include "AnnotationManager.h" +#include "AnnotationRedoUndoCommand.h" #include "Brain.h" +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" #include "CaretLogger.h" #include "DisplayPropertiesAnnotationTextSubstitution.h" #include "EventAnnotationGrouping.h" +#include "EventBrowserWindowContent.h" #include "EventGetBrainOpenGLTextRenderer.h" #include "EventGraphicsUpdateAllWindows.h" #include "EventManager.h" +#include "EventUserInterfaceUpdate.h" #include "GuiManager.h" #include "WuQMessageBox.h" #include "WuQtUtilities.h" @@ -77,6 +84,8 @@ m_browserWindowIndex(browserWindowIndex) addGroupingSelections(); + addTileTabsSelections(); + QObject::connect(this, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow())); QObject::connect(this, SIGNAL(triggered(QAction*)), @@ -182,6 +191,43 @@ AnnotationMenuArrange::addGroupingSelections() CaretAssert(m_ungroupAction); } +/** + * Add distribution items to the menu. + */ +void +AnnotationMenuArrange::addTileTabsSelections() +{ + bool addMenuFlag(false); + switch (m_userInputMode) { + case UserInputModeEnum::ANNOTATIONS: + break; + case UserInputModeEnum::BORDERS: + break; + case UserInputModeEnum::FOCI: + break; + case UserInputModeEnum::IMAGE: + break; + case UserInputModeEnum::INVALID: + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + addMenuFlag = true; + break; + case UserInputModeEnum::VIEW: + break; + case UserInputModeEnum::VOLUME_EDIT: + break; + } + + if ( ! addMenuFlag) { + return; + } + + addSeparator(); + + m_tileTabsExpandToFillAction = addAction("Expand to Fill Empty Space"); + +} + /* * Gets called when the menu is about to show * so that its menu items can be enabled/disabled. @@ -197,6 +243,18 @@ AnnotationMenuArrange::menuAboutToShow() AnnotationGroupingModeEnum::REGROUP)); m_ungroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, AnnotationGroupingModeEnum::UNGROUP)); + + if (m_tileTabsExpandToFillAction != NULL) { + std::unique_ptr windowEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); + EventManager::get()->sendEvent(windowEvent->getPointer()); + BrowserWindowContent* bwc = windowEvent->getBrowserWindowContent(); + CaretAssert(bwc); + int32_t numSelected = 0; + if (bwc->isManualModeTileTabsConfigurationEnabled()) { + numSelected = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex).size(); + } + m_tileTabsExpandToFillAction->setEnabled(numSelected == 1); + } } @@ -230,6 +288,9 @@ AnnotationMenuArrange::menuActionTriggered(QAction* action) else if (validGroupingFlag) { applyGrouping(annGroup); } + else if (processTileTabsMenu(action)) { + /* If true returned, a tile tabs menu item was selected */ + } else { const AString msg("Unrecognized Enum name in Annotation Align Menu \"" + enumName @@ -238,10 +299,63 @@ AnnotationMenuArrange::menuActionTriggered(QAction* action) CaretLogSevere(msg); } - EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } +/** + * Process the action if it is on the Tile Tabs Menu + * + * @param actionSelected + * Action selected by user + * @return + * True if the action was on this menu, else false. + */ +bool +AnnotationMenuArrange::processTileTabsMenu(QAction* actionSelected) +{ + bool menuSelectedFlag(false); + + if ((m_tileTabsExpandToFillAction != NULL) + && (actionSelected == m_tileTabsExpandToFillAction)) { + processExpandTabMenuItem(); + menuSelectedFlag = true; + } + + return menuSelectedFlag; +} + +void +AnnotationMenuArrange::processExpandTabMenuItem() +{ + BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(window); + std::vector allTabContent; + window->getAllTabContent(allTabContent); + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + std::vector selectedAnnotations = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex); + if (selectedAnnotations.size() == 1) { + CaretAssertVectorIndex(selectedAnnotations, 0); + AnnotationBrowserTab* selectedTabAnnotation = dynamic_cast(selectedAnnotations[0]); + AString errorMessage; + if (selectedTabAnnotation != NULL) { + const bool result = annMan->expandBrowserTabAnnotation(allTabContent, + selectedTabAnnotation, + m_userInputMode, + errorMessage); + if ( ! result) { + WuQMessageBox::errorOk(this, + errorMessage); + } + } + else { + WuQMessageBox::errorOk(this, + "Selected annotation must be a browser tab"); + } + } + +} /** * Apply alignment selection. diff --git a/src/GuiQt/AnnotationMenuArrange.h b/src/GuiQt/AnnotationMenuArrange.h index 1a5ea226f..923d1035b 100644 --- a/src/GuiQt/AnnotationMenuArrange.h +++ b/src/GuiQt/AnnotationMenuArrange.h @@ -59,6 +59,8 @@ namespace caret { void addGroupingSelections(); + void addTileTabsSelections(); + void applyAlignment(const AnnotationAlignmentEnum::Enum alignment); void applyDistribute(const AnnotationDistributeEnum::Enum distribute); @@ -89,15 +91,21 @@ namespace caret { const qreal x, const qreal y); + bool processTileTabsMenu(QAction* actionSelected); + + void processExpandTabMenuItem(); + const UserInputModeEnum::Enum m_userInputMode; const int32_t m_browserWindowIndex; - QAction* m_groupAction; + QAction* m_groupAction = NULL; + + QAction* m_regroupAction = NULL; - QAction* m_regroupAction; + QAction* m_ungroupAction = NULL; - QAction* m_ungroupAction; + QAction* m_tileTabsExpandToFillAction = NULL; // ADD_NEW_MEMBERS_HERE -- GitLab From 2836a525ee733af7184bb7bca37d572d2705a3b1 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 27 Aug 2019 16:34:39 -0500 Subject: [PATCH 022/584] WB-859 Manual Tile Tabs Layout System: Added context menu for Tile Tabs Manual Layout mode with selections for selecting all tabs, ordering (bring to front, etc.), and expanding to fill empty space. --- src/Brain/AnnotationManager.cxx | 24 +- src/Brain/AnnotationManager.h | 8 +- src/GuiQt/AnnotationMenuArrange.cxx | 25 +- src/GuiQt/CMakeLists.txt | 9 +- src/GuiQt/UserInputModeAnnotations.h | 12 +- .../UserInputModeTileTabsManualLayout.cxx | 48 +++ src/GuiQt/UserInputModeTileTabsManualLayout.h | 4 + ...putModeTileTabsManualLayoutContextMenu.cxx | 319 ++++++++++++++++++ ...InputModeTileTabsManualLayoutContextMenu.h | 102 ++++++ src/GuiQt/UserInputModeViewContextMenu.cxx | 8 +- ...erInputModeViewContextTileTabsSubMenu.cxx} | 20 +- ...UserInputModeViewContextTileTabsSubMenu.h} | 20 +- 12 files changed, 536 insertions(+), 63 deletions(-) create mode 100644 src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx create mode 100644 src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h rename src/GuiQt/{UserInputTileTabsContextMenu.cxx => UserInputModeViewContextTileTabsSubMenu.cxx} (89%) rename src/GuiQt/{UserInputTileTabsContextMenu.h => UserInputModeViewContextTileTabsSubMenu.h} (76%) diff --git a/src/Brain/AnnotationManager.cxx b/src/Brain/AnnotationManager.cxx index 5c8c74436..03d14f6cc 100644 --- a/src/Brain/AnnotationManager.cxx +++ b/src/Brain/AnnotationManager.cxx @@ -1113,12 +1113,12 @@ AnnotationManager::restoreFromScene(const SceneAttributes* sceneAttributes, } /** - * Expand a browser tab to fill available space in the window. MANUAL MODE ONLY ! + * Expand selected browser tab to fill available space in the window. MANUAL MODE ONLY ! * * @param tabsInWindow * Tabs displayed in the window (may or may not include selected tab) - * @param selectedTabAnnotation - * Tab that is expanded + * @param windowIndex + * Index of window * @param userInputMode * The current user input mode (browser tab always) * @param errorMessageOut @@ -1127,13 +1127,20 @@ AnnotationManager::restoreFromScene(const SceneAttributes* sceneAttributes, * True no error, else false. */ bool -AnnotationManager::expandBrowserTabAnnotation(const std::vector& tabsInWindow, - AnnotationBrowserTab* selectedTabAnnotation, - const UserInputModeEnum::Enum userInputMode, - AString& errorMessageOut) +AnnotationManager::expandSelectedBrowserTabAnnotation(const std::vector& tabsInWindow, + const int32_t windowIndex, + const UserInputModeEnum::Enum userInputMode, + AString& errorMessageOut) { errorMessageOut.clear(); + AnnotationBrowserTab* selectedTabAnnotation(NULL); + std::vector selectedAnnotations = getAnnotationsSelectedForEditing(windowIndex); + if (selectedAnnotations.size() == 1) { + CaretAssertVectorIndex(selectedAnnotations, 0); + selectedTabAnnotation = dynamic_cast(selectedAnnotations[0]); + } + CaretAssert(selectedTabAnnotation); if (selectedTabAnnotation != NULL) { @@ -1146,7 +1153,6 @@ AnnotationManager::expandBrowserTabAnnotation(const std::vector& tabsInWindow, - AnnotationBrowserTab* selectedTabAnnotation, - const UserInputModeEnum::Enum userInputMode, - AString& errorMessageOut); + bool expandSelectedBrowserTabAnnotation(const std::vector& tabsInWindow, + const int32_t windowIndex, + const UserInputModeEnum::Enum userInputMode, + AString& errorMessageOut); // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index e6a1fc03a..ce48c2b1e 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -334,27 +334,16 @@ AnnotationMenuArrange::processExpandTabMenuItem() window->getAllTabContent(allTabContent); AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - std::vector selectedAnnotations = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex); - if (selectedAnnotations.size() == 1) { - CaretAssertVectorIndex(selectedAnnotations, 0); - AnnotationBrowserTab* selectedTabAnnotation = dynamic_cast(selectedAnnotations[0]); - AString errorMessage; - if (selectedTabAnnotation != NULL) { - const bool result = annMan->expandBrowserTabAnnotation(allTabContent, - selectedTabAnnotation, + AString errorMessage; + const bool result = annMan->expandSelectedBrowserTabAnnotation(allTabContent, + m_browserWindowIndex, m_userInputMode, errorMessage); - if ( ! result) { - WuQMessageBox::errorOk(this, - errorMessage); - } - } - else { - WuQMessageBox::errorOk(this, - "Selected annotation must be a browser tab"); - } + if ( ! result) { + WuQMessageBox::errorOk(this, + errorMessage); } - + } /** diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 954980a63..1761f21f0 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -195,9 +195,10 @@ ELSE() UserInputModeBordersWidget.h UserInputModeFociWidget.h UserInputModeImageWidget.h + UserInputModeTileTabsManualLayoutContextMenu.h UserInputModeViewContextMenu.h + UserInputModeViewContextTileTabsSubMenu.h UserInputModeVolumeEditWidget.h - UserInputTileTabsContextMenu.h UsernamePasswordWidget.h VolumeFileCreateDialog.h VolumePropertiesEditorDialog.h @@ -468,11 +469,12 @@ UserInputModeFoci.h UserInputModeImageWidget.h UserInputModeImage.h UserInputModeTileTabsManualLayout.h +UserInputModeTileTabsManualLayoutContextMenu.h UserInputModeView.h UserInputModeViewContextMenu.h +UserInputModeViewContextTileTabsSubMenu.h UserInputModeVolumeEdit.h UserInputModeVolumeEditWidget.h -UserInputTileTabsContextMenu.h UsernamePasswordWidget.h ViewModeEnum.h VolumeFileCreateDialog.h @@ -748,11 +750,12 @@ UserInputModeFociWidget.cxx UserInputModeImage.cxx UserInputModeImageWidget.cxx UserInputModeTileTabsManualLayout.cxx +UserInputModeTileTabsManualLayoutContextMenu.cxx UserInputModeView.cxx UserInputModeViewContextMenu.cxx +UserInputModeViewContextTileTabsSubMenu.cxx UserInputModeVolumeEdit.cxx UserInputModeVolumeEditWidget.cxx -UserInputTileTabsContextMenu.cxx UsernamePasswordWidget.cxx ViewModeEnum.cxx VolumeFileCreateDialog.cxx diff --git a/src/GuiQt/UserInputModeAnnotations.h b/src/GuiQt/UserInputModeAnnotations.h index 480dce88d..057890092 100644 --- a/src/GuiQt/UserInputModeAnnotations.h +++ b/src/GuiQt/UserInputModeAnnotations.h @@ -128,6 +128,11 @@ namespace caret { UserInputModeAnnotations(const UserInputModeEnum::Enum userInputMode, const int32_t windowIndex); + void processMouseSelectAnnotation(const MouseEvent& mouseEvent, + const bool shiftKeyDownFlag); + + void processSelectAllAnnotations(); + private: class NewMouseDragCreateAnnotation { public: @@ -187,9 +192,6 @@ namespace caret { void processModeNewMouseLeftClick(const MouseEvent& mouseEvent); - void processMouseSelectAnnotation(const MouseEvent& mouseEvent, - const bool shiftKeyDownFlag); - void processModeSetCoordinate(const MouseEvent& mouseEvent); void setAnnotationUnderMouse(const MouseEvent& mouseEvent, @@ -207,8 +209,6 @@ namespace caret { void deleteSelectedAnnotations(); - void processSelectAllAnnotations(); - void resetAnnotationUnderMouse(); bool isEditMenuValid() const; @@ -248,6 +248,8 @@ namespace caret { */ friend class UserInputModeAnnotationsContextMenu; friend class UserInputModeAnnotationsWidget; + friend class UserInputModeTileTabsManualLayout; + friend class UserInputModeTileTabsManualLayoutContextMenu; }; #ifdef __USER_INPUT_MODE_ANNOTATIONS_DECLARE__ diff --git a/src/GuiQt/UserInputModeTileTabsManualLayout.cxx b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx index 7082ca681..3c9835601 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayout.cxx +++ b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx @@ -23,7 +23,10 @@ #include "UserInputModeTileTabsManualLayout.h" #undef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_DECLARE__ +#include "BrainOpenGLViewportContent.h" +#include "BrowserTabContent.h" #include "CaretAssert.h" +#include "UserInputModeTileTabsManualLayoutContextMenu.h" using namespace caret; @@ -54,3 +57,48 @@ UserInputModeTileTabsManualLayout::~UserInputModeTileTabsManualLayout() { } +/** + * Show a context menu (pop-up menu at mouse location) + * + * @param mouseEvent + * Mouse event information. + * @param menuPosition + * Point at which menu is displayed (passed to QMenu::exec()) + * @param openGLWidget + * OpenGL widget in which context menu is requested + */ +void +UserInputModeTileTabsManualLayout::showContextMenu(const MouseEvent& mouseEvent, + const QPoint& menuPosition, + BrainOpenGLWidget* openGLWidget) +{ + BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); + BrowserTabContent* tabContent = viewportContent->getBrowserTabContent(); + if (tabContent == NULL) { + return; + } + + /* + * Select any annotation that is under the mouse. + * There might not be an annotation under the + * mouse and that is okay. + */ + processMouseSelectAnnotation(mouseEvent, + false); + + UserInputModeTileTabsManualLayoutContextMenu contextMenu(this, + mouseEvent, + tabContent, + openGLWidget); + if (contextMenu.actions().size() > 0) { + contextMenu.exec(menuPosition); + +// Annotation* newAnnotation = contextMenu.getNewAnnotationCreatedByContextMenu(); +// if (newAnnotation != NULL) { +// selectAnnotation(newAnnotation); +// +// EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +// EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); +// } + } +} diff --git a/src/GuiQt/UserInputModeTileTabsManualLayout.h b/src/GuiQt/UserInputModeTileTabsManualLayout.h index e786eae86..d220fe1a0 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayout.h +++ b/src/GuiQt/UserInputModeTileTabsManualLayout.h @@ -42,6 +42,10 @@ namespace caret { UserInputModeTileTabsManualLayout& operator=(const UserInputModeTileTabsManualLayout&) = delete; + virtual void showContextMenu(const MouseEvent& mouseEvent, + const QPoint& menuPosition, + BrainOpenGLWidget* openGLWidget) override; + // ADD_NEW_METHODS_HERE diff --git a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx new file mode 100644 index 000000000..0cd428109 --- /dev/null +++ b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx @@ -0,0 +1,319 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_DECLARE__ +#include "UserInputModeTileTabsManualLayoutContextMenu.h" +#undef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_DECLARE__ + +#include + +#include + +#include "AnnotationBrowserTab.h" +#include "AnnotationManager.h" +#include "AnnotationRedoUndoCommand.h" +#include "Brain.h" +#include "BrainOpenGLWidget.h" +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "EventBrowserTabGetAll.h" +#include "EventBrowserWindowTileTabOperation.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" +#include "GuiManager.h" +#include "MathFunctions.h" +#include "MouseEvent.h" +#include "UserInputModeTileTabsManualLayout.h" +#include "WuQDataEntryDialog.h" +#include "WuQMessageBox.h" + +using namespace caret; + + + +/** + * \class caret::UserInputModeTileTabsManualLayoutContextMenu + * \brief Context (pop-up) menu for User Input Manual Tile Tabs Layout. + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param userInputTileTabsManualLayout + * The manual layout input processor + * @param mouseEvent + * The mouse event that caused display of this menu. + * @param browserTabContent + * Content of browser tab. + * @param parentOpenGLWidget + * Parent OpenGL Widget on which the menu is displayed. + */ +UserInputModeTileTabsManualLayoutContextMenu::UserInputModeTileTabsManualLayoutContextMenu(UserInputModeTileTabsManualLayout* userInputTileTabsManualLayout, + const MouseEvent& mouseEvent, + BrowserTabContent* browserTabContent, + BrainOpenGLWidget* parentOpenGLWidget) +: QMenu(parentOpenGLWidget), +m_userInputTileTabsManualLayout(userInputTileTabsManualLayout), +m_mouseEvent(mouseEvent), +m_browserTabContent(browserTabContent), +m_parentOpenGLWidget(parentOpenGLWidget) +{ + CaretAssert(m_userInputTileTabsManualLayout); + + const int32_t browserWindexIndex = m_mouseEvent.getBrowserWindowIndex(); + AnnotationManager* annotationManager = GuiManager::get()->getBrain()->getAnnotationManager(); + std::vector selectedAnnotations = annotationManager->getAnnotationsSelectedForEditing(browserWindexIndex); + for (auto ann : selectedAnnotations) { + AnnotationBrowserTab* abt = dynamic_cast(ann); + if (abt != NULL) { + m_selectedBrowserTabAnnotations.push_back(abt); + } + } + const bool oneTabSelectedFlag(m_selectedBrowserTabAnnotations.size() == 1); + + /* + * Select All annotations + */ + addAction(BrainBrowserWindowEditMenuItemEnum::toGuiName(BrainBrowserWindowEditMenuItemEnum::SELECT_ALL), + this, SLOT(selectAllAnnotations())); + + /* + * Separator + */ + addSeparator(); + + /* + * Order Operations + */ + QAction* bringToFrontAction = addAction("Bring to Front"); + QObject::connect(bringToFrontAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::applyOrderBringToFront); + QAction* bringForwardAction = addAction("Bring Forward"); + QObject::connect(bringForwardAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::applyOrderBringForward); + QAction* sendToBackAction = addAction("Send to Back"); + QObject::connect(sendToBackAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::applyOrderSendToBack); + QAction* sendBackwardAction = addAction("Send Backward"); + QObject::connect(sendBackwardAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::applyOrderSendBackward); + + bringToFrontAction->setEnabled(oneTabSelectedFlag); + bringForwardAction->setEnabled(oneTabSelectedFlag); + sendToBackAction->setEnabled(oneTabSelectedFlag); + sendBackwardAction->setEnabled(oneTabSelectedFlag); + + addSeparator(); + + /* + * Group annotations + */ + QAction* groupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::GROUP), + this, SLOT(applyGroupingGroup())); + groupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::GROUP)); + + /* + * Ungroup annotations + */ + QAction* ungroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::UNGROUP), + this, SLOT(applyGroupingUngroup())); + ungroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::UNGROUP)); + + /* + * Regroup annotations + */ + QAction* regroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::REGROUP), + this, SLOT(applyGroupingRegroup())); + regroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::REGROUP)); + + /* + * Expand option + */ + addSeparator(); + QAction* expendToFillAction = addAction("Expand to Fill Empty Space"); + QObject::connect(expendToFillAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::processExpandTabMenuItem); + expendToFillAction->setEnabled(oneTabSelectedFlag); +} + +/** + * Destructor. + */ +UserInputModeTileTabsManualLayoutContextMenu::~UserInputModeTileTabsManualLayoutContextMenu() +{ +} + +/** + * Select all annotations in the window. + */ +void +UserInputModeTileTabsManualLayoutContextMenu::selectAllAnnotations() +{ + m_userInputTileTabsManualLayout->processSelectAllAnnotations(); +} + +/** + * Group annotations. + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyGroupingGroup() +{ + applyGrouping(AnnotationGroupingModeEnum::GROUP); +} + +/** + * Ungroup annotations. + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyGroupingRegroup() +{ + applyGrouping(AnnotationGroupingModeEnum::REGROUP); +} + +/** + * Regroup annotations. + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyGroupingUngroup() +{ + applyGrouping(AnnotationGroupingModeEnum::UNGROUP); +} + +/** + * Apply grouping selection. + * + * @param grouping + * Selected grouping. + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyGrouping(const AnnotationGroupingModeEnum::Enum grouping) +{ + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + + AString errorMessage; + if ( ! annMan->applyGroupingMode(m_userInputTileTabsManualLayout->getUserInputMode(), + m_mouseEvent.getBrowserWindowIndex(), + grouping, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + } + + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); +} + +/** + * Called when expand to fill space menu item is selected + */ +void +UserInputModeTileTabsManualLayoutContextMenu::processExpandTabMenuItem() +{ + const int32_t browserWindowIndex = m_mouseEvent.getBrowserWindowIndex(); + BrainBrowserWindow* window = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); + CaretAssert(window); + std::vector allTabContent; + window->getAllTabContent(allTabContent); + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + AString errorMessage; + const bool result = annMan->expandSelectedBrowserTabAnnotation(allTabContent, + browserWindowIndex, + m_userInputTileTabsManualLayout->getUserInputMode(), + errorMessage); + if ( ! result) { + WuQMessageBox::errorOk(this, + errorMessage); + } + +} + +/** + * Called when bring to front is selected + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyOrderBringToFront() +{ + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT); +} + +/** + * Called when bring forward is selected + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyOrderBringForward() +{ + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD); +} + +/** + * Called when send to back is selected + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyOrderSendToBack() +{ + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK); +} + +/** + * Called when send backward is selected + */ +void +UserInputModeTileTabsManualLayoutContextMenu::applyOrderSendBackward() +{ + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); +} + +/** + * Called to process a tile tab operation + * + * @param operation + * The operation + */ +void +UserInputModeTileTabsManualLayoutContextMenu::processWindowTileTabOperation(const EventBrowserWindowTileTabOperation::Operation operation) +{ + std::vector emptyBrowserTabs; + + int tabIndex(-1); + if (m_browserTabContent != NULL) { + tabIndex = m_browserTabContent->getTabNumber(); + } + int windowViewport[4] { 0, 0, m_parentOpenGLWidget->width(), m_parentOpenGLWidget->height() }; + EventBrowserWindowTileTabOperation tileTabOperation(operation, + m_parentOpenGLWidget, + m_mouseEvent.getBrowserWindowIndex(), + tabIndex, + windowViewport, + m_mouseEvent.getX(), + m_mouseEvent.getY(), + emptyBrowserTabs); + EventManager::get()->sendEvent(tileTabOperation.getPointer()); +} + + + diff --git a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h new file mode 100644 index 000000000..25ea80dc4 --- /dev/null +++ b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h @@ -0,0 +1,102 @@ +#ifndef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_H__ +#define __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include "AnnotationGroupingModeEnum.h" +#include "EventBrowserWindowTileTabOperation.h" +#include "MouseEvent.h" + +namespace caret { + + class AnnotationBrowserTab; + class BrainOpenGLWidget; + class BrowserTabContent; + class UserInputModeTileTabsManualLayout; + + class UserInputModeTileTabsManualLayoutContextMenu : public QMenu { + + Q_OBJECT + + public: + UserInputModeTileTabsManualLayoutContextMenu(UserInputModeTileTabsManualLayout* userInputTileTabsManualLayout, + const MouseEvent& mouseEvent, + BrowserTabContent* browserTabContent, + BrainOpenGLWidget* parentOpenGLWidget); + + virtual ~UserInputModeTileTabsManualLayoutContextMenu(); + + // ADD_NEW_METHODS_HERE + + private slots: + void selectAllAnnotations(); + + void applyGroupingGroup(); + + void applyGroupingRegroup(); + + void applyGroupingUngroup(); + + void applyOrderBringToFront(); + + void applyOrderBringForward(); + + void applyOrderSendToBack(); + + void applyOrderSendBackward(); + + private: + UserInputModeTileTabsManualLayoutContextMenu(const UserInputModeTileTabsManualLayoutContextMenu&); + + UserInputModeTileTabsManualLayoutContextMenu& operator=(const UserInputModeTileTabsManualLayoutContextMenu&); + + void applyGrouping(const AnnotationGroupingModeEnum::Enum grouping); + + void processExpandTabMenuItem(); + + void processWindowTileTabOperation(const EventBrowserWindowTileTabOperation::Operation operation); + + UserInputModeTileTabsManualLayout* m_userInputTileTabsManualLayout = NULL; + + /* + * NOT a reference. Need to COPY as its source may be deleted. + */ + const MouseEvent m_mouseEvent; + + BrowserTabContent* m_browserTabContent; + + BrainOpenGLWidget* m_parentOpenGLWidget; + + std::vector m_selectedBrowserTabAnnotations; + + // ADD_NEW_MEMBERS_HERE + + }; + +#ifdef __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_DECLARE__ + // +#endif // __USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_DECLARE__ + +} // namespace +#endif //__USER_INPUT_MODE_TILE_TABS_MANUAL_LAYOUT_CONTEXT_MENU_H__ diff --git a/src/GuiQt/UserInputModeViewContextMenu.cxx b/src/GuiQt/UserInputModeViewContextMenu.cxx index 73615790e..c33a0758b 100644 --- a/src/GuiQt/UserInputModeViewContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextMenu.cxx @@ -76,7 +76,7 @@ #include "SessionManager.h" #include "Surface.h" #include "UserInputModeFociWidget.h" -#include "UserInputTileTabsContextMenu.h" +#include "UserInputModeViewContextTileTabsSubMenu.h" #include "VolumeDynamicConnectivityFile.h" #include "VolumeFile.h" #include "WuQDataEntryDialog.h" @@ -119,9 +119,9 @@ UserInputModeViewContextMenu::UserInputModeViewContextMenu(const MouseEvent& mou this->browserTabContent = viewportContent->getBrowserTabContent(); CaretAssert(this->browserTabContent); - UserInputTileTabsContextMenu* tabMenu = new UserInputTileTabsContextMenu(mouseEvent, - this->parentOpenGLWidget, - this->viewportContent); + UserInputModeViewContextTileTabsSubMenu* tabMenu = new UserInputModeViewContextTileTabsSubMenu(mouseEvent, + this->parentOpenGLWidget, + this->viewportContent); if (tabMenu->isValid()) { addMenu(tabMenu); } diff --git a/src/GuiQt/UserInputTileTabsContextMenu.cxx b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx similarity index 89% rename from src/GuiQt/UserInputTileTabsContextMenu.cxx rename to src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx index 58ce3b5de..1e64608c3 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx @@ -19,9 +19,9 @@ */ /*LICENSE_END*/ -#define __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ -#include "UserInputTileTabsContextMenu.h" -#undef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ +#define __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_DECLARE__ +#include "UserInputModeViewContextTileTabsSubMenu.h" +#undef __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_DECLARE__ #include "BrainBrowserWindow.h" #include "BrainOpenGLViewportContent.h" @@ -39,7 +39,7 @@ using namespace caret; /** - * \class caret::UserInputTileTabsContextMenu + * \class caret::UserInputModeViewContextTileTabsSubMenu * \brief Menu for tile tabs operations in a window context menu * \ingroup GuiQt */ @@ -54,7 +54,7 @@ using namespace caret; * @param viewportContent * Content of the viewport under the mouse. */ -UserInputTileTabsContextMenu::UserInputTileTabsContextMenu(const MouseEvent& mouseEvent, +UserInputModeViewContextTileTabsSubMenu::UserInputModeViewContextTileTabsSubMenu(const MouseEvent& mouseEvent, QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent) : QMenu("Tabs"), @@ -121,13 +121,13 @@ m_tabIndex(viewportContent->getTabIndex()) } QObject::connect(this, &QMenu::triggered, - this, &UserInputTileTabsContextMenu::actionTriggered); + this, &UserInputModeViewContextTileTabsSubMenu::actionTriggered); } /** * Destructor. */ -UserInputTileTabsContextMenu::~UserInputTileTabsContextMenu() +UserInputModeViewContextTileTabsSubMenu::~UserInputModeViewContextTileTabsSubMenu() { } @@ -135,7 +135,7 @@ UserInputTileTabsContextMenu::~UserInputTileTabsContextMenu() * @return Is this menu valid? */ bool -UserInputTileTabsContextMenu::isValid() const +UserInputModeViewContextTileTabsSubMenu::isValid() const { return (actions().size() > 0); } @@ -149,7 +149,7 @@ UserInputTileTabsContextMenu::isValid() const * The operation */ void -UserInputTileTabsContextMenu::addItemToMenu(const QString& text, +UserInputModeViewContextTileTabsSubMenu::addItemToMenu(const QString& text, const EventBrowserWindowTileTabOperation::Operation operation) { QAction* action = addAction(text); @@ -165,7 +165,7 @@ UserInputTileTabsContextMenu::addItemToMenu(const QString& text, * Action selected by user. */ void -UserInputTileTabsContextMenu::actionTriggered(QAction* action) +UserInputModeViewContextTileTabsSubMenu::actionTriggered(QAction* action) { if (action == NULL) { return; diff --git a/src/GuiQt/UserInputTileTabsContextMenu.h b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.h similarity index 76% rename from src/GuiQt/UserInputTileTabsContextMenu.h rename to src/GuiQt/UserInputModeViewContextTileTabsSubMenu.h index 303997fd5..1d66ceea1 100644 --- a/src/GuiQt/UserInputTileTabsContextMenu.h +++ b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.h @@ -1,5 +1,5 @@ -#ifndef __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ -#define __USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ +#ifndef __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_H__ +#define __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_H__ /*LICENSE_START*/ /* @@ -36,16 +36,16 @@ namespace caret { class BrainOpenGLViewportContent; class MouseEvent; - class UserInputTileTabsContextMenu : public QMenu { + class UserInputModeViewContextTileTabsSubMenu : public QMenu { Q_OBJECT public: - UserInputTileTabsContextMenu(const MouseEvent& mouseEvent, + UserInputModeViewContextTileTabsSubMenu(const MouseEvent& mouseEvent, QWidget* parentWidget, BrainOpenGLViewportContent* viewportContent); - virtual ~UserInputTileTabsContextMenu(); + virtual ~UserInputModeViewContextTileTabsSubMenu(); bool isValid() const; @@ -55,9 +55,9 @@ namespace caret { void actionTriggered(QAction* action); private: - UserInputTileTabsContextMenu(const UserInputTileTabsContextMenu&); + UserInputModeViewContextTileTabsSubMenu(const UserInputModeViewContextTileTabsSubMenu&); - UserInputTileTabsContextMenu& operator=(const UserInputTileTabsContextMenu&); + UserInputModeViewContextTileTabsSubMenu& operator=(const UserInputModeViewContextTileTabsSubMenu&); void addItemToMenu(const QString& text, const EventBrowserWindowTileTabOperation::Operation operation); @@ -94,9 +94,9 @@ namespace caret { }; -#ifdef __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ +#ifdef __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_DECLARE__ // -#endif // __USER_INPUT_TILE_TABS_CONTEXT_MENU_DECLARE__ +#endif // __USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_DECLARE__ } // namespace -#endif //__USER_INPUT_TILE_TABS_CONTEXT_MENU_H__ +#endif //__USER_INPUT_MODE_VIEW_CONTEXT_TILE_TABS_SUB_MENU_H__ -- GitLab From 46b3bab8de747a132f1023d6308cdb8f1da2682a Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Aug 2019 11:07:25 -0500 Subject: [PATCH 023/584] WB-859 Manual Tile Tabs Layout System: Add insertion of tab to Tile Tab Manual Layout editing; ensure new tab is fully within the window; fixed enabling of Redo/Undo part of toolbar. --- src/GuiQt/AnnotationMenuArrange.cxx | 2 +- src/GuiQt/AnnotationRedoUndoWidget.cxx | 4 ++- src/GuiQt/BrainBrowserWindowToolBar.cxx | 23 ++++++++++++++ .../UserInputModeTileTabsManualLayout.cxx | 6 ++-- ...putModeTileTabsManualLayoutContextMenu.cxx | 23 ++++++++++++-- ...InputModeTileTabsManualLayoutContextMenu.h | 6 ++-- ...serInputModeViewContextTileTabsSubMenu.cxx | 31 ++++++++++--------- 7 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index ce48c2b1e..e1938292e 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -224,7 +224,7 @@ AnnotationMenuArrange::addTileTabsSelections() addSeparator(); - m_tileTabsExpandToFillAction = addAction("Expand to Fill Empty Space"); + m_tileTabsExpandToFillAction = addAction("Expand Tab to Fill Empty Space"); } diff --git a/src/GuiQt/AnnotationRedoUndoWidget.cxx b/src/GuiQt/AnnotationRedoUndoWidget.cxx index bf693a749..32463791b 100644 --- a/src/GuiQt/AnnotationRedoUndoWidget.cxx +++ b/src/GuiQt/AnnotationRedoUndoWidget.cxx @@ -124,7 +124,9 @@ AnnotationRedoUndoWidget::updateContent(const std::vector& annotati m_undoAction->setEnabled(undoStack->canUndo()); m_undoAction->setToolTip(undoStack->undoText()); - setEnabled( ! annotations.empty()); + setEnabled(( ! annotations.empty()) + || m_redoAction->isEnabled() + || m_undoAction->isEnabled()); } diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index 977cb538b..d77f3b776 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -4744,6 +4744,29 @@ BrainBrowserWindowToolBar::processTileTabOperationEvent(EventBrowserWindowTileTa tabMinY = (tabMinY / windowHeight) * 100.0; tabMaxY = (tabMaxY / windowHeight) * 100.0; + /* + * Move tab if partially outside of window + */ + float offsetX(0.0); + if (tabMinX < 0.0) { + offsetX = 1.0 - tabMinX; + } + else if (tabMaxX >= 100) { + offsetX = -(tabMaxX - 99.0); + } + tabMinX += offsetX; + tabMaxX += offsetX; + + float offsetY(0.0); + if (tabMinY < 0.0) { + offsetY = 1.0 - tabMinY; + } + else if (tabMaxY >= 100.0) { + offsetY = -(tabMaxY - 99.0); + } + tabMinY += offsetY; + tabMaxY += offsetY; + AnnotationBrowserTab* tabAnnotation = btc->getManualLayoutBrowserTabAnnotation(); CaretAssert(tabAnnotation); tabAnnotation->setBounds2D(tabMinX, diff --git a/src/GuiQt/UserInputModeTileTabsManualLayout.cxx b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx index 3c9835601..87a9d63b3 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayout.cxx +++ b/src/GuiQt/UserInputModeTileTabsManualLayout.cxx @@ -74,9 +74,9 @@ UserInputModeTileTabsManualLayout::showContextMenu(const MouseEvent& mouseEvent, { BrainOpenGLViewportContent* viewportContent = mouseEvent.getViewportContent(); BrowserTabContent* tabContent = viewportContent->getBrowserTabContent(); - if (tabContent == NULL) { - return; - } +// if (tabContent == NULL) { +// return; +// } /* * Select any annotation that is under the mouse. diff --git a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx index 0cd428109..874b70766 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx +++ b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx @@ -149,12 +149,21 @@ m_parentOpenGLWidget(parentOpenGLWidget) this, SLOT(applyGroupingRegroup())); regroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, AnnotationGroupingModeEnum::REGROUP)); + + + addSeparator(); + + /* + * Insert new tab option + */ + QAction* insertNewTabAction = addAction("Insert New Tab"); + QObject::connect(insertNewTabAction, &QAction::triggered, + this, &UserInputModeTileTabsManualLayoutContextMenu::processInsertNewTabMenuItem); /* * Expand option */ - addSeparator(); - QAction* expendToFillAction = addAction("Expand to Fill Empty Space"); + QAction* expendToFillAction = addAction("Expand Tab to Fill Empty Space"); QObject::connect(expendToFillAction, &QAction::triggered, this, &UserInputModeTileTabsManualLayoutContextMenu::processExpandTabMenuItem); expendToFillAction->setEnabled(oneTabSelectedFlag); @@ -288,6 +297,16 @@ UserInputModeTileTabsManualLayoutContextMenu::applyOrderSendBackward() processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); } +/** + * Insert a new tab at mouse location + */ +void +UserInputModeTileTabsManualLayoutContextMenu::processInsertNewTabMenuItem() +{ + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB); +} + + /** * Called to process a tile tab operation * diff --git a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h index 25ea80dc4..950dbfbe4 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h +++ b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.h @@ -66,6 +66,10 @@ namespace caret { void applyOrderSendBackward(); + void processExpandTabMenuItem(); + + void processInsertNewTabMenuItem(); + private: UserInputModeTileTabsManualLayoutContextMenu(const UserInputModeTileTabsManualLayoutContextMenu&); @@ -73,8 +77,6 @@ namespace caret { void applyGrouping(const AnnotationGroupingModeEnum::Enum grouping); - void processExpandTabMenuItem(); - void processWindowTileTabOperation(const EventBrowserWindowTileTabOperation::Operation operation); UserInputModeTileTabsManualLayout* m_userInputTileTabsManualLayout = NULL; diff --git a/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx index 1e64608c3..00d09732b 100644 --- a/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx +++ b/src/GuiQt/UserInputModeViewContextTileTabsSubMenu.cxx @@ -92,21 +92,24 @@ m_tabIndex(viewportContent->getTabIndex()) } break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: - addItemToMenu("Insert Tab at Mouse", - EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB); - - if (tabContent != NULL) { - if (actions().count() > 0) { - addSeparator(); + const bool showManualTabLayoutOptionsFlag(false); + if (showManualTabLayoutOptionsFlag) { + addItemToMenu("Insert Tab at Mouse", + EventBrowserWindowTileTabOperation::OPERATION_MANUAL_NEW_TAB); + + if (tabContent != NULL) { + if (actions().count() > 0) { + addSeparator(); + } + addItemToMenu("Bring to Front", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT); + addItemToMenu("Bring Forward", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD); + addItemToMenu("Send to Back", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK); + addItemToMenu("Send Backward", + EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); } - addItemToMenu("Bring to Front", - EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT); - addItemToMenu("Bring Forward", - EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD); - addItemToMenu("Send to Back", - EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK); - addItemToMenu("Send Backward", - EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); } break; } -- GitLab From c53e74d988578b648360814e9ff1939e398a28cc Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 28 Aug 2019 15:05:48 -0500 Subject: [PATCH 024/584] WB-859 Manual Tile Tabs Layout System: Fixed selection of manual layout tabs in tile tabs editing and also fixed adjustment of tiles using the sizing handles. The problem was that identification processing was limited to the area within the tab viewport after application of aspect locking. It has been corrected to use the full area of the tab prior to aspect locking. --- src/Brain/BrainOpenGLViewportContent.cxx | 51 +++++++++++++++++++++++- src/Brain/BrainOpenGLViewportContent.h | 6 +++ src/Brain/BrainOpenGLWindowContent.cxx | 46 +++++++++++++++++++++ src/Brain/BrainOpenGLWindowContent.h | 3 ++ src/GuiQt/BrainOpenGLWidget.cxx | 46 ++++++++++++++++++++- src/GuiQt/BrainOpenGLWidget.h | 3 ++ 6 files changed, 151 insertions(+), 4 deletions(-) diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 875624e14..8d6804297 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -62,6 +62,8 @@ using namespace caret; * * @param windowViewport * Viewport of WINDOW in which drawing takes place. + * @param tabViewportManualLayoutBeforeAspectLocking + * Viewport before locking in a manual layout (for grid, same as tab viewport) * @param tabViewport * Viewport for TAB in which drawing takes place. * @param modelViewport @@ -78,6 +80,7 @@ using namespace caret; * Spacer Tab content that is being drawn (if not NULL) */ BrainOpenGLViewportContent::BrainOpenGLViewportContent(const int windowViewport[4], + const int tabViewportManualLayoutBeforeAspectLocking[4], const int tabViewport[4], const int modelViewport[4], const int windowIndex, @@ -100,6 +103,10 @@ m_spacerTabContent(spacerTabContent) m_tabWidth = tabViewport[2]; m_tabHeight = tabViewport[3]; + for (int32_t i = 0; i < 4; i++) { + m_tabViewportManualLayoutBeforeAspectLocking[i] = tabViewportManualLayoutBeforeAspectLocking[i]; + } + m_modelX = modelViewport[0]; m_modelY = modelViewport[1]; m_modelWidth = modelViewport[2]; @@ -180,6 +187,9 @@ BrainOpenGLViewportContent::initializeMembersBrainOpenGLViewportContent() m_windowHeight = 0; m_browserTabContent = NULL; m_spacerTabContent = NULL; + for (int32_t i = 0; i < 4; i++) { + m_tabViewportManualLayoutBeforeAspectLocking[i] = 0; + } } /** @@ -209,7 +219,10 @@ BrainOpenGLViewportContent::copyHelperBrainOpenGLViewportContent(const BrainOpen m_windowY = obj.m_windowY; m_windowWidth = obj.m_windowWidth; m_windowHeight = obj.m_windowHeight; - + for (int32_t i = 0; i < 4; i++) { + m_tabViewportManualLayoutBeforeAspectLocking[i] = obj.m_tabViewportManualLayoutBeforeAspectLocking[i]; + } + m_browserTabContent = obj.m_browserTabContent; m_spacerTabContent = obj.m_spacerTabContent; } @@ -402,6 +415,20 @@ BrainOpenGLViewportContent::getTabViewportBeforeApplyingMargins(int tabViewportO tabViewportOut[2] = m_tabWidth; tabViewportOut[3] = m_tabHeight; } +/** + * Get the viewport for drawing a tab in a manual layout before application of aspect locking + * + * @param tabViewportOut + * Output into which tab viewport dimensions are loaded. + * (x, y, width, height) + */ +void +BrainOpenGLViewportContent::getTabViewportManualLayoutBeforeAspectLocking(int tabViewportOut[4]) const +{ + for (int32_t i = 0; i < 4; i++) { + tabViewportOut[i] = m_tabViewportManualLayoutBeforeAspectLocking[i]; + } +} /** * @return Pointer to the viewport for the window. @@ -470,7 +497,7 @@ BrainOpenGLViewportContent::toString() const const QString windowMsg = QString(" Window x=%1 y=%2 w=%3 h=%4").arg(m_windowX).arg(m_windowY).arg(m_windowWidth).arg(m_windowHeight); const QString tabMsg = QString(" Tab x=%1 y=%2 w=%3 h=%4").arg(m_tabX).arg(m_tabY).arg(m_tabWidth).arg(m_tabHeight); const QString modelMsg = QString(" Model x=%1 y=%2 w=%3 h=%4").arg(m_modelX).arg(m_modelY).arg(m_modelWidth).arg(m_modelHeight); - + const QString manMsg = QString(" Model x=%1 y=%2 w=%3 h=%4").arg(m_tabViewportManualLayoutBeforeAspectLocking[0]).arg(m_tabViewportManualLayoutBeforeAspectLocking[1]).arg(m_tabViewportManualLayoutBeforeAspectLocking[2]).arg(m_tabViewportManualLayoutBeforeAspectLocking[3]); AString msgOut; if (m_chartDataViewportValidFlag) { const QString chartProjectionMsg = QString(" Chart Projection=" + m_chartDataProjectionMatrix.toFormattedString(" ")); @@ -486,6 +513,7 @@ BrainOpenGLViewportContent::toString() const msgOut.appendWithNewLine(windowMsg); msgOut.appendWithNewLine(tabMsg); msgOut.appendWithNewLine(modelMsg); + msgOut.appendWithNewLine(manMsg); return msgOut; } @@ -511,6 +539,13 @@ BrainOpenGLViewportContent::createViewportForSingleTab(std::vector eventContent = EventBrowserWindowContent::getWindowContent(windowIndex); EventManager::get()->sendEvent(eventContent->getPointer()); @@ -568,6 +604,7 @@ BrainOpenGLViewportContent::createViewportForSingleTab(std::vectorgetWindowIndex(), @@ -946,6 +984,7 @@ BrainOpenGLViewportContent::createViewportContentForGridTileTabs(std::vectorgetWindowIndex(), @@ -1063,6 +1102,13 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vectorgetWindowIndex(), diff --git a/src/Brain/BrainOpenGLViewportContent.h b/src/Brain/BrainOpenGLViewportContent.h index f822b43ea..8670426de 100644 --- a/src/Brain/BrainOpenGLViewportContent.h +++ b/src/Brain/BrainOpenGLViewportContent.h @@ -60,6 +60,8 @@ namespace caret { void getTabViewportBeforeApplyingMargins(int tabViewportOut[4]) const; + void getTabViewportManualLayoutBeforeAspectLocking(int tabViewportOut[4]) const; + void getWindowViewport(int windowViewportOut[4]) const; int getWindowIndex() const; @@ -135,6 +137,7 @@ namespace caret { }; BrainOpenGLViewportContent(const int windowViewport[4], + const int tabViewportManualLayoutBeforeAspectLocking[4], const int tabViewport[4], const int modelViewport[4], const int windowIndex, @@ -182,6 +185,9 @@ namespace caret { /** Tab viewport's Height */ int m_tabHeight; + /** Manual layout tab viewport before aspect locking is applied */ + int m_tabViewportManualLayoutBeforeAspectLocking[4]; + /** Chart data viewport's X-coordinate */ mutable int m_chartDataX; /** Chart data viewport's Y-coordinate */ diff --git a/src/Brain/BrainOpenGLWindowContent.cxx b/src/Brain/BrainOpenGLWindowContent.cxx index 34595a4f8..92a58e2b4 100644 --- a/src/Brain/BrainOpenGLWindowContent.cxx +++ b/src/Brain/BrainOpenGLWindowContent.cxx @@ -192,6 +192,52 @@ BrainOpenGLWindowContent::getTabViewportWithLockAspectXY(const int32_t x, return viewportContentOut; } +/** + * Get the tab viewport containing the given X/Y coordinates + * for a manual layout prior to aspect locking. + * + * @param x + * The X-coordinate + * @param y + * The Y-coordinate + * @return + * Tab viewport containing the coordinate or NULL if not found. + */ +const BrainOpenGLViewportContent* +BrainOpenGLWindowContent::getTabViewportManualLayoutWithoutAspectLocking(const int32_t x, + const int32_t y) const +{ + BrainOpenGLViewportContent* viewportContentOut(NULL); + + for (const auto& vp : m_tabViewports) { + int32_t viewport[4]; + vp->getTabViewportManualLayoutBeforeAspectLocking(viewport); + if ((x >= viewport[0]) + && (x < (viewport[0] + viewport[2])) + && (y >= viewport[1]) + && (y < (viewport[1] + viewport[3]))) { + if (viewportContentOut == NULL) { + viewportContentOut = vp.get(); + } + else { + /* + * Note: The tabs ONLY overlay in a manual tile tabs layout + */ + const BrowserTabContent* btc = vp.get()->getBrowserTabContent(); + const BrowserTabContent* btcOut = viewportContentOut->getBrowserTabContent(); + if ((btc != NULL) + && (btcOut != NULL)) { + if (btc->getManualLayoutBrowserTabAnnotation()->getStackingOrder() + > btcOut->getManualLayoutBrowserTabAnnotation()->getStackingOrder()) { + viewportContentOut = vp.get(); + } + } + } + } + } + + return viewportContentOut; +} /** * All viewports for all tabs. diff --git a/src/Brain/BrainOpenGLWindowContent.h b/src/Brain/BrainOpenGLWindowContent.h index 9109f795d..5c7f9ab46 100644 --- a/src/Brain/BrainOpenGLWindowContent.h +++ b/src/Brain/BrainOpenGLWindowContent.h @@ -56,6 +56,9 @@ namespace caret { const BrainOpenGLViewportContent* getTabViewportWithLockAspectXY(const int32_t x, const int32_t y) const; + const BrainOpenGLViewportContent* getTabViewportManualLayoutWithoutAspectLocking(const int32_t x, + const int32_t y) const; + const BrainOpenGLViewportContent* getWindowViewport() const; std::vector getAllTabViewports() const; diff --git a/src/GuiQt/BrainOpenGLWidget.cxx b/src/GuiQt/BrainOpenGLWidget.cxx index 4be5f222c..39e84e01f 100644 --- a/src/GuiQt/BrainOpenGLWidget.cxx +++ b/src/GuiQt/BrainOpenGLWidget.cxx @@ -1270,6 +1270,30 @@ BrainOpenGLWidget::getViewportContentAtXY(const int x, return m_windowContent.getWindowViewport(); } +/** + * Get the viewport content at the given location WITHOUT aspect locking. + * @param x + * X-coordinate. + * @param y + * Y-coordinate. + */ +const BrainOpenGLViewportContent* +BrainOpenGLWidget::getViewportContentManualLayoutWithoutLockAspectAtXY(const int x, + const int y) +{ + const BrainOpenGLViewportContent* tabViewportContent = m_windowContent.getTabViewportManualLayoutWithoutAspectLocking(x, y); + if (tabViewportContent != NULL) { + return tabViewportContent; + } + + /* + * If not in a tab, then use the window viewport information. + * This allows selection of annotations in window space that are not + * within a tab (tab may be small in height due to lock aspect). + */ + return m_windowContent.getWindowViewport(); +} + /** * Get all viewport content. If tile tabs is ON, the output will contain * viewport content for all tabs. Otherwise, the output will contain viewport @@ -1363,8 +1387,26 @@ SelectionItemAnnotation* BrainOpenGLWidget::performIdentificationAnnotations(const int x, const int y) { - const BrainOpenGLViewportContent* idViewport = this->getViewportContentAtXY(x, y); - + bool manLayoutFlag(false); + switch (this->selectedUserInputProcessor->getUserInputMode()) { + case UserInputModeEnum::ANNOTATIONS: + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + manLayoutFlag = true; + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + case UserInputModeEnum::VIEW: + case UserInputModeEnum::VOLUME_EDIT: + break; + } + + const BrainOpenGLViewportContent* idViewport = (manLayoutFlag + ? this->getViewportContentManualLayoutWithoutLockAspectAtXY(x, y) + : this->getViewportContentAtXY(x, y)); + this->makeCurrent(); CaretLogFine("Performing selection"); SelectionManager* idManager = GuiManager::get()->getBrain()->getSelectionManager(); diff --git a/src/GuiQt/BrainOpenGLWidget.h b/src/GuiQt/BrainOpenGLWidget.h index 3e70aa2a9..6b9e24960 100644 --- a/src/GuiQt/BrainOpenGLWidget.h +++ b/src/GuiQt/BrainOpenGLWidget.h @@ -161,6 +161,9 @@ namespace caret { const BrainOpenGLViewportContent* getViewportContentAtXY(const int x, const int y); + const BrainOpenGLViewportContent* getViewportContentManualLayoutWithoutLockAspectAtXY(const int x, + const int y); + void checkForMiddleMouseButton(Qt::MouseButtons& mouseButtons, Qt::MouseButton& button, Qt::KeyboardModifiers& keyModifiers, -- GitLab From 18dafc1f5c553de452ea8f80c7a5949a15d85f3d Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 29 Aug 2019 15:57:05 -0500 Subject: [PATCH 025/584] WB-859 Manual Tile Tabs Layout System: Added items to context menu when user right-clicks on a tab in the browser window and if a manual tab layout is currently selected: (1) Select for Manual Editing and (2) Show/Hide Tab Content in Window. "Select for Manual Editing" is enable when the Mode is Tile and allows the user select the tab for editing is layout properties. "Show/Hide Tab Content" is enabled when a manual layout is active and allows one to show or hide the tab's content in the graphics window. Also, fixed bug in toolbar related to tab dragging that disable graphics/user-interface events from the time the mouse was pressed until the mouse was released. However, when the pop-up (context sensitive) menu is displayed, the mouse pressed method is called by Qt but not the mouse released method. So, when the mouse is pressed, only block signals if the the left-button is detected as down. --- src/GuiQt/AnnotationNameWidget.cxx | 114 +++++++++++++--- src/GuiQt/AnnotationNameWidget.h | 9 ++ src/GuiQt/BrainBrowserWindowToolBar.cxx | 37 ++++-- src/GuiQt/BrainBrowserWindowToolBar.h | 4 +- .../BrainBrowserWindowToolBarTabPopUpMenu.cxx | 123 +++++++++++++++++- .../BrainBrowserWindowToolBarTabPopUpMenu.h | 12 +- src/GuiQt/TileTabsConfigurationDialog.cxx | 38 +----- src/GuiQt/UserInputModeAnnotationsWidget.cxx | 4 +- src/GuiQt/WuQTabBar.cxx | 4 +- src/GuiQt/WuQTabBar.h | 4 +- 10 files changed, 270 insertions(+), 79 deletions(-) diff --git a/src/GuiQt/AnnotationNameWidget.cxx b/src/GuiQt/AnnotationNameWidget.cxx index 4e28bc567..42c254b6d 100644 --- a/src/GuiQt/AnnotationNameWidget.cxx +++ b/src/GuiQt/AnnotationNameWidget.cxx @@ -23,13 +23,17 @@ #include "AnnotationNameWidget.h" #undef __ANNOTATION_NAME_WIDGET_DECLARE__ +#include #include -#include +#include #include "AnnotationBrowserTab.h" #include "AnnotationMenuArrange.h" #include "BrowserTabContent.h" #include "CaretAssert.h" +#include "EventGraphicsUpdateOneWindow.cxx" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" #include "WuQtUtilities.h" using namespace caret; @@ -58,9 +62,21 @@ m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { m_nameLabel = new QLabel(); - QHBoxLayout* layout = new QHBoxLayout(this); - WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); - layout->addWidget(m_nameLabel, 100, Qt::AlignVCenter); + + m_visibilityCheckBox = new QCheckBox("Visible"); + QObject::connect(m_visibilityCheckBox, &QCheckBox::stateChanged, + this, &AnnotationNameWidget::visibilityCheckStateChanged); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins(2, 2, 2, 2); + layout->addWidget(m_nameLabel, 0, Qt::AlignLeft); + layout->addWidget(m_visibilityCheckBox, 0, Qt::AlignLeft); + layout->addStretch(); + + /* + * No visibility checkbox for now + */ + m_visibilityCheckBox->setHidden(true); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -82,23 +98,87 @@ AnnotationNameWidget::~AnnotationNameWidget() void AnnotationNameWidget::updateContent(const std::vector& annotations) { - AString name; - const int32_t numSelected = static_cast(annotations.size()); - if (numSelected > 1) { - name = "+"; + m_browserTabAnnotations.clear(); + for (auto ann : annotations) { + if (ann != NULL) { + AnnotationBrowserTab* abt = dynamic_cast(ann); + if (abt != NULL) { + m_browserTabAnnotations.push_back(abt); + } + } } - else if (numSelected == 1) { - CaretAssertVectorIndex(annotations, 0); - AnnotationBrowserTab* browserTabAnnotation = dynamic_cast(annotations[0]); - if (browserTabAnnotation != NULL) { - const BrowserTabContent* tabContent = browserTabAnnotation->getBrowserTabContent(); - if (tabContent != NULL) { - name = tabContent->getTabName(); + + int32_t visibleCount(0); + int32_t hiddenCount(0); + AString nameText; + const int32_t numberOfAnnotations = static_cast(m_browserTabAnnotations.size()); + + for (auto browserTabAnnotation : m_browserTabAnnotations) { + CaretAssert(browserTabAnnotation); + const BrowserTabContent* tabContent = browserTabAnnotation->getBrowserTabContent(); + if (tabContent != NULL) { + if (numberOfAnnotations == 1) { + nameText = tabContent->getTabName(); + } + else { + if ( ! nameText.isEmpty()) { + nameText.append(","); + } + nameText.append(QString::number(tabContent->getTabNumber() + 1)); } } + + if (browserTabAnnotation->isBrowserTabDisplayed()) { + visibleCount++; + } + else { + hiddenCount++; + } } - setEnabled(numSelected > 0); - m_nameLabel->setText(name); + setEnabled(numberOfAnnotations > 0); + + m_nameLabel->setText(nameText); + + /* + * Need to block signals as QCheckBox::setCheckState() + * causes a emission of a signal + */ + QSignalBlocker checkBoxBlocker(m_visibilityCheckBox); + if ((visibleCount > 0) + && (hiddenCount > 0)) { + m_visibilityCheckBox->setCheckState(Qt::PartiallyChecked); + } + else if (visibleCount > 0) { + m_visibilityCheckBox->setCheckState(Qt::Checked); + } + else { + m_visibilityCheckBox->setCheckState(Qt::Unchecked); + } } +/** + * Called when state of visibility checkbox is changed + */ +void +AnnotationNameWidget::visibilityCheckStateChanged(int state) +{ + Qt::CheckState checkState = static_cast(state); + switch (checkState) { + case Qt::Unchecked: + for (auto bta : m_browserTabAnnotations) { + bta->setBrowserTabDisplayed(false); + } + break; + case Qt::PartiallyChecked: + break; + case Qt::Checked: + for (auto bta : m_browserTabAnnotations) { + bta->setBrowserTabDisplayed(true); + } + break; + } + + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); +} diff --git a/src/GuiQt/AnnotationNameWidget.h b/src/GuiQt/AnnotationNameWidget.h index fbef0d1ac..070fe85da 100644 --- a/src/GuiQt/AnnotationNameWidget.h +++ b/src/GuiQt/AnnotationNameWidget.h @@ -27,11 +27,13 @@ #include "UserInputModeEnum.h" +class QCheckBox; class QLabel; namespace caret { class Annotation; + class AnnotationBrowserTab; class AnnotationNameWidget : public QWidget { @@ -49,6 +51,9 @@ namespace caret { void updateContent(const std::vector& annotations); + private slots: + void visibilityCheckStateChanged(int state); + private: AnnotationNameWidget(const AnnotationNameWidget&); @@ -60,6 +65,10 @@ namespace caret { QLabel* m_nameLabel; + QCheckBox* m_visibilityCheckBox; + + std::vector m_browserTabAnnotations; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index d77f3b776..c46e4b470 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1678,38 +1679,47 @@ BrainBrowserWindowToolBar::resetTabIndexForTileTabsHighlighting() * Called when tab bar mouse pressed. */ void -BrainBrowserWindowToolBar::tabBarMousePressedSlot() +BrainBrowserWindowToolBar::tabBarMousePressedSlot(QMouseEvent* event) { /* + * Only block if LEFT button is used without modifiers. Otherwise, if user + * performs right-click with mouse to display menu, the "mouseReleased" is + * never called by Qt. In addition, we don't want to block signals when + * the pop-up menu is displayed. + * * Dragging tabs is slow because as the tab is moved, there are many graphics * and user-interface updates each time the tab changes. So, disable these updates * during the time the mouse is pressed and until it is released. Note that we * block the "all windows graphics" update but not the individual window update. * The individual window graphics update is needed to draw the box around the selected tab. */ - EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); - EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, true); + if (event->button() == Qt::LeftButton) { + EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, true); + EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, true); + } } /** * Called when tab bar mouse released. */ void -BrainBrowserWindowToolBar::tabBarMouseReleasedSlot() +BrainBrowserWindowToolBar::tabBarMouseReleasedSlot(QMouseEvent* event) { /* * Enable user-interface updates and graphics drawing since any tab * dragging has finished. */ - EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); - EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, false); - EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); - - /** - * Causes graphics and user-interface to update. - * A box is drawn around selected tab. - */ - selectedTabChanged(tabBar->currentIndex()); + if (event->button() == Qt::LeftButton) { + EventManager::get()->blockEvent(EventTypeEnum::EVENT_USER_INTERFACE_UPDATE, false); + EventManager::get()->blockEvent(EventTypeEnum::EVENT_GRAPHICS_UPDATE_ALL_WINDOWS, false); + EventManager::get()->sendEvent(EventUserInterfaceUpdate().setWindowIndex(this->browserWindowIndex).getPointer()); + + /** + * Causes graphics and user-interface to update. + * A box is drawn around selected tab. + */ + selectedTabChanged(tabBar->currentIndex()); + } } /** @@ -3065,7 +3075,6 @@ BrainBrowserWindowToolBar::createModeWidget() inputModeFociToolButton->sizePolicy().verticalPolicy()); inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0); inputModeLayout->addWidget(inputModeTileTabsManualLayoutButton, modeRow, 1); -// inputModeLayout->addWidget(inputModeFociToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); } modeRow++; inputModeLayout->addWidget(inputModeViewToolButton, modeRow, 0, 1, 2, Qt::AlignHCenter); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index 360868272..fe2219db6 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -268,8 +268,8 @@ namespace caret { void tabMoved(int, int); void tabCloseSelected(int); void showTabMenu(const QPoint& pos); - void tabBarMousePressedSlot(); - void tabBarMouseReleasedSlot(); + void tabBarMousePressedSlot(QMouseEvent* event); + void tabBarMouseReleasedSlot(QMouseEvent* event); private: enum class InsertTabMode { diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx index f2df57ec9..474503f16 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx @@ -23,9 +23,22 @@ #include "BrainBrowserWindowToolBarTabPopUpMenu.h" #undef __BRAIN_BROWSER_WINDOW_TOOL_BAR_TAB_POP_UP_MENU_DECLARE__ +#include "AnnotationBrowserTab.h" +#include "AnnotationManager.h" +#include "Brain.h" #include "BrainBrowserWindowToolBar.h" +#include "BrowserTabContent.h" +#include "BrowserWindowContent.h" #include "CaretAssert.h" +#include "EventBrowserTabGet.h" +#include "EventBrowserWindowContent.h" +#include "EventGetOrSetUserInputModeProcessor.h" +#include "EventGraphicsUpdateOneWindow.h" +#include "EventManager.h" +#include "EventUserInterfaceUpdate.h" +#include "GuiManager.h" #include "WuQTabBar.h" + using namespace caret; @@ -63,6 +76,40 @@ m_tabIndexUnderMouse(tabIndexUnderMouse) m_numberOfTabs = m_toolBar->tabBar->count(); m_activeTabIndex = m_toolBar->tabBar->currentIndex(); + m_browserWindowIndex = m_toolBar->browserWindowIndex; + static std::unique_ptr windowContentEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); + EventManager::get()->sendEvent(windowContentEvent->getPointer()); + const BrowserWindowContent* browserWindowContent = windowContentEvent->getBrowserWindowContent(); + + if (m_tabIndexUnderMouse >= 0) { + BrowserTabContent* tabContent = m_toolBar->getTabContentFromTab(m_tabIndexUnderMouse); + m_selectedBrowserTabAnnotation = NULL; + m_browserTabContentIndex = -1; + if (tabContent != NULL) { + m_browserTabContentIndex = tabContent->getTabNumber(); + + m_selectedBrowserTabAnnotation = tabContent->getManualLayoutBrowserTabAnnotation(); + } + } + + if (browserWindowContent != NULL) { + if (browserWindowContent->isManualModeTileTabsConfigurationEnabled()) { + if (m_selectedBrowserTabAnnotation != NULL) { + addItem(MenuItem::MANUAL_LAYOUT_SELECT_FOR_EDITING); + + if (m_selectedBrowserTabAnnotation->isBrowserTabDisplayed()) { + addItem(MenuItem::MANUAL_LAYOUT_SET_VISIBLE, + "Hide Tab Content in Window"); + } + else { + addItem(MenuItem::MANUAL_LAYOUT_SET_VISIBLE, + "Show Tab Content in Window"); + } + addSeparator(); + } + } + } + addItem(MenuItem::CREATE_NEW_TAB_BEFORE); addItem(MenuItem::CREATE_NEW_TAB_AFTER); addSeparator(); @@ -96,18 +143,19 @@ BrainBrowserWindowToolBarTabPopUpMenu::~BrainBrowserWindowToolBarTabPopUpMenu() * Item to be added to menu. */ void -BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem) +BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem, + const QString& overrideMenuItemText) { QString thisTabName = "This Tab"; QString activeTabName = "Active Tab"; + const int32_t activeTabIndex = m_toolBar->tabBar->currentIndex(); const bool includeNamesInMenuFlag = false; if (includeNamesInMenuFlag) { if (m_tabIndexUnderMouse >= 0) { thisTabName = ("Tab \"" + m_toolBar->tabBar->tabText(m_tabIndexUnderMouse) + "\""); } - const int32_t activeTabIndex = m_toolBar->tabBar->currentIndex(); if (activeTabIndex >= 0) { activeTabName = ("Tab \"" + m_toolBar->tabBar->tabText(activeTabIndex) + "\""); } @@ -136,6 +184,12 @@ BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem) case MenuItem::DUPLICATE_TAB_AT_END: text = "Duplicate " + thisTabName + " at End"; break; + case MenuItem::MANUAL_LAYOUT_SELECT_FOR_EDITING: + text = "Select for Manual Layout Editing"; + break; + case MenuItem::MANUAL_LAYOUT_SET_VISIBLE: + text = "Visible in Manual Layout"; + break; case MenuItem::MOVE_TAB_TO_BEGINNING: text = "Move " + thisTabName + " to Beginning"; break; @@ -153,6 +207,10 @@ BrainBrowserWindowToolBarTabPopUpMenu::addItem(const MenuItem menuItem) break; } + if ( ! overrideMenuItemText.isEmpty()) { + text = overrideMenuItemText; + } + QAction* action = addAction(text); action->setData(static_cast(menuItem)); action->setEnabled(isEnabled(menuItem)); @@ -168,6 +226,9 @@ void BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) { if (action != NULL) { + bool updateGraphicsFlag(false); + bool updateUserIterfaceFlag(false); + const BrowserTabContent* activeTabContent = m_toolBar->getTabContentFromTab(m_activeTabIndex); MenuItem menuItem = static_cast(action->data().toInt()); @@ -201,6 +262,25 @@ BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) case MenuItem::DUPLICATE_TAB_AT_END: duplicateToIndex = m_numberOfTabs; break; + case MenuItem::MANUAL_LAYOUT_SELECT_FOR_EDITING: + if (m_selectedBrowserTabAnnotation != NULL) { + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + CaretAssert(annMan); + annMan->selectAnnotationForEditing(m_browserWindowIndex, + AnnotationManager::SELECTION_MODE_EXTENDED, + true, + m_selectedBrowserTabAnnotation); + updateGraphicsFlag = true; + updateUserIterfaceFlag = true; + } + break; + case MenuItem::MANUAL_LAYOUT_SET_VISIBLE: + if (m_selectedBrowserTabAnnotation != NULL) { + m_selectedBrowserTabAnnotation->setBrowserTabDisplayed( ! m_selectedBrowserTabAnnotation->isBrowserTabDisplayed()); + updateGraphicsFlag = true; + updateUserIterfaceFlag = true; + } + break; case MenuItem::MOVE_TAB_TO_BEGINNING: moveToIndex = 0; break; @@ -259,6 +339,13 @@ BrainBrowserWindowToolBarTabPopUpMenu::menuItemSelected(QAction* action) if (updatedActiveTabIndex >= 0) { m_toolBar->tabBar->setCurrentIndex(updatedActiveTabIndex); } + + if (updateGraphicsFlag) { + EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(m_browserWindowIndex).getPointer()); + } + if (updateUserIterfaceFlag) { + EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); + } } } @@ -295,6 +382,38 @@ BrainBrowserWindowToolBarTabPopUpMenu::isEnabled(const MenuItem menuItem) const enabledFlag = true; } break; + case MenuItem::MANUAL_LAYOUT_SELECT_FOR_EDITING: + { + EventGetOrSetUserInputModeProcessor inputProcessorEvent(m_browserWindowIndex); + EventManager::get()->sendEvent(inputProcessorEvent.getPointer()); + switch (inputProcessorEvent.getUserInputMode()) { + case UserInputModeEnum::ANNOTATIONS: + break; + case UserInputModeEnum::BORDERS: + break; + case UserInputModeEnum::FOCI: + break; + case UserInputModeEnum::IMAGE: + break; + case UserInputModeEnum::INVALID: + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + if (m_selectedBrowserTabAnnotation != NULL) { + if (m_selectedBrowserTabAnnotation->isBrowserTabDisplayed()) { + enabledFlag = true; + } + } + break; + case UserInputModeEnum::VIEW: + break; + case UserInputModeEnum::VOLUME_EDIT: + break; + } + } + break; + case MenuItem::MANUAL_LAYOUT_SET_VISIBLE: + enabledFlag = (m_selectedBrowserTabAnnotation != NULL); + break; case MenuItem::MOVE_TAB_TO_BEGINNING: if (m_tabIndexUnderMouse > 0) { enabledFlag = true; diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h index 60ed6a911..a4efbb6bc 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.h @@ -29,6 +29,7 @@ namespace caret { + class AnnotationBrowserTab; class BrainBrowserWindowToolBar; class BrainBrowserWindowToolBarTabPopUpMenu : public QMenu { @@ -50,6 +51,8 @@ namespace caret { private: enum class MenuItem { NONE, + MANUAL_LAYOUT_SELECT_FOR_EDITING, + MANUAL_LAYOUT_SET_VISIBLE, CREATE_NEW_TAB_BEFORE, CREATE_NEW_TAB_AFTER, DUPLICATE_TAB_AT_BEGINNING, @@ -67,7 +70,8 @@ namespace caret { BrainBrowserWindowToolBarTabPopUpMenu& operator=(const BrainBrowserWindowToolBarTabPopUpMenu&); - void addItem(const MenuItem menuItem); + void addItem(const MenuItem menuItem, + const QString& overrideMenuItemText = ""); bool isEnabled(const MenuItem menuItem) const; @@ -79,6 +83,12 @@ namespace caret { int32_t m_activeTabIndex; + int32_t m_browserTabContentIndex = -1; + + int32_t m_browserWindowIndex = -1; + + AnnotationBrowserTab* m_selectedBrowserTabAnnotation = NULL; + // ADD_NEW_MEMBERS_HERE }; diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 61fb6a2c1..6efe782ae 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -500,9 +500,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() EventBrowserTabNewInGUI newTabEvent; EventManager::get()->sendEvent(newTabEvent.getPointer()); BrowserTabContent* btc = newTabEvent.getBrowserTab(); -// if (btc != NULL) { -// btc->getManualLayoutBrowserTabAnnotation()->setBrowserTabDisplayed(showTabsFlag); -// } updateGraphicsWindow(); if (btc != NULL) { if (showTabsFlag) { @@ -511,7 +508,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() else { tabsWithDisplayStatusOff.insert(btc); } -// btc->getManualLayoutBrowserTabAnnotation()->setBrowserTabDisplayed(showTabsFlag); } } } @@ -519,24 +515,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() else { return; } -// msg.append("Do you want to add tabs to available spaces in the layout?"); -// switch (WuQMessageBox::warningYesNoCancel(m_loadConfigurationPushButton, msg, "")) { -// case WuQMessageBox::RESULT_CANCEL: -// return; -// break; -// case WuQMessageBox::RESULT_NO: -// break; -// case WuQMessageBox::RESULT_YES: -// { -// const int32_t numTabsToAdd = numConfigTabs - numBrowserTabs; -// for (int32_t i = 0; i < numTabsToAdd; i++) { -// EventBrowserTabNewInGUI newTabEvent; -// EventManager::get()->sendEvent(newTabEvent.getPointer()); -// updateGraphicsWindow(); -// } -// } -// break; -// } } else { msg.append("Do you want to:"); @@ -581,19 +559,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() getBrowserWindow()->getAllTabContent(allTabContent); numBrowserTabs = static_cast(allTabContent.size()); - -// const int32_t numMissingTabs = numBrowserTabs - numConfigTabs; -// if (numMissingTabs > 0) { -// const QString msg("User configuration \"" -// + userManualConfig->getName() -// + "\" contains fewer tabs than in window. The last " -// + AString::number(numMissingTabs) -// + " will not change position."); -// if ( ! WuQMessageBox::warningOkCancel(m_loadConfigurationPushButton, msg)) { -// return; -// } -// } - std::vector tabViewports; getBrowserWindow()->getAllBrainOpenGLViewportContent(tabViewports); const int32_t numViewportContent = static_cast(tabViewports.size()); @@ -657,8 +622,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() } updateDialog(); -// updateGridStretchFactors(); -// updateManualGeometryEditorWidget(); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); updateGraphicsWindow(); } @@ -1840,6 +1803,7 @@ TileTabsConfigurationDialog::gridConfigurationStretchFactorWasChanged() updateGridStretchFactors(); updateGraphicsWindow(); + } /** diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index 860669c08..63e7b5948 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -198,7 +198,7 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() gridLayout->setContentsMargins(2, 2, 2, 2); gridLayout->setVerticalSpacing(0); int column = 0; - gridLayout->addWidget(m_nameWidget, 0, column, 2, 1); + gridLayout->addWidget(m_nameWidget, 0, column, 2, 1, Qt::AlignTop); column++; gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); column++; @@ -443,7 +443,7 @@ UserInputModeAnnotationsWidget::updateWidget() if (m_textAlignmentWidget != NULL) m_textAlignmentWidget->updateContent(textAnnotations); if (m_textOrientationWidget != NULL) m_textOrientationWidget->updateContent(textAnnotations); if (m_widthHeightWidget != NULL) m_widthHeightWidget->updateContent(twoDimAnnotations); - if (m_rotationWidget != NULL) m_rotationWidget->updateContent(selectedAnnotations); //twoDimAnnotations); + if (m_rotationWidget != NULL) m_rotationWidget->updateContent(selectedAnnotations); if (m_insertDeleteWidget != NULL) m_insertDeleteWidget->updateContent(); if (m_deleteWidget != NULL) m_deleteWidget->updateContent(); diff --git a/src/GuiQt/WuQTabBar.cxx b/src/GuiQt/WuQTabBar.cxx index 6b1a2934d..e74525a47 100644 --- a/src/GuiQt/WuQTabBar.cxx +++ b/src/GuiQt/WuQTabBar.cxx @@ -59,7 +59,7 @@ WuQTabBar::~WuQTabBar() void WuQTabBar::mousePressEvent(QMouseEvent* event) { - emit mousePressedSignal(); + emit mousePressedSignal(event); QTabBar::mousePressEvent(event); } @@ -73,7 +73,7 @@ WuQTabBar::mousePressEvent(QMouseEvent* event) void WuQTabBar::mouseReleaseEvent(QMouseEvent* event) { - emit mouseReleasedSignal(); + emit mouseReleasedSignal(event); QTabBar::mouseReleaseEvent(event); } diff --git a/src/GuiQt/WuQTabBar.h b/src/GuiQt/WuQTabBar.h index 84d294e2e..cc6bfd139 100644 --- a/src/GuiQt/WuQTabBar.h +++ b/src/GuiQt/WuQTabBar.h @@ -48,9 +48,9 @@ namespace caret { // ADD_NEW_METHODS_HERE signals: - void mousePressedSignal(); + void mousePressedSignal(QMouseEvent* event); - void mouseReleasedSignal(); + void mouseReleasedSignal(QMouseEvent* event); protected: virtual void mousePressEvent(QMouseEvent* event) override; -- GitLab From a08320eda493a30b40826c8ca7ff0f0db49653b7 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 30 Aug 2019 11:13:29 -0500 Subject: [PATCH 026/584] WB-859 Manual Tile Tabs Layout System: Add 2D coordinate widget to manual layout tile tabs toolbar; add labels to some widgets in toolbar; and improve layout. --- src/GuiQt/AnnotationBoundsWidget.cxx | 25 +- .../AnnotationCoordinateCenterXYWidget.cxx | 451 ++++++++++++++++++ .../AnnotationCoordinateCenterXYWidget.h | 94 ++++ src/GuiQt/AnnotationCoordinateWidget.cxx | 1 + src/GuiQt/AnnotationWidthHeightWidget.cxx | 13 +- src/GuiQt/CMakeLists.txt | 3 + src/GuiQt/UserInputModeAnnotationsWidget.cxx | 17 +- src/GuiQt/UserInputModeAnnotationsWidget.h | 3 + 8 files changed, 587 insertions(+), 20 deletions(-) create mode 100644 src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx create mode 100644 src/GuiQt/AnnotationCoordinateCenterXYWidget.h diff --git a/src/GuiQt/AnnotationBoundsWidget.cxx b/src/GuiQt/AnnotationBoundsWidget.cxx index dc1c8c831..dc52e958a 100644 --- a/src/GuiQt/AnnotationBoundsWidget.cxx +++ b/src/GuiQt/AnnotationBoundsWidget.cxx @@ -28,8 +28,8 @@ #include #include +#include #include -#include #include #include #include @@ -92,6 +92,7 @@ m_browserWindowIndex(browserWindowIndex) break; } + QLabel* boundsLabel = new QLabel("Bounds"); QLabel* xMinCoordLabel = new QLabel("Min X" + colonString); m_xMinCoordSpinBox = createSpinBox(); @@ -113,16 +114,20 @@ m_browserWindowIndex(browserWindowIndex) QObject::connect(m_yMaxCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), this, &AnnotationBoundsWidget::yMaxValueChanged); - QHBoxLayout* coordinateLayout = new QHBoxLayout(this); + QGridLayout* coordinateLayout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(coordinateLayout, 2, 0); - coordinateLayout->addWidget(xMinCoordLabel); - coordinateLayout->addWidget(m_xMinCoordSpinBox); - coordinateLayout->addWidget(xMaxCoordLabel); - coordinateLayout->addWidget(m_xMaxCoordSpinBox); - coordinateLayout->addWidget(yMinCoordLabel); - coordinateLayout->addWidget(m_yMinCoordSpinBox); - coordinateLayout->addWidget(yMaxCoordLabel); - coordinateLayout->addWidget(m_yMaxCoordSpinBox); + int32_t row(0); + coordinateLayout->addWidget(boundsLabel, row, 0, 1, 4, Qt::AlignHCenter); + row++; + coordinateLayout->addWidget(xMinCoordLabel, row, 0); + coordinateLayout->addWidget(m_xMinCoordSpinBox, row, 1); + coordinateLayout->addWidget(xMaxCoordLabel, row, 2); + coordinateLayout->addWidget(m_xMaxCoordSpinBox, row, 3); + row++; + coordinateLayout->addWidget(yMinCoordLabel, row, 0); + coordinateLayout->addWidget(m_yMinCoordSpinBox, row, 1); + coordinateLayout->addWidget(yMaxCoordLabel, row, 2); + coordinateLayout->addWidget(m_yMaxCoordSpinBox, row, 3); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); diff --git a/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx b/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx new file mode 100644 index 000000000..92e707c58 --- /dev/null +++ b/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx @@ -0,0 +1,451 @@ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + +#define __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_DECLARE__ +#include "AnnotationCoordinateCenterXYWidget.h" +#undef __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_DECLARE__ + +#include +#include +#include + +#include +#include +#include +#include + +#include "AnnotationColorBar.h" +#include "AnnotationManager.h" +#include "AnnotationCoordinate.h" +#include "AnnotationOneDimensionalShape.h" +#include "AnnotationRedoUndoCommand.h" +#include "AnnotationTwoDimensionalShape.h" +#include "Brain.h" +#include "BrainBrowserWindow.h" +#include "BrowserTabContent.h" +#include "CaretAssert.h" +#include "ChartTwoCartesianAxis.h" +#include "ChartTwoOverlaySet.h" +#include "EventBrowserWindowContent.h" +#include "EventGraphicsUpdateAllWindows.h" +#include "EventManager.h" +#include "EventOverlaySettingsEditorDialogRequest.h" +#include "GuiManager.h" +#include "MathFunctions.h" +#include "ModelChartTwo.h" +#include "WuQFactory.h" +#include "WuQMessageBox.h" +#include "WuQtUtilities.h" + +using namespace caret; + + + +/** + * \class caret::AnnotationCoordinateCenterXYWidget + * \brief Widget for editing annotation coordinate + * \ingroup GuiQt + */ + +/** + * Constructor. + * + * @param + * @param whichCoordinate + * Which coordinate, one (or only), or two + * @param browserWindowIndex + * Index of browser window + * @param parent + * Parent widget + */ +AnnotationCoordinateCenterXYWidget::AnnotationCoordinateCenterXYWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, + const WhichCoordinate whichCoordinate, + const int32_t browserWindowIndex, + QWidget* parent) +: QWidget(parent), +m_userInputMode(userInputMode), +m_parentWidgetType(parentWidgetType), +m_whichCoordinate(whichCoordinate), +m_browserWindowIndex(browserWindowIndex) +{ + + m_annotation = NULL; + + QString colonString; + switch (m_parentWidgetType) { + case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: + colonString = ":"; + break; + case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: + CaretAssert(0); + break; + } + + QLabel* centerLabel = new QLabel("Center"); + const int digitsRightOfDecimal = 1; + QLabel* xCoordLabel = new QLabel(" X" + colonString); + m_xCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, + this, SLOT(valueChanged())); + WuQtUtilities::setWordWrappedToolTip(m_xCoordSpinBox, + "X-coordinate of annotation\n" + " STEREOTAXIC: Stereotaxic X-Coordinate\n" + " TAB and WINDOW X-Range: [0.0%, 100.0%]\n" + " 0.0% => Left side of tab/window\n" + " 100.0% => Right side of tab/window\n"); + + QLabel* yCoordLabel = new QLabel(" Y" + colonString); + m_yCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, + this, SLOT(valueChanged())); + WuQtUtilities::setWordWrappedToolTip(m_yCoordSpinBox, + "Y-coordinate of annotation\n" + " STEREOTAXIC: Stereotaxic Y-Coordinate\n" + " TAB and WINDOW Y-Range: [0.0%, 100.0%]\n" + " 0.0% => Bottom of tab/window\n" + " 100.0% => Top of tab/window\n"); + + + const float spinBoxMaximumWidth = 80.0f; + m_xCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); + m_yCoordSpinBox->setMaximumWidth(spinBoxMaximumWidth); + + QGridLayout* layout = new QGridLayout(this); + WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); + int32_t row(0); + layout->addWidget(centerLabel, row, 0, 1, 2, Qt::AlignHCenter); + row++; + layout->addWidget(xCoordLabel, row, 0); + layout->addWidget(m_xCoordSpinBox, row, 1); + row++; + layout->addWidget(yCoordLabel, row, 0); + layout->addWidget(m_yCoordSpinBox, row, 1); + + setSizePolicy(QSizePolicy::Fixed, + QSizePolicy::Fixed); +} + +/** + * Destructor. + */ +AnnotationCoordinateCenterXYWidget::~AnnotationCoordinateCenterXYWidget() +{ +} + +AnnotationCoordinate* +AnnotationCoordinateCenterXYWidget::getCoordinate() +{ + AnnotationCoordinate* ac = NULL; + + + if (m_annotation != NULL) { + AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(m_annotation); + AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(m_annotation); + + switch (m_whichCoordinate) { + case COORDINATE_ONE: + if (oneDimShape != NULL) { + ac = oneDimShape->getStartCoordinate(); + } + else if (twoDimShape != NULL) { + ac = twoDimShape->getCoordinate(); + } + break; + case COORDINATE_TWO: + if (oneDimShape != NULL) { + ac = oneDimShape->getEndCoordinate(); + } + break; + } + } + + return ac; +} + + +/** + * Update with the given annotation coordinate. + * + * @param coordinate. + */ +void +AnnotationCoordinateCenterXYWidget::updateContent(std::vector& selectedAnnotations) +{ + m_annotation = NULL; + if (selectedAnnotations.size() == 1) { + CaretAssertVectorIndex(selectedAnnotations, 0); + Annotation* annotation(selectedAnnotations[0]); + if (annotation->testProperty(Annotation::Property::COORDINATE)) { + m_annotation = annotation; + } + } + + const AnnotationCoordinate* coordinate = getCoordinate(); + + if (coordinate != NULL) { + float xyz[3]; + coordinate->getXYZ(xyz); + + bool viewportSpaceFlag = false; + const double percentageMinimum = 0.0; + const double percentageMaximum = 100.0; + const double coordinateMinimum = -std::numeric_limits::max(); + const double coordinateMaximum = std::numeric_limits::max(); + double xMin = 0.0; + double xMax = 0.0; + double yMin = 0.0; + double yMax = 0.0; + double xStep = 0.1; + double yStep = 0.1; + QString suffix; + int32_t digitsRightOfDecimalX = 2; + int32_t digitsRightOfDecimalY = 2; + switch (m_annotation->getCoordinateSpace()) { + case AnnotationCoordinateSpaceEnum::CHART: + { + xMin = coordinateMinimum; + xMax = coordinateMaximum; + yMin = coordinateMinimum; + yMax = coordinateMaximum; + digitsRightOfDecimalX = 3; + digitsRightOfDecimalX = 3; + xStep = 1.0; + yStep = 1.0; + + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(bbw); + BrowserTabContent* browserTabContent = bbw->getBrowserTabContent(); + if (browserTabContent != NULL) { + ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); + const int32_t tabIndex = browserTabContent->getTabNumber(); + if (modelChartTwo != NULL) { + ChartTwoOverlaySet* chartOverlaySet = NULL; + switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: + chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: + chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); + break; + case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: + break; + } + + if (chartOverlaySet != NULL) { + float xAxisMin = std::numeric_limits::max(); + float xAxisMax = -std::numeric_limits::max(); + float yAxisMin = std::numeric_limits::max(); + float yAxisMax = -std::numeric_limits::max(); + + std::vector axes; + chartOverlaySet->getDisplayedChartAxes(axes); + const int32_t numAxes = static_cast(axes.size()); + for (int32_t i = 0; i < numAxes; i++) { + float rangeMin(0), rangeMax(0); + axes[i]->getDataRange(rangeMin, rangeMax); + + if (rangeMax > rangeMin) { + const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); + switch (axisLocation) { + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: + xAxisMin = std::min(xAxisMin, rangeMin); + xAxisMax = std::max(xAxisMax, rangeMax); + break; + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: + case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: + yAxisMin = std::min(yAxisMin, rangeMin); + yAxisMax = std::max(yAxisMax, rangeMax); + break; + } + } + } + + if (xAxisMax > xAxisMin) { + const float range(xAxisMax - xAxisMin); + int32_t digits = 6 - static_cast(std::round(std::log10(range))); + digitsRightOfDecimalX = MathFunctions::clamp(digits, 3, 6); + xStep = range * 0.001f; + } + if (yAxisMax > yAxisMin) { + const float range(yAxisMax - yAxisMin); + int32_t digits = 6 - static_cast(std::round(std::log10(range))); + digitsRightOfDecimalY = MathFunctions::clamp(digits, 3, 6); + yStep = range * 0.001f; + } + } + } + } + } + break; + case AnnotationCoordinateSpaceEnum::SPACER: + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + suffix = "%"; + break; + case AnnotationCoordinateSpaceEnum::STEREOTAXIC: + xMin = coordinateMinimum; + xMax = coordinateMaximum; + yMin = coordinateMinimum; + yMax = coordinateMaximum; + xStep = 1.0; + yStep = 1.0; + break; + case AnnotationCoordinateSpaceEnum::SURFACE: + break; + case AnnotationCoordinateSpaceEnum::TAB: + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + suffix = "%"; + break; + case AnnotationCoordinateSpaceEnum::VIEWPORT: + /* + * Cannot move + */ + xMin = xyz[0]; + xMax = xyz[0]; + yMin = xyz[1]; + yMax = xyz[1]; + viewportSpaceFlag = true; + break; + case AnnotationCoordinateSpaceEnum::WINDOW: + xMin = percentageMinimum; + xMax = percentageMaximum; + yMin = percentageMinimum; + yMax = percentageMaximum; + suffix = "%"; + break; + } + + m_xCoordSpinBox->blockSignals(true); + m_xCoordSpinBox->setRange(xMin, + xMax); + m_xCoordSpinBox->setSingleStep(xStep); + m_xCoordSpinBox->setSuffix(suffix); + m_xCoordSpinBox->setValue(xyz[0]); + m_xCoordSpinBox->setDecimals(digitsRightOfDecimalX); + m_xCoordSpinBox->blockSignals(false); + + m_yCoordSpinBox->blockSignals(true); + m_yCoordSpinBox->setRange(yMin, + yMax); + m_yCoordSpinBox->setSingleStep(yStep); + m_yCoordSpinBox->setSuffix(suffix); + m_yCoordSpinBox->setValue(xyz[1]); + m_yCoordSpinBox->setDecimals(digitsRightOfDecimalY); + m_yCoordSpinBox->blockSignals(false); + + if (viewportSpaceFlag) { + setEnabled(false); + } + else { + setEnabled(true); + } + } + else { + setEnabled(false); + } +} + +/** + * Gets called when a coordinate value is changed. + */ +void +AnnotationCoordinateCenterXYWidget::valueChanged() +{ + const AnnotationCoordinate* coordinate = getCoordinate(); + if ((m_annotation != NULL) + && (coordinate != NULL)) { + + switch (m_parentWidgetType) { + case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: + { + AnnotationCoordinate coordinateCopy(*coordinate); + + float xyz[3] = { + (float)m_xCoordSpinBox->value(), + (float)m_yCoordSpinBox->value(), + 0.0f + }; + coordinateCopy.setXYZ(xyz); + + std::vector selectedAnnotations; + selectedAnnotations.push_back(m_annotation); + + bool updateUserInterfaceFlag = false; + for (std::vector::iterator annIter = selectedAnnotations.begin(); + annIter != selectedAnnotations.end(); + annIter++) { + Annotation* ann = *annIter; + if (ann->getType() == AnnotationTypeEnum::COLOR_BAR) { + AnnotationColorBar* colorBar = dynamic_cast(ann); + CaretAssert(colorBar); + colorBar->setPositionMode(AnnotationColorBarPositionModeEnum::MANUAL); + updateUserInterfaceFlag = true; + } + } + + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + switch (m_whichCoordinate) { + case COORDINATE_ONE: + undoCommand->setModeCoordinateOne(coordinateCopy, + selectedAnnotations); + break; + case COORDINATE_TWO: + undoCommand->setModeCoordinateTwo(coordinateCopy, + selectedAnnotations); + break; + } + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + + AString errorMessage; + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); + } + + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); + if (updateUserInterfaceFlag) { + EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, + m_browserWindowIndex, + NULL, + (CaretMappableDataFile*)NULL, + -1).getPointer()); + } + } + break; + case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: + CaretAssert(0); + break; + } + + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + } +} + diff --git a/src/GuiQt/AnnotationCoordinateCenterXYWidget.h b/src/GuiQt/AnnotationCoordinateCenterXYWidget.h new file mode 100644 index 000000000..df6a8a216 --- /dev/null +++ b/src/GuiQt/AnnotationCoordinateCenterXYWidget.h @@ -0,0 +1,94 @@ +#ifndef __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_H__ +#define __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_H__ + +/*LICENSE_START*/ +/* + * Copyright (C) 2015 Washington University School of Medicine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/*LICENSE_END*/ + + +#include + +#include "AnnotationCoordinateSpaceEnum.h" +#include "AnnotationWidgetParentEnum.h" +#include "UserInputModeEnum.h" + +class QDoubleSpinBox; + +namespace caret { + + class Annotation; + class AnnotationCoordinate; + + class AnnotationCoordinateCenterXYWidget: public QWidget { + + Q_OBJECT + + public: + enum WhichCoordinate { + COORDINATE_ONE, + COORDINATE_TWO + }; + + AnnotationCoordinateCenterXYWidget(const UserInputModeEnum::Enum userInputMode, + const AnnotationWidgetParentEnum::Enum parentWidgetType, + const WhichCoordinate whichCoordinate, + const int32_t browserWindowIndex, + QWidget* parent = 0); + + virtual ~AnnotationCoordinateCenterXYWidget(); + + + // ADD_NEW_METHODS_HERE + + void updateContent(std::vector& selectedAnnotations); + + private slots: + void valueChanged(); + + private: + AnnotationCoordinateCenterXYWidget(const AnnotationCoordinateCenterXYWidget&); + + AnnotationCoordinateCenterXYWidget& operator=(const AnnotationCoordinateCenterXYWidget&); + + AnnotationCoordinate* getCoordinate(); + + // ADD_NEW_MEMBERS_HERE + + const UserInputModeEnum::Enum m_userInputMode; + + const AnnotationWidgetParentEnum::Enum m_parentWidgetType; + + const WhichCoordinate m_whichCoordinate; + + const int32_t m_browserWindowIndex; + + QDoubleSpinBox* m_xCoordSpinBox; + + QDoubleSpinBox* m_yCoordSpinBox; + + Annotation* m_annotation; + + }; + +#ifdef __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_DECLARE__ + // +#endif // __ANNOTATION_COORDINATE_CENTER_XY_WIDGET_DECLARE__ + +} // namespace +#endif //__ANNOTATION_COORDINATE_CENTER_XY_WIDGET_H__ diff --git a/src/GuiQt/AnnotationCoordinateWidget.cxx b/src/GuiQt/AnnotationCoordinateWidget.cxx index 702540e4c..34a2b6dc7 100644 --- a/src/GuiQt/AnnotationCoordinateWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateWidget.cxx @@ -484,6 +484,7 @@ AnnotationCoordinateWidget::updateContent(Annotation* annotation) m_zCoordSpinBox->setDecimals(digitsRightOfDecimalZ); m_zCoordSpinBox->blockSignals(false); + m_zCoordSpinBox->setEnabled(true); if (annotation->getType() == AnnotationTypeEnum::BROWSER_TAB) { m_zCoordSpinBox->setEnabled(false); } diff --git a/src/GuiQt/AnnotationWidthHeightWidget.cxx b/src/GuiQt/AnnotationWidthHeightWidget.cxx index 8f909007a..0b4f12720 100644 --- a/src/GuiQt/AnnotationWidthHeightWidget.cxx +++ b/src/GuiQt/AnnotationWidthHeightWidget.cxx @@ -109,12 +109,17 @@ m_browserWindowIndex(browserWindowIndex) break; case Qt::Vertical: { + QLabel* sizeLabel = new QLabel("Size"); QGridLayout* layout = new QGridLayout(this); WuQtUtilities::setLayoutSpacingAndMargins(layout, 2, 2); - layout->addWidget(widthLabel, 0, 0); - layout->addWidget(m_widthSpinBox, 0, 1); - layout->addWidget(heightLabel, 1, 0); - layout->addWidget(m_heightSpinBox, 1, 1); + int32_t row(0); + layout->addWidget(sizeLabel, row, 0, 1, 2, Qt::AlignHCenter); + row++; + layout->addWidget(widthLabel, row, 0); + layout->addWidget(m_widthSpinBox, row, 1); + row++; + layout->addWidget(heightLabel, row, 0); + layout->addWidget(m_heightSpinBox, row, 1); } break; } diff --git a/src/GuiQt/CMakeLists.txt b/src/GuiQt/CMakeLists.txt index 1761f21f0..7c9b084e8 100644 --- a/src/GuiQt/CMakeLists.txt +++ b/src/GuiQt/CMakeLists.txt @@ -47,6 +47,7 @@ ELSE() AnnotationBoundsWidget.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h + AnnotationCoordinateCenterXYWidget.h AnnotationCoordinateSelectionWidget.h AnnotationCoordinateSpaceWidget.h AnnotationCoordinateWidget.h @@ -270,6 +271,7 @@ AboutWorkbenchDialog.h AnnotationBoundsWidget.h AnnotationChangeCoordinateDialog.h AnnotationColorWidget.h +AnnotationCoordinateCenterXYWidget.h AnnotationCoordinateInformation.h AnnotationCoordinateSelectionWidget.h AnnotationCoordinateSpaceWidget.h @@ -552,6 +554,7 @@ AboutWorkbenchDialog.cxx AnnotationBoundsWidget.cxx AnnotationChangeCoordinateDialog.cxx AnnotationColorWidget.cxx +AnnotationCoordinateCenterXYWidget.cxx AnnotationCoordinateInformation.cxx AnnotationCoordinateSelectionWidget.cxx AnnotationCoordinateSpaceWidget.cxx diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.cxx b/src/GuiQt/UserInputModeAnnotationsWidget.cxx index 63e7b5948..4fbd275b0 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.cxx +++ b/src/GuiQt/UserInputModeAnnotationsWidget.cxx @@ -32,6 +32,7 @@ #include "AnnotationBoundsWidget.h" #include "AnnotationBrowserTab.h" +#include "AnnotationCoordinateCenterXYWidget.h" #include "AnnotationCoordinateSpaceWidget.h" #include "AnnotationCoordinateWidget.h" #include "AnnotationColorWidget.h" @@ -178,10 +179,10 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, m_browserWindowIndex); - m_coordinateOneWidget = new AnnotationCoordinateWidget(m_inputModeAnnotations->getUserInputMode(), - AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, - AnnotationCoordinateWidget::COORDINATE_ONE, - m_browserWindowIndex); + m_coordinateCenterXYWidget = new AnnotationCoordinateCenterXYWidget(m_inputModeAnnotations->getUserInputMode(), + AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, + AnnotationCoordinateCenterXYWidget::COORDINATE_ONE, + m_browserWindowIndex); m_widthHeightWidget = new AnnotationWidthHeightWidget(m_inputModeAnnotations->getUserInputMode(), AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET, @@ -202,8 +203,11 @@ UserInputModeAnnotationsWidget::createTileTabsEditingWidget() column++; gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); column++; - gridLayout->addWidget(m_boundsWidget, 0, column); - gridLayout->addWidget(m_coordinateOneWidget, 1, column); + gridLayout->addWidget(m_boundsWidget, 0, column, 2, 1, Qt::AlignTop); + column++; + gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); + column++; + gridLayout->addWidget(m_coordinateCenterXYWidget, 0, column, 2, 1, Qt::AlignTop); column++; gridLayout->addWidget(WuQtUtilities::createVerticalLineWidget(), 0, column, 2, 1); column++; @@ -453,6 +457,7 @@ UserInputModeAnnotationsWidget::updateWidget() coordEditAnnotation = selectedAnnotations[0]; coordEditOneDimAnnotation = dynamic_cast(coordEditAnnotation); } + if (m_coordinateCenterXYWidget != NULL) m_coordinateCenterXYWidget->updateContent(selectedAnnotations); if (m_coordinateOneWidget != NULL) m_coordinateOneWidget->updateContent(coordEditAnnotation); if (coordEditOneDimAnnotation != NULL) { if (m_coordinateTwoWidget != NULL) m_coordinateTwoWidget->updateContent(coordEditOneDimAnnotation); diff --git a/src/GuiQt/UserInputModeAnnotationsWidget.h b/src/GuiQt/UserInputModeAnnotationsWidget.h index 1bc1254c5..59900eb70 100644 --- a/src/GuiQt/UserInputModeAnnotationsWidget.h +++ b/src/GuiQt/UserInputModeAnnotationsWidget.h @@ -34,6 +34,7 @@ namespace caret { class Annotation; class AnnotationBoundsWidget; class AnnotationColorWidget; + class AnnotationCoordinateCenterXYWidget; class AnnotationCoordinateSpaceWidget; class AnnotationCoordinateWidget; class AnnotationDeleteWidget; @@ -95,6 +96,8 @@ namespace caret { AnnotationCoordinateSpaceWidget* m_coordinateSpaceWidget = NULL; + AnnotationCoordinateCenterXYWidget* m_coordinateCenterXYWidget = NULL; + AnnotationCoordinateWidget* m_coordinateOneWidget = NULL; AnnotationCoordinateWidget* m_coordinateTwoWidget = NULL; -- GitLab From 15dae632b6d921db3b622855f97fa85fb526b57f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 30 Aug 2019 14:25:14 -0500 Subject: [PATCH 027/584] WB-859 Manual Tile Tabs Layout System: Allow widgets for annotation editing (Bounds and coordinate 2D) support the selection of multiple annotations. --- src/GuiQt/AnnotationBoundsWidget.cxx | 119 +++- src/GuiQt/AnnotationBoundsWidget.h | 3 +- .../AnnotationCoordinateCenterXYWidget.cxx | 630 ++++++++++-------- .../AnnotationCoordinateCenterXYWidget.h | 9 +- 4 files changed, 450 insertions(+), 311 deletions(-) diff --git a/src/GuiQt/AnnotationBoundsWidget.cxx b/src/GuiQt/AnnotationBoundsWidget.cxx index dc52e958a..f509b33c0 100644 --- a/src/GuiQt/AnnotationBoundsWidget.cxx +++ b/src/GuiQt/AnnotationBoundsWidget.cxx @@ -79,9 +79,6 @@ m_userInputMode(userInputMode), m_parentWidgetType(parentWidgetType), m_browserWindowIndex(browserWindowIndex) { - - m_annotationBrowserTab = NULL; - QString colonString; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: @@ -164,37 +161,97 @@ AnnotationBoundsWidget::~AnnotationBoundsWidget() void AnnotationBoundsWidget::updateContent(std::vector& annotationBrowserTabs) { - m_annotationBrowserTab = NULL; - if (annotationBrowserTabs.size() == 1) { - CaretAssertVectorIndex(annotationBrowserTabs, 0); - m_annotationBrowserTab = annotationBrowserTabs[0]; - } + bool haveMultipleMinXValuesFlag(false); + bool haveMultipleMaxXValuesFlag(false); + bool haveMultipleMinYValuesFlag(false); + bool haveMultipleMaxYValuesFlag(false); + + float valueMinX(0.0); + float valueMaxX(0.0); + float valueMinY(0.0); + float valueMaxY(0.0); - if (m_annotationBrowserTab != NULL) { + bool firstFlag(true); + + m_annotationBrowserTabs = annotationBrowserTabs; + for (auto abt : annotationBrowserTabs) { float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); - m_annotationBrowserTab->getBounds2D(minX, maxX, minY, maxY); - - m_xMinCoordSpinBox->blockSignals(true); - m_xMinCoordSpinBox->setValue(minX); - m_xMinCoordSpinBox->blockSignals(false); + abt->getBounds2D(minX, maxX, minY, maxY); - m_xMaxCoordSpinBox->blockSignals(true); - m_xMaxCoordSpinBox->setValue(maxX); - m_xMaxCoordSpinBox->blockSignals(false); - - m_yMinCoordSpinBox->blockSignals(true); - m_yMinCoordSpinBox->setValue(minY); - m_yMinCoordSpinBox->blockSignals(false); - - m_yMaxCoordSpinBox->blockSignals(true); - m_yMaxCoordSpinBox->setValue(maxY); - m_yMaxCoordSpinBox->blockSignals(false); + if (firstFlag) { + valueMinX = minX; + valueMaxX = maxX; + valueMinY = minY; + valueMaxY = maxY; + firstFlag = false; + } + else { + if (minX != valueMinX) { + haveMultipleMinXValuesFlag = true; + } + if (maxX != valueMaxX) { + haveMultipleMaxXValuesFlag = true; + } + if (minY != valueMinY) { + haveMultipleMinYValuesFlag = true; + } + if (maxY != valueMaxY) { + haveMultipleMaxYValuesFlag = true; + } + + valueMinX = std::min(valueMinX, minX); + valueMaxX = std::max(valueMaxX, maxX); + valueMinY = std::min(valueMinY, minY); + valueMaxY = std::max(valueMaxY, maxY); + } + } + + /* + * If multiple annotations are selected, + * a plus sign (+) is appeneded to the value + */ + + m_xMinCoordSpinBox->blockSignals(true); + m_xMinCoordSpinBox->setValue(valueMinX); + if (haveMultipleMinXValuesFlag) { + m_xMinCoordSpinBox->setSuffix("%+"); + } + else { + m_xMinCoordSpinBox->setSuffix("%"); + } + m_xMinCoordSpinBox->blockSignals(false); - setEnabled(true); + m_xMaxCoordSpinBox->blockSignals(true); + m_xMaxCoordSpinBox->setValue(valueMaxX); + if (haveMultipleMaxXValuesFlag) { + m_xMaxCoordSpinBox->setSuffix("%+"); } else { - setEnabled(false); + m_xMaxCoordSpinBox->setSuffix("%"); } + m_xMaxCoordSpinBox->blockSignals(false); + + m_yMinCoordSpinBox->blockSignals(true); + m_yMinCoordSpinBox->setValue(valueMinY); + if (haveMultipleMinYValuesFlag) { + m_yMinCoordSpinBox->setSuffix("%+"); + } + else { + m_yMinCoordSpinBox->setSuffix("%"); + } + m_yMinCoordSpinBox->blockSignals(false); + + m_yMaxCoordSpinBox->blockSignals(true); + m_yMaxCoordSpinBox->setValue(valueMaxY); + if (haveMultipleMaxYValuesFlag) { + m_yMaxCoordSpinBox->setSuffix("%+"); + } + else { + m_yMaxCoordSpinBox->setSuffix("%"); + } + m_yMaxCoordSpinBox->blockSignals(false); + + setEnabled( ! m_annotationBrowserTabs.empty()); } /** @@ -257,9 +314,10 @@ void AnnotationBoundsWidget::valueChangedHelper(QDoubleSpinBox* spinBox, float value) { - if (m_annotationBrowserTab != NULL) { + if ( ! m_annotationBrowserTabs.empty()) { AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); - std::vector annotations { m_annotationBrowserTab }; + std::vector annotations(m_annotationBrowserTabs.begin(), + m_annotationBrowserTabs.end()); if (spinBox == m_xMinCoordSpinBox) { undoCommand->setBoundsMinX2D(value, annotations); @@ -292,8 +350,7 @@ AnnotationBoundsWidget::valueChangedHelper(QDoubleSpinBox* spinBox, /* * Update as annotation might adjust/limit coordinates */ - std::vector annTabs { m_annotationBrowserTab }; - updateContent(annTabs); + updateContent(m_annotationBrowserTabs); EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); diff --git a/src/GuiQt/AnnotationBoundsWidget.h b/src/GuiQt/AnnotationBoundsWidget.h index f3f5c4b0e..9aa4f4fa6 100644 --- a/src/GuiQt/AnnotationBoundsWidget.h +++ b/src/GuiQt/AnnotationBoundsWidget.h @@ -85,8 +85,7 @@ namespace caret { QDoubleSpinBox* m_yMaxCoordSpinBox; - AnnotationBrowserTab* m_annotationBrowserTab; - + std::vector m_annotationBrowserTabs; }; #ifdef __ANNOTATION_BOUNDS_WIDGET_DECLARE__ diff --git a/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx b/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx index 92e707c58..1f56cad15 100644 --- a/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx +++ b/src/GuiQt/AnnotationCoordinateCenterXYWidget.cxx @@ -88,8 +88,6 @@ m_whichCoordinate(whichCoordinate), m_browserWindowIndex(browserWindowIndex) { - m_annotation = NULL; - QString colonString; switch (m_parentWidgetType) { case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: @@ -103,8 +101,13 @@ m_browserWindowIndex(browserWindowIndex) QLabel* centerLabel = new QLabel("Center"); const int digitsRightOfDecimal = 1; QLabel* xCoordLabel = new QLabel(" X" + colonString); - m_xCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, - this, SLOT(valueChanged())); + m_xCoordSpinBox = new QDoubleSpinBox(); + m_xCoordSpinBox->setMinimum(-100.0); + m_xCoordSpinBox->setMaximum( 200.0); + m_xCoordSpinBox->setSingleStep(0.1); + m_xCoordSpinBox->setDecimals(digitsRightOfDecimal); + QObject::connect(m_xCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationCoordinateCenterXYWidget::xValueChanged); WuQtUtilities::setWordWrappedToolTip(m_xCoordSpinBox, "X-coordinate of annotation\n" " STEREOTAXIC: Stereotaxic X-Coordinate\n" @@ -113,8 +116,13 @@ m_browserWindowIndex(browserWindowIndex) " 100.0% => Right side of tab/window\n"); QLabel* yCoordLabel = new QLabel(" Y" + colonString); - m_yCoordSpinBox = WuQFactory::newDoubleSpinBoxWithMinMaxStepDecimalsSignalDouble(0.0, 100.0, 0.1, digitsRightOfDecimal, - this, SLOT(valueChanged())); + m_yCoordSpinBox = new QDoubleSpinBox(); + m_yCoordSpinBox->setMinimum(-100.0); + m_yCoordSpinBox->setMaximum( 200.0); + m_yCoordSpinBox->setSingleStep(0.1); + m_yCoordSpinBox->setDecimals(digitsRightOfDecimal); + QObject::connect(m_yCoordSpinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &AnnotationCoordinateCenterXYWidget::yValueChanged); WuQtUtilities::setWordWrappedToolTip(m_yCoordSpinBox, "Y-coordinate of annotation\n" " STEREOTAXIC: Stereotaxic Y-Coordinate\n" @@ -149,37 +157,6 @@ AnnotationCoordinateCenterXYWidget::~AnnotationCoordinateCenterXYWidget() { } -AnnotationCoordinate* -AnnotationCoordinateCenterXYWidget::getCoordinate() -{ - AnnotationCoordinate* ac = NULL; - - - if (m_annotation != NULL) { - AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(m_annotation); - AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(m_annotation); - - switch (m_whichCoordinate) { - case COORDINATE_ONE: - if (oneDimShape != NULL) { - ac = oneDimShape->getStartCoordinate(); - } - else if (twoDimShape != NULL) { - ac = twoDimShape->getCoordinate(); - } - break; - case COORDINATE_TWO: - if (oneDimShape != NULL) { - ac = oneDimShape->getEndCoordinate(); - } - break; - } - } - - return ac; -} - - /** * Update with the given annotation coordinate. * @@ -188,264 +165,367 @@ AnnotationCoordinateCenterXYWidget::getCoordinate() void AnnotationCoordinateCenterXYWidget::updateContent(std::vector& selectedAnnotations) { - m_annotation = NULL; - if (selectedAnnotations.size() == 1) { - CaretAssertVectorIndex(selectedAnnotations, 0); - Annotation* annotation(selectedAnnotations[0]); - if (annotation->testProperty(Annotation::Property::COORDINATE)) { - m_annotation = annotation; - } - } + m_annotations = selectedAnnotations; - const AnnotationCoordinate* coordinate = getCoordinate(); + bool firstFlag(true); + bool haveMultipleXValuesFlag(false); + bool haveMultipleYValuesFlag(false); + float xValue(0.0); + float yValue(0.0); - if (coordinate != NULL) { - float xyz[3]; - coordinate->getXYZ(xyz); - - bool viewportSpaceFlag = false; - const double percentageMinimum = 0.0; - const double percentageMaximum = 100.0; - const double coordinateMinimum = -std::numeric_limits::max(); - const double coordinateMaximum = std::numeric_limits::max(); - double xMin = 0.0; - double xMax = 0.0; - double yMin = 0.0; - double yMax = 0.0; - double xStep = 0.1; - double yStep = 0.1; - QString suffix; - int32_t digitsRightOfDecimalX = 2; - int32_t digitsRightOfDecimalY = 2; - switch (m_annotation->getCoordinateSpace()) { - case AnnotationCoordinateSpaceEnum::CHART: - { - xMin = coordinateMinimum; - xMax = coordinateMaximum; - yMin = coordinateMinimum; - yMax = coordinateMaximum; - digitsRightOfDecimalX = 3; - digitsRightOfDecimalX = 3; - xStep = 1.0; - yStep = 1.0; - - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); - CaretAssert(bbw); - BrowserTabContent* browserTabContent = bbw->getBrowserTabContent(); - if (browserTabContent != NULL) { - ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); - const int32_t tabIndex = browserTabContent->getTabNumber(); - if (modelChartTwo != NULL) { - ChartTwoOverlaySet* chartOverlaySet = NULL; - switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: - chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: - chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); - break; - case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: - break; - } - - if (chartOverlaySet != NULL) { - float xAxisMin = std::numeric_limits::max(); - float xAxisMax = -std::numeric_limits::max(); - float yAxisMin = std::numeric_limits::max(); - float yAxisMax = -std::numeric_limits::max(); - - std::vector axes; - chartOverlaySet->getDisplayedChartAxes(axes); - const int32_t numAxes = static_cast(axes.size()); - for (int32_t i = 0; i < numAxes; i++) { - float rangeMin(0), rangeMax(0); - axes[i]->getDataRange(rangeMin, rangeMax); - - if (rangeMax > rangeMin) { - const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); - switch (axisLocation) { - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: - xAxisMin = std::min(xAxisMin, rangeMin); - xAxisMax = std::max(xAxisMax, rangeMax); - break; - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: - case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: - yAxisMin = std::min(yAxisMin, rangeMin); - yAxisMax = std::max(yAxisMax, rangeMax); - break; - } - } - } - - if (xAxisMax > xAxisMin) { - const float range(xAxisMax - xAxisMin); - int32_t digits = 6 - static_cast(std::round(std::log10(range))); - digitsRightOfDecimalX = MathFunctions::clamp(digits, 3, 6); - xStep = range * 0.001f; - } - if (yAxisMax > yAxisMin) { - const float range(yAxisMax - yAxisMin); - int32_t digits = 6 - static_cast(std::round(std::log10(range))); - digitsRightOfDecimalY = MathFunctions::clamp(digits, 3, 6); - yStep = range * 0.001f; - } - } + if (! m_annotations.empty()) { + for (auto ann : m_annotations) { + AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(ann); + AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(ann); + + AnnotationCoordinate* ac(NULL); + switch (m_whichCoordinate) { + case COORDINATE_ONE: + if (oneDimShape != NULL) { + ac = oneDimShape->getStartCoordinate(); + } + else if (twoDimShape != NULL) { + ac = twoDimShape->getCoordinate(); } + break; + case COORDINATE_TWO: + if (oneDimShape != NULL) { + ac = oneDimShape->getEndCoordinate(); + } + break; + } + CaretAssert(ac); + + float xyz[3]; + ac->getXYZ(xyz); + const float x = xyz[0]; + const float y = xyz[1]; + + if (firstFlag) { + xValue = x; + yValue = y; + firstFlag = false; + } + else { + if (x != xValue) { + haveMultipleXValuesFlag = true; } + if (y != yValue) { + haveMultipleYValuesFlag = true; + } + + xValue = std::min(xValue, x); + yValue = std::min(yValue, y); } - break; - case AnnotationCoordinateSpaceEnum::SPACER: - xMin = percentageMinimum; - xMax = percentageMaximum; - yMin = percentageMinimum; - yMax = percentageMaximum; - suffix = "%"; - break; - case AnnotationCoordinateSpaceEnum::STEREOTAXIC: - xMin = coordinateMinimum; - xMax = coordinateMaximum; - yMin = coordinateMinimum; - yMax = coordinateMaximum; - xStep = 1.0; - yStep = 1.0; - break; - case AnnotationCoordinateSpaceEnum::SURFACE: - break; - case AnnotationCoordinateSpaceEnum::TAB: - xMin = percentageMinimum; - xMax = percentageMaximum; - yMin = percentageMinimum; - yMax = percentageMaximum; - suffix = "%"; - break; - case AnnotationCoordinateSpaceEnum::VIEWPORT: - /* - * Cannot move - */ - xMin = xyz[0]; - xMax = xyz[0]; - yMin = xyz[1]; - yMax = xyz[1]; - viewportSpaceFlag = true; - break; - case AnnotationCoordinateSpaceEnum::WINDOW: - xMin = percentageMinimum; - xMax = percentageMaximum; - yMin = percentageMinimum; - yMax = percentageMaximum; - suffix = "%"; - break; - } - - m_xCoordSpinBox->blockSignals(true); - m_xCoordSpinBox->setRange(xMin, - xMax); - m_xCoordSpinBox->setSingleStep(xStep); - m_xCoordSpinBox->setSuffix(suffix); - m_xCoordSpinBox->setValue(xyz[0]); - m_xCoordSpinBox->setDecimals(digitsRightOfDecimalX); - m_xCoordSpinBox->blockSignals(false); - - m_yCoordSpinBox->blockSignals(true); - m_yCoordSpinBox->setRange(yMin, - yMax); - m_yCoordSpinBox->setSingleStep(yStep); - m_yCoordSpinBox->setSuffix(suffix); - m_yCoordSpinBox->setValue(xyz[1]); - m_yCoordSpinBox->setDecimals(digitsRightOfDecimalY); - m_yCoordSpinBox->blockSignals(false); - - if (viewportSpaceFlag) { - setEnabled(false); - } - else { - setEnabled(true); } + + setEnabled(true); } else { setEnabled(false); } + + QSignalBlocker xBlocker(m_xCoordSpinBox); + m_xCoordSpinBox->setValue(xValue); + if (haveMultipleXValuesFlag) { + m_xCoordSpinBox->setSuffix("%+"); + } + else { + m_xCoordSpinBox->setSuffix("%"); + } + + QSignalBlocker yBlocker(m_yCoordSpinBox); + m_yCoordSpinBox->setValue(yValue); + if (haveMultipleYValuesFlag) { + m_yCoordSpinBox->setSuffix("%+"); + } + else { + m_yCoordSpinBox->setSuffix("%"); + } + + +// m_annotation = NULL; +// if (selectedAnnotations.size() == 1) { +// CaretAssertVectorIndex(selectedAnnotations, 0); +// Annotation* annotation(selectedAnnotations[0]); +// if (annotation->testProperty(Annotation::Property::COORDINATE)) { +// m_annotation = annotation; +// } +// } +// +// const AnnotationCoordinate* coordinate = getCoordinate(); +// +// if (coordinate != NULL) { +// float xyz[3]; +// coordinate->getXYZ(xyz); +// +// bool viewportSpaceFlag = false; +// const double percentageMinimum = 0.0; +// const double percentageMaximum = 100.0; +// const double coordinateMinimum = -std::numeric_limits::max(); +// const double coordinateMaximum = std::numeric_limits::max(); +// double xMin = 0.0; +// double xMax = 0.0; +// double yMin = 0.0; +// double yMax = 0.0; +// double xStep = 0.1; +// double yStep = 0.1; +// QString suffix; +// int32_t digitsRightOfDecimalX = 2; +// int32_t digitsRightOfDecimalY = 2; +// switch (m_annotation->getCoordinateSpace()) { +// case AnnotationCoordinateSpaceEnum::CHART: +// { +// xMin = coordinateMinimum; +// xMax = coordinateMaximum; +// yMin = coordinateMinimum; +// yMax = coordinateMaximum; +// digitsRightOfDecimalX = 3; +// digitsRightOfDecimalX = 3; +// xStep = 1.0; +// yStep = 1.0; +// +// BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); +// CaretAssert(bbw); +// BrowserTabContent* browserTabContent = bbw->getBrowserTabContent(); +// if (browserTabContent != NULL) { +// ModelChartTwo* modelChartTwo = browserTabContent->getDisplayedChartTwoModel(); +// const int32_t tabIndex = browserTabContent->getTabNumber(); +// if (modelChartTwo != NULL) { +// ChartTwoOverlaySet* chartOverlaySet = NULL; +// switch (modelChartTwo->getSelectedChartTwoDataType(tabIndex)) { +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_INVALID: +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_HISTOGRAM: +// chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_LINE_SERIES: +// chartOverlaySet = modelChartTwo->getChartTwoOverlaySet(tabIndex); +// break; +// case ChartTwoDataTypeEnum::CHART_DATA_TYPE_MATRIX: +// break; +// } +// +// if (chartOverlaySet != NULL) { +// float xAxisMin = std::numeric_limits::max(); +// float xAxisMax = -std::numeric_limits::max(); +// float yAxisMin = std::numeric_limits::max(); +// float yAxisMax = -std::numeric_limits::max(); +// +// std::vector axes; +// chartOverlaySet->getDisplayedChartAxes(axes); +// const int32_t numAxes = static_cast(axes.size()); +// for (int32_t i = 0; i < numAxes; i++) { +// float rangeMin(0), rangeMax(0); +// axes[i]->getDataRange(rangeMin, rangeMax); +// +// if (rangeMax > rangeMin) { +// const ChartAxisLocationEnum::Enum axisLocation = axes[i]->getAxisLocation(); +// switch (axisLocation) { +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_BOTTOM: +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_TOP: +// xAxisMin = std::min(xAxisMin, rangeMin); +// xAxisMax = std::max(xAxisMax, rangeMax); +// break; +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_LEFT: +// case ChartAxisLocationEnum::CHART_AXIS_LOCATION_RIGHT: +// yAxisMin = std::min(yAxisMin, rangeMin); +// yAxisMax = std::max(yAxisMax, rangeMax); +// break; +// } +// } +// } +// +// if (xAxisMax > xAxisMin) { +// const float range(xAxisMax - xAxisMin); +// int32_t digits = 6 - static_cast(std::round(std::log10(range))); +// digitsRightOfDecimalX = MathFunctions::clamp(digits, 3, 6); +// xStep = range * 0.001f; +// } +// if (yAxisMax > yAxisMin) { +// const float range(yAxisMax - yAxisMin); +// int32_t digits = 6 - static_cast(std::round(std::log10(range))); +// digitsRightOfDecimalY = MathFunctions::clamp(digits, 3, 6); +// yStep = range * 0.001f; +// } +// } +// } +// } +// } +// break; +// case AnnotationCoordinateSpaceEnum::SPACER: +// xMin = percentageMinimum; +// xMax = percentageMaximum; +// yMin = percentageMinimum; +// yMax = percentageMaximum; +// suffix = "%"; +// break; +// case AnnotationCoordinateSpaceEnum::STEREOTAXIC: +// xMin = coordinateMinimum; +// xMax = coordinateMaximum; +// yMin = coordinateMinimum; +// yMax = coordinateMaximum; +// xStep = 1.0; +// yStep = 1.0; +// break; +// case AnnotationCoordinateSpaceEnum::SURFACE: +// break; +// case AnnotationCoordinateSpaceEnum::TAB: +// xMin = percentageMinimum; +// xMax = percentageMaximum; +// yMin = percentageMinimum; +// yMax = percentageMaximum; +// suffix = "%"; +// break; +// case AnnotationCoordinateSpaceEnum::VIEWPORT: +// /* +// * Cannot move +// */ +// xMin = xyz[0]; +// xMax = xyz[0]; +// yMin = xyz[1]; +// yMax = xyz[1]; +// viewportSpaceFlag = true; +// break; +// case AnnotationCoordinateSpaceEnum::WINDOW: +// xMin = percentageMinimum; +// xMax = percentageMaximum; +// yMin = percentageMinimum; +// yMax = percentageMaximum; +// suffix = "%"; +// break; +// } +// +// m_xCoordSpinBox->blockSignals(true); +// m_xCoordSpinBox->setRange(xMin, +// xMax); +// m_xCoordSpinBox->setSingleStep(xStep); +// m_xCoordSpinBox->setSuffix(suffix); +// m_xCoordSpinBox->setValue(xyz[0]); +// m_xCoordSpinBox->setDecimals(digitsRightOfDecimalX); +// m_xCoordSpinBox->blockSignals(false); +// +// m_yCoordSpinBox->blockSignals(true); +// m_yCoordSpinBox->setRange(yMin, +// yMax); +// m_yCoordSpinBox->setSingleStep(yStep); +// m_yCoordSpinBox->setSuffix(suffix); +// m_yCoordSpinBox->setValue(xyz[1]); +// m_yCoordSpinBox->setDecimals(digitsRightOfDecimalY); +// m_yCoordSpinBox->blockSignals(false); +// +// if (viewportSpaceFlag) { +// setEnabled(false); +// } +// else { +// setEnabled(true); +// } +// } +// else { +// setEnabled(false); +// } } /** - * Gets called when a coordinate value is changed. + * Called when the X-value is changed + * + * @param value + * New value */ void -AnnotationCoordinateCenterXYWidget::valueChanged() +AnnotationCoordinateCenterXYWidget::xValueChanged(double value) { - const AnnotationCoordinate* coordinate = getCoordinate(); - if ((m_annotation != NULL) - && (coordinate != NULL)) { - - switch (m_parentWidgetType) { - case AnnotationWidgetParentEnum::ANNOTATION_TOOL_BAR_WIDGET: - { - AnnotationCoordinate coordinateCopy(*coordinate); - - float xyz[3] = { - (float)m_xCoordSpinBox->value(), - (float)m_yCoordSpinBox->value(), - 0.0f - }; - coordinateCopy.setXYZ(xyz); - - std::vector selectedAnnotations; - selectedAnnotations.push_back(m_annotation); - - bool updateUserInterfaceFlag = false; - for (std::vector::iterator annIter = selectedAnnotations.begin(); - annIter != selectedAnnotations.end(); - annIter++) { - Annotation* ann = *annIter; - if (ann->getType() == AnnotationTypeEnum::COLOR_BAR) { - AnnotationColorBar* colorBar = dynamic_cast(ann); - CaretAssert(colorBar); - colorBar->setPositionMode(AnnotationColorBarPositionModeEnum::MANUAL); - updateUserInterfaceFlag = true; - } - } - - AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); - switch (m_whichCoordinate) { - case COORDINATE_ONE: - undoCommand->setModeCoordinateOne(coordinateCopy, - selectedAnnotations); - break; - case COORDINATE_TWO: - undoCommand->setModeCoordinateTwo(coordinateCopy, - selectedAnnotations); - break; - } - - AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + processValueChanged(m_xCoordSpinBox, + value); +} - AString errorMessage; - if ( ! annMan->applyCommand(m_userInputMode, - undoCommand, - errorMessage)) { - WuQMessageBox::errorOk(this, - errorMessage); - } - - EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); - if (updateUserInterfaceFlag) { - EventManager::get()->sendEvent(EventOverlaySettingsEditorDialogRequest(EventOverlaySettingsEditorDialogRequest::MODE_UPDATE_ALL, - m_browserWindowIndex, - NULL, - (CaretMappableDataFile*)NULL, - -1).getPointer()); - } +/** + * Called when the Y-value is changed + * + * @param value + * New value + */ +void +AnnotationCoordinateCenterXYWidget::yValueChanged(double value) +{ + processValueChanged(m_yCoordSpinBox, + value); +} + +/** + * Called when an X- or Y-Value is changed + * + * @param spinBox + * The spin box that was changed + * @param value + * The new value + */ +void +AnnotationCoordinateCenterXYWidget::processValueChanged(QDoubleSpinBox* spinBox, + const double value) +{ + if (! m_annotations.empty()) { + for (auto ann : m_annotations) { + AnnotationOneDimensionalShape* oneDimShape = dynamic_cast(ann); + AnnotationTwoDimensionalShape* twoDimShape = dynamic_cast(ann); + + AnnotationCoordinate* ac(NULL); + switch (m_whichCoordinate) { + case COORDINATE_ONE: + if (oneDimShape != NULL) { + ac = oneDimShape->getStartCoordinate(); + } + else if (twoDimShape != NULL) { + ac = twoDimShape->getCoordinate(); + } + break; + case COORDINATE_TWO: + if (oneDimShape != NULL) { + ac = oneDimShape->getEndCoordinate(); + } + break; + } + CaretAssert(ac); + + + AnnotationCoordinate coordinateCopy(*ac); + float xyz[3]; + coordinateCopy.getXYZ(xyz); + + if (spinBox == m_xCoordSpinBox) { + xyz[0] = value; + } + else if (spinBox == m_yCoordSpinBox) { + xyz[1] = value; + } + coordinateCopy.setXYZ(xyz); + + std::vector annForCommand { ann }; + AnnotationRedoUndoCommand* undoCommand = new AnnotationRedoUndoCommand(); + switch (m_whichCoordinate) { + case COORDINATE_ONE: + undoCommand->setModeCoordinateOne(coordinateCopy, + annForCommand); + break; + case COORDINATE_TWO: + undoCommand->setModeCoordinateTwo(coordinateCopy, + annForCommand); + break; + } + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + + AString errorMessage; + if ( ! annMan->applyCommand(m_userInputMode, + undoCommand, + errorMessage)) { + WuQMessageBox::errorOk(this, + errorMessage); } - break; - case AnnotationWidgetParentEnum::PARENT_ENUM_FOR_LATER_USE: - CaretAssert(0); - break; } - + EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); + EventManager::get()->sendSimpleEvent(EventTypeEnum::EVENT_ANNOTATION_TOOLBAR_UPDATE); } } diff --git a/src/GuiQt/AnnotationCoordinateCenterXYWidget.h b/src/GuiQt/AnnotationCoordinateCenterXYWidget.h index df6a8a216..d4c24bf95 100644 --- a/src/GuiQt/AnnotationCoordinateCenterXYWidget.h +++ b/src/GuiQt/AnnotationCoordinateCenterXYWidget.h @@ -59,14 +59,17 @@ namespace caret { void updateContent(std::vector& selectedAnnotations); private slots: - void valueChanged(); + void xValueChanged(double value); + + void yValueChanged(double value); private: AnnotationCoordinateCenterXYWidget(const AnnotationCoordinateCenterXYWidget&); AnnotationCoordinateCenterXYWidget& operator=(const AnnotationCoordinateCenterXYWidget&); - AnnotationCoordinate* getCoordinate(); + void processValueChanged(QDoubleSpinBox* spinBox, + const double value); // ADD_NEW_MEMBERS_HERE @@ -82,7 +85,7 @@ namespace caret { QDoubleSpinBox* m_yCoordSpinBox; - Annotation* m_annotation; + std::vector m_annotations; }; -- GitLab From 2908a9f634df806224c431c1591c9118d4e6a48c Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 30 Aug 2019 14:58:47 -0500 Subject: [PATCH 028/584] WB-859 Manual Tile Tabs Layout System: Fixed memory leak in Toolbar's popup-menu. --- src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx index 474503f16..43d1d361d 100644 --- a/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBarTabPopUpMenu.cxx @@ -77,7 +77,7 @@ m_tabIndexUnderMouse(tabIndexUnderMouse) m_activeTabIndex = m_toolBar->tabBar->currentIndex(); m_browserWindowIndex = m_toolBar->browserWindowIndex; - static std::unique_ptr windowContentEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); + std::unique_ptr windowContentEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); EventManager::get()->sendEvent(windowContentEvent->getPointer()); const BrowserWindowContent* browserWindowContent = windowContentEvent->getBrowserWindowContent(); -- GitLab From e78e8a32794ee1699a16c3549dc42a617b57d993 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 30 Aug 2019 16:47:45 -0500 Subject: [PATCH 029/584] WB-859 Manual Tile Tabs Layout System: Added "Preview" of the selected User Configuration on the Tile Tabs Configuration Dialog. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 103 +++++++++++++++++++++- src/GuiQt/TileTabsConfigurationDialog.h | 4 + 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 6efe782ae..694560b17 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -202,7 +203,12 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() "Load the selected User Configuration into the Configuration Type and Settings."); QObject::connect(m_loadConfigurationPushButton, SIGNAL(clicked()), this, SLOT(loadIntoActiveConfigurationPushButtonClicked())); - + + m_configurationPreviewLabel = new QLabel(); + QGroupBox* previewGroupBox = new QGroupBox("Configuration Preview"); + QVBoxLayout* previewLayout = new QVBoxLayout(previewGroupBox); + previewLayout->addWidget(m_configurationPreviewLabel); + QWidget* widget = new QWidget(); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); @@ -210,8 +216,10 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() layout->addWidget(m_addConfigurationPushButton); layout->addSpacing(10); layout->addWidget(m_replaceConfigurationPushButton); - layout->addSpacing(50); + layout->addSpacing(25); layout->addWidget(m_loadConfigurationPushButton); + layout->addSpacing(25); + layout->addWidget(previewGroupBox); layout->addStretch(); return widget; @@ -722,6 +730,8 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() { m_userConfigurationSelectionListWidget = new WuQListWidget(); m_userConfigurationSelectionListWidget->setSelectionMode(QListWidget::SingleSelection); + QObject::connect(m_userConfigurationSelectionListWidget, &QListWidget::itemSelectionChanged, + this, &TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged); QHBoxLayout* selectionLayout = new QHBoxLayout(); WuQtUtilities::setLayoutMargins(selectionLayout, @@ -758,6 +768,94 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() return configurationWidget; } +void +TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() +{ + QPixmap pixmap(101, 101); + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(m_configurationPreviewLabel, + pixmap); + QPen pen = painter->pen(); + pen.setWidth(3); + pen.setColor(QColor(255, 0, 0)); + + AString uuid = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + if ( ! uuid.isEmpty()) { + std::unique_ptr config = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(uuid); + switch (config->getLayoutType()) { + case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: + break; + case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: + { + TileTabsLayoutGridConfiguration* gridConfig = config->castToGridConfiguration(); + CaretAssert(gridConfig); + const int32_t numModels(gridConfig->getNumberOfRows() * gridConfig->getNumberOfColumns()); + std::vector rowHeights; + std::vector columnWidths; + gridConfig->getRowHeightsAndColumnWidthsForWindowSize(pixmap.width(), + pixmap.height(), + numModels, + TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID, + rowHeights, + columnWidths); + + const int32_t numRows = static_cast(rowHeights.size()); + const int32_t numCols = static_cast(columnWidths.size()); + int32_t topY = pixmap.height() - 1; + for (int32_t iRow = 0; iRow < numRows; iRow++) { + int32_t colX(0); + CaretAssertVectorIndex(rowHeights, iRow); + const int32_t height = rowHeights[iRow]; + + for (int32_t jCol = 0; jCol < numCols; jCol++) { + CaretAssertVectorIndex(columnWidths, jCol); + const float width = columnWidths[jCol]; + + QPoint bottomLeft(colX, topY - height); + QPoint bottomRight(colX + width, topY - height); + QPoint topRight(colX + width, topY); + QPoint topLeft(colX, topY); + painter->drawLine(bottomLeft, bottomRight); + painter->drawLine(bottomRight, topRight); + painter->drawLine(topRight, topLeft); + painter->drawLine(topLeft, bottomLeft); + + colX += width; + } + + topY -= height; + + } + } + break; + case TileTabsLayoutConfigurationTypeEnum::MANUAL: + { + TileTabsLayoutManualConfiguration* manConfig = config->castToManualConfiguration(); + CaretAssert(manConfig); + const int32_t numTabs = manConfig->getNumberOfTabs(); + for (int32_t i = 0; i < numTabs; i++) { + TileTabsBrowserTabGeometry* geom = manConfig->getTabInfo(i); + CaretAssert(geom); + float minX(0.0), maxX(0.0), minY(0.0), maxY(0.0); + geom->getBounds(minX, maxX, minY, maxY); + + QPointF bottomLeft(minX, minY); + QPointF bottomRight(maxX, minY); + QPointF topRight(maxX, maxY); + QPointF topLeft(minX, maxY); + painter->drawLine(bottomLeft, bottomRight); + painter->drawLine(bottomRight, topRight); + painter->drawLine(topRight, topLeft); + painter->drawLine(topLeft, bottomLeft); + } + } + break; + } + } + + m_configurationPreviewLabel->setPixmap(pixmap); + +} + /** * @return Instance of workbench window widget. */ @@ -1599,6 +1697,7 @@ TileTabsConfigurationDialog::updateDialog() updateGridStretchFactors(); updateManualGeometryEditorWidget(); + userConfigurationSelectionListWidgetItemChanged(); } /** diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index d909e817b..560086e79 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -112,6 +112,8 @@ namespace caret { void manualConfigurationSetMenuFromCustomItemTriggered(); + void userConfigurationSelectionListWidgetItemChanged(); + protected: void focusGained(); @@ -238,6 +240,8 @@ namespace caret { */ CaretPreferences* m_caretPreferences; + QLabel* m_configurationPreviewLabel; + friend class TileTabGridRowColumnWidgets; static const int32_t s_maximumRowsColumns = 50; -- GitLab From 786f47d3af0b8201b0a13b553c60c70dda6c28d5 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 3 Sep 2019 09:44:16 -0500 Subject: [PATCH 030/584] WB-859 Manual Tile Tabs Layout System: On Tile Tabs Configuration Dialog, show a preview of a configuration when the configuration is clicked in the user configuration list box. The preview is an image containing outlines of the tab layout in the configuration. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 45 +++++++++++++++++------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 694560b17..6f74c5d7d 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -204,7 +204,12 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() QObject::connect(m_loadConfigurationPushButton, SIGNAL(clicked()), this, SLOT(loadIntoActiveConfigurationPushButtonClicked())); + WuQtUtilities::matchWidgetWidths(m_addConfigurationPushButton, + m_replaceConfigurationPushButton, + m_loadConfigurationPushButton); + m_configurationPreviewLabel = new QLabel(); + m_configurationPreviewLabel->setScaledContents(true); /* scale pixmap in label to fill space */ QGroupBox* previewGroupBox = new QGroupBox("Configuration Preview"); QVBoxLayout* previewLayout = new QVBoxLayout(previewGroupBox); previewLayout->addWidget(m_configurationPreviewLabel); @@ -213,11 +218,11 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() QVBoxLayout* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); layout->addSpacing(50); - layout->addWidget(m_addConfigurationPushButton); + layout->addWidget(m_addConfigurationPushButton, 0, Qt::AlignHCenter); layout->addSpacing(10); - layout->addWidget(m_replaceConfigurationPushButton); + layout->addWidget(m_replaceConfigurationPushButton, 0, Qt::AlignHCenter); layout->addSpacing(25); - layout->addWidget(m_loadConfigurationPushButton); + layout->addWidget(m_loadConfigurationPushButton, 0, Qt::AlignHCenter); layout->addSpacing(25); layout->addWidget(previewGroupBox); layout->addStretch(); @@ -758,8 +763,13 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 1, Qt::AlignHCenter); buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 1, Qt::AlignHCenter); +// QTabBar* tabBar = new QTabBar(); +// tabBar->addTab("Template"); +// tabBar->addTab("User"); QGroupBox* configurationWidget = new QGroupBox("User Configurations"); QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); +// configurationLayout->addWidget(tabBar, +// 0); configurationLayout->addWidget(m_userConfigurationSelectionListWidget, 100); configurationLayout->addLayout(buttonsLayout, @@ -768,15 +778,24 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() return configurationWidget; } +/** + * Called when a configuration is highlighted and shows an outline of the layout in the + * configuration preview label + */ void TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() { - QPixmap pixmap(101, 101); + QPixmap pixmap(106, 106); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(m_configurationPreviewLabel, - pixmap); + pixmap); + painter->translate(3, 3); + QPen pen = painter->pen(); pen.setWidth(3); - pen.setColor(QColor(255, 0, 0)); + painter->setPen(pen); + painter->drawRect(0, 0, 100, 100); + pen.setWidth(1); + painter->setPen(pen); AString uuid = getSelectedUserTileTabsConfigurationUniqueIdentifier(); if ( ! uuid.isEmpty()) { @@ -791,8 +810,10 @@ TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() const int32_t numModels(gridConfig->getNumberOfRows() * gridConfig->getNumberOfColumns()); std::vector rowHeights; std::vector columnWidths; - gridConfig->getRowHeightsAndColumnWidthsForWindowSize(pixmap.width(), - pixmap.height(), + const int32_t windowWidth(100); + const int32_t windowHeight(100); + gridConfig->getRowHeightsAndColumnWidthsForWindowSize(windowWidth, + windowHeight, numModels, TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID, rowHeights, @@ -800,7 +821,7 @@ TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() const int32_t numRows = static_cast(rowHeights.size()); const int32_t numCols = static_cast(columnWidths.size()); - int32_t topY = pixmap.height() - 1; + int32_t topY(windowHeight); for (int32_t iRow = 0; iRow < numRows; iRow++) { int32_t colX(0); CaretAssertVectorIndex(rowHeights, iRow); @@ -808,11 +829,11 @@ TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() for (int32_t jCol = 0; jCol < numCols; jCol++) { CaretAssertVectorIndex(columnWidths, jCol); - const float width = columnWidths[jCol]; + const int width = columnWidths[jCol]; QPoint bottomLeft(colX, topY - height); - QPoint bottomRight(colX + width, topY - height); - QPoint topRight(colX + width, topY); + QPoint bottomRight(colX + width - 1, topY - height); + QPoint topRight(colX + width - 1, topY); QPoint topLeft(colX, topY); painter->drawLine(bottomLeft, bottomRight); painter->drawLine(bottomRight, topRight); -- GitLab From bc0d1043dc2c1740a0b3fd28843ad5c91c828a38 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 4 Sep 2019 10:03:36 -0500 Subject: [PATCH 031/584] WB-859 Manual Tile Tabs Layout System: Added template configurations to the Tile Tabs Dialog. Template configurations are hardcoded in the source code and intended to be available for common layout configurations. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 474 +++++++++++++++++----- src/GuiQt/TileTabsConfigurationDialog.h | 53 ++- 2 files changed, 418 insertions(+), 109 deletions(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 6f74c5d7d..9c3cdf398 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -76,6 +76,7 @@ #include "WuQDataEntryDialog.h" #include "WuQListWidget.h" #include "WuQMessageBox.h" +#include "WuQTextEditorDialog.h" #include "WuQtUtilities.h" using namespace caret; @@ -98,7 +99,7 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par : WuQDialogNonModal("Tile Tabs Configurations", parentBrainBrowserWindow) { - m_blockReadConfigurationsFromPreferences = false; + m_blockReadUserConfigurationsFromPreferences = false; m_caretPreferences = SessionManager::get()->getCaretPreferences(); QWidget* workbenchWindowWidget = createWorkbenchWindowWidget(); @@ -300,7 +301,7 @@ TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() return; } - m_blockReadConfigurationsFromPreferences = true; + m_blockReadUserConfigurationsFromPreferences = true; switch (getBrowserWindowContent()->getTileTabsConfigurationMode()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: @@ -331,7 +332,7 @@ TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() break; } - m_blockReadConfigurationsFromPreferences = false; + m_blockReadUserConfigurationsFromPreferences = false; updateDialog(); } @@ -341,6 +342,8 @@ TileTabsConfigurationDialog::addUserConfigurationPushButtonClicked() void TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() { + CaretAssert(getSelectedConfigurationSourceType() == ConfigurationSourceTypeEnum::USER); + const AString tileTabsUniqueID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); if (tileTabsUniqueID.isEmpty()) { WuQMessageBox::errorOk(this, @@ -351,12 +354,12 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() const AString msg("Do you want to replace the configuration?"); if ( ! WuQMessageBox::warningOkCancel(m_replaceConfigurationPushButton, msg)) { - m_blockReadConfigurationsFromPreferences = false; + m_blockReadUserConfigurationsFromPreferences = false; return; } } - m_blockReadConfigurationsFromPreferences = true; + m_blockReadUserConfigurationsFromPreferences = true; switch (getBrowserWindowContent()->getTileTabsConfigurationMode()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: @@ -397,7 +400,7 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() break; } - m_blockReadConfigurationsFromPreferences = false; + m_blockReadUserConfigurationsFromPreferences = false; updateDialog(); } @@ -407,26 +410,38 @@ TileTabsConfigurationDialog::replaceUserConfigurationPushButtonClicked() void TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() { - if (m_automaticGridConfigurationRadioButton->isChecked()) { - return; - } - - const AString userConfigID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); - if (userConfigID.isEmpty()) { - WuQMessageBox::errorOk(m_loadConfigurationPushButton, "No user configuration is selected."); - return; + std::unique_ptr configuration; + switch (getSelectedConfigurationSourceType()) { + case TEMPLATE: + { + configuration = getSelectedTemplateConfiguration(); + } + break; + case USER: + { + const AString userConfigID = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + if (userConfigID.isEmpty()) { + WuQMessageBox::errorOk(m_loadConfigurationPushButton, "No user configuration is selected."); + return; + } + + configuration = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(userConfigID); + if ( ! configuration) { + WuQMessageBox::errorOk(m_loadConfigurationPushButton, + ("User configuration with UniqueID=" + + userConfigID + + " was not found")); + return; + } + } + break; } - std::unique_ptr userConfiguration = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(userConfigID); - if ( ! userConfiguration) { - WuQMessageBox::errorOk(m_loadConfigurationPushButton, - ("User configuration with UniqueID=" - + userConfigID - + " was not found")); + if ( ! configuration) { return; } - switch (userConfiguration->getLayoutType()) { + switch (configuration->getLayoutType()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: CaretAssert(0); break; @@ -435,7 +450,7 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() TileTabsLayoutGridConfiguration* customGridConfiguration = getCustomTileTabsGridConfiguration(); CaretAssert(customGridConfiguration); - const TileTabsLayoutGridConfiguration* userGridConfig = userConfiguration->castToGridConfiguration(); + const TileTabsLayoutGridConfiguration* userGridConfig = configuration->castToGridConfiguration(); CaretAssert(userGridConfig); customGridConfiguration->copy(*userGridConfig); @@ -445,7 +460,7 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: { - const TileTabsLayoutManualConfiguration* userManualConfig = userConfiguration->castToManualConfiguration(); + const TileTabsLayoutManualConfiguration* userManualConfig = configuration->castToManualConfiguration(); CaretAssert(userManualConfig); const int32_t numConfigTabs = userManualConfig->getNumberOfTabs(); @@ -737,12 +752,23 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() m_userConfigurationSelectionListWidget->setSelectionMode(QListWidget::SingleSelection); QObject::connect(m_userConfigurationSelectionListWidget, &QListWidget::itemSelectionChanged, this, &TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged); + + loadTemplateLayoutConfigurations(); - QHBoxLayout* selectionLayout = new QHBoxLayout(); - WuQtUtilities::setLayoutMargins(selectionLayout, - 0); - selectionLayout->addWidget(m_userConfigurationSelectionListWidget, 100); - + m_templateConfigurationSelectionListWidget = new WuQListWidget(); + m_templateConfigurationSelectionListWidget->setSelectionMode(QListWidget::SingleSelection); + for (const auto& tc : m_templateLayoutConfigurations) { + m_templateConfigurationSelectionListWidget->addItem(tc->getName() + + " (" + + AString::number(tc->getNumberOfTabs()) + + ")"); + } + if (m_templateConfigurationSelectionListWidget->count() > 0) { + m_templateConfigurationSelectionListWidget->setCurrentRow(0); + } + QObject::connect(m_templateConfigurationSelectionListWidget, &QListWidget::itemSelectionChanged, + this, &TileTabsConfigurationDialog::templateConfigurationSelectionListWidgetItemChanged); + const AString newToolTip = WuQtUtilities::createWordWrappedToolTipText("Create new User Configuration by entering a name.\n" "It will contain rows/columns/factors from the Custom Configuration"); @@ -757,27 +783,126 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() m_deleteConfigurationPushButton->setAutoDefault(false); QObject::connect(m_deleteConfigurationPushButton, SIGNAL(clicked()), this, SLOT(deleteUserConfigurationButtonClicked())); + + m_showConfigurationXmlPushButton = new QPushButton("Show XML..."); + m_showConfigurationXmlPushButton->setToolTip("Show XML representation of User Configuration"); + m_showConfigurationXmlPushButton->setAutoDefault(false); + QObject::connect(m_showConfigurationXmlPushButton, &QPushButton::clicked, + this, &TileTabsConfigurationDialog::showConfigurationXmlPushButtonClicked); QGridLayout* buttonsLayout = new QGridLayout(); buttonsLayout->setContentsMargins(0, 0, 0, 0); - buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 1, Qt::AlignHCenter); - buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 1, Qt::AlignHCenter); - -// QTabBar* tabBar = new QTabBar(); -// tabBar->addTab("Template"); -// tabBar->addTab("User"); - QGroupBox* configurationWidget = new QGroupBox("User Configurations"); + buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 0, Qt::AlignHCenter); + buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 0, Qt::AlignHCenter); + buttonsLayout->addWidget(m_showConfigurationXmlPushButton, 2, 0, Qt::AlignHCenter); + + m_configurationSourceTabWidget = new QTabWidget(); + m_configurationSourceTemplateTabIndex = m_configurationSourceTabWidget->addTab(m_templateConfigurationSelectionListWidget, + "Template"); + m_configurationSourceUserTabIndex = m_configurationSourceTabWidget->addTab(m_userConfigurationSelectionListWidget, + "User"); + m_configurationSourceTabWidget->setCurrentIndex(m_configurationSourceUserTabIndex); + QObject::connect(m_configurationSourceTabWidget, &QTabWidget::tabBarClicked, + this, &TileTabsConfigurationDialog::configurationSourceTabWidgetClicked); + + QGroupBox* configurationWidget = new QGroupBox("Configurations"); QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); -// configurationLayout->addWidget(tabBar, -// 0); - configurationLayout->addWidget(m_userConfigurationSelectionListWidget, - 100); + configurationLayout->addWidget(m_configurationSourceTabWidget, + 0); configurationLayout->addLayout(buttonsLayout, 0); return configurationWidget; } +/** + * Called when configuration source tab bar is clicked by user + * + * @param index + * Index of item in tab bar + */ +void +TileTabsConfigurationDialog::configurationSourceTabWidgetClicked(int index) +{ + /* + * Note: This method is called before the tab widget updates + * its internal's with the new index. As a result, when + * the selected tab changes, the index passed to this method + * will be different than that returned by QTabWidget::currentIndex() + */ + ConfigurationSourceTypeEnum sourceType = ConfigurationSourceTypeEnum::USER; + if (index == m_configurationSourceUserTabIndex) { + sourceType = ConfigurationSourceTypeEnum::USER; + userConfigurationSelectionListWidgetItemChanged(); + } + else if (index == m_configurationSourceTemplateTabIndex) { + sourceType = ConfigurationSourceTypeEnum::TEMPLATE; + templateConfigurationSelectionListWidgetItemChanged(); + } + + updatePushButtons(sourceType); +} + +/** + * @return The selected configuration source type (template or user) + */ +TileTabsConfigurationDialog::ConfigurationSourceTypeEnum +TileTabsConfigurationDialog::getSelectedConfigurationSourceType() const +{ + if (m_configurationSourceUserTabIndex == m_configurationSourceTabWidget->currentIndex()) { + return ConfigurationSourceTypeEnum::USER; + } + else if (m_configurationSourceTemplateTabIndex == m_configurationSourceTabWidget->currentIndex()) { + return ConfigurationSourceTypeEnum::TEMPLATE; + } + + CaretAssert(0); + return ConfigurationSourceTypeEnum::USER; +} + +/** + * @return The selected user configuration + */ +std::unique_ptr +TileTabsConfigurationDialog::getSelectedUserConfiguration() const +{ + std::unique_ptr config; + + AString uuid = getSelectedUserTileTabsConfigurationUniqueIdentifier(); + if ( ! uuid.isEmpty()) { + config = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(uuid); + } + + return config; +} + +/** + * @return The selected template configuration + */ +std::unique_ptr +TileTabsConfigurationDialog::getSelectedTemplateConfiguration() const +{ + std::unique_ptr config; + + const int32_t index = m_templateConfigurationSelectionListWidget->currentIndex().row(); + if (index >= 0) { + CaretAssertVectorIndex(m_templateLayoutConfigurations, index); + config.reset(m_templateLayoutConfigurations[index]->newCopyWithNewUniqueIdentifier()); + } + + return config; +} + +/** + * Called when a configuration is highlighted and shows an outline of the layout in the + * configuration preview label + */ +void +TileTabsConfigurationDialog::templateConfigurationSelectionListWidgetItemChanged() +{ + loadConfigurationPreviewLabel(getSelectedTemplateConfiguration().get()); +} + /** * Called when a configuration is highlighted and shows an outline of the layout in the * configuration preview label @@ -785,6 +910,21 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() void TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() { + std::unique_ptr config = getSelectedUserConfiguration(); + loadConfigurationPreviewLabel(config.get()); +} + +/** + * Load the given configuration into the configuration preview label + * + * @param configuration + * The configuration to show in label + */ +void +TileTabsConfigurationDialog::loadConfigurationPreviewLabel(TileTabsLayoutBaseConfiguration* configuration) +{ + + QPixmap pixmap(106, 106); QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(m_configurationPreviewLabel, pixmap); @@ -797,15 +937,13 @@ TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() pen.setWidth(1); painter->setPen(pen); - AString uuid = getSelectedUserTileTabsConfigurationUniqueIdentifier(); - if ( ! uuid.isEmpty()) { - std::unique_ptr config = m_caretPreferences->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(uuid); - switch (config->getLayoutType()) { + if (configuration != NULL) { + switch (configuration->getLayoutType()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: break; case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: { - TileTabsLayoutGridConfiguration* gridConfig = config->castToGridConfiguration(); + TileTabsLayoutGridConfiguration* gridConfig = configuration->castToGridConfiguration(); CaretAssert(gridConfig); const int32_t numModels(gridConfig->getNumberOfRows() * gridConfig->getNumberOfColumns()); std::vector rowHeights; @@ -850,7 +988,7 @@ TileTabsConfigurationDialog::userConfigurationSelectionListWidgetItemChanged() break; case TileTabsLayoutConfigurationTypeEnum::MANUAL: { - TileTabsLayoutManualConfiguration* manConfig = config->castToManualConfiguration(); + TileTabsLayoutManualConfiguration* manConfig = configuration->castToManualConfiguration(); CaretAssert(manConfig); const int32_t numTabs = manConfig->getNumberOfTabs(); for (int32_t i = 0; i < numTabs; i++) { @@ -1537,7 +1675,7 @@ TileTabsConfigurationDialog::createConfigurationSettingsWidget() QScrollArea* stretchFactorScrollArea = new QScrollArea(); stretchFactorScrollArea->setWidget(m_editConfigurationStackedWidget); - stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); stretchFactorScrollArea->setWidgetResizable(true); QGroupBox* layoutSettingsGroupBox = new QGroupBox("Configuration Settings"); @@ -1626,12 +1764,12 @@ TileTabsConfigurationDialog::updateDialogWithSelectedTileTabsFromWindow(BrainBro } /** - * Read the configurations from the preferences. + * Read the user configurations from the preferences. */ void -TileTabsConfigurationDialog::readConfigurationsFromPreferences() +TileTabsConfigurationDialog::readUserConfigurationsFromPreferences() { - if (m_blockReadConfigurationsFromPreferences) { + if (m_blockReadUserConfigurationsFromPreferences) { return; } @@ -1684,8 +1822,29 @@ TileTabsConfigurationDialog::updateDialog() updateConfigurationEditingWidget(); - readConfigurationsFromPreferences(); + readUserConfigurationsFromPreferences(); + + updateUserConfigurationListWidget(); + + updateGridStretchFactors(); + updateManualGeometryEditorWidget(); + switch (getSelectedConfigurationSourceType()) { + case TEMPLATE: + templateConfigurationSelectionListWidgetItemChanged(); + break; + case USER: + userConfigurationSelectionListWidgetItemChanged(); + break; + } +} + +/** + * Update the user configuration list widget + */ +void +TileTabsConfigurationDialog::updateUserConfigurationListWidget() +{ int defaultIndex = m_userConfigurationSelectionListWidget->currentRow(); QSignalBlocker blocker(m_userConfigurationSelectionListWidget); @@ -1715,10 +1874,43 @@ TileTabsConfigurationDialog::updateDialog() if (defaultIndex < m_userConfigurationSelectionListWidget->count()) { m_userConfigurationSelectionListWidget->setCurrentRow(defaultIndex); } +} + +/** + * Update the template configuration list widget + */ +void +TileTabsConfigurationDialog::updateTemplateConfigurationListWidget() +{ + int defaultIndex = m_templateConfigurationSelectionListWidget->currentRow(); - updateGridStretchFactors(); - updateManualGeometryEditorWidget(); - userConfigurationSelectionListWidgetItemChanged(); + QSignalBlocker blocker(m_templateConfigurationSelectionListWidget); + m_templateConfigurationSelectionListWidget->clear(); + + const bool includeManualConfigurationsFlag(true); + std::vector> nameUniqueIDs = + m_caretPreferences->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(includeManualConfigurationsFlag); + + for (const auto nameID : nameUniqueIDs) { + /* + * Second element is user data which contains the Unique ID + */ + QListWidgetItem* item = new QListWidgetItem(nameID.first); + item->setData(Qt::UserRole, + QVariant(nameID.second)); + m_templateConfigurationSelectionListWidget->addItem(item); + } + + const int32_t numItemsInComboBox = m_templateConfigurationSelectionListWidget->count(); + if (defaultIndex >= numItemsInComboBox) { + defaultIndex = numItemsInComboBox - 1; + } + if (defaultIndex < 0) { + defaultIndex = 0; + } + if (defaultIndex < m_templateConfigurationSelectionListWidget->count()) { + m_templateConfigurationSelectionListWidget->setCurrentRow(defaultIndex); + } } /** @@ -1741,31 +1933,68 @@ TileTabsConfigurationDialog::updateGridStretchFactors() m_numberOfGridColumnsSpinBox->setValue(configuration->getNumberOfColumns()); } - const bool editableFlag = ( ! m_automaticGridConfigurationRadioButton->isChecked()); - - m_addConfigurationPushButton->setEnabled(editableFlag); - m_loadConfigurationPushButton->setEnabled(editableFlag); - m_replaceConfigurationPushButton->setEnabled(editableFlag); + updatePushButtons(getSelectedConfigurationSourceType()); } /** - * Select the tile tabs configuration with the given name. + * Update the push buttons enabled status + * + * @param sourceType + * The selected configuration source type. */ void -TileTabsConfigurationDialog::selectTileTabConfigurationByUniqueID(const AString& uniqueID) +TileTabsConfigurationDialog::updatePushButtons(const ConfigurationSourceTypeEnum sourceType) { - const int32_t numItems = m_userConfigurationSelectionListWidget->count(); - for (int32_t i = 0; i < numItems; i++) { - QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(i); - const AString itemID = item->data(Qt::UserRole).toString(); - if (itemID == uniqueID) { - QSignalBlocker blocker(m_userConfigurationSelectionListWidget); - m_userConfigurationSelectionListWidget->setCurrentItem(item); + bool addEnabledFlag(false); + bool replaceEnabledFlag(false); + bool deleteRenameEnabledFlag(false); + bool loadEnabledFlag(false); + bool showXmlVisibleFlag(m_caretPreferences->isDevelopMenuEnabled()); + bool showXmlEnabledFlag(false); + + switch (sourceType) { + case TEMPLATE: + { + const bool haveTemplateConfigurationFlag = (getSelectedTemplateConfiguration() != NULL); + if (haveTemplateConfigurationFlag) { + loadEnabledFlag = true; + } + } break; + case USER: + { + const bool haveUserConfigurationFlag(getSelectedUserConfiguration() != NULL); + if (m_automaticGridConfigurationRadioButton->isChecked()) { + /* Nothing */ + } + else { + addEnabledFlag = true; + if (haveUserConfigurationFlag) { + replaceEnabledFlag = true; + } + } + + if (haveUserConfigurationFlag) { + deleteRenameEnabledFlag = true; + loadEnabledFlag = true; + showXmlEnabledFlag = true; + } } + break; } -} + + m_addConfigurationPushButton->setEnabled(addEnabledFlag); + m_replaceConfigurationPushButton->setEnabled(replaceEnabledFlag); + m_loadConfigurationPushButton->setEnabled(loadEnabledFlag); + + m_renameConfigurationPushButton->setEnabled(deleteRenameEnabledFlag); + m_deleteConfigurationPushButton->setEnabled(deleteRenameEnabledFlag); + + m_showConfigurationXmlPushButton->setVisible(showXmlVisibleFlag); + m_showConfigurationXmlPushButton->setVisible(showXmlVisibleFlag + && showXmlEnabledFlag); +} /** * Called when delete user configuration button is clicked. @@ -1812,7 +2041,7 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() &ok); if (ok && ( ! newName.isEmpty())) { - m_blockReadConfigurationsFromPreferences = true; + m_blockReadUserConfigurationsFromPreferences = true; AString errorMessage; if (m_caretPreferences->renameTileTabsUserConfiguration(uniqueID, newName, @@ -1822,7 +2051,7 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() WuQMessageBox::errorOk(m_renameConfigurationPushButton, errorMessage); } - m_blockReadConfigurationsFromPreferences = false; + m_blockReadUserConfigurationsFromPreferences = false; updateDialog(); } } @@ -1832,6 +2061,23 @@ TileTabsConfigurationDialog::renameUserConfigurationButtonClicked() } } +/** + * Called when show configuration XML button is clicked + */ +void +TileTabsConfigurationDialog::showConfigurationXmlPushButtonClicked() +{ + std::unique_ptr config = getSelectedUserConfiguration(); + if (config) { + const QString xml = config->encodeInXML(); + WuQTextEditorDialog::runNonModal("XML", + xml, + WuQTextEditorDialog::TextMode::PLAIN, + WuQTextEditorDialog::WrapMode::NO, + m_showConfigurationXmlPushButton); + } +} + /** * @return A pointer to the custom tile tabs configuration. */ @@ -1844,42 +2090,12 @@ TileTabsConfigurationDialog::getCustomTileTabsGridConfiguration() return configuration; } -/** - * Get the name and unique identifier for the selected user configuration - * - * @param nameOut - * Output with name - * @param uniqueIDOut - * Output with Unique ID - * @return - * True if the output data is valid or false if no configuration is selected - */ -bool -TileTabsConfigurationDialog::getSelectedUserConfigurationNameAndUniqueID(AString& nameOut, - AString& uniqueIDOut) const -{ - const int32_t indx = m_userConfigurationSelectionListWidget->currentRow(); - if ((indx >= 0) - && (indx < m_userConfigurationSelectionListWidget->count())) { - QListWidgetItem* item = m_userConfigurationSelectionListWidget->item(indx); - nameOut = item->text(); - uniqueIDOut = item->data(Qt::UserRole).toString(); - - return true; - } - - nameOut.clear(); - uniqueIDOut.clear(); - - return false; -} - /** * @return The Unique Identifier of the selected user tile tabs configuration. * Empty if no configuration is selected. */ AString -TileTabsConfigurationDialog::getSelectedUserTileTabsConfigurationUniqueIdentifier() +TileTabsConfigurationDialog::getSelectedUserTileTabsConfigurationUniqueIdentifier() const { AString uniqueID; @@ -1976,3 +2192,59 @@ TileTabsConfigurationDialog::helpButtonClicked() } +/** + * Load the template layout configurations + */ +void +TileTabsConfigurationDialog::loadTemplateLayoutConfigurations() +{ + { + const QString configXML(R""""(" + "" + "" + "" + ")""""); + loadTemplateLayoutConfigurationFromXML(configXML); + } + + { + const QString configXML(R""""( + + + + )""""); + loadTemplateLayoutConfigurationFromXML(configXML); + } + + { + const QString configXML(R""""( + + + + + )""""); + loadTemplateLayoutConfigurationFromXML(configXML); + } +} + +/** + * Load a template configuration from the given XML + */ +void +TileTabsConfigurationDialog::loadTemplateLayoutConfigurationFromXML(const QString& xml) +{ + AString errorMessage; + TileTabsLayoutBaseConfiguration* config = TileTabsLayoutBaseConfiguration::decodeFromXML(xml, + errorMessage); + if (config != NULL) { + std::unique_ptr configPtr(config); + m_templateLayoutConfigurations.push_back(std::move(configPtr)); + } + else { + CaretLogWarning("Failed to laod template configuration from XML:\n" + + xml); + } +} + + + diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index 560086e79..8daa4bf6b 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -37,6 +37,7 @@ class QPushButton; class QRadioButton; class QSpinBox; class QStackedWidget; +class QTabWidget; class QToolButton; namespace caret { @@ -86,6 +87,8 @@ namespace caret { void renameUserConfigurationButtonClicked(); + void showConfigurationXmlPushButtonClicked(); + void gridConfigurationNumberOfRowsOrColumnsChanged(); void gridConfigurationStretchFactorWasChanged(); @@ -114,26 +117,30 @@ namespace caret { void userConfigurationSelectionListWidgetItemChanged(); + void templateConfigurationSelectionListWidgetItemChanged(); + + void configurationSourceTabWidgetClicked(int index); + protected: void focusGained(); virtual void helpButtonClicked() override; private: + enum ConfigurationSourceTypeEnum { + TEMPLATE, + USER + }; + // ADD_NEW_MEMBERS_HERE QWidget* createCopyLoadPushButtonsWidget(); QWidget* createWorkbenchWindowWidget(); - void selectTileTabConfigurationByUniqueID(const AString& uniqueID); - TileTabsLayoutGridConfiguration* getCustomTileTabsGridConfiguration(); - AString getSelectedUserTileTabsConfigurationUniqueIdentifier(); - - bool getSelectedUserConfigurationNameAndUniqueID(AString& nameOut, - AString& uniqueIDOut) const; + AString getSelectedUserTileTabsConfigurationUniqueIdentifier() const; QWidget* createUserConfigurationSelectionWidget(); @@ -168,7 +175,11 @@ namespace caret { void updateCustomOptionsWidget(); - void readConfigurationsFromPreferences(); + void readUserConfigurationsFromPreferences(); + + void updateUserConfigurationListWidget(); + + void updateTemplateConfigurationListWidget(); void manualConfigurationSetMenuFromGridConfiguration(TileTabsLayoutGridConfiguration* gridConfiguration); @@ -184,6 +195,20 @@ namespace caret { TileTabsLayoutManualConfiguration* createManualConfigurationFromCurrentTabs() const; + std::unique_ptr getSelectedUserConfiguration() const; + + std::unique_ptr getSelectedTemplateConfiguration() const; + + ConfigurationSourceTypeEnum getSelectedConfigurationSourceType() const; + + void loadConfigurationPreviewLabel(TileTabsLayoutBaseConfiguration* configuration); + + void updatePushButtons(const ConfigurationSourceTypeEnum sourceType); + + void loadTemplateLayoutConfigurations(); + + void loadTemplateLayoutConfigurationFromXML(const QString& xml); + BrainBrowserWindowComboBox* m_browserWindowComboBox; QStackedWidget* m_editConfigurationStackedWidget; @@ -200,14 +225,24 @@ namespace caret { QPushButton* m_renameConfigurationPushButton; + QPushButton* m_showConfigurationXmlPushButton; + QPushButton* m_addConfigurationPushButton; QPushButton* m_replaceConfigurationPushButton; QPushButton* m_loadConfigurationPushButton; + QTabWidget* m_configurationSourceTabWidget; + + int32_t m_configurationSourceTemplateTabIndex; + + int32_t m_configurationSourceUserTabIndex; + WuQListWidget* m_userConfigurationSelectionListWidget; + WuQListWidget* m_templateConfigurationSelectionListWidget; + QSpinBox* m_numberOfGridRowsSpinBox; QSpinBox* m_numberOfGridColumnsSpinBox; @@ -230,8 +265,10 @@ namespace caret { std::vector m_manualGeometryEditorWidgets; + std::vector> m_templateLayoutConfigurations; + /** Blocks reading of preferences since that may invalidate data pointers */ - bool m_blockReadConfigurationsFromPreferences; + bool m_blockReadUserConfigurationsFromPreferences; /** * Keep a pointer to preferences but DO NOT delete it -- GitLab From 17470223c048e3b89fe093b3ff373992fc11d44f Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 4 Sep 2019 14:50:51 -0500 Subject: [PATCH 032/584] WB-859 Manual Tile Tabs Layout System: Added ordering operations (Bring to Front, Bring Forward, Send to Back, Send Backward) to the Tile Tabs Toolbar's Arrange Menu. --- src/GuiQt/AnnotationMenuArrange.cxx | 236 +++++++++++++++++++++++----- src/GuiQt/AnnotationMenuArrange.h | 23 +++ 2 files changed, 222 insertions(+), 37 deletions(-) diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index e1938292e..5290c4b94 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -74,13 +74,29 @@ AnnotationMenuArrange::AnnotationMenuArrange(const UserInputModeEnum::Enum userI m_userInputMode(userInputMode), m_browserWindowIndex(browserWindowIndex) { + switch (m_userInputMode) { + case UserInputModeEnum::ANNOTATIONS: + m_menuMode = MenuMode::ANNOTATIONS; + break; + case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: + m_menuMode = MenuMode::TILE_TABS; + break; + case UserInputModeEnum::BORDERS: + case UserInputModeEnum::FOCI: + case UserInputModeEnum::IMAGE: + case UserInputModeEnum::INVALID: + case UserInputModeEnum::VIEW: + case UserInputModeEnum::VOLUME_EDIT: + CaretAssert(0); + return; + break; + } + addAlignmentSelections(); - addSeparator(); - addDistributeSelections(); - addSeparator(); + addOrderingSelections(); addGroupingSelections(); @@ -105,6 +121,10 @@ AnnotationMenuArrange::~AnnotationMenuArrange() void AnnotationMenuArrange::addAlignmentSelections() { + if ( ! actions().isEmpty()) { + addSeparator(); + } + std::vector alignments; AnnotationAlignmentEnum::getAllEnums(alignments); @@ -129,6 +149,10 @@ AnnotationMenuArrange::addAlignmentSelections() void AnnotationMenuArrange::addDistributeSelections() { + if ( ! actions().isEmpty()) { + addSeparator(); + } + std::vector distributes; AnnotationDistributeEnum::getAllEnums(distributes); @@ -153,6 +177,10 @@ AnnotationMenuArrange::addDistributeSelections() void AnnotationMenuArrange::addGroupingSelections() { + if ( ! actions().isEmpty()) { + addSeparator(); + } + m_groupAction = NULL; m_regroupAction = NULL; m_ungroupAction = NULL; @@ -197,37 +225,49 @@ AnnotationMenuArrange::addGroupingSelections() void AnnotationMenuArrange::addTileTabsSelections() { - bool addMenuFlag(false); - switch (m_userInputMode) { - case UserInputModeEnum::ANNOTATIONS: - break; - case UserInputModeEnum::BORDERS: + switch (m_menuMode) { + case MenuMode::ANNOTATIONS: break; - case UserInputModeEnum::FOCI: - break; - case UserInputModeEnum::IMAGE: - break; - case UserInputModeEnum::INVALID: - break; - case UserInputModeEnum::TILE_TABS_MANUAL_LAYOUT_EDITING: - addMenuFlag = true; + case MenuMode::TILE_TABS: + { + if ( ! actions().isEmpty()) { + addSeparator(); + } + + m_tileTabsExpandToFillAction = addAction("Expand Tab to Fill Empty Space"); + } break; - case UserInputModeEnum::VIEW: + } +} + +/** + * Add ordering for tile tabs mode + */ +void +AnnotationMenuArrange::addOrderingSelections() +{ + switch (m_menuMode) { + case MenuMode::ANNOTATIONS: break; - case UserInputModeEnum::VOLUME_EDIT: + case MenuMode::TILE_TABS: + { + if ( ! actions().isEmpty()) { + addSeparator(); + } + + m_orderingBringToFrontAction = addAction("Bring to Front"); + + m_orderingBringForwardAction = addAction("Bring Forward"); + + m_orderingSendToBackAction = addAction("Send to Back"); + + m_orderingSendBackwardAction = addAction("Send Backward"); + } break; } - - if ( ! addMenuFlag) { - return; - } - - addSeparator(); - - m_tileTabsExpandToFillAction = addAction("Expand Tab to Fill Empty Space"); - } + /* * Gets called when the menu is about to show * so that its menu items can be enabled/disabled. @@ -244,20 +284,40 @@ AnnotationMenuArrange::menuAboutToShow() m_ungroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, AnnotationGroupingModeEnum::UNGROUP)); - if (m_tileTabsExpandToFillAction != NULL) { - std::unique_ptr windowEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); - EventManager::get()->sendEvent(windowEvent->getPointer()); - BrowserWindowContent* bwc = windowEvent->getBrowserWindowContent(); - CaretAssert(bwc); - int32_t numSelected = 0; - if (bwc->isManualModeTileTabsConfigurationEnabled()) { - numSelected = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex).size(); + switch (m_menuMode) { + case MenuMode::ANNOTATIONS: + break; + case MenuMode::TILE_TABS: + { + std::unique_ptr windowEvent = EventBrowserWindowContent::getWindowContent(m_browserWindowIndex); + EventManager::get()->sendEvent(windowEvent->getPointer()); + BrowserWindowContent* bwc = windowEvent->getBrowserWindowContent(); + CaretAssert(bwc); + int32_t numSelected = 0; + if (bwc->isManualModeTileTabsConfigurationEnabled()) { + numSelected = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex).size(); + } + const bool oneSelectedFlag(numSelected == 1); + + CaretAssert(m_tileTabsExpandToFillAction); + m_tileTabsExpandToFillAction->setEnabled(oneSelectedFlag); + + CaretAssert(m_orderingSendToBackAction); + m_orderingSendToBackAction->setEnabled(oneSelectedFlag); + + CaretAssert(m_orderingSendBackwardAction); + m_orderingSendBackwardAction->setEnabled(oneSelectedFlag); + + CaretAssert(m_orderingBringForwardAction); + m_orderingBringForwardAction->setEnabled(oneSelectedFlag); + + CaretAssert(m_orderingBringToFrontAction); + m_orderingBringToFrontAction->setEnabled(oneSelectedFlag); } - m_tileTabsExpandToFillAction->setEnabled(numSelected == 1); + break; } } - /** * Gets called when the user selects a menu item. */ @@ -291,6 +351,9 @@ AnnotationMenuArrange::menuActionTriggered(QAction* action) else if (processTileTabsMenu(action)) { /* If true returned, a tile tabs menu item was selected */ } + else if (processOrderingMenuItem(action)) { + /* If true returned, an ordering menu item was selected */ + } else { const AString msg("Unrecognized Enum name in Annotation Align Menu \"" + enumName @@ -325,6 +388,104 @@ AnnotationMenuArrange::processTileTabsMenu(QAction* actionSelected) return menuSelectedFlag; } +/** + * Process the action if it is on the Tile Tabs Menu + * + * @param actionSelected + * Action selected by user + * @return + * True if the action was on this menu, else false. + */ +bool +AnnotationMenuArrange::processOrderingMenuItem(QAction* actionSelected) +{ + bool menuSelectedFlag(false); + + switch (m_menuMode) { + case MenuMode::ANNOTATIONS: + break; + case MenuMode::TILE_TABS: + { + CaretAssert(m_orderingBringToFrontAction); + CaretAssert(m_orderingBringForwardAction); + CaretAssert(m_orderingSendBackwardAction); + CaretAssert(m_orderingSendToBackAction); + + if (actionSelected == m_orderingBringToFrontAction) { + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_TO_FRONT); + menuSelectedFlag = true; + } + else if (actionSelected == m_orderingBringForwardAction) { + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_BRING_FORWARD); + menuSelectedFlag = true; + } + else if (actionSelected == m_orderingSendBackwardAction) { + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_BACKWARD); + menuSelectedFlag = true; + } + else if (actionSelected == m_orderingSendToBackAction) { + processWindowTileTabOperation(EventBrowserWindowTileTabOperation::OPERATION_ORDER_SEND_TO_BACK); + menuSelectedFlag = true; + } + } + break; + } + + return menuSelectedFlag; +} + +/** + * Called to process a tile tab operation + * + * @param operation + * The operation + */ +void +AnnotationMenuArrange::processWindowTileTabOperation(const EventBrowserWindowTileTabOperation::Operation operation) +{ + std::vector emptyBrowserTabs; + + AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); + BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(m_browserWindowIndex); + CaretAssert(bbw); + BrowserWindowContent* bwc = bbw->getBrowerWindowContent(); + CaretAssert(bwc); + + int32_t tabIndex(-1); + if (bwc->isManualModeTileTabsConfigurationEnabled()) { + std::vector selectedAnnotations = annMan->getAnnotationsSelectedForEditing(m_browserWindowIndex); + if (selectedAnnotations.size() == 1) { + CaretAssertVectorIndex(selectedAnnotations, 0); + Annotation* ann = selectedAnnotations[0]; + CaretAssert(ann); + AnnotationBrowserTab* abt = dynamic_cast(ann); + if (abt != NULL) { + tabIndex = abt->getTabIndex(); + } + else { + CaretLogSevere("Program Error: Selected annotation is not a browser tab"); + } + } + else { + CaretLogSevere("Program Error: Only one tab should be selected for an ordering operation"); + return; + } + } + + int windowViewport[4] { 0, 0, 10, 10 }; + const int32_t mouseX(50); + const int32_t mouseY(50); + EventBrowserWindowTileTabOperation tileTabOperation(operation, + bbw, + m_browserWindowIndex, + tabIndex, + windowViewport, + mouseX, + mouseY, + emptyBrowserTabs); + EventManager::get()->sendEvent(tileTabOperation.getPointer()); +} + void AnnotationMenuArrange::processExpandTabMenuItem() { @@ -448,6 +609,7 @@ AnnotationMenuArrange::applyGrouping(const AnnotationGroupingModeEnum::Enum grou EventManager::get()->sendEvent(EventGraphicsUpdateAllWindows().getPointer()); } + /** * Create an alignment pixmap. * diff --git a/src/GuiQt/AnnotationMenuArrange.h b/src/GuiQt/AnnotationMenuArrange.h index 923d1035b..bfd1298d6 100644 --- a/src/GuiQt/AnnotationMenuArrange.h +++ b/src/GuiQt/AnnotationMenuArrange.h @@ -29,7 +29,9 @@ #include "AnnotationAlignmentEnum.h" #include "AnnotationDistributeEnum.h" #include "AnnotationGroupingModeEnum.h" +#include "EventBrowserWindowTileTabOperation.h" #include "UserInputModeEnum.h" +#include "UserInputModeTileTabsManualLayoutContextMenu.h" namespace caret { @@ -53,6 +55,11 @@ namespace caret { void menuAboutToShow(); private: + enum class MenuMode { + ANNOTATIONS, + TILE_TABS + }; + void addAlignmentSelections(); void addDistributeSelections(); @@ -61,6 +68,8 @@ namespace caret { void addTileTabsSelections(); + void addOrderingSelections(); + void applyAlignment(const AnnotationAlignmentEnum::Enum alignment); void applyDistribute(const AnnotationDistributeEnum::Enum distribute); @@ -93,12 +102,18 @@ namespace caret { bool processTileTabsMenu(QAction* actionSelected); + bool processOrderingMenuItem(QAction* actionSelected); + void processExpandTabMenuItem(); + void processWindowTileTabOperation(const EventBrowserWindowTileTabOperation::Operation operation); + const UserInputModeEnum::Enum m_userInputMode; const int32_t m_browserWindowIndex; + MenuMode m_menuMode = MenuMode::ANNOTATIONS; + QAction* m_groupAction = NULL; QAction* m_regroupAction = NULL; @@ -107,6 +122,14 @@ namespace caret { QAction* m_tileTabsExpandToFillAction = NULL; + QAction* m_orderingBringToFrontAction = NULL; + + QAction* m_orderingBringForwardAction = NULL; + + QAction* m_orderingSendToBackAction = NULL; + + QAction* m_orderingSendBackwardAction = NULL; + // ADD_NEW_MEMBERS_HERE }; -- GitLab From d1997eeedbac26a2d3f563d6c65a9a3dc07439ae Mon Sep 17 00:00:00 2001 From: John Harwell Date: Wed, 4 Sep 2019 15:27:07 -0500 Subject: [PATCH 033/584] For Tile Tabs Editing, hide the grouping selections in the menus (pop-up in graphics window and Arrange in toolbar). --- src/GuiQt/AnnotationMenuArrange.cxx | 31 ++++++++--- src/GuiQt/AnnotationNameWidget.cxx | 2 +- ...putModeTileTabsManualLayoutContextMenu.cxx | 54 ++++++++++--------- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/GuiQt/AnnotationMenuArrange.cxx b/src/GuiQt/AnnotationMenuArrange.cxx index 5290c4b94..2103076f0 100644 --- a/src/GuiQt/AnnotationMenuArrange.cxx +++ b/src/GuiQt/AnnotationMenuArrange.cxx @@ -177,6 +177,17 @@ AnnotationMenuArrange::addDistributeSelections() void AnnotationMenuArrange::addGroupingSelections() { + switch (m_menuMode) { + case MenuMode::ANNOTATIONS: + break; + case MenuMode::TILE_TABS: + /* + * No grouping for tile tabs + */ + return; + break; + } + if ( ! actions().isEmpty()) { addSeparator(); } @@ -277,13 +288,19 @@ AnnotationMenuArrange::menuAboutToShow() { AnnotationManager* annMan = GuiManager::get()->getBrain()->getAnnotationManager(); - m_groupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, - AnnotationGroupingModeEnum::GROUP)); - m_regroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, - AnnotationGroupingModeEnum::REGROUP)); - m_ungroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, - AnnotationGroupingModeEnum::UNGROUP)); - + if (m_groupAction != NULL) { + m_groupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, + AnnotationGroupingModeEnum::GROUP)); + } + if (m_regroupAction != NULL) { + m_regroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, + AnnotationGroupingModeEnum::REGROUP)); + } + if (m_ungroupAction != NULL) { + m_ungroupAction->setEnabled(annMan->isGroupingModeValid(m_browserWindowIndex, + AnnotationGroupingModeEnum::UNGROUP)); + } + switch (m_menuMode) { case MenuMode::ANNOTATIONS: break; diff --git a/src/GuiQt/AnnotationNameWidget.cxx b/src/GuiQt/AnnotationNameWidget.cxx index 42c254b6d..a982aab8b 100644 --- a/src/GuiQt/AnnotationNameWidget.cxx +++ b/src/GuiQt/AnnotationNameWidget.cxx @@ -31,7 +31,7 @@ #include "AnnotationMenuArrange.h" #include "BrowserTabContent.h" #include "CaretAssert.h" -#include "EventGraphicsUpdateOneWindow.cxx" +#include "EventGraphicsUpdateOneWindow.h" #include "EventManager.h" #include "EventUserInterfaceUpdate.h" #include "WuQtUtilities.h" diff --git a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx index 874b70766..300ef2e82 100644 --- a/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx +++ b/src/GuiQt/UserInputModeTileTabsManualLayoutContextMenu.cxx @@ -124,33 +124,35 @@ m_parentOpenGLWidget(parentOpenGLWidget) sendToBackAction->setEnabled(oneTabSelectedFlag); sendBackwardAction->setEnabled(oneTabSelectedFlag); - addSeparator(); - - /* - * Group annotations - */ - QAction* groupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::GROUP), - this, SLOT(applyGroupingGroup())); - groupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, - AnnotationGroupingModeEnum::GROUP)); - - /* - * Ungroup annotations - */ - QAction* ungroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::UNGROUP), - this, SLOT(applyGroupingUngroup())); - ungroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, - AnnotationGroupingModeEnum::UNGROUP)); - - /* - * Regroup annotations - */ - QAction* regroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::REGROUP), - this, SLOT(applyGroupingRegroup())); - regroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, - AnnotationGroupingModeEnum::REGROUP)); + const bool showGroupingOptionsFlag(false); + if (showGroupingOptionsFlag) { + addSeparator(); + + /* + * Group annotations + */ + QAction* groupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::GROUP), + this, SLOT(applyGroupingGroup())); + groupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::GROUP)); + + /* + * Ungroup annotations + */ + QAction* ungroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::UNGROUP), + this, SLOT(applyGroupingUngroup())); + ungroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::UNGROUP)); + + /* + * Regroup annotations + */ + QAction* regroupAction = addAction(AnnotationGroupingModeEnum::toGuiName(AnnotationGroupingModeEnum::REGROUP), + this, SLOT(applyGroupingRegroup())); + regroupAction->setEnabled(annotationManager->isGroupingModeValid(browserWindexIndex, + AnnotationGroupingModeEnum::REGROUP)); + } - addSeparator(); /* -- GitLab From 6b08b45560300a87e844f877a87d0d83598b9a3b Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Sep 2019 12:42:40 -0500 Subject: [PATCH 034/584] WB-859 Manual Tile Tabs Layout System: Add another Tile Tabs Layout template (offset rows) and when drawing preview image for selected layout, do not draw the window outline so that empty regions in the window are visible. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 9c3cdf398..f9e6e89fb 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -931,9 +931,6 @@ TileTabsConfigurationDialog::loadConfigurationPreviewLabel(TileTabsLayoutBaseCon painter->translate(3, 3); QPen pen = painter->pen(); - pen.setWidth(3); - painter->setPen(pen); - painter->drawRect(0, 0, 100, 100); pen.setWidth(1); painter->setPen(pen); @@ -2225,6 +2222,16 @@ TileTabsConfigurationDialog::loadTemplateLayoutConfigurations() )""""); loadTemplateLayoutConfigurationFromXML(configXML); } + + { + const QString configXML(R""""( + + + + + )""""); + loadTemplateLayoutConfigurationFromXML(configXML); + } } /** -- GitLab From 81414c6fdb47d2c4aca4c91e70b4c5a287aaadec Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Sep 2019 14:33:41 -0500 Subject: [PATCH 035/584] WB-859 Manual Tile Tabs Layout System: Fixed crash that occurred when a second window was opened. --- src/GuiQt/BrainBrowserWindowToolBar.cxx | 52 +++++++++++-------------- src/GuiQt/BrainBrowserWindowToolBar.h | 2 + 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindowToolBar.cxx b/src/GuiQt/BrainBrowserWindowToolBar.cxx index c46e4b470..9220a72bf 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.cxx +++ b/src/GuiQt/BrainBrowserWindowToolBar.cxx @@ -167,7 +167,8 @@ BrainBrowserWindowToolBar::BrainBrowserWindowToolBar(const int32_t browserWindow QToolButton* toolBarLockWindowAndAllTabAspectRatioButton, const QString& objectNamePrefix, BrainBrowserWindow* parentBrainBrowserWindow) -: QToolBar(parentBrainBrowserWindow) +: QToolBar(parentBrainBrowserWindow), +m_parentBrainBrowserWindow(parentBrainBrowserWindow) { this->browserWindowIndex = browserWindowIndex; m_tabIndexForTileTabsHighlighting = -1; @@ -959,9 +960,8 @@ BrainBrowserWindowToolBar::allowAddingNewTab() return true; } - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - CaretAssert(browserWindow); - BrowserWindowContent* browserWindowContent = browserWindow->getBrowerWindowContent(); + CaretAssert(m_parentBrainBrowserWindow); + BrowserWindowContent* browserWindowContent = m_parentBrainBrowserWindow->getBrowerWindowContent(); CaretAssert(browserWindowContent); /* @@ -1026,9 +1026,8 @@ BrainBrowserWindowToolBar::allowAddingNewTab() void BrainBrowserWindowToolBar::showMacroDialog() { - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - CaretAssert(bbw); - WuQMacroManager::instance()->showMacrosDialog(bbw); + CaretAssert(m_parentBrainBrowserWindow); + WuQMacroManager::instance()->showMacrosDialog(m_parentBrainBrowserWindow); } /** @@ -1630,9 +1629,8 @@ BrainBrowserWindowToolBar::selectedTabChanged(int indx) this->updateToolBox(); emit viewedModelChanged(); - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - if (browserWindow != NULL) { - if (browserWindow->isTileTabsSelected()) { + if (m_parentBrainBrowserWindow != NULL) { + if (m_parentBrainBrowserWindow->isTileTabsSelected()) { const BrowserTabContent* btc = getTabContentFromSelectedTab(); if (btc != NULL) { if (m_tileTabsHighlightingTimerEnabledFlag) { @@ -1986,9 +1984,8 @@ BrainBrowserWindowToolBar::updateToolBar() this->updateAllTabNames(); - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - if (browserWindow != NULL) { - if (browserWindow->isFullScreen()) { + if (m_parentBrainBrowserWindow != NULL) { + if (m_parentBrainBrowserWindow->isFullScreen()) { this->setVisible(false); } else { @@ -3151,9 +3148,8 @@ BrainBrowserWindowToolBar::modeInputModeActionTriggered(QAction* action) if (action == this->modeInputModeAnnotationsAction) { if (currentMode != UserInputModeEnum::ANNOTATIONS) { - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); - CaretAssert(bbw); - if ( ! bbw->changeInputModeToAnnotationsWarningDialog()) { + CaretAssert(m_parentBrainBrowserWindow); + if ( ! m_parentBrainBrowserWindow->changeInputModeToAnnotationsWarningDialog()) { /* * Since mode is rejected, need to update toolbar */ @@ -3222,6 +3218,10 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte return; } + CaretAssert(m_parentBrainBrowserWindow); + BrowserWindowContent* browserWindowContent = m_parentBrainBrowserWindow->getBrowerWindowContent(); + CaretAssert(browserWindowContent); + this->modeWidgetGroup->blockAllSignals(true); EventGetOrSetUserInputModeProcessor getInputModeEvent(this->browserWindowIndex); @@ -3256,11 +3256,6 @@ BrainBrowserWindowToolBar::updateModeWidget(BrowserTabContent* /*browserTabConte break; } - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - CaretAssert(browserWindow); - BrowserWindowContent* browserWindowContent = browserWindow->getBrowerWindowContent(); - CaretAssert(browserWindowContent); - /* * Enable "Tile" button only if Tile Tabs enabled and * Manual Configuration is selected @@ -4188,8 +4183,8 @@ BrainBrowserWindowToolBar::customViewActionTriggered() QAction* selectedAction = menu.exec(QCursor::pos()); if (selectedAction != NULL) { if (selectedAction == editAction) { - BrainBrowserWindow* bbw = GuiManager::get()->getBrowserWindowByWindowIndex(browserWindowIndex); - GuiManager::get()->processShowCustomViewDialog(bbw); + CaretAssert(m_parentBrainBrowserWindow); + GuiManager::get()->processShowCustomViewDialog(m_parentBrainBrowserWindow); } else { const AString customViewName = selectedAction->text(); @@ -4574,16 +4569,14 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) CaretAssert(getModelEvent); if (getModelEvent->getBrowserWindowIndex() == this->browserWindowIndex) { - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - - if (browserWindow != NULL) { + if (m_parentBrainBrowserWindow != NULL) { const int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); getModelEvent->addBrowserTab(btc); } - BrowserWindowContent* windowContent = browserWindow->getBrowerWindowContent(); + BrowserWindowContent* windowContent = m_parentBrainBrowserWindow->getBrowerWindowContent(); getModelEvent->setBrowserWindowContent(windowContent); if (windowContent->isTileTabsEnabled()) { @@ -4668,9 +4661,8 @@ BrainBrowserWindowToolBar::receiveEvent(Event* event) EventBrowserTabGetAllViewed* viewedTabsEvent = dynamic_cast(event); CaretAssert(viewedTabsEvent); - BrainBrowserWindow* browserWindow = GuiManager::get()->getBrowserWindowByWindowIndex(this->browserWindowIndex); - if (browserWindow != NULL) { - if (browserWindow->isTileTabsSelected()) { + if (m_parentBrainBrowserWindow != NULL) { + if (m_parentBrainBrowserWindow->isTileTabsSelected()) { const int32_t numTabs = this->tabBar->count(); for (int32_t i = 0; i < numTabs; i++) { BrowserTabContent* btc = this->getTabContentFromTab(i); diff --git a/src/GuiQt/BrainBrowserWindowToolBar.h b/src/GuiQt/BrainBrowserWindowToolBar.h index fe2219db6..703dfcddf 100644 --- a/src/GuiQt/BrainBrowserWindowToolBar.h +++ b/src/GuiQt/BrainBrowserWindowToolBar.h @@ -436,6 +436,8 @@ namespace caret { QAction* toolBarToolButtonAction; QAction* toolBoxToolButtonAction; + BrainBrowserWindow* m_parentBrainBrowserWindow = NULL; + int32_t browserWindowIndex; private slots: -- GitLab From b1cb3c112ee804dfceca77b9dea5b9812cff63ea Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Sep 2019 15:18:53 -0500 Subject: [PATCH 036/584] WB-859 Manual Tile Tabs Layout System: Avoid crashes and logging warning messages when a drawing viewport contains an invalid (non-positive) width or height. This occurs if the user is editing the geometry of a tab on the tile tabs configuration dialog (user sets left edge to larger that right edge and then corrects by setting right edge). --- src/Brain/BrainOpenGLFixedPipeline.cxx | 26 +++++++---- src/Brain/BrainOpenGLViewportContent.cxx | 57 +++++++++++++----------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/Brain/BrainOpenGLFixedPipeline.cxx b/src/Brain/BrainOpenGLFixedPipeline.cxx index c0ee3257e..ebd595fb1 100644 --- a/src/Brain/BrainOpenGLFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLFixedPipeline.cxx @@ -714,18 +714,23 @@ BrainOpenGLFixedPipeline::drawModelsImplementation(const int32_t windowIndex, continue; } + const bool logInvalidViewportFlag(false); if (tabViewport[2] <= 0) { - CaretLogSevere("Invalid TAB width=" - + AString::number(tabViewport[2]) - + " for index=" - + AString::number(i)); + if (logInvalidViewportFlag) { + CaretLogSevere("Invalid TAB width=" + + AString::number(tabViewport[2]) + + " for index=" + + AString::number(i)); + } continue; } if (tabViewport[3] <= 0) { - CaretLogSevere("Invalid TAB height=" - + AString::number(tabViewport[3]) - + " for index=" - + AString::number(i)); + if (logInvalidViewportFlag) { + CaretLogSevere("Invalid TAB height=" + + AString::number(tabViewport[3]) + + " for index=" + + AString::number(i)); + } continue; } } @@ -1111,6 +1116,11 @@ BrainOpenGLFixedPipeline::drawTabAnnotations(const BrainOpenGLViewportContent* t int tabViewport[4]; tabContent->getModelViewport(tabViewport); + if ((tabViewport[2] <= 0) + || (tabViewport[3] <= 0)) { + /* Viewport may be invalid when tabs edited by user */ + return; + } CaretAssertMessage(m_brain, "m_brain must NOT be NULL for drawing window annotations."); glViewport(tabViewport[0], tabViewport[1], diff --git a/src/Brain/BrainOpenGLViewportContent.cxx b/src/Brain/BrainOpenGLViewportContent.cxx index 8d6804297..34f54a50f 100644 --- a/src/Brain/BrainOpenGLViewportContent.cxx +++ b/src/Brain/BrainOpenGLViewportContent.cxx @@ -1133,34 +1133,41 @@ BrainOpenGLViewportContent::createViewportContentForManualTileTabs(std::vectorgetTabNumber(); - const bool highlightTabFlag(highlightTabIndex == tabIndex); - int modelViewport[4] = { 0, 0, 0, 0 }; - createModelViewport(tabViewport, - tabIndex, - gapsAndMargins, - modelViewport); + if ((tabWidth > 0) + && (tabHeight > 0)) { + const int tabViewport[4] = { + tabX, + tabY, + tabWidth, + tabHeight + }; + + /* + * Model is drawn in the model viewport inside any margins. + */ + const int32_t tabIndex = tab->getTabNumber(); + const bool highlightTabFlag(highlightTabIndex == tabIndex); + int modelViewport[4] = { 0, 0, 0, 0 }; + createModelViewport(tabViewport, + tabIndex, + gapsAndMargins, + modelViewport); - SpacerTabContent* invalidSpaceTabContent(NULL); - BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, - tabViewportBeforeAspectLocking, - tabViewport, - modelViewport, - browserWindowContent->getWindowIndex(), - highlightTabFlag, - tab, - invalidSpaceTabContent); - viewportContentsOut.push_back(vpContent); + SpacerTabContent* invalidSpaceTabContent(NULL); + BrainOpenGLViewportContent* vpContent = new BrainOpenGLViewportContent(windowViewport, + tabViewportBeforeAspectLocking, + tabViewport, + modelViewport, + browserWindowContent->getWindowIndex(), + highlightTabFlag, + tab, + invalidSpaceTabContent); + viewportContentsOut.push_back(vpContent); + } } return viewportContentsOut; -- GitLab From c0f69aed1bbdd19495294bb39b67dc2c878c3245 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 9 Sep 2019 16:11:20 -0500 Subject: [PATCH 037/584] WB-859 Manual Tile Tabs Layout System: On Tile Tabs Configuration Dialog, If the user attempts to switch to the Custom Grid Type or Load a Custom Grid that contains fewer tabs than there are tabs in the window, pop-up a dialog to warn the user that some tabs may not be visible if the grid layout is used. --- .../TileTabsLayoutGridConfiguration.cxx | 30 ++++++++- src/GuiQt/TileTabsConfigurationDialog.cxx | 63 +++++++++++++++++-- src/GuiQt/TileTabsConfigurationDialog.h | 2 + 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/Common/TileTabsLayoutGridConfiguration.cxx b/src/Common/TileTabsLayoutGridConfiguration.cxx index d93533b8a..a419196e1 100644 --- a/src/Common/TileTabsLayoutGridConfiguration.cxx +++ b/src/Common/TileTabsLayoutGridConfiguration.cxx @@ -195,12 +195,38 @@ TileTabsLayoutGridConfiguration::copy(const TileTabsLayoutBaseConfiguration& rhs } /** - * @return Number of tabs in this layout + * @return Number of tabs in this layout (spacers are excluded) */ int32_t TileTabsLayoutGridConfiguration::getNumberOfTabs() const { - const int32_t numTabs = getNumberOfRows() * getNumberOfColumns(); + /* + * Need to exclude spacer rows/columns + */ + + int32_t rowCount(0); + for (const auto row : m_rows) { + switch (row.getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + rowCount++; + break; + } + } + + int32_t columnCount(0); + for (const auto col : m_columns) { + switch (col.getContentType()) { + case TileTabsGridRowColumnContentTypeEnum::SPACE: + break; + case TileTabsGridRowColumnContentTypeEnum::TAB: + columnCount++; + break; + } + } + + const int32_t numTabs = rowCount * columnCount; return numTabs; } diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index f9e6e89fb..e66d8875f 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -441,6 +441,10 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() return; } + std::vector allTabContent; + getBrowserWindow()->getAllTabContent(allTabContent); + int32_t numBrowserTabs = static_cast(allTabContent.size()); + switch (configuration->getLayoutType()) { case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: CaretAssert(0); @@ -453,6 +457,10 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() const TileTabsLayoutGridConfiguration* userGridConfig = configuration->castToGridConfiguration(); CaretAssert(userGridConfig); + if ( ! warnIfGridConfigurationTooSmallDialog(userGridConfig)) { + return; + } + customGridConfiguration->copy(*userGridConfig); getBrowserWindowContent()->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); @@ -472,10 +480,6 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() return; } - std::vector allTabContent; - getBrowserWindow()->getAllTabContent(allTabContent); - int32_t numBrowserTabs = static_cast(allTabContent.size()); - /* * Display status of tabs must be set after * configuration is copied from User Configurations @@ -654,6 +658,51 @@ TileTabsConfigurationDialog::loadIntoActiveConfigurationPushButtonClicked() updateGraphicsWindow(); } +/** + * If the given grid configuration contains fewer tabs than the number of tabs in the window, + * warn the user, with the option to continue. + * + * @param gridConfiguration + * The grid configuration + * @return + * True if processing should continue (use the configuration), else false indicating cancel. + */ +bool +TileTabsConfigurationDialog::warnIfGridConfigurationTooSmallDialog(const TileTabsLayoutGridConfiguration* gridConfiguration) const +{ + CaretAssert(gridConfiguration); + + std::vector allTabContent; + getBrowserWindow()->getAllTabContent(allTabContent); + int32_t numBrowserTabs = static_cast(allTabContent.size()); + + const int32_t numConfigTabs = gridConfiguration->getNumberOfTabs(); + if (numConfigTabs <= 0) { + WuQMessageBox::errorOk(m_loadConfigurationPushButton, + ("User configuration \"" + + gridConfiguration->getName() + + "\" is invalid (does not have any tabs)")); + return false; + } + + if (numConfigTabs < numBrowserTabs) { + AString msg("" + "The Window contains " + + AString::number(numBrowserTabs) + + " tabs.

" + "The Grid contains space for " + + AString::number(numConfigTabs) + + " tabs.

" + "If you continue, not all tabs will be visible but you can edit the configuration to view all tabs." + ""); + return WuQMessageBox::warningOkCancel(m_loadConfigurationPushButton, + msg); + } + + return true; +} + + /** * @return the BrainOpenGLViewportContent for the tab with the given index (NULL if not found) */ @@ -1726,6 +1775,12 @@ TileTabsConfigurationDialog::automaticCustomButtonClicked(QAbstractButton* butto browserWindowContent->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID); } else if (button == m_customGridConfigurationRadioButton) { + const TileTabsLayoutGridConfiguration* gridConfig = browserWindowContent->getCustomGridTileTabsConfiguration(); + if (gridConfig != NULL) { + if ( ! warnIfGridConfigurationTooSmallDialog(gridConfig)) { + return; + } + } browserWindowContent->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); } else if (button == m_manualConfigurationRadioButton) { diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index 8daa4bf6b..18f91911c 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -209,6 +209,8 @@ namespace caret { void loadTemplateLayoutConfigurationFromXML(const QString& xml); + bool warnIfGridConfigurationTooSmallDialog(const TileTabsLayoutGridConfiguration* gridConfiguration) const; + BrainBrowserWindowComboBox* m_browserWindowComboBox; QStackedWidget* m_editConfigurationStackedWidget; -- GitLab From 715e757ef6f3f559aac58e4d19edfea8dd5ebaec Mon Sep 17 00:00:00 2001 From: John Harwell Date: Tue, 10 Sep 2019 12:30:52 -0500 Subject: [PATCH 038/584] WB-859 Manual Tile Tabs Layout System: In the tile tabs configuration dialog, the construction buttons for custom grid layouts were not getting enabled when the parent stacked widget was disabled (such as when switching to automatic grid configuration and back to custom grid configuration). So, when the grid layout row/column is updated, enable the action in the construction menu to fix the problem. --- src/GuiQt/TileTabGridRowColumnWidgets.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/GuiQt/TileTabGridRowColumnWidgets.cxx b/src/GuiQt/TileTabGridRowColumnWidgets.cxx index eb3bf2d09..4a2e97a28 100644 --- a/src/GuiQt/TileTabGridRowColumnWidgets.cxx +++ b/src/GuiQt/TileTabGridRowColumnWidgets.cxx @@ -261,6 +261,15 @@ TileTabGridRowColumnWidgets::updateContent(TileTabsGridRowColumnElement* element m_stretchValueSpinBox->setSuffix(""); break; } + + /* + * These configuration widgets are placed into a stacked widget. The stacked widget + * is disabled when an automatic configuration is selected. However, when the stacked + * widget is enabled (custom grid selected), the menu action fails to get reenabled and + * that causes the menu to remain disabled. So, enable the menu here so that + * the construction menu is enabled correctly. + */ + m_constructionAction->setEnabled(true); } m_gridLayoutGroup->setVisible(showFlag); -- GitLab From dd5308db30b36a61b5c7c667fdf18af5d0672481 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 12 Sep 2019 11:08:14 -0500 Subject: [PATCH 039/584] WB-859 Manual Tile Tabs Layout System: When in Tile Editing mode, draw a stippled (dashed) line around each tab so that the user can see the tab boundaries when moving tabs around. Without the outline, it is difficult to know where the boundaries of the tabs are located. --- .../BrainOpenGLAnnotationDrawingFixedPipeline.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx index 73df81be5..8c9245a57 100644 --- a/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx +++ b/src/Brain/BrainOpenGLAnnotationDrawingFixedPipeline.cxx @@ -1905,6 +1905,20 @@ BrainOpenGLAnnotationDrawingFixedPipeline::drawBrowserTab(AnnotationFile* annota s_sizingHandleLineWidthInPixels, browserTab->getRotationAngle()); } + else if (m_inputs->m_tileTabsManualLayoutUserInputModeFlag) { + glPushAttrib(GL_LINE_BIT); + glLineStipple(1, 0xf000); + glEnable(GL_LINE_STIPPLE); + glLineWidth(1); + glColor4ubv(foregroundRGBA); + glBegin(GL_LINE_LOOP); + glVertex3fv(bottomLeft); + glVertex3fv(bottomRight); + glVertex3fv(topRight); + glVertex3fv(topLeft); + glEnd(); + glPopAttrib(); + } } setDepthTestingStatus(savedDepthTestStatus); -- GitLab From 1c543eaaa98d2578292e95e7d0fe3b7767fa66ad Mon Sep 17 00:00:00 2001 From: John Harwell Date: Thu, 12 Sep 2019 15:39:36 -0500 Subject: [PATCH 040/584] WB-859 Manual Tile Tabs Layout System: Changed layout in Tile Tabs Configuration dialog to reduce the width of the dialog. --- src/GuiQt/TileTabsConfigurationDialog.cxx | 82 +++++++++++++++-------- src/GuiQt/TileTabsConfigurationDialog.h | 4 +- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index e66d8875f..2aa736e05 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -109,9 +109,21 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par setStandardButtonText(QDialogButtonBox::Help, "Help"); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); - EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); - +// QWidget* dialogWidget = new QWidget(); +// QGridLayout* dialogLayout = new QGridLayout(dialogWidget); +// dialogLayout->setColumnStretch(0, 0); +// dialogLayout->setColumnStretch(1, 0); +// dialogLayout->setColumnStretch(2, 100); +// dialogLayout->addWidget(workbenchWindowWidget, +// 0, 0, Qt::AlignLeft); +// dialogLayout->addWidget(createConfigurationTypeWidget(), +// 1, 0); +// dialogLayout->addWidget(createConfigurationSettingsWidget(), +// 2, 0); +// dialogLayout->addWidget(createCopyLoadPushButtonsWidget(), +// 1, 1, 2, 1); +// dialogLayout->addWidget(createUserConfigurationSelectionWidget(), +// 1, 2, 2, 1); QWidget* dialogWidget = new QWidget(); QGridLayout* dialogLayout = new QGridLayout(dialogWidget); dialogLayout->setColumnStretch(0, 0); @@ -122,12 +134,12 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par dialogLayout->addWidget(createConfigurationTypeWidget(), 1, 0); dialogLayout->addWidget(createConfigurationSettingsWidget(), - 2, 0); + 2, 0, 1, 2); dialogLayout->addWidget(createCopyLoadPushButtonsWidget(), - 1, 1, 2, 1); + 0, 1, 2, 1, Qt::AlignBottom); dialogLayout->addWidget(createUserConfigurationSelectionWidget(), - 1, 2, 2, 1); - + 0, 2, 3, 1); + setCentralWidget(dialogWidget, WuQDialog::SCROLL_AREA_NEVER); updateDialogWithSelectedTileTabsFromWindow(parentBrainBrowserWindow); @@ -136,6 +148,11 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par 500); disableAutoDefaultForAllPushButtons(); + + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_GRAPHICS_HAVE_BEEN_REDRAWN); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_USER_INTERFACE_UPDATE); + EventManager::get()->addEventListener(this, EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE); + } /** @@ -166,6 +183,9 @@ TileTabsConfigurationDialog::receiveEvent(Event* event) updateDialog(); } } + else if (event->getEventType() == EventTypeEnum::EVENT_BROWSER_WINDOW_MENUS_UPDATE) { + updateTemplateUserConfigurationPushButtons(getSelectedConfigurationSourceType()); + } } /** @@ -209,24 +229,17 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() m_replaceConfigurationPushButton, m_loadConfigurationPushButton); - m_configurationPreviewLabel = new QLabel(); - m_configurationPreviewLabel->setScaledContents(true); /* scale pixmap in label to fill space */ - QGroupBox* previewGroupBox = new QGroupBox("Configuration Preview"); - QVBoxLayout* previewLayout = new QVBoxLayout(previewGroupBox); - previewLayout->addWidget(m_configurationPreviewLabel); - QWidget* widget = new QWidget(); + widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); - layout->addSpacing(50); +// layout->addSpacing(50); layout->addWidget(m_addConfigurationPushButton, 0, Qt::AlignHCenter); - layout->addSpacing(10); +// layout->addSpacing(10); layout->addWidget(m_replaceConfigurationPushButton, 0, Qt::AlignHCenter); - layout->addSpacing(25); + layout->addSpacing(10); layout->addWidget(m_loadConfigurationPushButton, 0, Qt::AlignHCenter); - layout->addSpacing(25); - layout->addWidget(previewGroupBox); - layout->addStretch(); +// layout->addStretch(); return widget; } @@ -839,11 +852,19 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() QObject::connect(m_showConfigurationXmlPushButton, &QPushButton::clicked, this, &TileTabsConfigurationDialog::showConfigurationXmlPushButtonClicked); + WuQtUtilities::matchWidgetWidths(m_renameConfigurationPushButton, + m_deleteConfigurationPushButton, + m_showConfigurationXmlPushButton); + QGridLayout* buttonsLayout = new QGridLayout(); buttonsLayout->setContentsMargins(0, 0, 0, 0); - buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 0, Qt::AlignHCenter); - buttonsLayout->addWidget(m_deleteConfigurationPushButton, 1, 0, Qt::AlignHCenter); - buttonsLayout->addWidget(m_showConfigurationXmlPushButton, 2, 0, Qt::AlignHCenter); + buttonsLayout->addWidget(m_renameConfigurationPushButton, 0, 0); + buttonsLayout->addWidget(m_deleteConfigurationPushButton, 0, 1); + buttonsLayout->addWidget(m_showConfigurationXmlPushButton, 1, 0, 1, 2, Qt::AlignHCenter); + + QLabel* previewTextLabel = new QLabel("Configuration Preview"); + m_configurationImagePreviewLabel = new QLabel(); + m_configurationImagePreviewLabel->setScaledContents(true); /* scale pixmap in label to fill space */ m_configurationSourceTabWidget = new QTabWidget(); m_configurationSourceTemplateTabIndex = m_configurationSourceTabWidget->addTab(m_templateConfigurationSelectionListWidget, @@ -858,6 +879,9 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); configurationLayout->addWidget(m_configurationSourceTabWidget, 0); + configurationLayout->addWidget(previewTextLabel); + configurationLayout->addWidget(m_configurationImagePreviewLabel, + 0); configurationLayout->addLayout(buttonsLayout, 0); @@ -889,7 +913,7 @@ TileTabsConfigurationDialog::configurationSourceTabWidgetClicked(int index) templateConfigurationSelectionListWidgetItemChanged(); } - updatePushButtons(sourceType); + updateTemplateUserConfigurationPushButtons(sourceType); } /** @@ -975,7 +999,7 @@ TileTabsConfigurationDialog::loadConfigurationPreviewLabel(TileTabsLayoutBaseCon QPixmap pixmap(106, 106); - QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(m_configurationPreviewLabel, + QSharedPointer painter = WuQtUtilities::createPixmapWidgetPainterOriginBottomLeft(m_configurationImagePreviewLabel, pixmap); painter->translate(3, 3); @@ -1057,7 +1081,7 @@ TileTabsConfigurationDialog::loadConfigurationPreviewLabel(TileTabsLayoutBaseCon } } - m_configurationPreviewLabel->setPixmap(pixmap); + m_configurationImagePreviewLabel->setPixmap(pixmap); } @@ -1403,7 +1427,7 @@ TileTabsConfigurationDialog::addManualGeometryWidget(QGridLayout* gridLayout, gridLayout->setHorizontalSpacing(8); gridLayout->addWidget(new QLabel("Show"), rowIndex, columnIndex++, Qt::AlignLeft); - gridLayout->addWidget(new QLabel("Name"), rowIndex, columnIndex++, Qt::AlignLeft); + gridLayout->addWidget(new QLabel("Tab Name"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Left"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Right"), rowIndex, columnIndex++, Qt::AlignLeft); gridLayout->addWidget(new QLabel("Bottom"), rowIndex, columnIndex++, Qt::AlignLeft); @@ -1985,7 +2009,7 @@ TileTabsConfigurationDialog::updateGridStretchFactors() m_numberOfGridColumnsSpinBox->setValue(configuration->getNumberOfColumns()); } - updatePushButtons(getSelectedConfigurationSourceType()); + updateTemplateUserConfigurationPushButtons(getSelectedConfigurationSourceType()); } /** @@ -1995,7 +2019,7 @@ TileTabsConfigurationDialog::updateGridStretchFactors() * The selected configuration source type. */ void -TileTabsConfigurationDialog::updatePushButtons(const ConfigurationSourceTypeEnum sourceType) +TileTabsConfigurationDialog::updateTemplateUserConfigurationPushButtons(const ConfigurationSourceTypeEnum sourceType) { bool addEnabledFlag(false); bool replaceEnabledFlag(false); @@ -2043,7 +2067,7 @@ TileTabsConfigurationDialog::updatePushButtons(const ConfigurationSourceTypeEnum m_deleteConfigurationPushButton->setEnabled(deleteRenameEnabledFlag); m_showConfigurationXmlPushButton->setVisible(showXmlVisibleFlag); - m_showConfigurationXmlPushButton->setVisible(showXmlVisibleFlag + m_showConfigurationXmlPushButton->setEnabled(showXmlVisibleFlag && showXmlEnabledFlag); } diff --git a/src/GuiQt/TileTabsConfigurationDialog.h b/src/GuiQt/TileTabsConfigurationDialog.h index 18f91911c..2aff82777 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.h +++ b/src/GuiQt/TileTabsConfigurationDialog.h @@ -203,7 +203,7 @@ namespace caret { void loadConfigurationPreviewLabel(TileTabsLayoutBaseConfiguration* configuration); - void updatePushButtons(const ConfigurationSourceTypeEnum sourceType); + void updateTemplateUserConfigurationPushButtons(const ConfigurationSourceTypeEnum sourceType); void loadTemplateLayoutConfigurations(); @@ -279,7 +279,7 @@ namespace caret { */ CaretPreferences* m_caretPreferences; - QLabel* m_configurationPreviewLabel; + QLabel* m_configurationImagePreviewLabel; friend class TileTabGridRowColumnWidgets; -- GitLab From ff0066ca2fa79e1abcbae04260a9ec26e286d099 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Fri, 13 Sep 2019 09:36:00 -0500 Subject: [PATCH 041/584] WB-859 Manual Tile Tabs Layout System: Clean up View Menu and some improvements in labels on Tile Tabs Configuration Dialog. --- src/GuiQt/BrainBrowserWindow.cxx | 117 +++------------------- src/GuiQt/BrainBrowserWindow.h | 4 - src/GuiQt/TileTabsConfigurationDialog.cxx | 24 +---- 3 files changed, 15 insertions(+), 130 deletions(-) diff --git a/src/GuiQt/BrainBrowserWindow.cxx b/src/GuiQt/BrainBrowserWindow.cxx index c7f4c8f33..94c738d3a 100644 --- a/src/GuiQt/BrainBrowserWindow.cxx +++ b/src/GuiQt/BrainBrowserWindow.cxx @@ -2590,34 +2590,6 @@ BrainBrowserWindow::modifyTileTabsConfiguration(EventTileTabsGridConfigurationMo modEvent->setEventProcessed(); } -/** - * Update the tile tabs configuration menu just before it is shown. - */ -void -BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow() -{ - /* - * QMenu::clear will delete the actions that were in the menu - */ - m_viewTileTabsLoadUserConfigurationMenu->clear(); - m_viewCustomTileTabsConfigurationActions.clear(); - - const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - - const bool includeManualConfigurationsFlag(false); - std::vector> nameUniqueIDs = - prefs->getTileTabsUserConfigurationsNamesAndUniqueIdentifiers(includeManualConfigurationsFlag); - - for (const auto nameID : nameUniqueIDs) { - /* - * Second element is user data which contains the Unique ID - */ - QAction* action = m_viewTileTabsLoadUserConfigurationMenu->addAction(nameID.first); - m_viewCustomTileTabsConfigurationActions.push_back(std::make_pair(action, - nameID.second)); - } -} - /** * Called when automatic/custom menu item is selected. * @@ -2645,74 +2617,6 @@ BrainBrowserWindow::processViewTileTabsAutomaticCustomTriggered(QAction* action) EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); } -/** - * Process an item selected from the tile tabs configuration menu. - */ -void -BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered(QAction* action) -{ - CaretAssert(action); - - const CaretPreferences* prefs = SessionManager::get()->getCaretPreferences(); - - BrowserWindowContent* bwc = getBrowerWindowContent(); - bwc->setTileTabsConfigurationMode(TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID); - - AString tileTabsConfigID; - for (auto& config : m_viewCustomTileTabsConfigurationActions) { - if (config.first == action) { - tileTabsConfigID = config.second; - break; - } - } - - std::unique_ptr tileTabsConfig = prefs->getCopyOfTileTabsUserConfigurationByUniqueIdentifier(tileTabsConfigID); - if (tileTabsConfig) { - switch (tileTabsConfig->getLayoutType()) { - case TileTabsLayoutConfigurationTypeEnum::AUTOMATIC_GRID: - CaretAssert(0); - break; - case TileTabsLayoutConfigurationTypeEnum::CUSTOM_GRID: - { - const TileTabsLayoutGridConfiguration* gridConfig = tileTabsConfig->castToGridConfiguration(); - CaretAssert(gridConfig); - - bwc->getCustomGridTileTabsConfiguration()->copy(*gridConfig); - } - break; - case TileTabsLayoutConfigurationTypeEnum::MANUAL: - /* - * The method processViewTileTabsLoadUserConfigurationMenuAboutToShow() - * excludes manual configurations so we should never get here. - */ - CaretAssert(0); - break; - } - - EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer()); - EventManager::get()->sendEvent(EventGraphicsUpdateOneWindow(getBrowserWindowIndex()).getPointer()); - } - else { - WuQMessageBox::errorOk(this, "Unable to find User Configuration with UniqueID: " - + tileTabsConfigID); - } -} - -/** - * @return Instance of the tile tabs configuration menu. - */ -QMenu* -BrainBrowserWindow::createMenuViewTileTabsLoadUserConfiguration() -{ - QMenu* menu = new QMenu("Set Tile Tabs to User Configuration"); - QObject::connect(menu, &QMenu::aboutToShow, - this, &BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuAboutToShow); - QObject::connect(menu, &QMenu::triggered, - this, &BrainBrowserWindow::processViewTileTabsLoadUserConfigurationMenuItemTriggered); - - return menu; -} - /** * Create the view menu. * @return the view menu. @@ -2723,17 +2627,19 @@ BrainBrowserWindow::createMenuView() QMenu* menu = new QMenu("View", this); QObject::connect(menu, SIGNAL(aboutToShow()), this, SLOT(processViewMenuAboutToShow())); - - QMenu* tileTabsModeMenu = new QMenu("Tile Tabs Configuration Layout"); - tileTabsModeMenu->addAction(m_viewAutomaticTileTabsConfigurationAction); - tileTabsModeMenu->addAction(m_viewCustomTileTabsConfigurationAction); - tileTabsModeMenu->addAction(m_viewManualTileTabsConfigurationAction); + + const bool showTileTabsModeMenuFlag(false); + QMenu* tileTabsModeMenu(NULL); + if (showTileTabsModeMenuFlag) { + tileTabsModeMenu = new QMenu("Tile Tabs Configuration Layout"); + tileTabsModeMenu->addAction(m_viewAutomaticTileTabsConfigurationAction); + tileTabsModeMenu->addAction(m_viewCustomTileTabsConfigurationAction); + tileTabsModeMenu->addAction(m_viewManualTileTabsConfigurationAction); + } m_viewMoveFeaturesToolBoxMenu = createMenuViewMoveFeaturesToolBox(); m_viewMoveOverlayToolBoxMenu = createMenuViewMoveOverlayToolBox(); - m_viewTileTabsLoadUserConfigurationMenu = createMenuViewTileTabsLoadUserConfiguration(); - menu->addAction(m_showToolBarAction); menu->addMenu(m_viewMoveFeaturesToolBoxMenu); menu->addMenu(m_viewMoveOverlayToolBoxMenu); @@ -2745,8 +2651,9 @@ BrainBrowserWindow::createMenuView() menu->addSeparator(); menu->addAction(m_viewTileTabsAction); menu->addAction(m_viewTileTabsConfigurationDialogAction); - menu->addMenu(tileTabsModeMenu); - menu->addMenu(m_viewTileTabsLoadUserConfigurationMenu); + if (tileTabsModeMenu != NULL) { + menu->addMenu(tileTabsModeMenu); + } return menu; } diff --git a/src/GuiQt/BrainBrowserWindow.h b/src/GuiQt/BrainBrowserWindow.h index 9190a82d4..1a9a476b1 100644 --- a/src/GuiQt/BrainBrowserWindow.h +++ b/src/GuiQt/BrainBrowserWindow.h @@ -188,8 +188,6 @@ namespace caret { void processShowIdentifyBrainordinateDialog(); void processGapsAndMargins(); - void processViewTileTabsLoadUserConfigurationMenuAboutToShow(); - void processViewTileTabsLoadUserConfigurationMenuItemTriggered(QAction* action); void processViewTileTabsAutomaticCustomTriggered(QAction* action); @@ -300,7 +298,6 @@ namespace caret { QMenu* createMenuView(); QMenu* createMenuViewMoveOverlayToolBox(); QMenu* createMenuViewMoveFeaturesToolBox(); - QMenu* createMenuViewTileTabsLoadUserConfiguration(); QMenu* createMenuConnect(); QMenu* createMenuData(); QMenu* createMenuSurface(); @@ -386,7 +383,6 @@ namespace caret { QMenu* m_viewMoveFeaturesToolBoxMenu; QMenu* m_viewMoveOverlayToolBoxMenu; - QMenu* m_viewTileTabsLoadUserConfigurationMenu; QAction* m_viewFullScreenAction; QAction* m_viewTileTabsAction; diff --git a/src/GuiQt/TileTabsConfigurationDialog.cxx b/src/GuiQt/TileTabsConfigurationDialog.cxx index 2aa736e05..9132136cb 100644 --- a/src/GuiQt/TileTabsConfigurationDialog.cxx +++ b/src/GuiQt/TileTabsConfigurationDialog.cxx @@ -109,21 +109,6 @@ TileTabsConfigurationDialog::TileTabsConfigurationDialog(BrainBrowserWindow* par setStandardButtonText(QDialogButtonBox::Help, "Help"); -// QWidget* dialogWidget = new QWidget(); -// QGridLayout* dialogLayout = new QGridLayout(dialogWidget); -// dialogLayout->setColumnStretch(0, 0); -// dialogLayout->setColumnStretch(1, 0); -// dialogLayout->setColumnStretch(2, 100); -// dialogLayout->addWidget(workbenchWindowWidget, -// 0, 0, Qt::AlignLeft); -// dialogLayout->addWidget(createConfigurationTypeWidget(), -// 1, 0); -// dialogLayout->addWidget(createConfigurationSettingsWidget(), -// 2, 0); -// dialogLayout->addWidget(createCopyLoadPushButtonsWidget(), -// 1, 1, 2, 1); -// dialogLayout->addWidget(createUserConfigurationSelectionWidget(), -// 1, 2, 2, 1); QWidget* dialogWidget = new QWidget(); QGridLayout* dialogLayout = new QGridLayout(dialogWidget); dialogLayout->setColumnStretch(0, 0); @@ -233,13 +218,10 @@ TileTabsConfigurationDialog::createCopyLoadPushButtonsWidget() widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QVBoxLayout* layout = new QVBoxLayout(widget); layout->setContentsMargins(0, 0, 0, 0); -// layout->addSpacing(50); layout->addWidget(m_addConfigurationPushButton, 0, Qt::AlignHCenter); -// layout->addSpacing(10); layout->addWidget(m_replaceConfigurationPushButton, 0, Qt::AlignHCenter); layout->addSpacing(10); layout->addWidget(m_loadConfigurationPushButton, 0, Qt::AlignHCenter); -// layout->addStretch(); return widget; } @@ -875,7 +857,7 @@ TileTabsConfigurationDialog::createUserConfigurationSelectionWidget() QObject::connect(m_configurationSourceTabWidget, &QTabWidget::tabBarClicked, this, &TileTabsConfigurationDialog::configurationSourceTabWidgetClicked); - QGroupBox* configurationWidget = new QGroupBox("Configurations"); + QGroupBox* configurationWidget = new QGroupBox("Configuration Library"); QVBoxLayout* configurationLayout = new QVBoxLayout(configurationWidget); configurationLayout->addWidget(m_configurationSourceTabWidget, 0); @@ -1714,7 +1696,7 @@ TileTabsConfigurationDialog::createConfigurationTypeWidget() m_manualConfigurationSetButton = createManualConfigurationSetToolButton(); - QGroupBox* layoutTypeGroupBox = new QGroupBox("Configuration Type"); + QGroupBox* layoutTypeGroupBox = new QGroupBox("Active Configuration Type"); QGridLayout* buttonTypeLayout = new QGridLayout(layoutTypeGroupBox); buttonTypeLayout->setColumnStretch(0, 0); buttonTypeLayout->setColumnStretch(1, 0); @@ -1748,7 +1730,7 @@ TileTabsConfigurationDialog::createConfigurationSettingsWidget() stretchFactorScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); stretchFactorScrollArea->setWidgetResizable(true); - QGroupBox* layoutSettingsGroupBox = new QGroupBox("Configuration Settings"); + QGroupBox* layoutSettingsGroupBox = new QGroupBox("Active Configuration Settings"); QVBoxLayout* settingsGroupBoxLayout = new QVBoxLayout(layoutSettingsGroupBox); settingsGroupBoxLayout->addWidget(stretchFactorScrollArea); -- GitLab From 3c1df0d1ef5840cb2e4473e46a599730b12e95f0 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 16 Sep 2019 14:28:57 -0500 Subject: [PATCH 042/584] Updated Help files for new Tile Tabs Manual Layout. --- .../RightClickPopUpMenu.png | Bin 0 -> 20602 bytes .../TabBar_Tab_Menu.png | Bin 0 -> 49306 bytes .../Tile_Tabs_Configuration.html | 484 ++++++++++++++---- .../Tile_Tabs_Configuration.png | Bin 103169 -> 348600 bytes .../Tile_Tabs_Configuration_AutomaticGrid.png | Bin 0 -> 149727 bytes .../Tile_Tabs_Configuration_Manual.png | Bin 0 -> 158846 bytes .../Toolbar_Arrange_Menu.png | Bin 0 -> 70094 bytes .../Window_Tile_Editing_Toolbar.png | Bin 0 -> 283523 bytes src/Resources/Help/help_resources.qrc | 7 + 9 files changed, 386 insertions(+), 105 deletions(-) create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/RightClickPopUpMenu.png create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/TabBar_Tab_Menu.png create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration_AutomaticGrid.png create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration_Manual.png create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Toolbar_Arrange_Menu.png create mode 100644 src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Window_Tile_Editing_Toolbar.png diff --git a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/RightClickPopUpMenu.png b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/RightClickPopUpMenu.png new file mode 100644 index 0000000000000000000000000000000000000000..651038c934c9b1e9ddb3cb96e6fde5d3b9f539d1 GIT binary patch literal 20602 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 z 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 R3+dobQ&mSLSK0jDe*raBMu`9b literal 0 HcmV?d00001 diff --git a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html index fe88ce268..e00ee5010 100644 --- a/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html +++ b/src/Resources/Help/HelpFiles/Menus/View_Menu/Tile_Tabs_Configuration/Tile_Tabs_Configuration.html @@ -13,97 +13,128 @@ - - - - - - - - - - - - Tabs in the Viewing + Area
+
+ dialog
+ +

Tile Tabs Configuration in Workbench Window
+

+ This section contains the tile tabs + configuration for the selected Workbench Window.  If a Scene is saved, the + selected Configuration is saved to the Scene and is restored + when the Scene is displayed.
+
+
+

Workbench + Window 

+
+ Selects the window for control of the window's Tile Tabs + Configuration
+
+

Active Configuration Type
+

+