diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
.*.swp
.*.swo
+.arcconfig
diff --git a/lib/qt.js b/lib/qt.js
--- a/lib/qt.js
+++ b/lib/qt.js
@@ -1607,6 +1607,8 @@
};
+function parse($TEXT, options) {
+
/* -----[ Parser (constants) ]----- */
var UNARY_PREFIX = makePredicate([
@@ -1655,8 +1657,6 @@
/* -----[ Parser ]----- */
-function parse($TEXT, options) {
-
options = defaults(options, {
strict : false,
filename : null,
@@ -4509,6 +4509,12 @@
},
"name": function(src) {
return bindout(tree, src);
+ },
+ "string": function(src) {
+ return src;
+ },
+ "num": function(src) {
+ return src;
}
};
@@ -7030,7 +7036,34 @@
Key_Play: 250,
Key_Sleep: 95,
Key_Zoom: 251,
- Key_Cancel: 3
+ Key_Cancel: 3,
+ // CursorShape
+ ArrowCursor: 0,
+ UpArrowCursor: 1,
+ CrossCursor: 2,
+ WaitCursor: 3,
+ IBeamCursor: 4,
+ SizeVerCursor: 5,
+ SizeHorCursor: 6,
+ SizeBDiagCursor: 7,
+ SizeFDiagCursor: 8,
+ SizeAllCursor: 9,
+ BlankCursor: 10,
+ SplitVCursor: 11,
+ SplitHCursor: 12,
+ PointingHandCursor: 13,
+ ForbiddenCursor: 14,
+ WhatsThisCursor: 15,
+ BusyCursor: 16,
+ OpenHandCursor: 17,
+ ClosedHandCursor: 18,
+ DragCopyCursor: 19,
+ DragMoveCursor: 20,
+ DragLinkCursor: 21,
+ LastCursor: 21, //DragLinkCursor,
+ BitmapCursor: 24,
+ CustomCursor: 25
+
}
/**
@@ -7304,21 +7337,32 @@
if (meta.object.$class in constructors) {
item = new constructors[meta.object.$class](meta);
} else if (cTree = engine.loadComponent(meta.object.$class)) {
- if (cTree.$children.length !== 1)
+ if (cTree.$children.length !== 1) {
console.error("A QML component must only contain one root element!");
- var item = (new QMLComponent({ object: cTree, context: meta.context })).createObject(meta.parent);
-
+ }
+
+ var component = new QMLComponent({ object: cTree, context: meta.context });
+ component.finalizeImports();
+
+ var item = component.createObject(meta.parent);
+
// Recall QMLBaseObject with the meta of the instance in order to get property
// definitions, etc. from the instance
QMLBaseObject.call(item, meta);
+
if (typeof item.dom != 'undefined')
item.dom.className += " " + meta.object.$class + (meta.object.id ? " " + meta.object.id : "");
+
var dProp; // Handle default properties
} else {
console.log("No constructor found for " + meta.object.$class);
return;
}
+ if (!global.qmlEngine.doc) {
+ global.qmlEngine.doc = item;
+ }
+
// id
if (meta.object.id)
meta.context[meta.object.id] = item;
@@ -7557,7 +7601,7 @@
if (source != null) {
global.qmlEngine = new QMLEngine();
- qmlEngine.loadFile(source);
+ qmlEngine.loadFile(source, null);
qmlEngine.start();
break ;
}
@@ -7625,6 +7669,12 @@
this.getAttributes = function() { return (attributes); }
}
+registerQmlType({
+ module: 'QtQuick',
+ name: 'QtObject',
+ versions: /.*/,
+ constructor: QMLBaseObject
+});
// TODO
function QMLColor(val) {
@@ -7711,36 +7761,40 @@
if (!qrc.includesFile(file)) {
var src = getUrlContents(file);
- console.log('loading file', file);
- qrc[file] = qmlparse(src);
+ if (src) {
+ console.log('Loading file [', file,']');
+ qrc[file] = qmlparse(src);
+ }else {
+ console.log('Can nor load file [', file,']');
+ }
}
}
-
+
// Load file, parse and construct (.qml or .qml.js)
- this.loadFile = function(file) {
+ this.loadFile = function(file, parentComponent) {
var tree;
basePath = this.pathFromFilepath(file);
this.basePath = basePath;
this.ensureFileIsLoadedInQrc(file);
tree = convertToEngine(qrc[file]);
- this.loadQMLTree(tree);
+ return this.loadQMLTree(tree, parentComponent);
}
// parse and construct qml
this.loadQML = function(src) {
- this.loadQMLTree(parseQML(src));
+ this.loadQMLTree(parseQML(src), null);
}
- this.loadQMLTree = function(tree) {
+ this.loadQMLTree = function(tree, parentComponent) {
engine = this;
if (options.debugTree) {
options.debugTree(tree);
}
// Create and initialize objects
- var component = new QMLComponent({ object: tree, parent: null });
- doc = component.createObject(null);
+ var component = new QMLComponent({ object: tree, parent: parentComponent });
+ doc = component.createObject(parentComponent);
component.finalizeImports();
this.$initializePropertyBindings();
@@ -7750,10 +7804,12 @@
for (var i in this.completedSignals) {
this.completedSignals[i]();
}
+
+ return component;
}
this.rootContext = function() {
- return doc.$context;
+ return global.qmlEngine.doc.$context;
}
this.focusedElement = (function() {
@@ -7901,7 +7957,9 @@
// Initialize property bindings
for (var i = 0; i < this.bindedProperties.length; i++) {
var property = this.bindedProperties[i];
- property.binding.compile();
+ if (property.binding!=null) {
+ property.binding.compile();
+ }
property.update();
}
this.bindedProperties = [];
@@ -8090,7 +8148,8 @@
}
QMLPositioner.slotChildrenChanged = function() {
- for (var i = 0; i < this.children.length; i++) {
+ var c = this.children.length;
+ for (var i = 0; i < c; i++) {
var child = this.children[i];
if (!child.widthChanged.isConnected(this, this.layoutChildren))
child.widthChanged.connect(this, this.layoutChildren);
@@ -8349,6 +8408,8 @@
this.width = width;
this.$updatingGeometry = false;
+
+ if (this.parent != undefined) updateChildrenRect(this.parent);
}
function updateVGeometry(newVal, oldVal, propName) {
@@ -8448,38 +8509,43 @@
this.height = height;
this.$updatingGeometry = false;
+
+ if (this.parent != undefined) updateChildrenRect(this.parent);
}
-
-
-function QMLButton(meta) {
- this.dom = document.createElement("button");
- QMLItem.call(this, meta);
- var self = this;
-
- this.dom.style.pointerEvents = "auto";
- this.dom.innerHTML = "";
-
- createSimpleProperty("string", this, "text");
- this.clicked = Signal();
-
- this.Component.completed.connect(this, function() {
- this.implicitWidth = this.dom.firstChild.offsetWidth + 20;
- this.implicitHeight = this.dom.firstChild.offsetHeight + 5;
- });
- this.textChanged.connect(this, function(newVal) {
- this.dom.firstChild.innerHTML = newVal;
- //TODO: Replace those statically sized borders
- this.implicitWidth = this.dom.firstChild.offsetWidth + 20;
- this.implicitHeight = this.dom.firstChild.offsetHeight + 5;
- });
-
- this.dom.onclick = function(e) {
- self.clicked();
- }
+function updateChildrenRect(component){
+
+ var children = component !== undefined ? component.children : undefined
+ if ( children == undefined || children.length == 0 )
+ return;
+
+ var maxWidth = 0;
+ var maxHeight = 0;
+ var minX = children.length>0 ? children[0].x : 0;
+ var minY = children.length>0 ? children[0].y : 0;
+ var h=0;
+ var w=0;
+
+ for(var i in children){
+ var child = children[i];
+
+ h = child.$isUsingImplicitHeight !== 0 ? child.implicitHeight : child.height;
+ w = child.$isUsingImplicitWidth !== 0 ? child.implicitWidth : child.width;
+
+ maxWidth = Math.max(maxWidth, child.x + w);
+ maxHeight = Math.max(maxHeight, child.y + h);
+ minX = Math.min(minX, child.x);
+ minY = Math.min(minX, child.y);
+ }
+
+ component.childrenRect.x = minX;
+ component.childrenRect.y = minY;
+ component.childrenRect.width = maxWidth;
+ component.childrenRect.height = maxHeight;
+
}
-registerQmlType('Button', QMLButton);
+
QMLComponent.prototype.createObject = function(parent, properties) {
var oldState = engine.operationState;
@@ -8517,11 +8583,15 @@
if (typeof qmlEngine.basePath != 'undefined')
src = qmlEngine.basePath + src;
- if (typeof qrc[src] != 'undefined')
+
+ if (typeof qrc[src] != 'undefined') {
js = qrc[src];
- else
+ }
+ else {
js = jsparse(getUrlContents(src));
- var $context = qmlEngine.rootContext();
+ }
+
+ var $context = this.$context;
$context[importDesc.alias] = {};
importJavascriptInContext(js, $context[importDesc.alias]);
}
@@ -8683,6 +8753,7 @@
this.$isUsingImplicitWidth = true;
this.$isUsingImplicitHeight = true;
+ // anchors property
this.anchors = new QObject(this);
createSimpleProperty("real", this.anchors, "left");
createSimpleProperty("real", this.anchors, "right");
@@ -8714,6 +8785,14 @@
this.anchors.marginsChanged.connect(this, updateHGeometry);
this.anchors.marginsChanged.connect(this, updateVGeometry);
+ // childrenRect property
+ this.childrenRect = new QObject(this);
+ createSimpleProperty("real", this.childrenRect, "x","rw"); //todo ro
+ createSimpleProperty("real", this.childrenRect, "y","rw"); // todo ro
+ createSimpleProperty("real", this.childrenRect, "width","rw"); // todo ro
+ createSimpleProperty("real", this.childrenRect, "height","rw"); // todo ro
+
+
createSimpleProperty("list", this, "states");
createSimpleProperty("string", this, "state");
createSimpleProperty("list", this, "transitions");
@@ -8913,7 +8992,11 @@
this.transform = [];
this.rotation = 0;
this.scale = 1;
-
+ this.childrenRect.x = 0;
+ this.childrenRect.y = 0;
+ this.childrenRect.width = 0;
+ this.childrenRect.height = 0;
+
// Init size of root element
if (this.$parent === null && engine.rootElement == undefined) {
window.onresize();
@@ -9294,6 +9377,35 @@
}
});
+function QMLButton(meta) {
+ this.dom = document.createElement("button");
+ QMLItem.call(this, meta);
+ var self = this;
+
+ this.dom.style.pointerEvents = "auto";
+ this.dom.innerHTML = "";
+
+ createSimpleProperty("string", this, "text");
+ this.clicked = Signal();
+
+ this.Component.completed.connect(this, function() {
+ this.implicitWidth = this.dom.firstChild.offsetWidth + 20;
+ this.implicitHeight = this.dom.firstChild.offsetHeight + 5;
+ });
+ this.textChanged.connect(this, function(newVal) {
+ this.dom.firstChild.innerHTML = newVal;
+ //TODO: Replace those statically sized borders
+ this.implicitWidth = this.dom.firstChild.offsetWidth + 20;
+ this.implicitHeight = this.dom.firstChild.offsetHeight + 5;
+ });
+
+ this.dom.onclick = function(e) {
+ self.clicked();
+ }
+}
+
+registerQmlType('Button', QMLButton);
+
registerQmlType({
module: 'QtQuick.Controls',
name: 'CheckBox',
@@ -9331,7 +9443,85 @@
};
}
});
+registerQmlType({
+ module: 'QtQuick',
+ name: 'ComboBox',
+ versions: /.*/,
+ constructor: QMLComboBox
+});
+function QMLComboBox(meta) {
+ QMLItem.call(this, meta);
+ var self = this;
+
+ this.dom.style.pointerEvents = "auto";
+ this.name = "QMLComboBox";
+
+ createSimpleProperty("int", this, "count");
+ createSimpleProperty("int", this, "currentIndex");
+ createSimpleProperty("string", this, "currentText");
+ createSimpleProperty("array", this, "menu");
+ createSimpleProperty("array", this, "model");
+ createSimpleProperty("bool", this, "pressed");
+
+ this.count = 0;
+ this.currentIndex = 0;
+ this.currentText = "";
+ this.menu = [];
+ this.model = [];
+ this.pressed = false;
+
+ var updateCB = function(){
+ var head = "";
+ var html = head;
+
+ var model = self.model;
+ var count = model.length;
+ self.count = count;
+
+ for (var i = 0; i < count; i++) {
+ var elt = model[i];
+ //if (elt instanceof Array) { // TODO - optgroups? update model !
+ // var count_i = elt.length;
+ // for (var j = 0; j < count_i; j++)
+ // html += "";
+ //}
+ //else
+ html += "";
+ }
+ html += tail;
+ return html;
+ };
+
+ this.accepted = Signal();
+ this.activated = Signal([{type: "int", name: "index"}]);
+
+ this.find = function(text) {
+ return self.model.indexOf(text)
+ };
+ this.selectAll = function () {}; // TODO
+ this.textAt = function(index) {
+ return this.model[index];
+ };
+
+ this.Component.completed.connect(this, function () {
+ this.dom.innerHTML = updateCB();
+ var child = this.dom.firstChild;
+ this.implicitWidth = child.offsetWidth;
+ this.implicitHeight = child.offsetHeight;
+ });
+
+ this.modelChanged.connect(updateCB);
+
+ this.dom.onclick = function (e) {
+ var index = self.dom.firstChild.selectedIndex;
+ self.currentIndex = index ;
+ self.currentText = self.model[index];
+ self.accepted();
+ self.activated(index);
+ };
+}
registerQmlType({
module: 'QtQuick.Controls',
name: 'TextArea',
@@ -9557,15 +9747,35 @@
QMLColumn.prototype.layoutChildren = function() {
var curPos = 0,
maxWidth = 0;
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i];
- if (!(child.visible && child.opacity && child.width && child.height))
+ var children = [];
+ var child = undefined;
+ var QMLRepeater = getConstructor('QtQuick', '2.0', 'Repeater');
+ var QMLListView = getConstructor('QtQuick', '2.0', 'ListView');
+
+ for (var key in this.children) {
+ child = this.children[key];
+
+ if ( child instanceof QMLRepeater || child instanceof QMLListView) {
+ children = children.concat(child.children);
+ }
+ else {
+ children.push(child);
+ }
+ }
+
+ if (children.length == 0) return;
+
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
+ if (!(child.visible && child.opacity && child.width && child.height)) {
continue;
+ }
+
maxWidth = child.width > maxWidth ? child.width : maxWidth;
-
child.y = curPos;
curPos += child.height + this.spacing;
}
+
this.implicitWidth = maxWidth;
this.implicitHeight = curPos - this.spacing; // We want no spacing at the bottom side
}
@@ -9651,48 +9861,70 @@
this.layoutDirectionChanged.connect(this, this.layoutChildren);
this.widthChanged.connect(this, this.layoutChildren);
- this.flow = 0;
- this.layoutDirection = 0;
+ this.flow = this.Flow.LeftToRight;
+ this.layoutDirection = 0 ;
}
QMLFlow.prototype.layoutChildren = function() {
var curHPos = 0,
curVPos = 0,
rowSize = 0;
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i];
+ var children = [];
+ var child = undefined;
+ var QMLRepeater = getConstructor('QtQuick', '2.0', 'Repeater');
+
+ for (var key in this.children){
+ child = this.children[key];
+
+ if ( child instanceof QMLRepeater) {
+ children = children.concat(child.children);
+ }
+ else{
+ children.push(child);
+ }
+ }
+
+ if (children.length == 0) return;
+
+ var flowWidth = this.$isUsingImplicitWidth ? this.implicitWidth : this.width;
+ var flowHeight = this.$isUsingImplicitHeight ? this.implicitHeight : this.height;
+
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
if (!(child.visible && child.opacity && child.width && child.height))
continue;
- if (this.flow == 0) {
- if (curHPos + child.width > this.width) {
- curHPos = 0;
+ if (this.flow == this.Flow.LeftToRight) {
+ if (curHPos + child.width > flowWidth) {
+ if (this.$isUsingImplicitWidth == false ) curHPos = 0;
curVPos += rowSize + this.spacing;
rowSize = 0;
}
rowSize = child.height > rowSize ? child.height : rowSize;
child.x = this.layoutDirection == 1
- ? this.width - curHPos - child.width : curHPos;
+ ? flowWidth - curHPos - child.width : curHPos;
child.y = curVPos;
curHPos += child.width + this.spacing;
} else {
- if (curVPos + child.height > this.height) {
- curVPos = 0;
+ if (curVPos + child.height > flowHeight) {
+ if (this.$isUsingImplicitHeight == false ) curVPos = 0;
curHPos += rowSize + this.spacing;
rowSize = 0;
}
rowSize = child.width > rowSize ? child.width : rowSize;
child.x = this.layoutDirection == 1
- ? this.width - curHPos - child.width : curHPos;
+ ? flowWidth - curHPos - child.width : curHPos;
child.y = curVPos;
curVPos += child.height + this.spacing;
}
}
- if (this.flow == 0)
+
+ if (this.$isUsingImplicitHeight)
this.implicitHeight = curVPos + rowSize;
- else
+
+ if (this.$isUsingImplicitWidth)
this.implicitWidth = curHPos + rowSize;
}
@@ -10189,31 +10421,28 @@
});
-registerQmlType({
- module: 'QtQuick',
- name: 'ListElement',
- versions: /.*/,
- constructor: function QMLListElement(meta) {
+function QMLListElement(meta) {
QMLBaseObject.call(this, meta);
for (var i in meta.object) {
if (i[0] != "$") {
createSimpleProperty("variant", this, i);
}
}
applyProperties(meta.object, this, this, this.$context);
- }
-});
+}
registerQmlType({
module: 'QtQuick',
- name: 'ListModel',
+ name: 'ListElement',
versions: /.*/,
- constructor: function QMLListModel(meta) {
+ constructor: QMLListElement
+});
+
+function QMLListModel(meta) {
QMLBaseObject.call(this, meta);
var self = this,
firstItem = true;
- var QMLListElement = getConstructor('QtQuick', '2.0', 'ListElement');
createSimpleProperty("int", this, "count");
createSimpleProperty("list", this, "$items");
@@ -10223,17 +10452,8 @@
this.count = 0;
this.$itemsChanged.connect(this, function(newVal) {
- if (firstItem) {
- firstItem = false;
- var roleNames = [];
- var dict = newVal[0];
- for (var i in (dict instanceof QMLListElement) ? dict.$properties : dict) {
- if (i != "index")
- roleNames.push(i);
- }
- this.$model.setRoleNames(roleNames);
- }
this.count = this.$items.length;
+ updateRoleNames(newVal);
});
this.$model.data = function(index, role) {
@@ -10244,7 +10464,21 @@
}
this.append = function(dict) {
- this.insert(this.$items.length, dict);
+ var index = this.$items.length;
+ var c = 0;
+
+ if (dict instanceof Array){
+ for (var key in dict) {
+ this.$items.push(dict[key]);
+ c++;
+ }
+ }else {
+ this.$items.push(dict);
+ c=1;
+ }
+
+ this.$itemsChanged(this.$items);
+ this.$model.rowsInserted(index, index + c);
}
this.clear = function() {
this.$items = [];
@@ -10257,7 +10491,7 @@
this.insert = function(index, dict) {
this.$items.splice(index, 0, dict);
this.$itemsChanged(this.$items);
- this.$model.rowsInserted(index, index+1);
+ this.$model.rowsInserted(index, index + 1);
}
this.move = function(from, to, n) {
var vals = this.$items.splice(from, n);
@@ -10273,11 +10507,34 @@
}
this.set = function(index, dict) {
this.$items[index] = dict;
+ engine.$requestDraw();
}
this.setProperty = function(index, property, value) {
this.$items[index][property] = value;
+ engine.$requestDraw();
}
- }
+
+ function updateRoleNames(newVal){
+ if (firstItem && newVal.length > 0 ) {
+ firstItem = false;
+ var roleNames = [];
+ var dict = newVal[0];
+
+ for (var i in (dict instanceof QMLListElement) ? dict.$properties : dict) {
+ if (i != "index")
+ roleNames.push(i);
+ }
+
+ self.$model.setRoleNames(roleNames);
+ }
+ }
+}
+
+registerQmlType({
+ module: 'QtQuick',
+ name: 'ListModel',
+ versions: /.*/,
+ constructor: QMLListModel
});
registerQmlType({
@@ -10322,6 +10579,144 @@
}
});
+/**
+ *
+ * Loader is used to dynamically load QML components.
+ *
+ * Loader can load a QML file (using the source property)
+ * or a Component object (using the sourceComponent property).
+ * It is useful for delaying the creation of a component until
+ * it is required: for example, when a component should be created
+ * on demand, or when a component should not be created unnecessarily
+ * for performance reasons.
+ *
+ */
+
+registerQmlType({
+ module: 'QtQuick',
+ name: 'Loader',
+ versions: /.*/,
+ constructor: function(meta) {
+ QMLItem.call(this, meta);
+
+ var self = this;
+
+ createSimpleProperty('bool', this, 'active'); //totest
+ createSimpleProperty('bool', this, 'asynchronous'); //todo
+ createSimpleProperty('var', this, 'item');
+ createSimpleProperty('real', this, 'progress'); //todo
+ createSimpleProperty('url', this, 'source');
+ createSimpleProperty('Component', this, 'sourceComponent'); //totest
+ createSimpleProperty('enum', this, 'status');
+
+
+ this.active = true;
+ this.asynchronous = false;
+ this.item = undefined;
+ this.progress = 0.0;
+ this.source = undefined;
+ this.sourceComponent = undefined;
+ this.status = 1;
+ this.sourceUrl = '';
+
+ this.loaded = Signal();
+
+ implicitWidth = this.item ? this.item.width : 0;
+ implicitHeight = this.item ? this.item.height : 0;
+
+ this.activeChanged.connect( function(newVal) {
+
+ if (self.active){
+ if (self.source)
+ sourceChanged();
+ else if (self.sourceComponent)
+ sourceComponentChanged();
+ }else{
+ unload();
+ }
+ });
+
+ this.sourceChanged.connect( function(newVal) {
+ if (self.active == false )//|| (newVal == self.sourceUrl && self.item !== undefined) ) //todo
+ {
+ console.log( " Loader isn't active.");
+ return;
+ }
+
+ unload();
+
+ if (self.source.length>0) {
+ var fileName = newVal.lastIndexOf(".qml") == newVal.length-4 ? newVal.substring(0, newVal.length-4) : "";
+
+ if ( fileName !== "" ) {
+ var tree = engine.loadComponent(fileName);
+
+ var component = new QMLComponent({ object: tree, context: self , parent: self});
+ var loadedComponent = component.createObject(self);
+
+ loadedComponent.parent = self;
+ component.finalizeImports();
+
+ self.childrenChanged();
+
+ if (engine.operationState !== QMLOperationState.Init) {
+ // We don't call those on first creation, as they will be called
+ // by the regular creation-procedures at the right time.
+ engine.$initializePropertyBindings();
+ callOnCompleted(loadedComponent);
+ }
+
+ self.sourceComponent = loadedComponent;
+ self.sourceUrl = newVal;
+ }
+ }
+
+ } );
+
+ this.sourceComponentChanged.connect(function(newVal) {
+
+ if ( self.active == false ) {
+ return;
+ }
+
+ self.item = newVal;
+
+ if (self.item){
+ if (!self.$isUsingImplicitWidth) {
+ self.item.width = self.width;
+ }
+ if (!self.$isUsingImplicitHeight) {
+ self.item.height = self.height;
+ }
+
+ self.loaded();
+ }
+ } );
+
+ function unload(){
+ if (self.item){
+
+ self.item.$delete();
+ self.item.parent = undefined;
+ self.item = undefined;
+ }
+ }
+
+ function callOnCompleted(child) {
+ child.Component.completed();
+ for (var i = 0; i < child.children.length; i++)
+ callOnCompleted(child.children[i]);
+ }
+
+ this.setSource = function(url, options) {
+ this.sourceUrl = url;
+ this.props = options;
+ this.source = url;
+ }
+
+ }
+});
+
registerQmlType({
module: 'QtQuick',
name: 'MouseArea',
@@ -10345,6 +10740,9 @@
createSimpleProperty("real", this, "mouseY");
createSimpleProperty("bool", this, "pressed");
createSimpleProperty("bool", this, "containsMouse");
+ createSimpleProperty("enum", this, "cursorShape");
+
+
this.clicked = Signal([{type: "variant", name: "mouse"}]);
this.entered = Signal();
this.exited = Signal();
@@ -10354,7 +10752,8 @@
this.enabled = true;
this.hoverEnabled = false;
this.containsMouse = false;
-
+ this.cursorShape = Qt.ArrowCursor;
+
function eventToMouse(e) {
return {
accepted: true,
@@ -10400,14 +10799,56 @@
self.containsMouse = false;
self.exited();
}
+ this.dom.onmouseover = function(e) {
+ self.containsMouse = true;
+ self.dom.style.cursor = cursorShapeToCSS();
+ self.entered();
+ }
+ this.dom.onmouseout = function(e) {
+ self.containsMouse = false;
+ self.dom.style.cursor = "auto";
+ self.exited();
+ }
this.dom.onmousemove = function(e) {
if (self.enabled && (self.hoverEnabled || self.pressed)) {
var mouse = eventToMouse(e);
self.positionChanged(mouse);
self.mouseX = mouse.x;
self.mouseY = mouse.y;
}
}
+
+ function cursorShapeToCSS(){
+ var cursor = "auto";
+ switch (self.cursorShape) {
+ case Qt.ArrowCursor: cursor = "default"; break;
+ case Qt.UpArrowCursor: cursor = "auto";break;
+ case Qt.CrossCursor: cursor = "crosshair";break;
+ case Qt.WaitCursor: cursor = "wait";break;
+ case Qt.IBeamCursor: cursor = "auto";break;
+ case Qt.SizeVerCursor: cursor = "auto";break;
+ case Qt.SizeHorCursor: cursor = "auto";break;
+ case Qt.SizeBDiagCursor: cursor = "auto";break;
+ case Qt.SizeFDiagCursor: cursor = "auto";break;
+ case Qt.SizeAllCursor: cursor = "auto";break;
+ case Qt.BlankCursor: cursor = "auto";break;
+ case Qt.SplitVCursor: cursor = "auto";break;
+ case Qt.SplitHCursor: cursor = "auto";break;
+ case Qt.PointingHandCursor: cursor = "pointer";break;
+ case Qt.ForbiddenCursor: cursor = "not-allowed";break;
+ case Qt.WhatsThisCursor: cursor = "auto";break;
+ case Qt.BusyCursor: cursor = "progress";break;
+ case Qt.OpenHandCursor: cursor = "auto";break;
+ case Qt.ClosedHandCursor: cursor = "move";break;
+ case Qt.DragCopyCursor: cursor = "auto";break;
+ case Qt.DragMoveCursor: cursor = "auto";break;
+ case Qt.DragLinkCursor: cursor = "auto";break;
+ case Qt.LastCursor: cursor = "auto";break;
+ case Qt.BitmapCursor: cursor = "auto";break;
+ case Qt.CustomCursor: cursor = "auto"; break;
+ }
+ return cursor;
+ }
}
});
@@ -10856,8 +11297,11 @@
constructor: function QMLRepeater(meta) {
QMLItem.call(this, meta);
var self = this;
+
var QMLListModel = getConstructor('QtQuick', '2.0', 'ListModel');
+ this.parent = meta.parent; // TODO: some (all ?) of the components including Repeater needs to know own parent at creation time. Please consider this major change.
+
createSimpleProperty("Component", this, "delegate");
this.container = function() { return this.parent; }
this.$defaultProperty = "delegate";
@@ -10869,8 +11313,8 @@
this.modelChanged.connect(applyModel);
this.delegateChanged.connect(applyModel);
+ this.childrenChanged.connect
- this.model = 0;
this.count = 0;
this.itemAt = function(index) {
@@ -10883,20 +11327,31 @@
callOnCompleted(child.children[i]);
}
function insertChildren(startIndex, endIndex) {
- for (var index = startIndex; index < endIndex; index++) {
+ var index = 0;
+ var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
+
+ for ( index = startIndex; index < endIndex; index++) {
var newItem = self.delegate.createObject(self);
+ newItem.parent = self; // Repeater children
+ self.delegate.finalizeImports(); // To properly import JavaScript in the context of a component
createSimpleProperty("int", newItem, "index");
- var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
- for (var i in model.roleNames) {
- if (typeof newItem.$properties[model.roleNames[i]] == 'undefined')
- createSimpleProperty("variant", newItem, model.roleNames[i]);
- newItem.$properties[model.roleNames[i]].set(model.data(index, model.roleNames[i]), true, newItem, self.model.$context);
+
+ if ( typeof model == "number" || model instanceof Array ) {
+ if (typeof newItem.$properties["modelData"] == 'undefined'){
+ createSimpleProperty("variant", newItem, "modelData");
+ }
+
+ var value = model instanceof Array ? model[index] : typeof model == "number" ? index : "undefined";
+ newItem.$properties["modelData"].set(value, true, newItem, model.$context);
+ } else {
+ for (var i in model.roleNames) {
+ if (typeof newItem.$properties[model.roleNames[i]] == 'undefined')
+ createSimpleProperty("variant", newItem, model.roleNames[i]);
+ newItem.$properties[model.roleNames[i]].set(model.data(index, model.roleNames[i]), true, newItem, self.model.$context);
+ }
}
-
- self.container().children.splice(self.parent.children.indexOf(self) - self.$items.length + index, 0, newItem);
- newItem.parent = self.container();
- self.container().childrenChanged();
+
self.$items.splice(index, 0, newItem);
newItem.index = index;
@@ -10908,6 +11363,11 @@
callOnCompleted(newItem);
}
}
+
+ if (index > 0) {
+ self.container().childrenChanged();
+ }
+
for (var i = endIndex; i < self.$items.length; i++)
self.$items[i].index = i;
@@ -10917,7 +11377,9 @@
function applyModel() {
if (!self.delegate)
return;
+
var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
+
if (model instanceof JSItemModel) {
model.dataChanged.connect(function(startIndex, endIndex) {
//TODO
@@ -10950,9 +11412,14 @@
} else if (typeof model == "number") {
removeChildren(0, self.$items.length);
insertChildren(0, model);
- }
+ } else if (model instanceof Array) {
+ removeChildren(0, self.$items.length);
+ insertChildren(0, model.length);
+ }
+
}
+
function removeChildren(startIndex, endIndex) {
var removed = self.$items.splice(startIndex, endIndex - startIndex);
for (var index in removed) {
@@ -10968,7 +11435,6 @@
}
}
});
-
registerQmlType({
module: 'QtQuick',
name: 'Rotation',
@@ -11024,25 +11490,48 @@
}
QMLRow.prototype.layoutChildren = function() {
- var curPos = 0,
- maxHeight = 0,
- // When layoutDirection is RightToLeft we need oposite order
- i = this.layoutDirection == 1 ? this.children.length - 1 : 0,
- endPoint = this.layoutDirection == 1 ? -1 : this.children.length,
+ var curPos = 0, maxHeight = 0;
+ var children = [];
+ var child = undefined;
+ var QMLRepeater = getConstructor('QtQuick', '2.0', 'Repeater');
+
+ for (var key in this.children){
+ child = this.children[key];
+
+ if ( child instanceof QMLRepeater) {
+ children = children.concat(child.children);
+ }
+ else{
+ children.push(child);
+ }
+ }
+
+ if (children.length == 0) return;
+
+ // When layoutDirection is RightToLeft we need oposite order
+ var i = this.layoutDirection == 1 ? children.length - 1 : 0,
+ endPoint = this.layoutDirection == 1 ? -1 : children.length,
step = this.layoutDirection == 1 ? -1 : 1;
+
+ var rowWidth = this.$isUsingImplicitWidth ? this.implicitWidth : this.width;
+ var rowHeight = this.$isUsingImplicitHeight ? this.implicitHeight : this.height;
+
for (; i !== endPoint; i += step) {
- var child = this.children[i];
+ child = children[i];
+
if (!(child.visible && child.opacity && child.width && child.height))
continue;
+
maxHeight = child.height > maxHeight ? child.height : maxHeight;
child.x = curPos;
curPos += child.width + this.spacing;
}
+
this.implicitHeight = maxHeight;
this.implicitWidth = curPos - this.spacing; // We want no spacing at the right side
+
}
-
registerQmlType({
module: 'QtQuick',
name: 'Scale',
@@ -11498,22 +11987,26 @@
var self = this;
- this.font = new getConstructor('QtQuick', '2.0', 'Font')(this);
+ var QMLFont = new getConstructor('QtQuick', '2.0', 'Font');
+ this.font = new QMLFont(this);
this.dom.innerHTML = ""
this.dom.firstChild.style.pointerEvents = "auto";
// In some browsers text-inputs have a margin by default, which distorts
// the positioning, so we need to manually set it to 0.
this.dom.firstChild.style.margin = "0";
+ this.dom.firstChild.style.padding = "0";
this.dom.firstChild.style.width = "100%";
+ this.dom.firstChild.style.height = "100%";
this.setupFocusOnDom(this.dom.firstChild);
createSimpleProperty("string", this, "text");
createSimpleProperty("int", this, "maximumLength");
createSimpleProperty("bool", this, "readOnly");
createSimpleProperty("var", this, "validator");
createSimpleProperty("enum", this, "echoMode");
+
this.accepted = Signal();
this.readOnly = false;
this.maximumLength = -1;
@@ -11711,6 +12204,43 @@
});
registerQmlType({
+ module: 'QtQuick',
+ name: 'Screen',
+ versions: /.*/,
+ constructor: QMLScreen
+});
+
+function QMLScreen(meta) {
+ QMLItem.call(this, meta);
+ var self = this;
+
+ createSimpleProperty("int", this, "desktopAvailableHeight");
+ createSimpleProperty("int", this, "desktopAvailableWidth");
+ createSimpleProperty("real", this, "devicePixelRatio");
+ createSimpleProperty("int", this, "height");
+ createSimpleProperty("string", this, "name");
+ createSimpleProperty("enum", this, "orientation");
+ createSimpleProperty("enum", this, "orientationUpdateMask");
+ createSimpleProperty("real", this, "pixelDensity");
+ createSimpleProperty("enum", this, "primaryOrientation");
+ createSimpleProperty("int", this, "width");
+
+ this.Component.completed.connect(this, updateSC);
+
+ function updateSC() {
+ self.desktopAvailableHeight = window.outerHeight;
+ self.desktopAvailableWidth = window.outerWidth;
+ self.devicePixelRatio = window.devicePixelRatio;
+ self.height = window.innerHeight;
+ self.name = this.name;
+ self.orientation = Qt.PrimaryOrientation;
+ self.orientationUpdateMask = 0;
+ self.pixelDensity = 100.0; // TODO
+ self.primaryOrientation = Qt.PrimaryOrientation;
+ self.width = window.innerWidth;
+ }
+}
+registerQmlType({
module: 'QmlWeb',
name: 'RestModel',
versions: /.*/,
diff --git a/readme_gulp b/readme_gulp
new file mode 100644
--- /dev/null
+++ b/readme_gulp
@@ -0,0 +1,8 @@
+
+To rebuild library run
+
+./node_modules/.bin/gulp qt
+
+or
+
+./node_modules/.bin/gulp qt.min
diff --git a/src/qtcore/qml/AutoLoader.js b/src/qtcore/qml/AutoLoader.js
--- a/src/qtcore/qml/AutoLoader.js
+++ b/src/qtcore/qml/AutoLoader.js
@@ -7,7 +7,7 @@
if (source != null) {
global.qmlEngine = new QMLEngine();
- qmlEngine.loadFile(source);
+ qmlEngine.loadFile(source, null);
qmlEngine.start();
break ;
}
diff --git a/src/qtcore/qml/QMLBaseObject.js b/src/qtcore/qml/QMLBaseObject.js
--- a/src/qtcore/qml/QMLBaseObject.js
+++ b/src/qtcore/qml/QMLBaseObject.js
@@ -59,3 +59,9 @@
this.getAttributes = function() { return (attributes); }
}
+registerQmlType({
+ module: 'QtQuick',
+ name: 'QtObject',
+ versions: /.*/,
+ constructor: QMLBaseObject
+});
diff --git a/src/qtcore/qml/QMLEngine.js b/src/qtcore/qml/QMLEngine.js
--- a/src/qtcore/qml/QMLEngine.js
+++ b/src/qtcore/qml/QMLEngine.js
@@ -44,7 +44,7 @@
var i;
if (this.operationState !== QMLOperationState.Running) {
this.operationState = QMLOperationState.Running;
- tickerId = setInterval(tick, this.$interval);
+ tickerId = setInterval(tick, this.$interval); // TODO: considering performance: shouldn't it we start only when we have active animation
for (i = 0; i < whenStart.length; i++) {
whenStart[i]();
}
@@ -77,36 +77,40 @@
if (!qrc.includesFile(file)) {
var src = getUrlContents(file);
- console.log('loading file', file);
- qrc[file] = qmlparse(src);
+ if (src) {
+ console.log('Loading file [', file,']');
+ qrc[file] = qmlparse(src);
+ }else {
+ console.log('Can nor load file [', file,']');
+ }
}
}
-
+
// Load file, parse and construct (.qml or .qml.js)
- this.loadFile = function(file) {
+ this.loadFile = function(file, parentComponent) {
var tree;
basePath = this.pathFromFilepath(file);
this.basePath = basePath;
this.ensureFileIsLoadedInQrc(file);
tree = convertToEngine(qrc[file]);
- this.loadQMLTree(tree);
+ return this.loadQMLTree(tree, parentComponent);
}
// parse and construct qml
this.loadQML = function(src) {
- this.loadQMLTree(parseQML(src));
+ this.loadQMLTree(parseQML(src), null);
}
- this.loadQMLTree = function(tree) {
+ this.loadQMLTree = function(tree, parentComponent) {
engine = this;
if (options.debugTree) {
options.debugTree(tree);
}
// Create and initialize objects
- var component = new QMLComponent({ object: tree, parent: null });
- doc = component.createObject(null);
+ var component = new QMLComponent({ object: tree, parent: parentComponent });
+ doc = component.createObject(parentComponent);
component.finalizeImports();
this.$initializePropertyBindings();
@@ -116,10 +120,12 @@
for (var i in this.completedSignals) {
this.completedSignals[i]();
}
+
+ return component;
}
this.rootContext = function() {
- return doc.$context;
+ return global.qmlEngine.doc.$context;
}
this.focusedElement = (function() {
@@ -264,13 +270,19 @@
}
this.$initializePropertyBindings = function() {
+ var property;
+
// Initialize property bindings
for (var i = 0; i < this.bindedProperties.length; i++) {
- var property = this.bindedProperties[i];
- property.binding.compile();
+ property = this.bindedProperties[i];
+ if (!property) continue;
+
+ if (property.binding != null) {
+ property.binding.compile();
+ }
property.update();
}
- this.bindedProperties = [];
+ this.bindedProperties.length = 0;
}
this.$getTextMetrics = function(text, fontCss)
diff --git a/src/qtcore/qml/QMLList.js b/src/qtcore/qml/QMLList.js
--- a/src/qtcore/qml/QMLList.js
+++ b/src/qtcore/qml/QMLList.js
@@ -1,10 +1,12 @@
+
function QMLList(meta) {
var list = [];
- if (meta.object instanceof Array)
- for (var i in meta.object)
+ if (meta.object instanceof Array) {
+ for (var i=0;i 0) {
- var item = this.$tidyupList[0];
- if (item.$delete) // It's a QObject
+ item = this.$tidyupList[0];
+ if (item.$delete) {// It's a QObject
item.$delete();
+ item.parent = undefined;
+ }
else // It must be a signal
item.disconnect(this);
}
+ var prop;
for (var i in this.$properties) {
- var prop = this.$properties[i];
+ prop = this.$properties[i];
while (prop.$tidyupList.length > 0)
prop.$tidyupList[0].disconnect(prop);
}
diff --git a/src/qtcore/qml/UpdateGeometry.js b/src/qtcore/qml/UpdateGeometry.js
--- a/src/qtcore/qml/UpdateGeometry.js
+++ b/src/qtcore/qml/UpdateGeometry.js
@@ -95,6 +95,8 @@
this.width = width;
this.$updatingGeometry = false;
+
+ if (this.parent != undefined) updateChildrenRect(this.parent);
}
function updateVGeometry(newVal, oldVal, propName) {
@@ -194,6 +196,39 @@
this.height = height;
this.$updatingGeometry = false;
+
+ if (this.parent != undefined) updateChildrenRect(this.parent);
}
+function updateChildrenRect(component){
+
+ var children = component !== undefined ? component.children : undefined
+ if ( children == undefined || children.length == 0 )
+ return;
+
+ var maxWidth = 0;
+ var maxHeight = 0;
+ var minX = children.length>0 ? children[0].x : 0;
+ var minY = children.length>0 ? children[0].y : 0;
+ var h=0;
+ var w=0;
+ var child;
+
+ for (var i=0;i" + elt[j] + "";
+ //}
+ //else
+ html += "";
+ }
+ html += tail;
+ return html;
+ };
+
+ this.accepted = Signal();
+ this.activated = Signal([{type: "int", name: "index"}]);
+
+ this.find = function(text) {
+ return self.model.indexOf(text)
+ };
+ this.selectAll = function () {}; // TODO
+ this.textAt = function(index) {
+ return this.model[index];
+ };
+
+ this.Component.completed.connect(this, function () {
+ this.dom.innerHTML = updateCB();
+ var child = this.dom.firstChild;
+ this.implicitWidth = child.offsetWidth;
+ this.implicitHeight = child.offsetHeight;
+ });
+
+ this.modelChanged.connect(updateCB);
+
+ this.dom.onclick = function (e) {
+ var index = self.dom.firstChild.selectedIndex;
+ self.currentIndex = index ;
+ self.currentText = self.model[index];
+ self.accepted();
+ self.activated(index);
+ };
+}
\ No newline at end of file
diff --git a/src/qtcore/qml/elements/QtQuick.Controls/ScrollView.js b/src/qtcore/qml/elements/QtQuick.Controls/ScrollView.js
new file mode 100644
--- /dev/null
+++ b/src/qtcore/qml/elements/QtQuick.Controls/ScrollView.js
@@ -0,0 +1,108 @@
+registerQmlType({
+ module: 'QtQuick.Controls',
+ name: 'ScrollView',
+ versions: /.*/,
+ constructor: function QMLScrollView(meta) {
+ QMLItem.call(this, meta);
+
+ var self = this;
+
+
+ this.dom.style.pointerEvents = "auto";
+ this.setupFocusOnDom(this.dom);
+
+ createSimpleProperty("Item", this, "contentItem");
+ this.$defaultProperty = "contentItem";
+ createSimpleProperty("Item", this, "flickableItem"); //TODO 0) implement it 1) make it read-only
+ createSimpleProperty("Item", this, "viewport"); //TODO
+ createSimpleProperty("bool", this, "frameVisible");
+ createSimpleProperty("bool", this, "highlightOnFocus"); //TODO test
+ createSimpleProperty("enum", this, "verticalScrollBarPolicy");
+ createSimpleProperty("enum", this, "horizontalScrollBarPolicy");
+ createSimpleProperty("Component", this, "style"); //TODO
+
+
+ this.contentItemChanged.connect(this, function(newItem){
+ if (typeof newItem !== undefined)
+ {
+ newItem.parent = self;
+ }
+ });
+ this.flickableItemChanged.connect(this, function(newItem){});
+
+ this.viewportChanged.connect(this, function(newViewport){});
+
+ this.frameVisibleChanged.connect(this, function(visible){
+ this.dom.style.border= visible ? "1px solid gray" : "hidden";
+ });
+ this.highlightOnFocusChanged.connect(this, function(highlight){
+
+ });
+
+ this.horizontalScrollBarPolicyChanged.connect(this, function(newPolicy){
+ var newVal = "auto";
+ switch (newPolicy){
+ case Qt.ScrollBarAsNeeded:{
+ newVal = "auto";
+ break;
+ }
+ case Qt.ScrollBarAlwaysOff:{
+ newVal = "hidden";
+ break;
+ }
+ case Qt.ScrollBarAlwaysOn:{
+ newVal = "scroll";
+ break;
+ }
+ }
+
+ this.dom.style.overflowX = newVal;
+ });
+ this.verticalScrollBarPolicyChanged.connect(this, function(newPolicy){
+ var newVal = "auto";
+ switch (newPolicy){
+ case Qt.ScrollBarAsNeeded:{
+ newVal = "auto";
+ break;
+ }
+ case Qt.ScrollBarAlwaysOff:{
+ newVal = "hidden";
+ break;
+ }
+ case Qt.ScrollBarAlwaysOn:{
+ newVal= "scroll";
+ break;
+ }
+ }
+
+ this.dom.style.overflowY = newVal;
+ });
+
+ this.styleChanged.connect(this, function(newStyle){});
+
+ ////
+ this.childrenChanged.connect(this, function(){
+ if (typeof self.contentItem == undefined && self.children.length == 1){
+ self.contentItem = self.children[0];
+ }
+ });
+ this.focusChanged.connect(this, function(focus){
+ this.dom.style.outline = self.highlight && focus ? "outline: lightblue solid 2px;" : "";
+ });
+
+ this.width = this.implicitWidth = 240; // default QML ScrollView width
+ this.height = this.implicitHeight = 150; // default QML ScrollView height
+ this.width = this.implicitWidth;
+ this.height = this.implicitHeight;
+
+ this.contentItem = undefined;
+ this.flickableItem = undefined;
+ this.viewport = undefined;
+ this.frameVisible = false;
+ this.highlightOnFocus = false;
+ this.verticalScrollBarPolicy = Qt.ScrollBarAsNeeded;
+ this.horizontalScrollBarPolicy = Qt.ScrollBarAsNeeded;
+ this.style = undefined;
+
+ }
+});
diff --git a/src/qtcore/qml/elements/QtQuick.Window/Screen.js b/src/qtcore/qml/elements/QtQuick.Window/Screen.js
new file mode 100644
--- /dev/null
+++ b/src/qtcore/qml/elements/QtQuick.Window/Screen.js
@@ -0,0 +1,37 @@
+registerQmlType({
+ module: 'QtQuick',
+ name: 'Screen',
+ versions: /.*/,
+ constructor: QMLScreen
+});
+
+function QMLScreen(meta) {
+ QMLItem.call(this, meta);
+ var self = this;
+
+ createSimpleProperty("int", this, "desktopAvailableHeight");
+ createSimpleProperty("int", this, "desktopAvailableWidth");
+ createSimpleProperty("real", this, "devicePixelRatio");
+ createSimpleProperty("int", this, "height");
+ createSimpleProperty("string", this, "name");
+ createSimpleProperty("enum", this, "orientation");
+ createSimpleProperty("enum", this, "orientationUpdateMask");
+ createSimpleProperty("real", this, "pixelDensity");
+ createSimpleProperty("enum", this, "primaryOrientation");
+ createSimpleProperty("int", this, "width");
+
+ this.Component.completed.connect(this, updateSC);
+
+ function updateSC() {
+ self.desktopAvailableHeight = window.outerHeight;
+ self.desktopAvailableWidth = window.outerWidth;
+ self.devicePixelRatio = window.devicePixelRatio;
+ self.height = window.innerHeight;
+ self.name = this.name;
+ self.orientation = Qt.PrimaryOrientation;
+ self.orientationUpdateMask = 0;
+ self.pixelDensity = 100.0; // TODO
+ self.primaryOrientation = Qt.PrimaryOrientation;
+ self.width = window.innerWidth;
+ }
+}
\ No newline at end of file
diff --git a/src/qtcore/qml/elements/QtQuick/Column.js b/src/qtcore/qml/elements/QtQuick/Column.js
--- a/src/qtcore/qml/elements/QtQuick/Column.js
+++ b/src/qtcore/qml/elements/QtQuick/Column.js
@@ -3,19 +3,29 @@
}
QMLColumn.prototype.layoutChildren = function() {
- var curPos = 0,
- maxWidth = 0;
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i];
- if (!(child.visible && child.opacity && child.width && child.height))
+ var curPos = 0, maxWidth = 0;
+ var children = this.children;
+ var child = undefined;
+ var childWidth =0, childHeight = 0;
+ var i,l = children.length;
+ if ( l == 0) return;
+
+ for (i = 0; i < l; i++) {
+ child = children[i];
+ childHeight = child.$isUsingImplicitHeight ? child.implicitHeight : child.height;
+ childWidth = child.$isUsingImplicitWidth ? child.implicitWidth : child.width;
+
+ if (!(child.visible && childWidth && childHeight)) {
continue;
- maxWidth = child.width > maxWidth ? child.width : maxWidth;
-
+ }
+
+ maxWidth = childWidth > maxWidth ? childWidth : maxWidth;
child.y = curPos;
- curPos += child.height + this.spacing;
+ curPos += childHeight + this.spacing;
}
- this.implicitWidth = maxWidth;
- this.implicitHeight = curPos - this.spacing; // We want no spacing at the bottom side
+
+ if (this.$isUsingImplicitWidth) this.implicitWidth = maxWidth;
+ if (this.$isUsingImplicitHeight) this.implicitHeight = curPos - this.spacing; // We want no spacing at the bottom side
}
registerQmlType({
diff --git a/src/qtcore/qml/elements/QtQuick/Flow.js b/src/qtcore/qml/elements/QtQuick/Flow.js
--- a/src/qtcore/qml/elements/QtQuick/Flow.js
+++ b/src/qtcore/qml/elements/QtQuick/Flow.js
@@ -11,49 +11,75 @@
this.flowChanged.connect(this, this.layoutChildren);
this.layoutDirectionChanged.connect(this, this.layoutChildren);
this.widthChanged.connect(this, this.layoutChildren);
-
- this.flow = 0;
- this.layoutDirection = 0;
+ this.implicitWidthChanged.connect(this, this.layoutChildren);
+
+ this.flow = this.Flow.LeftToRight;
+ this.layoutDirection = 0 ;
}
QMLFlow.prototype.layoutChildren = function() {
var curHPos = 0,
curVPos = 0,
rowSize = 0;
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i];
- if (!(child.visible && child.opacity && child.width && child.height))
+ var children = [];
+ var child = undefined;
+ var QMLRepeater = getConstructor('QtQuick', '2.0', 'Repeater');
+
+ for (var key in this.children){
+ child = this.children[key];
+
+ if ( child instanceof QMLRepeater) {
+ children = children.concat(child.children);
+ }
+ else{
+ children.push(child);
+ }
+ }
+
+ if (children.length == 0) return;
+
+ var flowWidth = this.$isUsingImplicitWidth ? this.implicitWidth : this.width;
+ var flowHeight = this.$isUsingImplicitHeight ? this.implicitHeight : this.height;
+
+ for (var i=0;i < children.length;i++) {
+ child = children[i];
+ childHeight = child.$isUsingImplicitHeight ? child.implicitHeight : child.height;
+ childWidth = child.$isUsingImplicitWidth ? child.implicitWidth : child.width;
+
+ if (!(child.visible && childWidth && childHeight))
continue;
- if (this.flow == 0) {
- if (curHPos + child.width > this.width) {
- curHPos = 0;
+ if (this.flow == this.Flow.LeftToRight) {
+ if (curHPos + childWidth > flowWidth) {
+ if (this.$isUsingImplicitWidth == false ) curHPos = 0;
curVPos += rowSize + this.spacing;
rowSize = 0;
}
- rowSize = child.height > rowSize ? child.height : rowSize;
+ rowSize = childHeight > rowSize ? childHeight : rowSize;
child.x = this.layoutDirection == 1
- ? this.width - curHPos - child.width : curHPos;
+ ? flowWidth - curHPos - childWidth : curHPos;
child.y = curVPos;
- curHPos += child.width + this.spacing;
+ curHPos += childWidth + this.spacing;
} else {
- if (curVPos + child.height > this.height) {
- curVPos = 0;
+ if (curVPos + childHeight > flowHeight) {
+ if (this.$isUsingImplicitHeight == false ) curVPos = 0;
curHPos += rowSize + this.spacing;
rowSize = 0;
}
- rowSize = child.width > rowSize ? child.width : rowSize;
+ rowSize = childWidth > rowSize ? childWidth : rowSize;
child.x = this.layoutDirection == 1
- ? this.width - curHPos - child.width : curHPos;
+ ? flowWidth - curHPos - childWidth : curHPos;
child.y = curVPos;
- curVPos += child.height + this.spacing;
+ curVPos += childHeight + this.spacing;
}
}
- if (this.flow == 0)
+
+ if (this.$isUsingImplicitHeight)
this.implicitHeight = curVPos + rowSize;
- else
+
+ if (this.$isUsingImplicitWidth)
this.implicitWidth = curHPos + rowSize;
}
diff --git a/src/qtcore/qml/elements/QtQuick/Grid.js b/src/qtcore/qml/elements/QtQuick/Grid.js
--- a/src/qtcore/qml/elements/QtQuick/Grid.js
+++ b/src/qtcore/qml/elements/QtQuick/Grid.js
@@ -35,11 +35,18 @@
gridHeight = -this.spacing,
curHPos = 0,
curVPos = 0;
-
+ var child =0, childWidth=0,childHeight=0;
+ var item =0, itemWidth=0, itemHeight=0;
+ var i = 0, j = 0;
+ var l = this.children.length;
+
// How many items are actually visible?
- for (var i = 0; i < this.children.length; i++) {
- var child = this.children[i];
- if (child.visible && child.opacity && child.width && child.height)
+ for (i = 0; i < l; i++) {
+ child = this.children[i];
+ childHeight = child.$isUsingImplicitHeight ? child.implicitHeight : child.height;
+ childWidth = child.$isUsingImplicitWidth ? child.implicitWidth : child.width;
+
+ if (child.visible && childWidth && childHeight)
visibleItems.push(this.children[i]);
}
@@ -57,27 +64,29 @@
// How big are the colums/rows?
if (this.flow == 0)
- for (var i = 0; i < r; i++) {
- for (var j = 0; j < c; j++) {
- var item = visibleItems[i*c+j];
- if (!item)
- break;
- if (!colWidth[j] || item.width > colWidth[j])
- colWidth[j] = item.width;
- if (!rowHeight[i] || item.height > rowHeight[i])
- rowHeight[i] = item.height;
+ for (i = 0; i < r; i++) {
+ for (j = 0; j < c; j++) {
+ item = visibleItems[i*c+j];
+ if (!item) break;
+
+ itemHeight = item.$isUsingImplicitHeight ? item.implicitHeight : item.height;
+ itemWidth = item.$isUsingImplicitWidth ? item.implicitWidth : item.width;
+
+ if (!colWidth[j] || itemWidth > colWidth[j]) colWidth[j] = itemWidth;
+ if (!rowHeight[i] || itemHeight > rowHeight[i]) rowHeight[i] = itemHeight;
}
}
else
- for (var i = 0; i < c; i++) {
- for (var j = 0; j < r; j++) {
- var item = visibleItems[i*r+j];
- if (!item)
- break;
- if (!rowHeight[j] || item.height > rowHeight[j])
- rowHeight[j] = item.height;
- if (!colWidth[i] || item.width > colWidth[i])
- colWidth[i] = item.width;
+ for (i = 0; i < c; i++) {
+ for (j = 0; j < r; j++) {
+ item = visibleItems[i*r+j];
+ if (!item) break;
+
+ itemHeight = item.$isUsingImplicitHeight ? item.implicitHeight : item.height;
+ itemWidth = item.$isUsingImplicitWidth ? item.implicitWidth : item.width;
+
+ if (!rowHeight[j] || itemHeight > rowHeight[j]) rowHeight[j] = itemHeight;
+ if (!colWidth[i] || itemWidth > colWidth[i]) colWidth[i] = itemWidth;
}
}
@@ -91,10 +100,11 @@
var step = this.layoutDirection == 1 ? -1 : 1,
startingPoint = this.layoutDirection == 1 ? c - 1 : 0,
endPoint = this.layoutDirection == 1 ? -1 : c;
- if (this.flow == 0)
- for (var i = 0; i < r; i++) {
- for (var j = startingPoint; j !== endPoint; j += step) {
- var item = visibleItems[i*c+j];
+
+ if (this.flow == 0) {
+ for (i = 0; i < r; i++) {
+ for (j = startingPoint; j !== endPoint; j += step) {
+ item = visibleItems[i*c+j];
if (!item)
break;
item.x = curHPos;
@@ -105,10 +115,11 @@
curVPos += rowHeight[i] + this.spacing;
curHPos = 0;
}
- else
- for (var i = startingPoint; i !== endPoint; i += step) {
- for (var j = 0; j < r; j++) {
- var item = visibleItems[i*r+j];
+ }
+ else {
+ for (i = startingPoint; i !== endPoint; i += step) {
+ for (j = 0; j < r; j++) {
+ item = visibleItems[i*r+j];
if (!item)
break;
item.x = curHPos;
@@ -119,7 +130,8 @@
curHPos += colWidth[i] + this.spacing;
curVPos = 0;
}
-
- this.implicitWidth = gridWidth;
- this.implicitHeight = gridHeight;
+ }
+
+ if (this.$isUsingImplicitWidth) this.implicitWidth = gridWidth;
+ if (this.$isUsingImplicitHeight) this.implicitHeight = gridHeight;
}
diff --git a/src/qtcore/qml/elements/QtQuick/ListElement.js b/src/qtcore/qml/elements/QtQuick/ListElement.js
--- a/src/qtcore/qml/elements/QtQuick/ListElement.js
+++ b/src/qtcore/qml/elements/QtQuick/ListElement.js
@@ -1,15 +1,17 @@
-registerQmlType({
- module: 'QtQuick',
- name: 'ListElement',
- versions: /.*/,
- constructor: function QMLListElement(meta) {
+function QMLListElement(meta) {
QMLBaseObject.call(this, meta);
for (var i in meta.object) {
if (i[0] != "$") {
createSimpleProperty("variant", this, i);
}
}
applyProperties(meta.object, this, this, this.$context);
- }
+}
+
+registerQmlType({
+ module: 'QtQuick',
+ name: 'ListElement',
+ versions: /.*/,
+ constructor: QMLListElement
});
diff --git a/src/qtcore/qml/elements/QtQuick/ListModel.js b/src/qtcore/qml/elements/QtQuick/ListModel.js
--- a/src/qtcore/qml/elements/QtQuick/ListModel.js
+++ b/src/qtcore/qml/elements/QtQuick/ListModel.js
@@ -1,32 +1,20 @@
-registerQmlType({
- module: 'QtQuick',
- name: 'ListModel',
- versions: /.*/,
- constructor: function QMLListModel(meta) {
+function QMLListModel(meta) {
QMLBaseObject.call(this, meta);
var self = this,
firstItem = true;
- var QMLListElement = getConstructor('QtQuick', '2.0', 'ListElement');
+ var QMLListElement = getConstructor('QtQuick', '2.0', 'ListElement');
+
createSimpleProperty("int", this, "count");
createSimpleProperty("list", this, "$items");
this.$defaultProperty = "$items";
this.$items = [];
this.$model = new JSItemModel();
this.count = 0;
this.$itemsChanged.connect(this, function(newVal) {
- if (firstItem) {
- firstItem = false;
- var roleNames = [];
- var dict = newVal[0];
- for (var i in (dict instanceof QMLListElement) ? dict.$properties : dict) {
- if (i != "index")
- roleNames.push(i);
- }
- this.$model.setRoleNames(roleNames);
- }
this.count = this.$items.length;
+ updateRoleNames(newVal);
});
this.$model.data = function(index, role) {
@@ -37,20 +25,34 @@
}
this.append = function(dict) {
- this.insert(this.$items.length, dict);
+ var index = this.$items.length;
+ var c = 0;
+
+ if (dict instanceof Array){
+ for (var key in dict) {
+ this.$items.push(dict[key]);
+ c++;
+ }
+ }else {
+ this.$items.push(dict);
+ c=1;
+ }
+
+ this.$itemsChanged(this.$items);
+ this.$model.rowsInserted(index, index + c);
}
this.clear = function() {
- this.$items = [];
this.$model.modelReset();
+ this.$items.length = 0;
this.count = 0;
}
this.get = function(index) {
return this.$items[index];
}
this.insert = function(index, dict) {
this.$items.splice(index, 0, dict);
this.$itemsChanged(this.$items);
- this.$model.rowsInserted(index, index+1);
+ this.$model.rowsInserted(index, index + 1);
}
this.move = function(from, to, n) {
var vals = this.$items.splice(from, n);
@@ -66,9 +68,32 @@
}
this.set = function(index, dict) {
this.$items[index] = dict;
+ engine.$requestDraw();
}
this.setProperty = function(index, property, value) {
this.$items[index][property] = value;
+ engine.$requestDraw();
+ }
+
+ function updateRoleNames(newVal){
+ if (firstItem && newVal.length > 0 ) {
+ firstItem = false;
+ var roleNames = [];
+ var dict = newVal[0];
+
+ for (var i in (dict instanceof QMLListElement) ? dict.$properties : dict) {
+ if (i != "index")
+ roleNames.push(i);
+ }
+
+ self.$model.setRoleNames(roleNames);
+ }
}
- }
+}
+
+registerQmlType({
+ module: 'QtQuick',
+ name: 'ListModel',
+ versions: /.*/,
+ constructor: QMLListModel
});
diff --git a/src/qtcore/qml/elements/QtQuick/Loader.js b/src/qtcore/qml/elements/QtQuick/Loader.js
new file mode 100644
--- /dev/null
+++ b/src/qtcore/qml/elements/QtQuick/Loader.js
@@ -0,0 +1,169 @@
+/**
+ *
+ * Loader is used to dynamically load QML components.
+ *
+ * Loader can load a QML file (using the source property)
+ * or a Component object (using the sourceComponent property).
+ * It is useful for delaying the creation of a component until
+ * it is required: for example, when a component should be created
+ * on demand, or when a component should not be created unnecessarily
+ * for performance reasons.
+ *
+ */
+
+registerQmlType({
+ module: 'QtQuick',
+ name: 'Loader',
+ versions: /.*/,
+ constructor: function QMLLoader(meta) {
+ QMLItem.call(this, meta);
+
+ var self = this;
+
+ createSimpleProperty('bool', this, 'active'); //totest
+ createSimpleProperty('bool', this, 'asynchronous'); //todo
+ createSimpleProperty('var', this, 'item');
+ createSimpleProperty('real', this, 'progress'); //todo
+ createSimpleProperty('url', this, 'source');
+ createSimpleProperty('Component', this, 'sourceComponent'); //totest
+ createSimpleProperty('enum', this, 'status');
+
+
+ this.active = true;
+ this.asynchronous = false;
+ this.item = undefined;
+ this.progress = 0.0;
+ this.source = undefined;
+ this.sourceComponent = undefined;
+ this.status = 1;
+ this.sourceUrl = '';
+
+ this.loaded = Signal();
+
+ this.activeChanged.connect( function(newVal) {
+
+ if (self.active){
+ if (self.source)
+ sourceChanged();
+ else if (self.sourceComponent)
+ sourceComponentChanged();
+ }else{
+ unload();
+ }
+ });
+
+ this.sourceChanged.connect( function(newVal) {
+ if (self.active == false )//|| (newVal == self.sourceUrl && self.item !== undefined) ) //todo
+ {
+ console.log( " Loader isn't active.");
+ return;
+ }
+
+ unload();
+
+ if (self.source.length>0) {
+ var fileName = newVal.lastIndexOf(".qml") == newVal.length-4 ? newVal.substring(0, newVal.length-4) : "";
+
+ if ( fileName !== "" ) {
+
+ var tree = engine.loadComponent(fileName);
+ var meta = { object: tree, context: self , parent: self};
+
+ var qmlComponent = new QMLComponent(meta);
+ var loadedComponent = createComponentObject(qmlComponent, self);
+
+ self.sourceComponent = loadedComponent;
+ self.sourceUrl = newVal;
+ }
+ }
+
+ } );
+
+ this.sourceComponentChanged.connect(function(newItem) {
+
+ if ( self.active == false ) {
+ return;
+ }
+
+ unload();
+
+ var qmlComponent = newItem;
+
+ if (newItem instanceof QMLComponent) {
+ var meta = { object: newItem.$metaObject, context: self , parent: self};
+ qmlComponent = construct(meta);
+ }
+
+ qmlComponent.parent = self;
+ self.item = qmlComponent;
+
+ updateGeometry();
+
+ if (self.item){
+ // setTimeout(self.loaded(), 5000)
+ self.loaded();
+ }
+ } );
+
+
+ this.widthChanged.connect(function(newWidth) {updateGeometry();} );
+ this.heightChanged.connect(function(newHeight) {updateGeometry();} );
+
+ function createComponentObject(qmlComponent, parent){
+ var newComponent = qmlComponent.createObject(parent);
+
+ newComponent.parent = parent;
+ qmlComponent.finalizeImports();
+
+ if (engine.operationState !== QMLOperationState.Init) {
+
+ // We don't call those on first creation, as they will be called
+ // by the regular creation-procedures at the right time.
+ engine.$initializePropertyBindings();
+ callOnCompleted(newComponent);
+ }
+
+ return newComponent;
+ }
+
+ function updateGeometry(){
+ // Loader size doesn't exist
+ if (!self.width) {
+ self.width = self.item ? self.item.width : 0;
+ }
+ else{
+ // Loader size exists
+ if (self.item) self.item.width = self.width;
+ }
+
+ if (!self.height) {
+ self.height = self.item ? self.item.height : 0;
+ } else {
+ // Loader size exists
+ if (self.item) self.item.height = self.height;
+ }
+ }
+
+ function unload(){
+ if (self.item){
+ self.item.$delete();
+ self.item.parent = undefined;
+ self.item = undefined;
+ }
+ }
+
+ function callOnCompleted(child) {
+ child.Component.completed();
+ for (var i = 0; i < child.children.length; i++)
+ callOnCompleted(child.children[i]);
+ }
+
+ this.setSource = function(url, options) {
+ this.sourceUrl = url;
+ this.props = options;
+ this.source = url;
+ }
+
+ }
+});
+
diff --git a/src/qtcore/qml/elements/QtQuick/MouseArea.js b/src/qtcore/qml/elements/QtQuick/MouseArea.js
--- a/src/qtcore/qml/elements/QtQuick/MouseArea.js
+++ b/src/qtcore/qml/elements/QtQuick/MouseArea.js
@@ -21,6 +21,9 @@
createSimpleProperty("real", this, "mouseY");
createSimpleProperty("bool", this, "pressed");
createSimpleProperty("bool", this, "containsMouse");
+ createSimpleProperty("enum", this, "cursorShape");
+
+
this.clicked = Signal([{type: "variant", name: "mouse"}]);
this.entered = Signal();
this.exited = Signal();
@@ -30,7 +33,8 @@
this.enabled = true;
this.hoverEnabled = false;
this.containsMouse = false;
-
+ this.cursorShape = Qt.ArrowCursor;
+
function eventToMouse(e) {
return {
accepted: true,
@@ -76,13 +80,55 @@
self.containsMouse = false;
self.exited();
}
+ this.dom.onmouseover = function(e) {
+ self.containsMouse = true;
+ self.dom.style.cursor = cursorShapeToCSS();
+ self.entered();
+ }
+ this.dom.onmouseout = function(e) {
+ self.containsMouse = false;
+ self.dom.style.cursor = "auto";
+ self.exited();
+ }
this.dom.onmousemove = function(e) {
if (self.enabled && (self.hoverEnabled || self.pressed)) {
var mouse = eventToMouse(e);
self.positionChanged(mouse);
self.mouseX = mouse.x;
self.mouseY = mouse.y;
}
}
+
+ function cursorShapeToCSS(){
+ var cursor = "auto";
+ switch (self.cursorShape) {
+ case Qt.ArrowCursor: cursor = "default"; break;
+ case Qt.UpArrowCursor: cursor = "auto";break;
+ case Qt.CrossCursor: cursor = "crosshair";break;
+ case Qt.WaitCursor: cursor = "wait";break;
+ case Qt.IBeamCursor: cursor = "auto";break;
+ case Qt.SizeVerCursor: cursor = "auto";break;
+ case Qt.SizeHorCursor: cursor = "auto";break;
+ case Qt.SizeBDiagCursor: cursor = "auto";break;
+ case Qt.SizeFDiagCursor: cursor = "auto";break;
+ case Qt.SizeAllCursor: cursor = "auto";break;
+ case Qt.BlankCursor: cursor = "auto";break;
+ case Qt.SplitVCursor: cursor = "auto";break;
+ case Qt.SplitHCursor: cursor = "auto";break;
+ case Qt.PointingHandCursor: cursor = "pointer";break;
+ case Qt.ForbiddenCursor: cursor = "not-allowed";break;
+ case Qt.WhatsThisCursor: cursor = "auto";break;
+ case Qt.BusyCursor: cursor = "progress";break;
+ case Qt.OpenHandCursor: cursor = "auto";break;
+ case Qt.ClosedHandCursor: cursor = "move";break;
+ case Qt.DragCopyCursor: cursor = "auto";break;
+ case Qt.DragMoveCursor: cursor = "auto";break;
+ case Qt.DragLinkCursor: cursor = "auto";break;
+ case Qt.LastCursor: cursor = "auto";break;
+ case Qt.BitmapCursor: cursor = "auto";break;
+ case Qt.CustomCursor: cursor = "auto"; break;
+ }
+ return cursor;
+ }
}
});
diff --git a/src/qtcore/qml/elements/QtQuick/Repeater.js b/src/qtcore/qml/elements/QtQuick/Repeater.js
--- a/src/qtcore/qml/elements/QtQuick/Repeater.js
+++ b/src/qtcore/qml/elements/QtQuick/Repeater.js
@@ -5,8 +5,11 @@
constructor: function QMLRepeater(meta) {
QMLItem.call(this, meta);
var self = this;
+
var QMLListModel = getConstructor('QtQuick', '2.0', 'ListModel');
+ this.parent = meta.parent; // TODO: some (all ?) of the components including Repeater needs to know own parent at creation time. Please consider this major change.
+
createSimpleProperty("Component", this, "delegate");
this.container = function() { return this.parent; }
this.$defaultProperty = "delegate";
@@ -18,8 +21,8 @@
this.modelChanged.connect(applyModel);
this.delegateChanged.connect(applyModel);
-
- this.model = 0;
+ this.parentChanged.connect(applyModel);
+
this.count = 0;
this.itemAt = function(index) {
@@ -32,87 +35,138 @@
callOnCompleted(child.children[i]);
}
function insertChildren(startIndex, endIndex) {
- for (var index = startIndex; index < endIndex; index++) {
- var newItem = self.delegate.createObject(self);
+
+ if (endIndex <= 0) return;
+
+ var index = 0;
+ var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
+ var newItem;
+ var l=0;
+ var roleName;
+ var isEngineInit = engine.operationState == QMLOperationState.Init;
+
+ for ( index = startIndex; index < endIndex; index++) {
+ newItem = self.delegate.createObject();
+ newItem.parent = self.parent;
+ self.delegate.finalizeImports(); // To properly import JavaScript in the context of a component
+
createSimpleProperty("int", newItem, "index");
- var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
- for (var i in model.roleNames) {
- if (typeof newItem.$properties[model.roleNames[i]] == 'undefined')
- createSimpleProperty("variant", newItem, model.roleNames[i]);
- newItem.$properties[model.roleNames[i]].set(model.data(index, model.roleNames[i]), true, newItem, self.model.$context);
+ newItem.index = index;
+
+ if ( typeof model == "number" || model instanceof Array ) {
+ if (typeof newItem.$properties["modelData"] == 'undefined'){
+ createSimpleProperty("variant", newItem, "modelData");
+ }
+
+ var value = model instanceof Array ? model[index] : typeof model == "number" ? index : "undefined";
+ newItem.$properties["modelData"].set(value, true, newItem, model.$context);
+ } else {
+ for (var i=0;i 0) {
+ self.container().childrenChanged();
+ }
+
+ l = self.$items.length;
+ for (var i = endIndex; i < l; i++)
self.$items[i].index = i;
- self.count = self.$items.length;
+ self.count = l;
}
+ function onModelDataChanged(startIndex, endIndex) { //TODO
+ }
+ function onRowsMoved(sourceStartIndex, sourceEndIndex, destinationIndex){
+ var i, l;
+ var vals = self.$items.splice(sourceStartIndex, sourceEndIndex-sourceStartIndex);
+
+ for (i = 0; i < vals.length; i++) {
+ self.$items.splice(destinationIndex + i, 0, vals[i]);
+ }
+ var smallestChangedIndex = sourceStartIndex < destinationIndex
+ ? sourceStartIndex : destinationIndex;
+ for (i = smallestChangedIndex; i < self.$items.length; i++) {
+ self.$items[i].index = i;
+ }
+ }
+ function onRowsRemoved(startIndex, endIndex){
+ removeChildren(startIndex, endIndex);
+
+ var l = self.$items.length;
+ for (var i = startIndex; i < l; i++) {
+ self.$items[i].index = i;
+ }
+ self.count = l;
+ }
+ function onModelReset(){
+ var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
+ removeChildren(0, self.$items.length);
+ }
function applyModel() {
- if (!self.delegate)
+
+ if (!self.delegate || !self.parent)
return;
+
+ removeChildren(0, self.$items.length);
+
var model = self.model instanceof QMLListModel ? self.model.$model : self.model;
+
if (model instanceof JSItemModel) {
- model.dataChanged.connect(function(startIndex, endIndex) {
- //TODO
- });
- model.rowsInserted.connect(insertChildren);
- model.rowsMoved.connect(function(sourceStartIndex, sourceEndIndex, destinationIndex) {
- var vals = self.$items.splice(sourceStartIndex, sourceEndIndex-sourceStartIndex);
- for (var i = 0; i < vals.length; i++) {
- self.$items.splice(destinationIndex + i, 0, vals[i]);
- }
- var smallestChangedIndex = sourceStartIndex < destinationIndex
- ? sourceStartIndex : destinationIndex;
- for (var i = smallestChangedIndex; i < self.$items.length; i++) {
- self.$items[i].index = i;
- }
- });
- model.rowsRemoved.connect(function(startIndex, endIndex) {
- removeChildren(startIndex, endIndex);
- for (var i = startIndex; i < self.$items.length; i++) {
- self.$items[i].index = i;
- }
- self.count = self.$items.length;
- });
- model.modelReset.connect(function() {
- removeChildren(0, self.$items.length);
- insertChildren(0, model.rowCount());
- });
-
+
+ if ( model.dataChanged.isConnected(onModelDataChanged) == false ) model.dataChanged.connect(onModelDataChanged);
+ if ( model.rowsInserted.isConnected(insertChildren) == false ) model.rowsInserted.connect(insertChildren);
+ if ( model.rowsMoved.isConnected(onRowsMoved) == false ) model.rowsMoved.connect(onRowsMoved);
+ if ( model.rowsRemoved.isConnected(onRowsRemoved) == false ) model.rowsRemoved.connect(onRowsRemoved);
+ if ( model.modelReset.isConnected(onModelReset) == false ) model.modelReset.connect(onModelReset);
+
insertChildren(0, model.rowCount());
} else if (typeof model == "number") {
- removeChildren(0, self.$items.length);
insertChildren(0, model);
- }
+ } else if (model instanceof Array) {
+ insertChildren(0, model.length);
+ }
+
}
-
+
function removeChildren(startIndex, endIndex) {
var removed = self.$items.splice(startIndex, endIndex - startIndex);
- for (var index in removed) {
- removed[index].$delete();
- removed[index].parent = undefined;
- removeChildProperties(removed[index]);
+ var l = removed.length;
+ var item;
+
+ for (var i=0;i maxHeight ? child.height : maxHeight;
+
+ maxHeight = childHeight > maxHeight ? childHeight : maxHeight;
child.x = curPos;
- curPos += child.width + this.spacing;
+ curPos += childWidth + this.spacing;
}
- this.implicitHeight = maxHeight;
- this.implicitWidth = curPos - this.spacing; // We want no spacing at the right side
-}
+
+ if (this.$isUsingImplicitHeight) this.implicitHeight = maxHeight;
+ if (this.$isUsingImplicitWidth) this.implicitWidth = curPos - this.spacing; // We want no spacing at the right side
+}
\ No newline at end of file
diff --git a/src/qtcore/qml/elements/QtQuick/Text.js b/src/qtcore/qml/elements/QtQuick/Text.js
--- a/src/qtcore/qml/elements/QtQuick/Text.js
+++ b/src/qtcore/qml/elements/QtQuick/Text.js
@@ -8,7 +8,7 @@
// We create another span inside the text to distinguish the actual
// (possibly html-formatted) text from child elements
this.dom.innerHTML = "";
- this.dom.style.pointerEvents = "auto";
+
this.dom.firstChild.style.width = "100%";
this.dom.firstChild.style.height = "100%";
@@ -76,6 +76,7 @@
break;
case 1:
this.dom.firstChild.style.whiteSpace = "pre-wrap";
+ this.dom.firstChild.style.wordWrap = "normal";
break;
case 2:
this.dom.firstChild.style.whiteSpace = "pre-wrap";
@@ -140,44 +141,25 @@
this.wrapMode = this.Text.NoWrap;
this.color = "black";
this.text = "";
-
- this.textChanged.connect(this, updateImplicitHeight);
- this.textChanged.connect(this, updateImplicitWidth);
- this.font.boldChanged.connect(this, updateImplicitHeight);
- this.font.boldChanged.connect(this, updateImplicitWidth);
- this.font.pixelSizeChanged.connect(this, updateImplicitHeight);
- this.font.pixelSizeChanged.connect(this, updateImplicitWidth);
- this.font.pointSizeChanged.connect(this, updateImplicitHeight);
- this.font.pointSizeChanged.connect(this, updateImplicitWidth);
- this.font.familyChanged.connect(this, updateImplicitHeight);
- this.font.familyChanged.connect(this, updateImplicitWidth);
- this.font.letterSpacingChanged.connect(this, updateImplicitHeight);
- this.font.wordSpacingChanged.connect(this, updateImplicitWidth);
-
- this.Component.completed.connect(this, updateImplicitHeight);
- this.Component.completed.connect(this, updateImplicitWidth);
-
- function updateImplicitHeight() {
- var height;
-
- if (this.text === Undefined || this.text === "") {
- height = 0;
+
+ this.textChanged.connect(this, updateImplicit);
+ this.font.boldChanged.connect(this, updateImplicit);
+ this.font.pixelSizeChanged.connect(this, updateImplicit);
+ this.font.pointSizeChanged.connect(this, updateImplicit);
+ this.font.familyChanged.connect(this, updateImplicit);
+ this.font.letterSpacingChanged.connect(this, updateImplicit);
+ this.font.wordSpacingChanged.connect(this, updateImplicit);
+
+ this.Component.completed.connect(this, updateImplicit);
+
+ function updateImplicit() {
+ if (typeof this.text == undefined || this.text === "" || !this.dom) {
+ this.implicitHeigh = this.implicitWidth = 0;
} else {
- height = this.dom ? this.dom.firstChild.offsetHeight : 0;
+ var fc = this.dom.firstChild;
+ this.implicitHeight = fc.offsetHeight;
+ this.implicitWidth = fc.offsetWidth;
}
-
- this.implicitHeight = height;
- }
-
- function updateImplicitWidth() {
- var width;
-
- if (this.text === Undefined || this.text === "")
- width = 0;
- else
- width = this.dom ? this.dom.firstChild.offsetWidth : 0;
-
- this.implicitWidth = width;
}
this.$drawItem = function(c) {
diff --git a/src/qtcore/qml/elements/QtQuick/TextInput.js b/src/qtcore/qml/elements/QtQuick/TextInput.js
--- a/src/qtcore/qml/elements/QtQuick/TextInput.js
+++ b/src/qtcore/qml/elements/QtQuick/TextInput.js
@@ -11,22 +11,26 @@
var self = this;
- this.font = new getConstructor('QtQuick', '2.0', 'Font')(this);
+ var QMLFont = new getConstructor('QtQuick', '2.0', 'Font');
+ this.font = new QMLFont(this);
this.dom.innerHTML = ""
this.dom.firstChild.style.pointerEvents = "auto";
// In some browsers text-inputs have a margin by default, which distorts
// the positioning, so we need to manually set it to 0.
this.dom.firstChild.style.margin = "0";
+ this.dom.firstChild.style.padding = "0";
this.dom.firstChild.style.width = "100%";
+ this.dom.firstChild.style.height = "100%";
this.setupFocusOnDom(this.dom.firstChild);
createSimpleProperty("string", this, "text");
createSimpleProperty("int", this, "maximumLength");
createSimpleProperty("bool", this, "readOnly");
createSimpleProperty("var", this, "validator");
createSimpleProperty("enum", this, "echoMode");
+
this.accepted = Signal();
this.readOnly = false;
this.maximumLength = -1;
diff --git a/src/qtcore/qml/lib/import.js b/src/qtcore/qml/lib/import.js
--- a/src/qtcore/qml/lib/import.js
+++ b/src/qtcore/qml/lib/import.js
@@ -52,7 +52,7 @@
var contents = getUrlContents(file + ".js");
if (contents) {
console.log("Using pre-processed content for " + file);
- return eval("(function(){return "+contents+"})();");
+ return new Function("(function(){return ",contents,"})();");
} else {
contents = getUrlContents(file);
if (contents) {
@@ -181,7 +181,7 @@
src += "}})()";
// evaluate source to get the object.
- return eval(src);
+ return new Function(src);
}
/**
diff --git a/src/qtcore/qml/lib/parser.js b/src/qtcore/qml/lib/parser.js
--- a/src/qtcore/qml/lib/parser.js
+++ b/src/qtcore/qml/lib/parser.js
@@ -1680,6 +1680,12 @@
},
"name": function(src) {
return bindout(tree, src);
+ },
+ "string": function(src) {
+ return src;
+ },
+ "num": function(src) {
+ return src;
}
};
diff --git a/src/qtcore/qml/qml.js b/src/qtcore/qml/qml.js
--- a/src/qtcore/qml/qml.js
+++ b/src/qtcore/qml/qml.js
@@ -168,34 +168,57 @@
* @return {Object} New qml object
*/
function construct(meta) {
- var item,
- cTree;
-
+ var item = 0,
+ cTree = 0;
+
if (meta.object.$class in constructors) {
item = new constructors[meta.object.$class](meta);
+
} else if (cTree = engine.loadComponent(meta.object.$class)) {
- if (cTree.$children.length !== 1)
+ if (cTree.$children.length !== 1) {
console.error("A QML component must only contain one root element!");
- var item = (new QMLComponent({ object: cTree, context: meta.context })).createObject(meta.parent);
+ }
+ var component = new QMLComponent( {object: cTree, context: meta.context });
+ //component.finalizeImports();
+
+ item = component.createObject(meta.parent);
+ component.finalizeImports();
+
// Recall QMLBaseObject with the meta of the instance in order to get property
// definitions, etc. from the instance
QMLBaseObject.call(item, meta);
+
+
if (typeof item.dom != 'undefined')
item.dom.className += " " + meta.object.$class + (meta.object.id ? " " + meta.object.id : "");
+
+
+// var metaObject = component.$metaObject;
+// // id
+// if (metaObject && metaObject.id) {
+// meta.context[metaObject.id] = item;
+// }
+
var dProp; // Handle default properties
} else {
console.log("No constructor found for " + meta.object.$class);
return;
}
- // id
- if (meta.object.id)
- meta.context[meta.object.id] = item;
-
- // Apply properties (Bindings won't get evaluated, yet)
- applyProperties(meta.object, item, item, meta.context);
-
+ if (!global.qmlEngine.doc) {
+ global.qmlEngine.doc = item;
+ }
+
+
+ // id
+ if (meta.object.id){
+ meta.context[meta.object.id] = item;
+ }
+
+ // Apply properties (Bindings won't get evaluated, yet)
+ applyProperties( meta.object, item, item, meta.context);
+
return item;
}
@@ -215,12 +238,12 @@
obj.$properties[propName] = prop;
getter = function() { return obj.$properties[propName].get(); };
if (access == 'rw')
- setter = function(newVal) { return obj.$properties[propName].set(newVal); };
+ setter = function(newVal) { obj.$properties[propName].set(newVal); };
else {
setter = function(newVal) {
if (obj.$canEditReadOnlyProperties != true)
throw "property '" + propName + "' has read only access";
- return obj.$properties[propName].set(newVal);
+ obj.$properties[propName].set(newVal);
}
}
setupGetterSetter(obj, propName, getter, setter);
@@ -287,17 +310,30 @@
* @param {Object} componentScope Component scope in which properties should be evaluated
*/
function applyProperties(metaObject, item, objectScope, componentScope) {
- var i;
+ var i, value, signalName;
+
objectScope = objectScope || item;
+
+ if (metaObject.$children && metaObject.$children.length !== 0) {
+ if (item.$defaultProperty)
+ item.$properties[item.$defaultProperty].set(metaObject.$children, true, objectScope, componentScope);
+ else
+ throw "Cannot assign to unexistant default property";
+ }
+ // We purposefully set the default property AFTER using it, in order to only have it applied for
+ // instanciations of this component, but not for its internal children
+ if (metaObject.$defaultProperty)
+ item.$defaultProperty = metaObject.$defaultProperty;
+
for (i in metaObject) {
- var value = metaObject[i];
+ value = metaObject[i];
// skip global id's and internal values
if (i == "id" || i[0] == "$") {
continue;
}
// slots
if (i.indexOf("on") == 0 && i[2].toUpperCase() == i[2]) {
- var signalName = i[2].toLowerCase() + i.slice(3);
+ signalName = i[2].toLowerCase() + i.slice(3);
if (!item[signalName]) {
console.warn("No signal called " + signalName + " found!");
continue;
@@ -356,25 +392,18 @@
continue;
}
}
- if (item.$properties && i in item.$properties)
+
+ if (item.$properties && i in item.$properties){
item.$properties[i].set(value, true, objectScope, componentScope);
+ }
else if (i in item)
item[i] = value;
else if (item.$setCustomData)
item.$setCustomData(i, value);
else
console.warn("Cannot assign to non-existent property \"" + i + "\". Ignoring assignment.");
}
- if (metaObject.$children && metaObject.$children.length !== 0) {
- if (item.$defaultProperty)
- item.$properties[item.$defaultProperty].set(metaObject.$children, true, objectScope, componentScope);
- else
- throw "Cannot assign to unexistant default property";
- }
- // We purposefully set the default property AFTER using it, in order to only have it applied for
- // instanciations of this component, but not for its internal children
- if (metaObject.$defaultProperty)
- item.$defaultProperty = metaObject.$defaultProperty;
+
if (typeof item.completed != 'undefined' && item.completedAlreadyCalled == false) {
item.completedAlreadyCalled = true;
item.completed();
diff --git a/src/qtcore/qt.js b/src/qtcore/qt.js
--- a/src/qtcore/qt.js
+++ b/src/qtcore/qt.js
@@ -181,5 +181,35 @@
Key_Play: 250,
Key_Sleep: 95,
Key_Zoom: 251,
- Key_Cancel: 3
+ Key_Cancel: 3,
+ // CursorShape
+ ArrowCursor: 0,
+ UpArrowCursor: 1,
+ CrossCursor: 2,
+ WaitCursor: 3,
+ IBeamCursor: 4,
+ SizeVerCursor: 5,
+ SizeHorCursor: 6,
+ SizeBDiagCursor: 7,
+ SizeFDiagCursor: 8,
+ SizeAllCursor: 9,
+ BlankCursor: 10,
+ SplitVCursor: 11,
+ SplitHCursor: 12,
+ PointingHandCursor: 13,
+ ForbiddenCursor: 14,
+ WhatsThisCursor: 15,
+ BusyCursor: 16,
+ OpenHandCursor: 17,
+ ClosedHandCursor: 18,
+ DragCopyCursor: 19,
+ DragMoveCursor: 20,
+ DragLinkCursor: 21,
+ LastCursor: 21, //DragLinkCursor,
+ BitmapCursor: 24,
+ CustomCursor: 25,
+ // ScrollBar Policy
+ ScrollBarAsNeeded: 0,
+ ScrollBarAlwaysOff: 1,
+ ScrollBarAlwaysOn: 2
}
diff --git a/src/qtcore/signal.js b/src/qtcore/signal.js
--- a/src/qtcore/signal.js
+++ b/src/qtcore/signal.js
@@ -13,9 +13,13 @@
var obj = options.obj
var signal = function() {
- for (var i in connectedSlots)
- connectedSlots[i].slot.apply(connectedSlots[i].thisObj, arguments);
+ for (var i=0;i