diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 317cd3a0..6a4ddbbe 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,31 +1,32 @@ if(NOT Qt5QuickTest_FOUND) message(STATUS "Qt5QuickTest not found, autotests will not be built.") return() endif() add_executable(qmltest qmltest.cpp) target_link_libraries(qmltest Qt5::QuickTest) macro(kirigami_add_tests) if (WIN32) set(_extra_args -platform offscreen) endif() foreach(test ${ARGV}) add_test(NAME ${test} COMMAND qmltest ${_extra_args} -import ${CMAKE_BINARY_DIR}/bin -input ${test} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endforeach() endmacro() kirigami_add_tests( tst_keynavigation.qml tst_listskeynavigation.qml tst_pagerow.qml tst_icon.qml + tst_actiontoolbar.qml ) diff --git a/autotests/tst_actiontoolbar.qml b/autotests/tst_actiontoolbar.qml new file mode 100644 index 00000000..d60e11ad --- /dev/null +++ b/autotests/tst_actiontoolbar.qml @@ -0,0 +1,137 @@ +/* + * SPDX-FileCopyrightText: 2020 Arjen Hiemstra + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtTest 1.0 +import org.kde.kirigami 2.11 as Kirigami + +// TODO: Find a nicer way to handle this +import "../src/controls/private" as KirigamiPrivate + +TestCase { + id: testCase + name: "IconTests" + + width: 500 + height: 400 + visible: true + + when: windowShown + + // These buttons are required for getting the right metrics. + // Since ActionToolBar bases all sizing on button sizes, we need to be able + // to verify that layouting does the right thing. + property ToolButton iconButton: KirigamiPrivate.PrivateActionToolButton { + display: Button.IconOnly + kirigamiAction: Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + } + property ToolButton textButton: KirigamiPrivate.PrivateActionToolButton { + display: Button.TextOnly + kirigamiAction: Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + } + property ToolButton textIconButton: KirigamiPrivate.PrivateActionToolButton { + kirigamiAction: Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + } + + Component { + id: single; + Kirigami.ActionToolBar { + actions: [ + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + ] + } + } + + Component { + id: multiple + Kirigami.ActionToolBar { + actions: [ + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" }, + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" }, + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + ] + } + } + + Component { + id: iconOnly + Kirigami.ActionToolBar { + display: Button.IconOnly + actions: [ + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" }, + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" }, + Kirigami.Action { icon.name: "overflow-menu"; text: "Test Action" } + ] + } + } + + Component { + id: qtActions + Kirigami.ActionToolBar { + actions: [ + Action { icon.name: "overflow-menu"; text: "Test Action" }, + Action { icon.name: "overflow-menu"; text: "Test Action" }, + Action { icon.name: "overflow-menu"; text: "Test Action" } + ] + } + } + + function test_layout_data() { + return [ + // One action + // Full window width, should just display a toolbutton + { tag: "single_full", component: single, width: testCase.width, expected: testCase.textIconButton.width }, + // Small width, should display the overflow button + { tag: "single_min", component: single, width: 50, expected: testCase.iconButton.width }, + // Half window width, should display a single toolbutton + { tag: "single_half", component: single, width: testCase.width / 2, expected: testCase.textIconButton.width }, + // Multiple actions + // Full window width, should display as many buttons as there are actions + { tag: "multi_full", component: multiple, width: testCase.width, + expected: testCase.textIconButton.width * 3 + Kirigami.Units.smallSpacing * 2 }, + // Small width, should display just the overflow button + { tag: "multi_min", component: multiple, width: 50, expected: testCase.iconButton.width }, + // Half window width, should display one action and overflow button + { tag: "multi_half", component: multiple, width: testCase.width / 2, + expected: testCase.textIconButton.width + testCase.iconButton.width }, + // Multiple actions, display set to icon only + // Full window width, should display as many icon-only buttons as there are actions + { tag: "icon_full", component: iconOnly, width: testCase.width, + expected: testCase.iconButton.width * 3 + Kirigami.Units.smallSpacing * 2 }, + // Small width, should display just the overflow button + { tag: "icon_min", component: iconOnly, width: 50, expected: testCase.iconButton.width }, + // Quarter window width, should display one icon-only button and the overflow button + { tag: "icon_quarter", component: iconOnly, width: testCase.width / 4, + expected: testCase.iconButton.width * 2 }, + // QtQuick Controls actions + // Full window width, should display as many buttons as there are actions + { tag: "qt_full", component: qtActions, width: testCase.width, + expected: testCase.textIconButton.width * 3 + Kirigami.Units.smallSpacing * 2 }, + // Small width, should display just the overflow button + { tag: "qt_min", component: qtActions, width: 50, expected: testCase.iconButton.width }, + // Half window width, should display one action and overflow button + { tag: "qt_half", component: qtActions, width: testCase.width / 2, + expected: testCase.textIconButton.width + testCase.iconButton.width } + ] + } + + // Test layouting of ActionToolBar + // + // ActionToolBar has some pretty complex behaviour, which generally boils down to it trying + // to fit as many visible actions as possible and placing the hidden ones in an overflow menu. + // This test, along with the data above, verifies that that this behaviour is correct. + function test_layout(data) { + var toolbar = createTemporaryObject(data.component, testCase) + + verify(toolbar) + verify(waitForRendering(toolbar)) + + toolbar.width = data.width + waitForRendering(toolbar) // Allow events to propagate so toolbar can resize properly + compare(toolbar.implicitWidth, data.expected) + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f962535..383f7c19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,110 +1,108 @@ project(kirigami) if (NOT STATIC_LIBRARY) ecm_create_qm_loader(kirigami_QM_LOADER libkirigami2plugin_qt) else() set(KIRIGAMI_STATIC_FILES libkirigami/basictheme.cpp libkirigami/platformtheme.cpp libkirigami/tabletmodewatcher.cpp libkirigami/kirigamipluginfactory.cpp) endif() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libkirigami ${CMAKE_CURRENT_BINARY_DIR}/libkirigami) set(kirigami_SRCS kirigamiplugin.cpp columnview.cpp enums.cpp delegaterecycler.cpp icon.cpp settings.cpp formlayoutattached.cpp pagepool.cpp scenepositionattached.cpp mnemonicattached.cpp wheelhandler.cpp ${kirigami_QM_LOADER} ${KIRIGAMI_STATIC_FILES} ) add_subdirectory(libkirigami) if(STATIC_LIBRARY) # `rcc` is a bit dumb and isn't designed to use auto generated files, to # avoid poluting the source directory, use absolute paths set(kirigami_QML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) # First, pre-process the QRC to add the files associated with the right Qt # version. configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../kirigami.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc @ONLY ) # When using the static library, all QML files need to be shipped within the # .a file. qt5_add_resources( RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/../kirigami.qrc ) if (UNIX AND NOT ANDROID AND NOT(APPLE) AND NOT(DISABLE_DBUS)) qt5_add_dbus_interface(kirigami_SRCS libkirigami/org.kde.KWin.TabletModeManager.xml tabletmodemanager_interface) endif() endif(STATIC_LIBRARY) add_library(kirigamiplugin ${kirigami_SRCS} ${RESOURCES}) if(STATIC_LIBRARY) SET_TARGET_PROPERTIES(kirigamiplugin PROPERTIES AUTOMOC_MOC_OPTIONS -Muri=org.kde.kirigami) if (UNIX AND NOT ANDROID AND NOT(APPLE) AND NOT(DISABLE_DBUS)) set(Kirigami_EXTRA_LIBS Qt5::DBus) else() set(Kirigami_EXTRA_LIBS "") endif() else(STATIC_LIBRARY) set(Kirigami_EXTRA_LIBS KF5::Kirigami2) endif(STATIC_LIBRARY) target_link_libraries(kirigamiplugin PUBLIC Qt5::Core PRIVATE ${Kirigami_EXTRA_LIBS} Qt5::Qml Qt5::Quick Qt5::QuickControls2 ) if (NOT STATIC_LIBRARY) - add_custom_command(TARGET kirigamiplugin POST_BUILD - COMMAND ${CMAKE_COMMAND} -E - make_directory ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/) - add_custom_command(TARGET kirigamiplugin POST_BUILD - COMMAND ${CMAKE_COMMAND} -E - copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/controls ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/) - add_custom_command(TARGET kirigamiplugin POST_BUILD - COMMAND ${CMAKE_COMMAND} -E - copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/styles ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/styles) - add_custom_command(TARGET kirigamiplugin POST_BUILD - COMMAND ${CMAKE_COMMAND} -E - copy $ ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/) + add_custom_target(copy_to_bin ALL + COMMAND ${CMAKE_COMMAND} -E + make_directory ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/ + COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/controls ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/ + COMMAND ${CMAKE_COMMAND} -E + copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/styles ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/styles + COMMAND ${CMAKE_COMMAND} -E + copy $ ${CMAKE_BINARY_DIR}/bin/org/kde/kirigami.2/ + ) install(DIRECTORY controls/ DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2) if (DESKTOP_ENABLED) install(DIRECTORY styles/org.kde.desktop DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) endif() install(DIRECTORY styles/Material DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2/styles) install(FILES ${platformspecific} DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2) include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME Kirigami2 LIB_NAME KF5Kirigami2 DEPS "core qml quick svg" FILENAME_VAR PRI_FILENAME ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) endif(NOT STATIC_LIBRARY) install(TARGETS kirigamiplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kirigami.2)