I want to change the size of a Rectangle in the QML drag and drop example on drop to the size of the drop area. But somehow the Rectangle will not render to the new size although it takes the width and height values.
DragTile.qml
import QtQuick 2.0
Item
{
id: rootItem
property int boxWidth: 0
property int boxHeight: 0
property Item dragParent
width: boxWidth
height: boxHeight
MouseArea
{
id: mouseArea
width: rootItem.boxWidth
height: rootItem.boxHeight
drag.target: msgTile
onReleased:
{
parent = msgTile.Drag.target !== null ? msgTile.Drag.target : rootItem
rootItem.boxHeight = parent.boxHeight
rootItem.boxWidth = parent.boxWidth
}
Rectangle
{
id: msgTile
color: "cyan"
width: mouseArea.width
height: mouseArea.height
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
//draging
states: State
{
when: mouseArea.drag.active
ParentChange { target: msgTile; parent: dragParent } // draw on top while draging
AnchorChanges { target: msgTile; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined }
}
}
}
}
The dragsource as well as the droparea take the size of a parent rectangle
in Main.qml
Rectangle
{
x: 100
y: 100
width: 100
height: 300
border.width: 1
DragSource
{
msgCount: 2
msgCapacity: 10
dragParent: topItem
}
}
Rectangle
{
x: 400
y: 100
width: 150
height: 300
border.width: 1
MsgDrop
{
msgCapacity: 12
}
}
The size of the droparea is a little bit larger, than the size of the dragtiles
Is there any order of rendering that I am missing?
I would be very happy for some advice.
Best regards
Related
I'm creating a symbol layer with the layer symbols using custom images which is working well.
I also want to create custom labels with HTML (basically a blue background with an eased border and the label) but I'm unsure whether that's possible or how. I'm including what I'm using right now to render the points, the get icons renders the custom images for each point which are loaded in advance using map.loadImage.
map.addLayer({
id: 'points',
type: 'symbol',
source: 'points',
paint: {
"text-color": "#ffffff",
},
layout: {
'icon-image': ['get', 'icon'], // 'cat',
'icon-size': 1,
'icon-allow-overlap': true,
'text-field': ['get', 'name'],
'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'],
'text-offset': [0, 2.00],
'text-size': 14,
'text-anchor': 'top',
'text-allow-overlap': false,
},
})
You can't use HTML in symbol layers. You can:
Use Marker objects instead of symbol layers.
Use formatted content within symbol layers, with a mixture of fonts, font weights etc.
Use 9-part images to make custom borders.
This is almost what I've done in the past for a house rental agency.
Basically, I had to show a label with a price, whether the house had 3d pictures, add a blue background ...
Below is the source code that you can modify to satisfy your needs
What I did, is code all the infos in "icon-image" like this:
...
'icon-image': ['concat', 'projectmarker|', ['get', 'id'], '|', ['get', 'price'], '|', ['get', '3d'], '|', ['get', 'name'], '|', ['get', 'highlight']]
...
What happens then is that mapbox does not find the image and calls a "styleimagemissing" callback which does all the work using the element and converting it to a dataimage at the very end
const missingImages = [];
map.on('styleimagemissing', function (e) {
const id = e.id;
const blue = '#1f2d41';
const white = '#ffffff';
const yellow = '#a3a326';
// only create once
if (missingImages.indexOf(id) !== -1) return;
missingImages.push(id);
// check if this missing icon is one this function can generate
if (id.indexOf('projectmarker') !== 0) return;
// extract infos
const projectId = parseInt((id.split('|')[1]));
let price = parseInt((id.split('|')[2])).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const hasPrice = price !== "0";
const threeD = 'true' === (id.split('|')[3]);
const highlight = '1' === (id.split('|')[5]);
if (!hasPrice) {
price = id.split('|')[4];
} else {
price += ' ' + currencyCode;
}
// create canvas
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const height = 20;
const leftWidth = 40;
const rightWidth = (8 * price.length) + 10;
const leftBg = blue;
const rightBg = highlight ? yellow : white;
const radius = 4;
if (threeD) {
// 3d bg
ctx.fillStyle = leftBg;
roundRect(ctx, 0, 0, leftWidth, height, {tl: radius, tr: 0, br: 0, bl: radius}, true, true);
// 3d text
ctx.textAlign = "center";
ctx.font = "bold 14px Arial";
ctx.fillStyle = white;
ctx.fillText('360°', leftWidth / 2, 16);
// price bg
ctx.fillStyle = rightBg;
roundRect(ctx, leftWidth, 0, rightWidth, height, {tl: 0, tr: radius, br: radius, bl: 0}, true, true);
} else {
// price bg
ctx.fillStyle = rightBg;
roundRect(ctx, 0, 0, rightWidth, height, radius, true, true);
}
// price
ctx.textAlign = "center";
ctx.font = "14px Arial";
ctx.fillStyle = blue;
ctx.fillText(price.replace(',', ' '), (threeD ? leftWidth : 0) + (rightWidth / 2), 15);
// extract data and create mapbox image
const imageData = ctx.getImageData(0, 0, (threeD ? leftWidth : 0) + rightWidth, height);
map.addImage(id, imageData);
});
Below is the roundRect helper
const roundRect = (ctx, x, y, width, height, radius, fill, stroke) => {
if (typeof stroke === 'undefined') {
stroke = true;
}
if (typeof radius === 'undefined') {
radius = 5;
}
if (typeof radius === 'number') {
radius = {tl: radius, tr: radius, br: radius, bl: radius};
} else {
const defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0};
for (let side in defaultRadius) {
radius[side] = radius[side] || defaultRadius[side];
}
}
ctx.beginPath();
ctx.moveTo(x + radius.tl, y);
ctx.lineTo(x + width - radius.tr, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
ctx.lineTo(x + width, y + height - radius.br);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
ctx.lineTo(x + radius.bl, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
ctx.lineTo(x, y + radius.tl);
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
ctx.closePath();
if (fill) {
ctx.fill();
}
if (stroke) {
ctx.stroke();
}
}
I have an item (a rectangle) which can be moved through the different positions of the grid (see code below).
The reference to decide whether the rectangle is in one cell or another is the top-left (x=0;y=0) of the rectangle. I want the reference to be the center of the rectangle. Any ideas?
Find the code below:
import QtQuick 2.5
import QtPositioning 5.5
import QtLocation 5.6
import QtGraphicalEffects 1.0
import QtQml 2.2
import QtQuick.Controls 1.0
Rectangle{
id: mainContainer
width:800; height:width
color: "red"
Grid {
id:gridA
anchors.centerIn: parent
width: parent.width; height:width;
columns: 2; rows: 2; spacing: 2
verticalItemAlignment: Grid.AlignHCenter
horizontalItemAlignment: Grid.AlignVCenter
Repeater {
id:cells
model: gridA.columns*gridA.rows
property int draggedItemIndex: -1
Rectangle {
width: gridA.width/gridA.columns; height: gridA.height/gridA.rows
color: "white"
DropArea {
id: dragTarget
property alias dropProxy: dragTarget
anchors.fill: parent
keys: [ "KEY_A" ]
Rectangle {
id: dropRectangle
anchors.fill: parent
states: [
State {
when: dragTarget.containsDrag
PropertyChanges { target: dropRectangle; color: "grey"}
PropertyChanges { target: cells; draggedItemIndex: index}
}
]
}
}
}
}
}
Rectangle{
id: icon
property var draggedIndex: 0
width: parent.width/3; height:width
color:"blue"
Drag.active: dragArea.drag.active
Drag.keys: [ "KEY_A" ]
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: icon
cursorShape: drag.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
onReleased: {
console.log("Drag: " + cells.draggedItemIndex)
if (cells.draggedItemIndex != icon.draggedIndex) {
icon.draggedIndex = cells.draggedItemIndex
cells.draggedItemIndex = -1
}
icon.x = cells.itemAt(icon.draggedIndex).x
icon.y = cells.itemAt(icon.draggedIndex).y
}
}
}
}
You have the Drag-attached property, which has the hotSpot-property of type PointF.
Set this property to Qt.point(width / 2, height / 2)
I want to make product listing page to use 3 columns instead of 4 default columns.
I've got some categories on my Magento2 Web, and some products on each category. I want them to show as 3 columns count, but it always shows as 4 default columns count, how can i change plz help me for this.
Magento 2 don't have an option to set a column count as Magento 1.
To change from 4 to 3 (for theme based on Luma) you will need to change CSS and to reset image size.
CSS code that you need to change is inside Magento_Catalog module, file:
_listings.less
and it is like this:
.media-width(#extremum, #break) when (#extremum = 'min') and (#break = #screen__l) {
.products-grid .product-item { width: 100%/5 }
.page-layout-1column .products-grid .product-item { width: 100%/6 }
.page-layout-3columns .products-grid .product-item { width: 100%/4 }
.page-products .products-grid .product-items { margin: 0; }
.page-products .products-grid .product-item {
width: 24.439%;
margin-left: calc(~"(100% - 4 * 32.439%) / 3");
padding: 0;
&:nth-child(3n+1) {
margin-left: 0;
}
}
.page-products.page-layout-1column .products-grid .product-item { width: 100%/5 }
.page-products.page-layout-3columns .products-grid .product-item { width: 100%/4 }
}
to have 3 columns, change it to (I recommend add this code to _theme.less):
.media-width(#extremum, #break) when (#extremum = 'min') and (#break = #screen__l) {
.products-grid .product-item { width: 100%/4 }
.page-layout-1column .products-grid .product-item { width: 100%/5 }
.page-layout-3columns .products-grid .product-item { width: 100%/3 }
.page-products .products-grid .product-items { margin: 0; }
.page-products .products-grid .product-item {
width: 32.439%;
margin-left: calc(~"(100% - 3 * 32.439%) / 2");
padding: 0;
&:nth-child(3n+1) {
margin-left: 0;
}
}
.page-products.page-layout-1column .products-grid .product-item { width: 100%/4 }
.page-products.page-layout-3columns .products-grid .product-item { width: 100%/3 }
}
after this in
/your_theme/etc/view.xml
change small image width and height. Now is 240 and 300, change it to something like 300 and 330.
Refresh and that is it.
Here's an example from Official Guide by Apple:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// prints "square.origin is now at (10.0, 10.0)”
This make me pretty confused why we need get/set here, even we actually can do without them, then I tried:
struct anotherRect {
var origin = Point()
var size = Size()
var center: Point{
return Point(x: (origin.x + size.width/2), y: (origin.y + size.height/2))
}
}
var anotherSquare = Rect(origin: Point(x: 20.0, y: 20.0), size: Size(width: 10.0, height: 10.0))
println("anotherSquare.center is (\(anotherSquare.center.x), \(anotherSquare.center.y))")
// prints "anotherSquare.center is (25.0, 25.0)"
anotherSquare.center = Point(x: 30.0, y: 30.0)
println("anotherSquare.origin is now at (\(anotherSquare.origin.x), \(anotherSquare.origin.y))")
// prints "anotherSquare.origin is now at (25.0, 25.0)"
With this, I can do get value or set a new value to the computed properties, exactly the same get/set by Apple's way. Do we really need get/set in our code? and Why?
I'm just a newcomer, so feel free let me know all about this stuff? I really appriciate your help!!
They are not the same. If you don't specify the get set keywords, you only implement the getter.
struct AnotherRect {
var origin = Point()
var size = Size()
var center: Point {
return Point(x: (origin.x + size.width/2), y: (origin.y + size.height/2))
}
}
is equivalent to
struct AnotherRect {
var origin = Point()
var size = Size()
var center: Point {
get {
return Point(x: (origin.x + size.width/2), y: (origin.y + size.height/2))
}
}
}
Your example got you confused because you have an error in your code:
var anotherSquare = Rect(origin: Point(x: 20.0, y: 20.0), size: Size(width: 10.0, height: 10.0))
should be
var anotherSquare = AnotherRect(origin: Point(x: 20.0, y: 20.0), size: Size(width: 10.0, height: 10.0))
Try that and you will notice that you cannot assign to the center property.
Also, the convention is that you name your custom types starting with a capital letter, e.g.: AnotherRect.
I'm writing my first QML/Javascript app for QtQuick 2.0.
I need to place a DatePicker control, but I haven't found any control like that under QtQuick.Controls -and nowhere, in fact-.
I'm starting to believe there is no way to call a 'native' DatePicker in QML. Do I have to implement one or there is exist one?
Just in case anyone else stumbles upon this, there is a Calendar element in QtQuick.Controls by now. This should make the implementation of such a Datepicker a lot easier: http://qt-project.org/doc/qt-5/qml-qtquick-controls-calendar.html
Well, I had to make my own control. It is called Datepicker.
It is intented to used in this way:
import QtQuick.Controls 1.1
ApplicationWindow {
id: main
Datepicker {
id: myDate
activeWindow: main
width: 200
}
}
It asumes you are using it from a Window object, and needs the parent reference to show the datepicker in the correct position (it shows a calendar in a new window).
You can download the source code from:
https://bitbucket.org/camolin3/datepicker
This is the first version and need a lot of polish to be ready, but is a start point.
**Code for DatePicker. Try this one **
*TextField {
id: textDate
x: 10
y: 42
width: 175
height: 33
placeholderText: qsTr("Text Field")
text:Qt.formatDate(cal.selectedDate, "dd-MM-yyyy")
font.bold: true
font.family:"times new roman"
font.pointSize: 12
}
Button {
id: button
x: 198
y: 42
width: 25
height: 29
Image {
x: -4
y: -4
id: img
width: 36
height: 44
source: "/Images/calendar-512.png"
}
onClicked:{
cal.visible=true
}
}
Calendar{
id:cal
x: 10
y: 82
width: 220
height: 205
visible: false
selectedDate: new Date()
onClicked: {
textDate.text=Qt.formatDate(cal.selectedDate, "dd-MM-yyyy");
cal.visible=false
}
}*
I wrote another date picker, relying purely on the JavaScript Date object as follows. It adheres to material design.
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Controls.Material.impl 2.15
Pane {
id: control
property int radius: 2
background: Rectangle {
color: control.Material.background
radius: control.Material.elevation > 0 ? control.radius : 0
layer.enabled: control.enabled && control.Material.elevation > 0
layer.effect: ElevationEffect {
elevation: control.Material.elevation
}
}
}
And then, here is it
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls.Material 2.15
Rectangle {
id: root
property int month: selectedDate.getMonth()
property int year: selectedDate.getFullYear()
property int day: selectedDate.getDate()
property int weekday: selectedDate.getDay()
property int daysInMonth: new Date(year, month + 1, 0).getDate()
property date selectedDate: new Date()
property int _start_weekday: new Date(year, month, 1).getDay()
implicitWidth: layout.width
implicitHeight: layout.height
color: "transparent"
ColumnLayout {
id: layout
Rectangle {
id: title
implicitHeight: 40
Layout.fillWidth: true
color: "transparent"
Text {
anchors.fill: parent
anchors.leftMargin: 8
text: selectedDate.toLocaleDateString(Qt.locale(), "ddd, MMM d")
font.pixelSize: 40
}
}
Rectangle {
color: "transparent"
implicitHeight: 28
Layout.fillWidth: true
}
Rectangle {
id: controls
color: "transparent"
implicitHeight: 24
RowLayout {
anchors.fill: parent
anchors.leftMargin: 8
spacing: 16
Layout.alignment: Qt.AlignHCenter
Text {
text: selectedDate.toLocaleDateString(Qt.locale(), "MMMM yyyy")
font.pixelSize: 16
}
RoundButton {
id: monthButton
contentItem: MIcon {
icon: "expand_more"
color: "black"
size: 16
}
Material.elevation: 0
onClicked: {
monthMenu.open()
}
Menu {
id: monthMenu
Repeater {
model: 12
MenuItem {
text: new Date(2020, index, 1).toLocaleDateString(Qt.locale(), "MMMM")
onTriggered: {
set_month(index)
monthMenu.close()
}
}
}
}
}
// 2 button to change month <>
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: 8
RoundButton {
Material.background: 'transparent'
contentItem: MIcon {
icon: 'navigate_before'
color: 'black'
size: 16
}
onClicked: {
set_month(month - 1)
}
}
RoundButton {
Material.background: 'transparent'
contentItem: MIcon {
icon: 'navigate_next'
color: 'black'
size: 16
}
onClicked: {
set_month(month + 1)
}
}
}
}
}
Rectangle {
color: "transparent"
implicitHeight: 16
Layout.fillWidth: true
}
Rectangle {
color: Material.accent
implicitHeight: 1
Layout.fillWidth: true
}
// Sunday - Saturday
RowLayout {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
spacing: 4
Repeater {
model: 7
Rectangle { // just for spacing
width: 40
height: 40
color: "transparent"
Text {
anchors.centerIn: parent
Layout.fillWidth: true
text: new Date(2020, 0, index - 2).toLocaleDateString(Qt.locale(), "ddd").slice(0, 1)
font.pixelSize: 16
horizontalAlignment: Text.AlignHCenter
}
}
}
}
// calendar
GridLayout {
id: grid
columns: 7
rows: 6
columnSpacing: 4
rowSpacing: 4
Repeater {
model: 42
delegate: Rectangle {
color: default_color()
radius: 20
border.width: 1
border.color: is_selected() ? Material.accent : "transparent"
width: 40
height: 40
Text {
anchors.centerIn: parent
text: get_day()
color: in_current_month() ? 'black' : 'gray'
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
cursorShape = Qt.PointingHandCursor
color = Material.color(Material.accent, Material.Shade200)
}
onExited: {
cursorShape = Qt.ArrowCursor
color = default_color()
}
onClicked: {
var _day = get_day()
if (!in_current_month()){
if (index < _start_weekday) {
set_month(month - 1)
} else {
set_month(month + 1)
}
}
set_day(_day)
}
}
function default_color() {
return 'transparent'
}
function in_current_month() {
return index >= _start_weekday && (index - _start_weekday) < daysInMonth
}
function is_selected() {
return day == get_day() && in_current_month()
}
function get_day() {
var this_day = index - _start_weekday + 1
if (this_day > daysInMonth) {
return this_day - daysInMonth
} else if (this_day < 1) {
return new Date(year, month, 0).getDate() + this_day
} else {
return this_day
}
}
}
}
}
}
function set_month(month) {
var days_in = new Date(year, month + 1, 0).getDate()
var new_day = Math.min(day, days_in)
selectedDate = new Date(year, month, new_day)
}
function set_day(day) {
day = Math.min(day, daysInMonth)
selectedDate = new Date(year, month, day)
}
}