461 lines
11 KiB
C++
461 lines
11 KiB
C++
/*
|
|
This file is part of KDDockWidgets.
|
|
|
|
SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
|
Author: Sérgio Martins <sergio.martins@kdab.com>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
|
|
|
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Application wide config to tune certain framework behaviors.
|
|
*
|
|
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
|
*/
|
|
|
|
#include "Config.h"
|
|
#include "core/layouting/Item_p.h"
|
|
#include "core/DockRegistry.h"
|
|
#include "core/DockRegistry_p.h"
|
|
#include "core/Utils_p.h"
|
|
#include "core/DragController_p.h"
|
|
#include "core/ViewFactory.h"
|
|
#include "core/Separator.h"
|
|
#include "core/Platform.h"
|
|
#include "core/View.h"
|
|
#include "core/Logging_p.h"
|
|
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
using namespace KDDockWidgets::Core;
|
|
|
|
namespace KDDockWidgets {
|
|
|
|
static ViewFactory *createDefaultViewFactory()
|
|
{
|
|
if (auto platform = Platform::instance())
|
|
return platform->createDefaultViewFactory();
|
|
|
|
KDDW_ERROR("No Platform found. Forgot to call KDDockWidgets::initFrontend(<platform>) ?");
|
|
std::terminate();
|
|
return nullptr;
|
|
}
|
|
|
|
class Config::Private
|
|
{
|
|
public:
|
|
Private()
|
|
: m_viewFactory(createDefaultViewFactory())
|
|
{
|
|
}
|
|
|
|
~Private()
|
|
{
|
|
delete m_viewFactory;
|
|
}
|
|
|
|
void fixFlags();
|
|
|
|
DockWidgetFactoryFunc m_dockWidgetFactoryFunc = nullptr;
|
|
MainWindowFactoryFunc m_mainWindowFactoryFunc = nullptr;
|
|
DropIndicatorAllowedFunc m_dropIndicatorAllowedFunc = nullptr;
|
|
DragAboutToStartFunc m_dragAboutToStartFunc = nullptr;
|
|
DragEndedFunc m_dragEndedFunc = nullptr;
|
|
DockWidgetTabIndexOverrideFunc m_restorePlaceholderTabIndexOverride = nullptr;
|
|
ViewFactory *m_viewFactory = nullptr;
|
|
Flags m_flags = Flag_Default;
|
|
MDIFlags m_mdiFlags = MDIFlag_None;
|
|
InternalFlags m_internalFlags = InternalFlag_None;
|
|
CustomizableWidgets m_disabledPaintEvents = CustomizableWidget_None;
|
|
double m_draggedWindowOpacity = std::numeric_limits<double>::quiet_NaN();
|
|
bool m_transparencyOnlyOverDropIndicator = false;
|
|
int m_mdiPopupThreshold = 250;
|
|
int m_startDragDistance = -1;
|
|
bool m_dropIndicatorsInhibited = false;
|
|
bool m_layoutSaverStrictMode = false;
|
|
bool m_showTabsAtBottom = false;
|
|
};
|
|
|
|
Config::Config()
|
|
: d(new Private())
|
|
{
|
|
d->fixFlags();
|
|
}
|
|
|
|
Config &Config::self()
|
|
{
|
|
static Config config;
|
|
return config;
|
|
}
|
|
|
|
Config::~Config()
|
|
{
|
|
delete d;
|
|
if (Platform::isInitialized()) {
|
|
delete Platform::instance();
|
|
}
|
|
}
|
|
|
|
Config::Flags Config::flags() const
|
|
{
|
|
return d->m_flags;
|
|
}
|
|
|
|
Config::MDIFlags Config::mdiFlags() const
|
|
{
|
|
return d->m_mdiFlags;
|
|
}
|
|
|
|
void Config::setMDIFlags(MDIFlags flags)
|
|
{
|
|
d->m_mdiFlags = flags;
|
|
}
|
|
|
|
void Config::setFlags(Flags f)
|
|
{
|
|
// Most flags aren't allowed to be changed at runtime.
|
|
// Some are. More can be supported but they need to be examined in a case-by-case
|
|
// basis.
|
|
|
|
static const Flags mutableFlags = Flag::Flag_AutoHideAsTabGroups;
|
|
const Flags changedFlags = f ^ d->m_flags;
|
|
const bool nonMutableFlagsChanged = (changedFlags & ~mutableFlags);
|
|
|
|
if (nonMutableFlagsChanged) {
|
|
auto dr = DockRegistry::self();
|
|
if (!dr->isEmpty(/*excludeBeingDeleted=*/true)) {
|
|
std::cerr
|
|
<< "Config::setFlags: "
|
|
<< "Only use this function at startup before creating any DockWidget or MainWindow"
|
|
<< "; These are already created: " << dr->mainWindowsNames().size() << dr->dockWidgetNames().size()
|
|
<< dr->floatingWindows().size() << "\n";
|
|
return;
|
|
}
|
|
}
|
|
|
|
d->m_flags = f;
|
|
d->fixFlags();
|
|
}
|
|
|
|
/** static*/
|
|
bool Config::hasFlag(Flag flag)
|
|
{
|
|
return (Config::self().flags() & flag) == flag;
|
|
}
|
|
|
|
/** static*/
|
|
bool Config::hasMDIFlag(MDIFlag flag)
|
|
{
|
|
return (Config::self().mdiFlags() & flag) == flag;
|
|
}
|
|
|
|
void Config::setDockWidgetFactoryFunc(DockWidgetFactoryFunc func)
|
|
{
|
|
d->m_dockWidgetFactoryFunc = func;
|
|
}
|
|
|
|
DockWidgetFactoryFunc Config::dockWidgetFactoryFunc() const
|
|
{
|
|
return d->m_dockWidgetFactoryFunc;
|
|
}
|
|
|
|
void Config::setMainWindowFactoryFunc(MainWindowFactoryFunc func)
|
|
{
|
|
d->m_mainWindowFactoryFunc = func;
|
|
}
|
|
|
|
MainWindowFactoryFunc Config::mainWindowFactoryFunc() const
|
|
{
|
|
return d->m_mainWindowFactoryFunc;
|
|
}
|
|
|
|
void Config::setViewFactory(ViewFactory *factory)
|
|
{
|
|
if (factory == d->m_viewFactory)
|
|
return;
|
|
|
|
assert(factory);
|
|
delete d->m_viewFactory;
|
|
d->m_viewFactory = factory;
|
|
|
|
Core::Platform::instance()->onViewFactoryChanged();
|
|
}
|
|
|
|
ViewFactory *Config::viewFactory() const
|
|
{
|
|
return d->m_viewFactory;
|
|
}
|
|
|
|
int Config::separatorThickness() const
|
|
{
|
|
return Item::separatorThickness;
|
|
}
|
|
|
|
int Config::layoutSpacing() const
|
|
{
|
|
return Item::layoutSpacing;
|
|
}
|
|
|
|
void Config::setSeparatorThickness(int value)
|
|
{
|
|
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/true)) {
|
|
std::cerr
|
|
<< "Config::setSeparatorThickness: Only use this function at startup before creating any DockWidget or MainWindow\n";
|
|
return;
|
|
}
|
|
|
|
if (value < 0 || value >= 100) {
|
|
std::cerr << "Config::setSeparatorThickness: Invalid value" << value << "\n";
|
|
return;
|
|
}
|
|
|
|
Item::separatorThickness = value;
|
|
Item::layoutSpacing = value;
|
|
}
|
|
|
|
void Config::setLayoutSpacing(int value)
|
|
{
|
|
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/true)) {
|
|
std::cerr
|
|
<< "Config::setLayoutSpacing: Only use this function at startup before creating any DockWidget or MainWindow\n";
|
|
return;
|
|
}
|
|
|
|
if (value < 0 || value >= 100) {
|
|
std::cerr << "Config::setLayoutSpacing: Invalid value" << value << "\n";
|
|
return;
|
|
}
|
|
|
|
Item::layoutSpacing = value;
|
|
}
|
|
|
|
void Config::setDraggedWindowOpacity(double opacity)
|
|
{
|
|
d->m_draggedWindowOpacity = opacity;
|
|
}
|
|
|
|
void Config::setTransparencyOnlyOverDropIndicator(bool only)
|
|
{
|
|
d->m_transparencyOnlyOverDropIndicator = only;
|
|
}
|
|
|
|
double Config::draggedWindowOpacity() const
|
|
{
|
|
return d->m_draggedWindowOpacity;
|
|
}
|
|
|
|
bool Config::transparencyOnlyOverDropIndicator() const
|
|
{
|
|
return d->m_transparencyOnlyOverDropIndicator;
|
|
}
|
|
|
|
void Config::setDropIndicatorAllowedFunc(DropIndicatorAllowedFunc func)
|
|
{
|
|
d->m_dropIndicatorAllowedFunc = func;
|
|
}
|
|
|
|
DropIndicatorAllowedFunc Config::dropIndicatorAllowedFunc() const
|
|
{
|
|
return d->m_dropIndicatorAllowedFunc;
|
|
}
|
|
|
|
void Config::setDragAboutToStartFunc(DragAboutToStartFunc func)
|
|
{
|
|
d->m_dragAboutToStartFunc = func;
|
|
}
|
|
|
|
DragAboutToStartFunc Config::dragAboutToStartFunc() const
|
|
{
|
|
return d->m_dragAboutToStartFunc;
|
|
}
|
|
|
|
void Config::setDragEndedFunc(DragEndedFunc func)
|
|
{
|
|
d->m_dragEndedFunc = func;
|
|
}
|
|
|
|
DragEndedFunc Config::dragEndedFunc() const
|
|
{
|
|
return d->m_dragEndedFunc;
|
|
}
|
|
|
|
void Config::setDockWidgetTabIndexOverrideFunc(DockWidgetTabIndexOverrideFunc func)
|
|
{
|
|
d->m_restorePlaceholderTabIndexOverride = func;
|
|
}
|
|
|
|
DockWidgetTabIndexOverrideFunc Config::dockWidgetTabIndexOverrideFunc() const
|
|
{
|
|
return d->m_restorePlaceholderTabIndexOverride;
|
|
}
|
|
|
|
void Config::setAbsoluteWidgetMinSize(Size size)
|
|
{
|
|
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/false)) {
|
|
std::cerr
|
|
<< "Config::setAbsoluteWidgetMinSize: Only use this function at startup before creating any DockWidget or MainWindow\n";
|
|
return;
|
|
}
|
|
|
|
Item::hardcodedMinimumSize = size;
|
|
}
|
|
|
|
Size Config::absoluteWidgetMinSize() const
|
|
{
|
|
return Item::hardcodedMinimumSize;
|
|
}
|
|
|
|
void Config::setAbsoluteWidgetMaxSize(Size size)
|
|
{
|
|
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/false)) {
|
|
std::cerr
|
|
<< "Config::setAbsoluteWidgetMinSize: Only use this function at startup before creating any DockWidget or MainWindow\n";
|
|
return;
|
|
}
|
|
|
|
Item::hardcodedMaximumSize = size;
|
|
}
|
|
|
|
Size Config::absoluteWidgetMaxSize() const
|
|
{
|
|
return Item::hardcodedMaximumSize;
|
|
}
|
|
|
|
void Config::setTabsAtBottom(bool show)
|
|
{
|
|
d->m_showTabsAtBottom = show;
|
|
}
|
|
|
|
bool Config::tabsAtBottom() const
|
|
{
|
|
return d->m_showTabsAtBottom;
|
|
}
|
|
|
|
Config::InternalFlags Config::internalFlags() const
|
|
{
|
|
return d->m_internalFlags;
|
|
}
|
|
|
|
void Config::setInternalFlags(InternalFlags flags)
|
|
{
|
|
d->m_internalFlags = flags;
|
|
}
|
|
|
|
void Config::Private::fixFlags()
|
|
{
|
|
if (Platform::instance()->supportsAeroSnap()) {
|
|
// Unconditional now
|
|
m_flags |= Flag_AeroSnapWithClientDecos;
|
|
} else {
|
|
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
|
}
|
|
|
|
// These are mutually exclusive:
|
|
if ((m_flags & Flag_AeroSnapWithClientDecos) && (m_flags & Flag_NativeTitleBar)) {
|
|
// We're either using native or client decorations, let's use native.
|
|
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
|
}
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
if (KDDockWidgets::isWayland()) {
|
|
// Native title bar is forced on Wayland. Needed for moving the window.
|
|
// The inner KDDW title bar is used for DnD.
|
|
m_flags |= Flag_NativeTitleBar;
|
|
} else {
|
|
// On Linux, dragging the title bar of a window doesn't generate NonClientMouseEvents
|
|
// at least with KWin anyway. We can make this more granular and allow it for other
|
|
// X11 window managers
|
|
m_flags = m_flags & ~Flag_NativeTitleBar;
|
|
}
|
|
#endif
|
|
|
|
#if (!defined(KDDW_FRONTEND_QT_WINDOWS) && !defined(Q_OS_MACOS))
|
|
// QtQuick doesn't support AeroSnap yet. Some problem with the native events not being
|
|
// received...
|
|
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
|
#endif
|
|
|
|
|
|
#if defined(DOCKS_DEVELOPER_MODE)
|
|
// We allow to disable aero-snap during development
|
|
if (m_internalFlags & InternalFlag_NoAeroSnap) {
|
|
// The only way to disable AeroSnap
|
|
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
|
}
|
|
#endif
|
|
|
|
if (m_flags & Flag_DontUseUtilityFloatingWindows) {
|
|
m_internalFlags |= InternalFlag_DontUseParentForFloatingWindows;
|
|
m_internalFlags |= InternalFlag_DontUseQtToolWindowsForFloatingWindows;
|
|
}
|
|
|
|
if (m_flags & Flag_ShowButtonsOnTabBarIfTitleBarHidden) {
|
|
// Flag_ShowButtonsOnTabBarIfTitleBarHidden doesn't make sense if used alone
|
|
m_flags |= Flag_HideTitleBarWhenTabsVisible;
|
|
}
|
|
}
|
|
|
|
void Config::setDisabledPaintEvents(CustomizableWidgets widgets)
|
|
{
|
|
d->m_disabledPaintEvents = widgets;
|
|
}
|
|
|
|
Config::CustomizableWidgets Config::disabledPaintEvents() const
|
|
{
|
|
return d->m_disabledPaintEvents;
|
|
}
|
|
|
|
void Config::setMDIPopupThreshold(int threshold)
|
|
{
|
|
d->m_mdiPopupThreshold = threshold;
|
|
}
|
|
|
|
int Config::mdiPopupThreshold() const
|
|
{
|
|
return d->m_mdiPopupThreshold;
|
|
}
|
|
|
|
void Config::setDropIndicatorsInhibited(bool inhibit) const
|
|
{
|
|
if (d->m_dropIndicatorsInhibited != inhibit) {
|
|
d->m_dropIndicatorsInhibited = inhibit;
|
|
DockRegistry::self()->dptr()->dropIndicatorsInhibitedChanged.emit(inhibit);
|
|
}
|
|
}
|
|
|
|
bool Config::dropIndicatorsInhibited() const
|
|
{
|
|
return d->m_dropIndicatorsInhibited;
|
|
}
|
|
|
|
void Config::setStartDragDistance(int pixels)
|
|
{
|
|
d->m_startDragDistance = pixels;
|
|
}
|
|
|
|
int Config::startDragDistance() const
|
|
{
|
|
return d->m_startDragDistance;
|
|
}
|
|
|
|
void Config::printDebug()
|
|
{
|
|
std::cerr << "Flags: " << d->m_flags << d->m_internalFlags << "\n";
|
|
}
|
|
|
|
void Config::setLayoutSaverStrictMode(bool is)
|
|
{
|
|
d->m_layoutSaverStrictMode = is;
|
|
}
|
|
|
|
bool Config::layoutSaverUsesStrictMode() const
|
|
{
|
|
return d->m_layoutSaverStrictMode;
|
|
}
|
|
|
|
}
|