Increase a variable in Less - less

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;
}

Related

QML: Move a frameless window by dragging

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;
}

Styling elements based on sibling count in LESS

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);

Is there a way to create a less mixin that calculates a grid which divides the space available?

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

Add color to match text highlighting in twitter typeahead

As far as I can tell there's no configuration for the styling of text matched in the suggestion box. Is there something I'm missing? Would just like to color the text matching the search query, rather than bold it.
By default twitter typeahead.js wrap the matches into <strong> tags. So if you just want to change the color of the matching text, you could simply just style the <strong> tag :
strong {
font-weight: normal;
color: red;
}
you probably only want to style <strong> within the dropdown :
.tt-suggestion strong {
font-weight: normal;
color: red;
}
see demo -> http://jsfiddle.net/vrs95w3g/
There is also some highlight where you are supposed to be able to change the tagName and className, but honestly never got it to work. Still prefers the good old bootstrap typeahead :)
Here is btw a good example how to style typeahead.js in general (border, input, dropdown etc) -> https://stackoverflow.com/a/20205623/1407478
Gonna go one up, and give the code for fuzzy highlighting
function fuzzyMe(term, query) {
var score = 0;
var termLength = term.length;
var queryLength = query.length;
var highlighting = '';
var ti = 0;
// -1 would not work as this would break the calculations of bonus
// points for subsequent character matches. Something like
// Number.MIN_VALUE would be more appropriate, but unfortunately
// Number.MIN_VALUE + 1 equals 1...
var previousMatchingCharacter = -2;
for (var qi = 0; qi < queryLength && ti < termLength; qi++) {
var qc = query.charAt(qi);
var lowerQc = qc.toLowerCase();
for (; ti < termLength; ti++) {
var tc = term.charAt(ti);
if (lowerQc === tc.toLowerCase()) {
score++;
if ((previousMatchingCharacter + 1) === ti) {
score += 2;
}
highlighting += "<em>" + tc + "</em>";
previousMatchingCharacter = ti;
ti++;
break;
} else {
highlighting += tc;
}
}
}
highlighting += term.substring(ti, term.length);
return {
score: score,
term: term,
query: query,
highlightedTerm: highlighting
};
}
The above takes care of the fuzziness. Then you can just iterate over all your select 2 elements
On typeahead:change
$('#search-bar').typeahead({....}).on('change', function(e) {
var query = $('#search-bar').typeahead('val');
$(".tt-suggestion.tt-selectable .name").each(function() {
var term = $(this).text();
$(this).html(fuzzyMe(term, query).highlightedTerm);
});
});
Credit for fuzzy code -: https://github.com/bripkens/fuzzy.js

SCSS variable string parse to individual mixin vars

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;
}
}