From 87a6f60750c0432a965c49e71a046b9a84305e7c Mon Sep 17 00:00:00 2001 From: kusti8 Date: Sun, 15 Sep 2019 11:57:40 -0400 Subject: [PATCH] Add image resizing and TextInput --- package-lock.json | 72 ++++++++++++++++++++--------------- package.json | 2 + src/components/Image.js | 65 ++++++++++++++++++++++++++++--- src/components/Root.js | 2 + src/components/TextInput.js | 76 +++++++++++++++++++++++++++++++++++++ src/components/Window.js | 9 +++-- src/components/index.js | 4 +- src/index.js | 4 ++ src/utils/createElement.js | 13 ++++++- src/utils/requireImpl.js | 4 +- testprog.js | 38 ++++--------------- 11 files changed, 217 insertions(+), 72 deletions(-) create mode 100644 src/components/TextInput.js diff --git a/package-lock.json b/package-lock.json index 7a5688a..b4ebc8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2212,7 +2212,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-union": { @@ -2717,7 +2717,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -3007,7 +3007,7 @@ }, "concat-stream": { "version": "1.6.2", - "resolved": "http://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { @@ -3208,7 +3208,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -3405,7 +3405,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -3922,7 +3922,7 @@ }, "fs-extra": { "version": "0.30.0", - "resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "dev": true, "requires": { @@ -3944,7 +3944,7 @@ "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha1-4y/AMKLM7kSmtTcTCNpUvgs5fSc=", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", "dev": true }, "fs.realpath": { @@ -4584,7 +4584,7 @@ }, "got": { "version": "6.7.1", - "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -4820,6 +4820,11 @@ "minimatch": "^3.0.4" } }, + "image-size": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.4.tgz", + "integrity": "sha512-GqPgxs+VkOr12aWwjSkyRzf5atzObWpFtiRuDgxCl2I/SDpZOKZFRD3iIAeAN6/usmn8SeLWRt7a8JRYK0Whbw==" + }, "import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", @@ -4875,7 +4880,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=" + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "invariant": { "version": "2.2.4", @@ -4926,7 +4931,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-callable": { @@ -5180,6 +5185,17 @@ "requires": { "node-fetch": "^1.0.1", "whatwg-fetch": ">=0.10.0" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + } } }, "isstream": { @@ -6656,7 +6672,7 @@ }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -7237,7 +7253,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -7448,7 +7464,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -7466,7 +7482,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -7534,7 +7550,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } @@ -7698,13 +7714,9 @@ "integrity": "sha512-FXWH6mqjWgU8ewuahp4spec8LkroFZK2NicOv6bNwZC3kcwZUI8LeZdG80UzTSLLhK4T7MsgNwlYDVRlDdfTDg==" }, "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha1-mA9vcthSEaU0fGsrwYxbhMPrR+8=", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" }, "node-int64": { "version": "0.4.0", @@ -7887,7 +7899,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -8382,7 +8394,7 @@ }, "pretty-bytes": { "version": "1.0.4", - "resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "dev": true, "requires": { @@ -8420,7 +8432,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "dev": true }, "process-nextick-args": { @@ -8441,7 +8453,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { "asap": "~2.0.3" } @@ -8545,7 +8557,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -9916,7 +9928,7 @@ }, "through2": { "version": "0.2.3", - "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", "dev": true, "requires": { @@ -9932,7 +9944,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -9944,7 +9956,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } diff --git a/package.json b/package.json index bb2eeb4..39f3ae0 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "color": "^3.1.2", "fbjs": "^1.0.0", "file-type": "^12.0.0", + "image-size": "^0.7.4", "lodash": "^4.17.11", + "node-fetch": "^2.6.0", "node-qt-napi": "github:kusti8/node-qt-napi", "react": "^16.8.6", "react-reconciler": "^0.20.4", diff --git a/src/components/Image.js b/src/components/Image.js index 55da41c..51a7d42 100644 --- a/src/components/Image.js +++ b/src/components/Image.js @@ -6,6 +6,7 @@ import PropTypes from 'prop-types'; import propsUpdater from '../utils/propsUpdater'; import convertStyleSheet from '../utils/convertStyleSheet'; import { YogaComponent } from './YogaComponent'; +import fetch from 'node-fetch'; export default p => { const propTypes = { @@ -24,21 +25,47 @@ export default p => { style: {}, onResponderGrant: () => {}, onResponderRelease: () => {}, - resizeMode: 'stretch', }; const element = new qt.QLabel(); + element.setScaledContents(false); const pixElement = new qt.QPixmap(); let props = { ...p }; props = propChecker(props, propTypes, defaultProps, 'Image'); - let resizeMode = props.resizeMode; + const resizeMode = { r: props.resizeMode || 'stretch' }; - const applyPixSize = (width, height, mode) => {}; + const applyPixSize = (width, height, mode) => { + console.log('Set size', width, height); + console.log('Repeating', mode); + console.log(element.width(), element.height()); + element.setAlignment(qt.Alignment.AlignLeft | qt.Alignment.AlignVCenter); + if (mode == 'cover') { + pixElement.scaled( + width, + height, + qt.AspectRatioMode.KeepAspectRatioByExpanding + ); + } else if (mode == 'contain') { + pixElement.scaled(width, height, qt.AspectRatioMode.KeepAspectRatio); + } else if (mode == 'stretch') { + console.log('Scaled', width, height); + pixElement.scaled(width, height, qt.AspectRatioMode.IgnoreAspectRatio); + } else if (mode == 'center') { + element.setAlignment(qt.Alignment.AlignCenter); + pixElement.scaled(width, height, qt.AspectRatioMode.KeepAspectRatio); + } else if (mode == 'repeat') { + pixElement.scaledTile(width, height); + } + element.setPixmap(pixElement); + element.show(); + element.adjustSize(); + console.log('Pix size', pixElement.width(), pixElement.height()); + }; const yogaProps = YogaComponent(element, layout => { - applyPixSize(layout.width, layout.height, resizeMode); + applyPixSize(layout.width, layout.height, resizeMode.r); }); const handlers = { @@ -79,11 +106,39 @@ export default p => { [handlers, 'onResponderGrant', 'onResponderRelease'], { style: style => { + if (style.resizeMode) { + console.log(style); + resizeMode.r = style.resizeMode; + } element.setStyleSheet(convertStyleSheet(style)); yogaProps.applyYogaStyle(style); }, resizeMode: r => { - resizeMode = r; + resizeMode.r = r; + }, + source: source => { + if (source.uri) { + // need to figure out what width and height work with, and also work with arrays + if ( + source.uri.startsWith('http://') || + source.uri.startsWith('https://') || + source.uri.startsWith('ftp://') + ) { + fetch(source.uri, { + method: source.method || 'GET', + body: source.body, + headers: source.headers, + }) + .then(out => out.buffer()) + .then(out => { + pixElement.loadFromData(out); + element.setPixmap(pixElement); + }); + } else { + pixElement.load(source.uri); + element.setPixmap(pixElement); + } + } }, } ); diff --git a/src/components/Root.js b/src/components/Root.js index 2e03315..0aa4d56 100644 --- a/src/components/Root.js +++ b/src/components/Root.js @@ -25,6 +25,7 @@ export default props => { const queue = [host]; while (queue.length) { const next = queue.pop(); + console.log(next.element); if (next && next.applyYoga) { let root = true; if (next.parent && next.parent.applyYoga) { @@ -45,6 +46,7 @@ export default props => { }; const afterCommit = host => { + console.log('After commit'); traverseYoga(host); }; diff --git a/src/components/TextInput.js b/src/components/TextInput.js new file mode 100644 index 0000000..76888df --- /dev/null +++ b/src/components/TextInput.js @@ -0,0 +1,76 @@ +import propChecker from '../utils/propChecker'; +import { disconnectDevtools } from '../devtools'; +import qt from 'node-qt-napi'; +import { Container } from './Container'; +import PropTypes from 'prop-types'; +import propsUpdater from '../utils/propsUpdater'; +import convertStyleSheet from '../utils/convertStyleSheet'; +import { YogaComponent } from './YogaComponent'; + +export default p => { + const propTypes = { + style: PropTypes.object, + onChangeText: PropTypes.func, + value: PropTypes.string, + }; + const defaultProps = { + style: {}, + onChangeText: () => {}, + value: '', + }; + + const element = new qt.QLineEdit(); + + let props = { ...p }; + props = propChecker(props, propTypes, defaultProps, 'TextInput'); + + const yogaProps = YogaComponent(element); + + const handlers = { + onChangeText: props.onChangeText, + }; + + element.textChangedEvent(text => { + handlers.onChangeText(text); + }); + + const containerProps = Container( + child => { + child.element.setParent(element); + if (child.node) { + yogaProps.node.insertChild(child.node, yogaProps.node.getChildCount()); + } + }, + child => { + child.element.del(); + if (child.node) { + yogaProps.node.removeChild(child.node); + } + }, + (child, i) => { + child.element.setParent(element); + if (child.node) { + yogaProps.node.insertChild(child.node, i); + } + } + ); + + const updateProps = propsUpdater([handlers, 'onChangeText'], { + style: style => { + element.setStyleSheet(convertStyleSheet(style)); + yogaProps.applyYogaStyle(style); + }, + value: value => { + element.setText(value); + }, + }); + + updateProps(props); + + return { + ...containerProps, + ...yogaProps, + element, + updateProps, + }; +}; diff --git a/src/components/Window.js b/src/components/Window.js index 0f96c73..cd2ca99 100644 --- a/src/components/Window.js +++ b/src/components/Window.js @@ -47,11 +47,12 @@ export default p => { style: style => { element.setStyleSheet(convertStyleSheet(style)); const size = percentToSize(style.width, style.height); - if (size.h) { - element.resize(element.width(), size.h); - } - if (size.w) { + if (size.h && size.w) { + element.resize(size.w, size.h); + } else if (size.w) { element.resize(size.w, element.height()); + } else if (size.h) { + element.resize(element.width(), size.h); } }, }); diff --git a/src/components/index.js b/src/components/index.js index 235ff24..8fe05db 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -4,5 +4,7 @@ import Window from './Window'; import View from './View'; import VirtualText from './VirtualText'; import RootText from './RootText'; +import Image from './Image'; +import TextInput from './TextInput'; -export { App, Root, Window, View, VirtualText, RootText }; +export { App, Root, Window, View, VirtualText, RootText, Image, TextInput }; diff --git a/src/index.js b/src/index.js index 41fe666..2f85af8 100644 --- a/src/index.js +++ b/src/index.js @@ -16,6 +16,8 @@ const View = 'VIEW'; const App = 'APP'; const VirtualText = 'VIRTUALTEXT'; const RootText = 'ROOTTEXT'; +const Image = 'IMAGE'; +const TextInput = 'TEXTINPUT'; export { AppRegistry, @@ -30,4 +32,6 @@ export { TouchableOpacity, TouchableHighlight, Button, + Image, + TextInput, }; diff --git a/src/utils/createElement.js b/src/utils/createElement.js index c695499..9273d7e 100644 --- a/src/utils/createElement.js +++ b/src/utils/createElement.js @@ -1,4 +1,13 @@ -import { Root, App, View, Window, VirtualText, RootText } from '../components/'; +import { + Root, + App, + View, + Window, + VirtualText, + RootText, + Image, + TextInput, +} from '../components/'; // Creates an element with an element type, props and a root instance function createElement(type, props) { @@ -9,6 +18,8 @@ function createElement(type, props) { WINDOW: () => new Window(props), VIRTUALTEXT: () => new VirtualText(props), ROOTTEXT: () => new RootText(props), + IMAGE: () => new Image(props), + TEXTINPUT: () => new TextInput(props), default: undefined, }; return COMPONENTS[type]() || COMPONENTS.default; diff --git a/src/utils/requireImpl.js b/src/utils/requireImpl.js index 0dd9eaf..9fe65ab 100644 --- a/src/utils/requireImpl.js +++ b/src/utils/requireImpl.js @@ -2,6 +2,7 @@ import Module from 'module'; import fileType from 'file-type'; import readChunk from 'read-chunk'; import fs from 'fs'; +import sizeOf from 'image-size'; const originalLoader = Module._load; @@ -11,5 +12,6 @@ Module._load = function(request, parent) { if (type.split('/')[0] != 'image') return originalLoader.apply(this, arguments); - return fs.readFileSync(request); + const size = sizeOf(request); + return { uri: request, width: size.width, height: size.height }; }; diff --git a/testprog.js b/testprog.js index d2e823c..a9b92e0 100644 --- a/testprog.js +++ b/testprog.js @@ -10,6 +10,8 @@ import { TouchableOpacity, TouchableHighlight, Button, + Image, + TextInput, } from './src/'; class Example extends Component { @@ -18,42 +20,18 @@ class Example extends Component { a: true, }; componentDidMount() { - setTimeout(() => this.setState({ test: 'dsawewwww' }), 3000); - setTimeout(() => this.setState({ a: false }), 3000); + //setTimeout(() => this.setState({ test: "dsawewwww" }), 3000); + //setTimeout(() => this.setState({ a: false }), 3000); } render() { return ( - - -