I have this Less mixin (courtesy of Lea Verou):
I would like to pass a variable of max-items (8) and based on this create the rule set below with a loop. So I don't have to repeat code for every number of child elements (1,2,3,4,...).
.list-elements-count-undefined-width() {
/* one item */
&:first-child:nth-last-child(1) {
width: 100%;
}
/* two items */
&:first-child:nth-last-child(2),
&:first-child:nth-last-child(2) ~ li {
width: 50%;
}
/* three items */
&:first-child:nth-last-child(3),
&:first-child:nth-last-child(3) ~ li {
width: (100% / 3);
}
/* four items */
&:first-child:nth-last-child(4),
&:first-child:nth-last-child(4) ~ li {
width: 25%;
}
/* five items */
&:first-child:nth-last-child(5),
&:first-child:nth-last-child(5) ~ li {
width: 20%;
}
/* six items */
&:first-child:nth-last-child(6),
&:first-child:nth-last-child(6) ~ li {
width: (100% / 6);
}
}
.list-elements-count-undefined-width(#i) when (#i > 0) {
.list-elements-count-undefined-width((#i - 1));
&:first-child:nth-last-child(#{i}),
&:first-child:nth-last-child(#{i}) ~ li{
width: (100% / #i);
}
}
.list-elements-count-undefined-width(8);
Related
I have a frameless QQuickWindow, and I want to move it with the mouse by dragging. Before trying in my big application, I have created a simple test application to try what I found here, using cursor position from C++ class to avoid problems from QML:
http://www.tickanswer.com/solved/5390888353/dragging-frameless-window-jiggles-in-qml
But I failed with the code below. When I press over the red RECT and move the mouse, my yellow rect (root RECT) moves, but only inside the original size it had (in this case, 500x500)... What am I doing wrong?
Thanks in advance
In my main.cpp:
int main(int argc, char *argv[])
{
QtQuickControlsApplication a(argc, argv);
QQuickView* pView = new QQuickView();
CursorPosProvider mousePosProvider;
pView->rootContext()->setContextProperty("mousePosition", &mousePosProvider);
pView->setSource(QUrl("qrc:/Test.qml"));
pView->setFlags(Qt::FramelessWindowHint);
pView->show();
return a.exec();
}
Test.qml:
import QtQuick 2.0
Rectangle {
id: myWindow
width: 500; height: 500
color: "yellow"
Rectangle {
anchors.centerIn: parent
width: 200; height: 200
color: "red"
MouseArea {
id: titleBarMouseRegion
property var clickPos
anchors.fill: parent
onPressed: clickPos = { x: mousePosition.cursorPos().x, y: mousePosition.cursorPos().y }
onPositionChanged: {
myWindow.x = mousePosition.cursorPos().x - clickPos.x
myWindow.y = mousePosition.cursorPos().y - clickPos.y
}
}
}
}
cursorprovider.h:
#ifndef CURSORPOSPROVIDER_H
#define CURSORPOSPROVIDER_H
#include <QObject>
#include <QPointF>
#include <QCursor>
class CursorPosProvider : public QObject
{
Q_OBJECT
public:
explicit CursorPosProvider(QObject *parent = nullptr) : QObject(parent)
{
}
virtual ~CursorPosProvider() = default;
Q_INVOKABLE QPointF cursorPos()
{
return QCursor::pos();
}
};
#endif // CURSORPOSPROVIDER_H
I wrote this example and I see no jiggle (running on Linux)
ApplicationWindow {
id: iWindow
visible: true
title: "My title"
color: "gray"
width: 500
height: 500
MouseArea{
id: iMouseArea
property int prevX: 0
property int prevY: 0
anchors.fill: parent
onPressed: {prevX=mouse.x; prevY=mouse.y}
onPositionChanged:{
var deltaX = mouse.x - prevX;
iWindow.x += deltaX;
prevX = mouse.x - deltaX;
var deltaY = mouse.y - prevY
iWindow.y += deltaY;
prevY = mouse.y - deltaY;
}
}
}
I have changed the structure, I have used a QQuickWidget with a QML inside, and now I have what I wanted. Here is my code in case anyone needs something similar
main.cpp
...
MovableWidget *view = new MovableWidget;
view->setSource(QUrl("qrc:/Test.qml"));
view->setWindowFlags(Qt::FramelessWindowHint);
view->show();
...
Test.qml
import QtQuick 2.0
Rectangle {
id: myWindow
width: 500; height: 500
color: "yellow"
Rectangle {
anchors.centerIn: parent
width: 200; height: 200
color: "red"
}
}
MovableWidget.cpp
#include "movableWidget.h"
#include <QMouseEvent>
// ****************************************************************************
MovableWidget::MovableWidget(QWidget *parent)
: QQuickWidget(parent),
m_previousPos(0,0)
{
installEventFilter(this);
}
// ****************************************************************************
bool MovableWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress)
{
m_previousPos = QCursor:os();
}
else if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if(mouseEvent->buttons() == Qt::LeftButton)
{
QPoint offset = m_previousPos - QCursor:os();
m_previousPos = QCursor:os();
move(pos() - offset);
}
}
return false;
}
Is it possible to increase a variable in Less?
#i: 0;
.one { border: #i++; }
.two { border: #i++; }
.tree { border: #i++; }
or perhaps using mixins in a way, like
.increase() {
#i: #i+1;
#increase: #i;
}
To better explain the problem:
#icon_width: 32px;
.social{
background: url('snippet_with_n_images');
.facebook: background-position-x: -#icon_width*0;
.twitter: background-position-x: -#icon_width*1;
.googlep: background-position-x: -#icon_width*2;
...
.pinterest: background-position-x: -#icon_width*(n-1);
.linkedin: background-position-x: -#icon_width*n;
/*be replaced by */
.next(): {
background-position-x: -#icon_width*#i++;
}
.facebook: .next();
.twitter: .next();
.googlep: .next();
...
.pinterest: .next();
.linkedin: .next();
}
Simply speaking, it is not possible to increment the same variable without using a loop (mixin) in Less. This is because Less does lazy loading of variables and so the multiple increments result in recursive definition error. The following snippet:
#i: 0;
.one { #i: #i + 1; border: #i; }
.two { #i: #i + 1; border: #i; }
.three { #i: #i + 1; border: #i; }
when compiled would give:
NameError: Recursive variable definition for #i on line 4, column 7:
Using a mixin like in question (.increase()) would still result in the same error as provided above.
The best way to increment would be to make use of mixin loops. For the modified sample provided in the question, the loop should be like below:
#icon_width: 32px;
#social-networks: facebook, twitter, googlep, pinterest, linkedin; /* an array with list of networks */
.social{
background: url('snippet_with_n_images');
.loop-social(1); /* call loop with initial value as 1 */
}
.loop-social(#index) when (#index < length(#social-networks)){ /* iterate till index is less than array length */
#social-network: extract(#social-networks, #index); /* extract value corresponding to index from array */
.#{social-network}{ /* use extracted social network value as selector */
background-position-x: -#icon_width*#index; /* assign calculated value, the index would incremented for each iteration */
}
.loop-social(#index + 1); /* call next iteration with incremented value */
}
The above Less code when compiled would produce the following CSS:
.social {
background: url('snippet_with_n_images');
}
.social .facebook {
background-position-x: -32px;
}
.social .twitter {
background-position-x: -64px;
}
.social .googlep {
background-position-x: -96px;
}
.social .pinterest {
background-position-x: -128px;
}
We prefer grids that divide the available space like this:
grid-1 = 100%
grid-2 = 50%
grid-3 = 33.33333333%
We have the following less mixin which works great except that grid-1 should equal 100%;
#column-gutter-width: 2%;
.grid {
margin-left: -#column-gutter-width;
.clearfix();
.generate-grid-units(#i) when (#i > 0){
.grid-#{i} {
width: (100% / #i) - #column-gutter-width;
margin-left: #column-gutter-width;
}
.generate-grid-units((#i - 1));
}
.generate-grid-units(6);
}
This generates the following where the only incorrect unit is grid-1:
.grid .grid-2 {
width: 48%;
margin-left: 2%;
}
.grid .grid-1 {
width: 98%;
margin-left: 2%;
}
How can we alter the math so that grid-1 = 100% but have the other grid units remain the same?
Any help would be much appreciated.
Cheers
You could try the following:
#column-gutter-width: 2%;
#num-columns: 6;
.grid {
margin-left: -#column-gutter-width;
.clearfix();
.generate-grid-units(#i) when (#i > 1){
.grid-#{i} {
width: ((100% / #i) - #column-gutter-width);
margin-left: #column-gutter-width;
&:first-child {
margin-left: 0;
}
}
.generate-grid-units((#i - 1));
}
.generate-grid-units(#num-columns);
.grid-1 {
width:100%;
}
}
To clarify:
the loop only runs when #i > 1
.grid-1 is set manually
#num-columns is actualy used to generate the grid
width: ((100% / #i) - #column-gutter-width); now outputs final value rather than an expression
I'm trying to use a variable that gets pass into a mixin to display font settings.
Some variables will display 5 items ($w,$s,$lh,$f,$t) and some will display 3, which is why I'm trying to avoid using nth(selectors) to save me from doing multiple #if #else checks inside my mixin.
/* theme_vars.scss */
$theme__font: niceFont;
$font__value_1: unquote("$w:normal, $s:1.25em, $lh:1.5em, $f:#{$theme__font}, $t:capitalize");
$font__value_2: unquote("$w:bold, $s:2em, $f:#{$theme__font}");
/* theme/header.scss */
.logo {
#include customFont($font__values_1);
}
.title {
#include customFont($font__values_2);
}
/* mixins.scss */
#mixin customFont( $w:inherit, $s:inherit, $lh:inherit, $f:inherit, $t:inherit ) {
font-weight: $w;
font-size: $s;
line-height: $lh;
font-family: $f;
text-transform: $t;
}
But the output I'm getting is this:
.logo {
font-weight: $w:normal, $s:1.25em, $lh:1.5em, $f:#{$theme__font}, $t:capitalize;
font-size: inherit;
line-height: inherit;
font-family: inherit;
text-transform: inherit;
}
Is what I'm trying to do possible?
Thanks in advance, Adam
EDIT *****
$font__value_1: (normal, 1.25em, 1em, "#{$theme__font}", capitalize);
.logo {
#include customFont($font__value_1);
}
#mixin customFont( $list ) {
$wt: nth($list, 1);
$sz: nth($list, 2);
$lh: nth($list, 3);
$ff: nth($list, 4);
$tt: nth($list, 5);
#if $wt != null { font-weight: $wt; }
#if $sz != null { font-size: $sz; }
#if $lh != null { line-height: $lh; }
#if $ff != null { font-family: $ff; }
#if $tt != null { text-transform: $tt; }
}
Use collecions. Try this for fonts variables:
$font__value_1: (normal, 1.25em, 1.5em, "#{$theme__font}", capitalize);
$font__value_2: unquote(bold, 2em, null, "#{$theme__font}", null);
Edited(#Adam O'Brien comment)
Working mixin is:
#mixin customFont( $list ) {
$wt: nth($list, 1);
$sz: nth($list, 2);
$lh: nth($list, 3);
$ff: nth($list, 4);
$tt: nth($list, 5);
if $wt != null {
font-weight: $wt;
}
if $sz != null {
font-size: $sz;
}
if $lh != null {
line-height: $lh;
}
if $ff != null {
font-family: $ff;
}
if $tt != null {
text-transform: $tt;
}
}
I have a custom QDeclarativeItem subclass named Polygon.
I add a MouseArea in it but onEntered or onPressed does not working, or am i expect wrong thing to happen? I can see my polygons on the window but nothing is writing on console onPressed or onEntered.
Here is QML file:
import MyTypes 1.0
import QtQuick 1.0
import Qt 4.7
Item {
id: container
width: 350; height: 250
Polygon {
id: aPolygon
width: 20; height: 20
name: "A simple polygon"
color: "blue"
vertices:[
Point{x:20.0; y:40.0},
Point{x:40.0; y:40.0},
Point{x:40.0; y:20.0},
Point{x:20.0; y:20.0}
]
MouseArea{
anchors.fill: parent
drag.target: aPolygon
drag.axis: Drag.XandYAxis
drag.minimumX: 0
drag.maximumX: container.width - parent.width
drag.minimumY: 0
drag.maximumY: container.height - parent.width
onPressed:console.log("============== ==onPressed")
}
}
Polygon {
id: bPolygon
//anchors.centerIn: parent
width: 20; height: 20
name: "A simple polygon"
color: "blue"
vertices:[
Point{x:60.0; y:80.0},
Point{x:80.0; y:80.0},
Point{x:80.0; y:60.0},
Point{x:60.0; y:60.0}
]
MouseArea{
//hoverEnabled: false
enabled: visible
hoverEnabled: visible
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onEntered: {
console.log("============== ==onEntered")
}
}
}
}
Thanks for any idea.
Edit:
polygon.cpp
#include "polygon.h"
#include "point.h"
#include <QPainter>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <QGraphicsSceneDragDropEvent>
#include <QFocusEvent>
#include "DeclarativeDragDropEvent.h"
using namespace std;
using namespace Qt;
Polygon::Polygon(QDeclarativeItem *parent)
: QDeclarativeItem(parent)
{
// need to disable this flag to draw inside a QDeclarativeItem
//setFlag(QDeclarativeItem::ItemHasNoContents, false);
setFlags(ItemIsSelectable|ItemIsMovable|ItemIsFocusable);
setAcceptDrops(true);
setAcceptedMouseButtons( Qt::LeftButton );
}
/*void Polygon::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
forceActiveFocus();
}
void Polygon::focusOutEvent(QFocusEvent *event)
{
cout<<"focusout"<<endl;
this->setSelected( false );
}*/
/*QVariant Polygon::itemChange(GraphicsItemChange change, const QVariant &value)
{
return QGraphicsItem::itemChange(change, value);
}*/
/*void Polygon::focusInEvent ( QFocusEvent * event ){
cout<<"focusin"<<endl;
}*/
QRectF Polygon::boundingRect() const{
QVector<QPointF> vPnt=listToVector(m_vertices);
return QPolygonF(vPnt).boundingRect();
}
QPainterPath Polygon::shape () const
{
QPainterPath path;
QVector<QPointF> vPnt=listToVector(m_vertices);
path.addPolygon(QPolygonF(vPnt));
return path;
}
QString Polygon::name() const
{
return m_name;
}
void Polygon::setName(const QString &name)
{
m_name = name;
}
QColor Polygon::color() const
{
return m_color;
}
void Polygon::setColor(const QColor &color)
{
m_color = color;
}
void Polygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
QPen pen(m_color, 2);
painter->setPen(pen);
painter->setRenderHints(QPainter::Antialiasing, true);
QVector<QPointF> vPnt=listToVector(m_vertices);
painter->setBrush(QBrush(m_color,Qt::SolidPattern));
painter-> drawPolygon(QPolygonF(vPnt),Qt::OddEvenFill);
}
QVector<QPointF> Polygon:: listToVector(QList<Point *> lpnt) const{
QVector<QPointF> vPnt;
for(int i=0;i<lpnt.length();i++){
vPnt.append(QPointF(lpnt.at(i)->x(),lpnt.at(i)->y()));
}
return vPnt;
}
QDeclarativeListProperty<Point> Polygon::vertices()
{
return QDeclarativeListProperty<Point>(this, 0, &Polygon::append_vertex);
}
void Polygon::append_vertex(QDeclarativeListProperty<Point> *list, Point *vertex)
{
Polygon *polygon = qobject_cast<Polygon *>(list->object);
if (polygon) {
vertex->setParentItem(polygon);
polygon->m_vertices.append(vertex);
}
}
I believe you should set hoverEnabled to true, or is this intentionally set to visible? visible is a boolean property which might be false for a MouseArea.
MouseArea {
hoverEnabled: true
}
The same goes for enabled: visible