2019-07-29 17:34:46 +02:00

355 lines
9.4 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "TestBox.h"
#include <QskSizePolicy.h>
#include <QApplication>
#include <QListWidget>
#include <QDebug>
#include <functional>
#include <vector>
class Box : public TestBox
{
public:
Box( QWidget* parent = nullptr )
: TestBox( parent )
{
m_tests =
{
&Box::test0, &Box::test1, &Box::test2,
&Box::test3, &Box::test4, &Box::test5,
&Box::test6, &Box::test7, &Box::test8,
&Box::test9, &Box::test10
};
}
void showTest( int id )
{
reset();
id = qBound( 0, id, count() - 1 );
m_tests[id]( *this );
updateLabels();
}
int count() const
{
return m_tests.size();
}
private:
void insert( const char* colorName, int row, int column )
{
insert( colorName, row, column, 1, 1 );
}
using TestBox::insert;
void test0();
void test1();
void test2();
void test3();
void test4();
void test5();
void test6();
void test7();
void test8();
void test9();
void test10();
std::vector< std::function< void( Box& ) > > m_tests;
};
void Box::test0()
{
// something, that works with all layouts
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 1 );
insert( "SkyBlue", 2, 1 );
insert( "Coral", 2, 2 );
insert( "NavajoWhite", 3, 0, 1, 3 );
}
void Box::test1()
{
/*
Graphics layout adds the extra space to the stretchables
while the other layouts use the extra space for reaching
a ratio according to the stretch factor first,
That leads to column 0 being too large.
*/
setColumns( 1 );
// Quick layouts do not support row/column hints
enableGrid( Quick, false );
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 1 );
insert( "SkyBlue", 2, 1 );
insert( "Coral", 2, 2 );
setSizePolicyAt( 0, Qt::Horizontal, QskSizePolicy::Expanding );
setSizePolicyAt( 1, Qt::Horizontal, QskSizePolicy::Fixed );
setSizePolicyAt( 2, Qt::Horizontal, QskSizePolicy::Expanding );
setSizePolicyAt( 3, Qt::Horizontal, QskSizePolicy::Fixed );
setColumnSizeHint( 1, Qt::MinimumSize, 100 );
}
void Box::test2()
{
setColumns( 1 );
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 1 );
insert( "SkyBlue", 2, 1 );
insert( "Coral", 2, 2 );
setSizePolicyAt( 0, Qt::Horizontal, QskSizePolicy::Expanding );
setSizePolicyAt( 1, Qt::Horizontal, QskSizePolicy::Fixed );
setSizePolicyAt( 2, Qt::Horizontal, QskSizePolicy::Expanding );
setSizePolicyAt( 3, Qt::Horizontal, QskSizePolicy::Fixed );
setMinimumWidthAt( 1, 100 );
setMinimumWidthAt( 2, 100 );
}
void Box::test3()
{
/*
The Graphics layout uses a "magic" formula for how to apply
the stretch factors, while the other layouts result in
predictable sizes.
In the specific situation column 1 in the Graphics layout is
larger than twice of columns 0.
*/
setColumns( 3 );
// Quick layouts do not support row/column hints
enableGrid( Quick, false );
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 0 );
setRowStretchFactor( 0, 1 );
setRowStretchFactor( 1, 2 );
}
void Box::test4()
{
/*
When setting a maximum size together with an alignment the expected result
would be a cell that can grow beyond the maximum, while the content stays
at its maximum, being aligned inside the cell.
But with widgets, the cell size gets always bounded to the preferred size
as soon as an alignment has been set.
With graphics we have the effect, that the cells gets bounded to the
maximum size and we always end up with being aligned Top | Left.
*/
setColumns( 1 );
insert( "PaleVioletRed", 0, 0 );
setPreferredSizeAt( 0, QSize( 10, 10 ) );
setMaximumSizeAt( 0, QSize( 80, 80 ) );
setAlignmentAt( 0, Qt::AlignCenter );
}
void Box::test5()
{
/*
QGridLayoutEngine does not work correctly when putting more
than one element into the same cell. For the specific situation
below we have a wrong preferredSize for Quick and Graphic as only the
last element being inserted one cell goes into the calculation.
The reason behind this limitation is a second list for the elements
organized according to row/column that can only store one
element per cell. Unfortunately the implementation iterates in several
situations over rows/columns using this list.
Iterating over the elements instead avoids this limitation and would
be more efficient as well.
Actually the row/column organized list is ony useful for faster lookups,
when retrieving an item at a specific cell - beside that it
complicates the code without offering extra benefits.
The position of the rectangles differs because the systems have
default alignments.
*/
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 0, 0 );
setFixedSizeAt( 0, QSize( 100, 100 ) );
setFixedSizeAt( 1, QSize( 50, 50 ) );
setAlignmentAt( 0, Qt::AlignCenter );
setAlignmentAt( 1, Qt::AlignCenter );
}
void Box::test6()
{
/*
QGridLayoutEngine ignores the first column coming from
the multicell element at the bottom
*/
insert( "DarkSeaGreen", 1, 1 );
insert( "Coral", 2, 2 );
insert( "NavajoWhite", 3, 0, 1, 3 );
//setSpacing( 0 );
}
void Box::test7()
{
/*
This test is very similar to test6, but here we can see a
difference between Quick and Graphic. The hidden element has
an effect on the layout for Graphic, what is actually wrong, when
setRetainSizeWhenHidden is not set. The preferred width also
includes a wrong contribution from the hidden element.
*/
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 1 );
insert( "Coral", 2, 2 );
insert( "NavajoWhite", 3, 0, 1, 3 );
setVisibleAt( 0, false );
//setRetainSizeWhenHiddenAt( 0, true );
}
void Box::test8()
{
/*
This test creates a situation, where we have more space than
the minimum, but not enough for preferred. For this situation
all layout engines use a different algorithm how to distribute
the extra space. All of them are based on the difference between
preferred and minimum.
- Skinny simply uses the ratio of the differences
- Widgets seems to do something that works exponatially
( need to check the code ).
- Graphic/Quick ( QGridLayoutEngine ) levels the impact
of the differences down.
Hard to say what a user expects to happen.
*/
insert( "PaleVioletRed", 0, 0 );
insert( "DarkSeaGreen", 1, 1 );
for ( int i = 0; i < 2; i++ )
{
setMinimumSizeAt( i, QSize( 20, 20 ) );
setPreferredSizeAt( i, ( i + 1 ) * QSize( 2000, 2000 ) );
}
}
void Box::test9()
{
/*
This one is a bit unclear about how much space from the first
element goes to column 1/2. Skinny gives 50% to both,
while QGridLayoutEngine gives 100% to column 1 ( starting
at 0 + spacing() ). The Widgets implementation seems to be
wrong as column 1 grows beyond 100%.
The situation can be clarified by using setColumnFixedWidth -
unfortunately Quick does not support this.
*/
insert( "PaleVioletRed", 0, 0, 1, 2 );
insert( "DarkSeaGreen", 1, 1 );
setFixedWidthAt( 0, 100 );
//setColumnFixedWidth( 0, 50 );
}
void Box::test10()
{
/*
Widgets gives space to the bounded columns 1/2 instead
of 0/3, where they would be more useful.
*/
insert( "PaleVioletRed", 0, 0 );
insert( "NavajoWhite", 0, 1, 1, 2 );
insert( "Coral", 0, 3 );
setMaximumWidthAt( 1, 70 );
}
class MainWidget : public QWidget
{
public:
MainWidget( int id )
{
m_box = new Box( this );
m_box->showTest( id );
m_listBox = new QListWidget( this );
for ( int i = 0; i < m_box->count(); i++ )
m_listBox->addItem( QStringLiteral( "Test " ) + QString::number( i ) );
m_listBox->setCurrentRow( id );
connect( m_listBox, &QListWidget::currentRowChanged,
m_box, &Box::showTest );
}
protected:
void resizeEvent( QResizeEvent* ) override
{
/*
Not using layouts here to avoid confusion
while debugging.
*/
const auto r = contentsRect();
const int spacing = 5;
auto fm = m_listBox->fontMetrics();
const int w1 = fm.width( "Test 100" ) + 20;
const int w2 = r.width() - w1 - spacing;
m_listBox->setGeometry( r.left(), r.top(), w1, r.height() );
m_box->setGeometry( r.right() - w2, r.top(), w2, r.height() );
m_listBox->setFocus();
}
private:
QListWidget* m_listBox;
Box* m_box;
};
int main( int argc, char** argv )
{
QApplication a( argc, argv );
int testcase = 0;
if ( argc == 2 )
testcase = atoi( argv[1] );
MainWidget w( testcase );
w.resize( 600, 600 );
w.show();
return a.exec();
}