1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
|
/*
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.
*/
#include "MyWidget.h"
#include "MyMainWindow.h"
#include "MyViewFactory.h"
#include "CtrlKeyEventFilter.h"
#include <kddockwidgets/Config.h>
#include <kddockwidgets/qtwidgets/ViewFactory.h>
#include <kddockwidgets/core/DockWidget.h>
#include <kddockwidgets/core/Draggable_p.h>
#include <QStyleFactory>
#include <QApplication>
#include <QDebug>
#include <QCommandLineParser>
#include <algorithm>
// clazy:excludeall=qstring-allocations
using namespace KDDockWidgets;
int main(int argc, char **argv)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QApplication app(argc, argv);
QCoreApplication::setOrganizationName(QStringLiteral("KDAB"));
QCoreApplication::setApplicationName(QStringLiteral("Test app"));
KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets);
QCommandLineParser parser;
parser.setApplicationDescription("KDDockWidgets example application");
parser.addHelpOption();
// Fusion looks better in general, but feel free to change
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
QCommandLineOption customStyle(
"p",
QCoreApplication::translate("main",
"Shows how to style framework internals via ViewFactory"));
parser.addOption(customStyle);
QCommandLineOption reorderTabsOption(
"r", QCoreApplication::translate("main", "Support re-ordering tabs with mouse"));
parser.addOption(reorderTabsOption);
QCommandLineOption noTitleBars(
"t", QCoreApplication::translate("main", "Hide titlebars when tabs are visible"));
parser.addOption(noTitleBars);
QCommandLineOption alwaysTitleBarWhenFloating(
"q",
QCoreApplication::translate("main",
"Don't hide title bars if floating, even if "
"Flag_HideTitleBarWhenTabsVisible is specified."));
parser.addOption(alwaysTitleBarWhenFloating);
QCommandLineOption alwaysTabs(
"z", QCoreApplication::translate("main", "Show tabs even if there's only one"));
parser.addOption(alwaysTabs);
QCommandLineOption lazyResizeOption("l",
QCoreApplication::translate("main", "Use lazy resize"));
parser.addOption(lazyResizeOption);
QCommandLineOption multipleMainWindows(
"m", QCoreApplication::translate("main", "Shows two multiple main windows"));
parser.addOption(multipleMainWindows);
QCommandLineOption incompatibleMainWindows(
"i",
QCoreApplication::translate(
"main",
"Only usable with -m. Make the two main windows incompatible with each other. "
"(Illustrates (MainWindowBase::setAffinityName))"));
parser.addOption(incompatibleMainWindows);
QCommandLineOption tabsHaveCloseButton(
"c", QCoreApplication::translate("main", "Tabs have a close button"));
parser.addOption(tabsHaveCloseButton);
QCommandLineOption nonClosableDockWidget(
"n", QCoreApplication::translate("main", "DockWidget #0 will be non-closable"));
parser.addOption(nonClosableDockWidget);
QCommandLineOption relativeRestore(
"s",
QCoreApplication::translate(
"main", "Don't restore main window geometry, restore dock widgets in relative sizes"));
parser.addOption(relativeRestore);
QCommandLineOption doubleClickMaximize(
"x",
QCoreApplication::translate("main",
"Double clicking a title bar will maximize a floating window"));
parser.addOption(doubleClickMaximize);
QCommandLineOption nonDockable(
"d", QCoreApplication::translate("main", "DockWidget #9 will be non-dockable"));
parser.addOption(nonDockable);
QCommandLineOption maximizeButtonOption(
"b",
QCoreApplication::translate(
"main",
"Floating dockWidgets have maximize/restore buttons instead of float/dock button"));
parser.addOption(maximizeButtonOption);
QCommandLineOption minimizeButtonOption(
"k",
QCoreApplication::translate("main",
"Floating dockWidgets have a minimize button. Implies not "
"being an utility window (~Qt::Tool)"));
parser.addOption(minimizeButtonOption);
QCommandLineOption segmentedIndicators(
"y", QCoreApplication::translate("main", "Use segmented indicators instead of classical"));
parser.addOption(segmentedIndicators);
QCommandLineOption noUtilityWindows(
"u",
QCoreApplication::translate(
"main", "FloatingWindows will be normal windows instead of utility windows"));
parser.addOption(noUtilityWindows);
QCommandLineOption keepAbove(
"o",
QCoreApplication::translate("main",
"FloatingWindows will have Qt::WindowStaysOnTopHint. Implies "
"not being an utility window (try it with -u too)"));
parser.addOption(keepAbove);
parser.addPositionalArgument(
"savedlayout",
QCoreApplication::translate("main", "loads the specified json file at startup"));
QCommandLineOption dockableMainWindows(
"j",
QCoreApplication::translate("main",
"Allow main windows to be docked inside other main windows"));
parser.addOption(dockableMainWindows);
QCommandLineOption maxSizeOption(
"g", QCoreApplication::translate("main", "Make dock #8 have a max-size of 200x200."));
parser.addOption(maxSizeOption);
QCommandLineOption centralFrame(
"f", QCoreApplication::translate("main", "Persistent central group"));
QCommandLineOption autoHideSupport(
"w",
QCoreApplication::translate("main", "Enables auto-hide/minimization to side-bar support"));
parser.addOption(autoHideSupport);
QCommandLineOption closeOnlyCurrentTab(
"close-only-current-tab",
QCoreApplication::translate(
"main",
"The title bar's close button will only close the current tab instead of all. "
"Illustrates using Config::Flag_CloseOnlyCurrentTab"));
parser.addOption(closeOnlyCurrentTab);
QCommandLineOption dontCloseBeforeRestore(
"dont-close-widget-before-restore", // krazy:exclude=spelling
QCoreApplication::translate("main",
"DockWidgets 6, 7 and 8 won't be closed before a restore. Illustrates "
"LayoutSaverOption::Skip"));
parser.addOption(dontCloseBeforeRestore);
QCommandLineOption blockCloseEvent(
"block-close-event",
QCoreApplication::translate("main", "DockWidget #0 will block close events"));
parser.addOption(blockCloseEvent);
QCommandLineOption programmaticDragEvent(
"programmatic-drag",
QCoreApplication::translate("main", "Shows how to start a drag programmatically (advanced usage)"));
parser.addOption(programmaticDragEvent);
QCommandLineOption showButtonsInTabBarIfTitleBarHidden(
"show-buttons-in-tabbar-if-titlebar-hidden",
QCoreApplication::translate("main",
"If we're not using title bars we'll still show the close and "
"float button in the tab bar"));
parser.addOption(showButtonsInTabBarIfTitleBarHidden);
QCommandLineOption centralWidget(
"central-widget",
QCoreApplication::translate("main",
"The main window will have a non-detachable central widget"));
parser.addOption(centralWidget);
QCommandLineOption centralWidgetAllExtraSize(
"central-widget-all-extra-size",
QCoreApplication::translate("main",
"The main window will have a non-detachable central widget which "
"gets all the extra space when the window is enlarged (imples --central-widget"));
parser.addOption(centralWidgetAllExtraSize);
QCommandLineOption tabsAtBottom("tabs-at-bottom", QCoreApplication::translate("main", "Shows tabs at bottom"));
parser.addOption(tabsAtBottom);
QCommandLineOption ctxtMenuOnTabs(
"allow-switch-tabs-via-menu",
QCoreApplication::translate("main", "Allow switching tabs via context menu in tabs area"));
parser.addOption(ctxtMenuOnTabs);
QCommandLineOption hideCertainDockingIndicators(
"hide-certain-docking-indicators",
QCoreApplication::translate("main",
"Illustrates usage of Config::setDropIndicatorAllowedFunc()"));
parser.addOption(hideCertainDockingIndicators);
QCommandLineOption ctrlTogglesDropIndicators(
"ctrl-toggles-drop-indicators",
QCoreApplication::translate("main", "Ctrl key toggles drop indicators"));
parser.addOption(ctrlTogglesDropIndicators);
#if defined(DOCKS_DEVELOPER_MODE)
parser.addOption(centralFrame);
QCommandLineOption noQtTool(
"no-qttool", QCoreApplication::translate("main", "(internal) Don't use Qt::Tool"));
QCommandLineOption noParentForFloating(
"no-parent-for-floating",
QCoreApplication::translate("main", "(internal) FloatingWindows won't have a parent"));
QCommandLineOption nativeTitleBar(
"native-title-bar",
QCoreApplication::translate("main", "(internal) FloatingWindows a native title bar"));
QCommandLineOption noDropIndicators(
"no-drop-indicators",
QCoreApplication::translate("main", "(internal) Don't use any drop indicators"));
parser.addOption(noQtTool);
parser.addOption(noParentForFloating);
parser.addOption(nativeTitleBar);
parser.addOption(noDropIndicators);
#if defined(Q_OS_WIN)
QCommandLineOption noAeroSnap(
"no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap"));
parser.addOption(noAeroSnap);
#endif
#else
KDDW_UNUSED(centralFrame)
#endif
parser.process(app);
if (parser.isSet(customStyle)) {
Config::self().setViewFactory(new CustomWidgetFactory()); // Sets our custom factory
// Increase the separator size, just for demo
Config::self().setSeparatorThickness(10);
}
if (parser.isSet(segmentedIndicators))
KDDockWidgets::Core::ViewFactory::s_dropIndicatorType =
KDDockWidgets::DropIndicatorType::Segmented;
MainWindowOptions options = MainWindowOption_None;
auto flags = KDDockWidgets::Config::self().flags();
#if defined(DOCKS_DEVELOPER_MODE)
auto internalFlags = KDDockWidgets::Config::self().internalFlags();
options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralGroup : MainWindowOption_None;
if (parser.isSet(centralWidget))
options |= MainWindowOption_HasCentralWidget;
if (parser.isSet(centralWidgetAllExtraSize)) {
options |= MainWindowOption_HasCentralWidget;
options |= MainWindowOption_CentralWidgetGetsAllExtraSpace;
}
if (parser.isSet(noQtTool))
internalFlags |= KDDockWidgets::Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows;
if (parser.isSet(keepAbove))
flags |= KDDockWidgets::Config::Flag_KeepAboveIfNotUtilityWindow;
if (parser.isSet(noParentForFloating))
internalFlags |= KDDockWidgets::Config::InternalFlag_DontUseParentForFloatingWindows;
if (parser.isSet(nativeTitleBar))
flags |= KDDockWidgets::Config::Flag_NativeTitleBar;
if (parser.isSet(noDropIndicators))
KDDockWidgets::Core::ViewFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::None;
#if defined(Q_OS_WIN)
if (parser.isSet(noAeroSnap))
internalFlags |= KDDockWidgets::Config::InternalFlag_NoAeroSnap;
#endif
Config::self().setInternalFlags(internalFlags);
#endif
if (parser.isSet(autoHideSupport))
flags |= Config::Flag_AutoHideSupport;
if (parser.isSet(closeOnlyCurrentTab))
flags |= Config::Flag_CloseOnlyCurrentTab;
if (parser.isSet(showButtonsInTabBarIfTitleBarHidden))
flags |= Config::Flag_ShowButtonsOnTabBarIfTitleBarHidden;
if (parser.isSet(noTitleBars))
flags |= KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible;
if (parser.isSet(noUtilityWindows))
flags |= KDDockWidgets::Config::Flag_DontUseUtilityFloatingWindows;
if (parser.isSet(alwaysTabs))
flags |= KDDockWidgets::Config::Flag_AlwaysShowTabs;
if (parser.isSet(alwaysTitleBarWhenFloating)) {
flags |= KDDockWidgets::Config::Flag_AlwaysTitleBarWhenFloating;
if (!(flags & KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible)) {
qWarning() << "Flag_AlwaysTitleBarWhenFloating is unneeded if "
"Flag_HideTitleBarWhenTabsVisible isn't used."
<< "As floating windows already have title bars by default.";
}
}
if (parser.isSet(customStyle) || qEnvironmentVariableIsSet("KDDW_DEBUG_FOCUS"))
flags |= KDDockWidgets::Config::Flag_TitleBarIsFocusable; // also showing title bar focus
// with -p, just to not introduce
// another switch
if (parser.isSet(reorderTabsOption))
flags |= KDDockWidgets::Config::Flag_AllowReorderTabs;
if (parser.isSet(maximizeButtonOption))
flags |= KDDockWidgets::Config::Flag_TitleBarHasMaximizeButton;
if (parser.isSet(minimizeButtonOption))
flags |= KDDockWidgets::Config::Flag_TitleBarHasMinimizeButton;
if (parser.isSet(lazyResizeOption))
flags |= KDDockWidgets::Config::Flag_LazyResize;
if (parser.isSet(tabsHaveCloseButton))
flags |= KDDockWidgets::Config::Flag_TabsHaveCloseButton;
if (parser.isSet(ctxtMenuOnTabs))
flags |= KDDockWidgets::Config::Flag_AllowSwitchingTabsViaMenu;
if (parser.isSet(doubleClickMaximize))
flags |= KDDockWidgets::Config::Flag_DoubleClickMaximizes;
if (parser.isSet(incompatibleMainWindows) && !parser.isSet(multipleMainWindows)) {
qWarning() << "Error: Argument -i requires -m";
return 1;
}
if (parser.isSet(programmaticDragEvent) && parser.isSet(ctrlTogglesDropIndicators)) {
qWarning() << "Error: Arguments --programmatic-drag and --ctrl-toggles-drop-indicators are "
"mutually exclusive. The latter is already included in the former.";
return 1;
}
if (parser.isSet(hideCertainDockingIndicators)) {
// Here we exemplify adding a restriction to "Dock Widget 8"
// Dock widget 8 will only be allowed to dock to the outer areas
auto func = [](KDDockWidgets::DropLocation location,
const KDDockWidgets::Core::DockWidget::List &source,
const KDDockWidgets::Core::DockWidget::List &target,
Core::DropArea *) {
KDDW_UNUSED(target); // When dragging into a tab, 'target' would have the list of already
// tabbed dock widgets
const bool isDraggingDW8 =
std::find_if(source.cbegin(), source.cend(),
[](KDDockWidgets::Core::DockWidget *dw) {
return dw->uniqueName() == QLatin1String("DockWidget #8");
})
!= source.cend();
return (location & KDDockWidgets::DropLocation_Outter) || !isDraggingDW8;
};
KDDockWidgets::Config::self().setDropIndicatorAllowedFunc(func);
}
KDDockWidgets::Config::self().setTabsAtBottom(parser.isSet(tabsAtBottom));
KDDockWidgets::Config::self().setFlags(flags);
MyMainWindow::ExampleOptions exampleOptions = {};
if (parser.isSet(ctrlTogglesDropIndicators))
exampleOptions |= MyMainWindow::ExampleOption::CtrlKeyFiltersDropIndicators;
if (parser.isSet(nonClosableDockWidget))
exampleOptions |= MyMainWindow::ExampleOption::DockWidget0IsNonClosable;
if (parser.isSet(relativeRestore))
exampleOptions |= MyMainWindow::ExampleOption::RestoreIsRelative;
if (parser.isSet(nonDockable))
exampleOptions |= MyMainWindow::ExampleOption::NonDockableDockWidget9;
if (parser.isSet(maxSizeOption))
exampleOptions |= MyMainWindow::ExampleOption::MaxSizeForDockWidget8;
if (parser.isSet(dontCloseBeforeRestore))
exampleOptions |= MyMainWindow::ExampleOption::DockWidgets678DontCloseBeforeRestore;
if (parser.isSet(blockCloseEvent))
exampleOptions |= MyMainWindow::ExampleOption::Dock0BlocksCloseEvent;
if (parser.isSet(programmaticDragEvent)) {
exampleOptions |= MyMainWindow::ExampleOption::ProgrammaticDragEvent;
static auto s_ctrlKeyEventFilter = new CtrlKeyEventFilter(qApp);
/// Here we demonstrate how to use setDragAboutToStartFunc()/setDragEndedFunc() to prevent a drag from happening
/// In this made up example:
/// 1. If ctrl is pressed, we always allow the drag
/// 2. If the drag is programmatic (DockWidget::startDrag()), we always allow the drag as well
/// 3. If the dragged widget is already a window, we allow a drag to move it, but not dock it
/// 3.1. We also install an event filter to show the drop indicators when ctrl is pressed
KDDockWidgets::Config::self().setDragAboutToStartFunc([](Core::Draggable *draggable) -> bool {
const bool ctrlIsPressed = qGuiApp->keyboardModifiers() & Qt::ControlModifier;
if (ctrlIsPressed || draggable->isInProgrammaticDrag()) {
KDDockWidgets::Config::self().setDropIndicatorsInhibited(false);
return true;
}
if (draggable->isWindow()) {
qGuiApp->installEventFilter(s_ctrlKeyEventFilter);
// Ctrl might already be pressed before the DnD even starts, so honour that as well
KDDockWidgets::Config::self().setDropIndicatorsInhibited(!ctrlIsPressed);
return true;
}
return false;
});
KDDockWidgets::Config::self().setDragEndedFunc([]() {
// cleanup
qGuiApp->removeEventFilter(s_ctrlKeyEventFilter);
});
}
const bool usesMainWindowsWithAffinity = parser.isSet(multipleMainWindows);
const bool usesDockableMainWindows = parser.isSet(dockableMainWindows);
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, exampleOptions);
mainWindow.setWindowTitle("Main Window 1");
mainWindow.resize(1200, 1200);
mainWindow.show();
if (usesMainWindowsWithAffinity) {
if (usesDockableMainWindows) {
qWarning() << "MainWindows with affinity option is incompatible with Dockable Main "
"Windows option";
return 1;
}
// By default a dock widget can dock into any main window.
// By setting an affinity name we can prevent that. Dock widgets of different affinities are
// incompatible.
const QString affinity =
parser.isSet(incompatibleMainWindows) ? QStringLiteral("affinity1") : QString();
auto mainWindow2 =
new MyMainWindow(QStringLiteral("MyMainWindow-2"), options, exampleOptions, affinity);
if (affinity.isEmpty())
mainWindow2->setWindowTitle("Main Window 2");
else
mainWindow2->setWindowTitle("Main Window 2 (different affinity)");
mainWindow2->resize(1200, 1200);
mainWindow2->show();
} else if (usesDockableMainWindows) {
auto mainWindowDockWidget =
new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyMainWindow-2-DW"));
const QString affinity = QStringLiteral("Inner-DockWidgets-2");
MyMainWindow::ExampleOptions exampleOptions2 = {};
if (parser.isSet(relativeRestore))
exampleOptions2 |= MyMainWindow::ExampleOption::RestoreIsRelative;
auto dockableMainWindow =
new MyMainWindow(QStringLiteral("MyMainWindow-2"), options, exampleOptions2, affinity);
dockableMainWindow->setAffinities({ affinity });
dockableMainWindow->setStyleSheet(QStringLiteral("background: yellow"));
dockableMainWindow->setWindowTitle("Dockable Main Window");
dockableMainWindow->show();
mainWindowDockWidget->setWidget(dockableMainWindow);
mainWindowDockWidget->open();
mainWindowDockWidget->resize(QSize(800, 800));
}
const QStringList args = parser.positionalArguments();
if (!args.isEmpty()) {
const QString sourceJsonFileName = args[0];
KDDockWidgets::LayoutSaver loader;
if (!loader.restoreFromFile(sourceJsonFileName)) {
qWarning() << Q_FUNC_INFO << "Failed to restore from" << sourceJsonFileName;
return 1;
}
}
return app.exec();
}
|