mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 13:51:13 +00:00
node: api review adjustements part I (#3766)
* Update api/node/src/types/brush.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update tests/cases/callbacks/handler_with_arg.slint Co-authored-by: Olivier Goffart <olivier.goffart@slint.dev> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Olivier Goffart <olivier.goffart@slint.dev>
This commit is contained in:
parent
081e7fe456
commit
0045787e1c
18 changed files with 340 additions and 142 deletions
|
@ -128,7 +128,7 @@ export component MyComponent inherits Window {
|
|||
}
|
||||
```
|
||||
|
||||
The callbacks in JavaScript are exposed as property that has a setHandler function, and that can be called as a function.
|
||||
The callbacks in JavaScript are exposed as property and that can be called as a function.
|
||||
|
||||
**`main.js`**
|
||||
|
||||
|
@ -139,7 +139,7 @@ let ui = slint.loadFile("ui/my-component.slint");
|
|||
let component = new ui.MyComponent();
|
||||
|
||||
// connect to a callback
|
||||
component.clicked.setHandler(function() { console.log("hello"); })
|
||||
component.clicked = function() { console.log("hello"); };
|
||||
// emit a callback
|
||||
component.clicked();
|
||||
```
|
||||
|
|
|
@ -22,25 +22,25 @@ test('loadFile', (t) => {
|
|||
t.is(error?.message, "Could not compile " + errorPath);
|
||||
t.deepEqual(error?.diagnostics, [
|
||||
{
|
||||
column: 18,
|
||||
columnNumber: 18,
|
||||
level: 0,
|
||||
lineNumber: 7,
|
||||
message: 'Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type',
|
||||
sourceFile: errorPath
|
||||
fileName: errorPath
|
||||
},
|
||||
{
|
||||
column: 22,
|
||||
columnNumber: 22,
|
||||
level: 0,
|
||||
lineNumber: 7,
|
||||
message: 'Syntax error: expected \';\'',
|
||||
sourceFile: errorPath
|
||||
fileName: errorPath
|
||||
},
|
||||
{
|
||||
column: 22,
|
||||
columnNumber: 22,
|
||||
level: 0,
|
||||
lineNumber: 7,
|
||||
message: 'Parse error',
|
||||
sourceFile: errorPath
|
||||
fileName: errorPath
|
||||
},
|
||||
]);
|
||||
})
|
||||
|
@ -50,7 +50,6 @@ test('constructor parameters', (t) => {
|
|||
let hello = "";
|
||||
let test = new demo.Test({ say_hello: function() { hello = "hello"; }, check: "test"});
|
||||
|
||||
// test.say_hello.setHandler(function () { blub = "hello"; });
|
||||
test.say_hello();
|
||||
|
||||
t.is(test.check, "test");
|
||||
|
|
|
@ -15,6 +15,20 @@ test('get/set include paths', (t) => {
|
|||
t.deepEqual(compiler.includePaths, ["path/one/", "path/two/", "path/three/"]);
|
||||
})
|
||||
|
||||
test('get/set library paths', (t) => {
|
||||
let compiler = new private_api.ComponentCompiler;
|
||||
|
||||
compiler.libraryPaths = {
|
||||
"libfile.slint" : "third_party/libfoo/ui/lib.slint",
|
||||
"libdir" : "third_party/libbar/ui/",
|
||||
};
|
||||
|
||||
t.deepEqual(compiler.libraryPaths, {
|
||||
"libfile.slint" : "third_party/libfoo/ui/lib.slint",
|
||||
"libdir" : "third_party/libbar/ui/",
|
||||
});
|
||||
})
|
||||
|
||||
test('get/set style', (t) => {
|
||||
let compiler = new private_api.ComponentCompiler;
|
||||
|
||||
|
@ -209,8 +223,8 @@ test('compiler diagnostics', (t) => {
|
|||
level: 0,
|
||||
message: 'Parse error',
|
||||
lineNumber: 2,
|
||||
column: 12,
|
||||
sourceFile: 'testsource.slint'
|
||||
columnNumber: 12,
|
||||
fileName: 'testsource.slint'
|
||||
});
|
||||
})
|
||||
|
||||
|
|
|
@ -190,9 +190,9 @@ test('get/set image properties', async (t) => {
|
|||
t.not(instance, null);
|
||||
|
||||
let slintImage = instance!.getProperty("image");
|
||||
if (t.true((slintImage instanceof ImageData))) {
|
||||
t.deepEqual((slintImage as ImageData).width, 64);
|
||||
t.deepEqual((slintImage as ImageData).height, 64);
|
||||
if (t.true((slintImage instanceof private_api.ImageData))) {
|
||||
t.deepEqual((slintImage as private_api.ImageData).width, 64);
|
||||
t.deepEqual((slintImage as private_api.ImageData).height, 64);
|
||||
|
||||
let image = await Jimp.read(path.join(__dirname, "resources/rgb.png"));
|
||||
|
||||
|
@ -237,6 +237,8 @@ test('get/set brush properties', (t) => {
|
|||
in-out property <brush> black: #000000;
|
||||
in-out property <brush> trans: transparent;
|
||||
in-out property <brush> ref: transparent;
|
||||
in-out property <brush> linear-gradient: @linear-gradient(90deg, #3f87a6 0%, #ebf8e1 50%, #f69d3c 100%);
|
||||
in-out property <brush> radial-gradient: @radial-gradient(circle, #f00 0%, #0f0 50%, #00f 100%);
|
||||
}
|
||||
`, "");
|
||||
t.not(definition, null);
|
||||
|
@ -271,7 +273,7 @@ test('get/set brush properties', (t) => {
|
|||
t.assert((transparent as Brush).isTransparent);
|
||||
}
|
||||
|
||||
let ref = Brush.fromColor(Color.fromRgb(100, 110, 120));
|
||||
let ref = new Brush({ red: 100, green: 110, blue: 120, alpha: 255 });
|
||||
instance!.setProperty("ref", ref);
|
||||
|
||||
let instance_ref = instance!.getProperty("ref");
|
||||
|
@ -281,6 +283,21 @@ test('get/set brush properties', (t) => {
|
|||
t.deepEqual(ref_color.red, 100);
|
||||
t.deepEqual(ref_color.green, 110);
|
||||
t.deepEqual(ref_color.blue, 120);
|
||||
t.deepEqual(ref_color.alpha, 255);
|
||||
}
|
||||
|
||||
let radialGradient = instance!.getProperty("radial-gradient");
|
||||
|
||||
if (t.true((radialGradient instanceof Brush))) {
|
||||
t.is((radialGradient as Brush).toString(),
|
||||
"radial-gradient(circle, rgba(255, 0, 0, 255) 0%, rgba(0, 255, 0, 255) 50%, rgba(0, 0, 255, 255) 100%)");
|
||||
}
|
||||
|
||||
let linearGradient = instance!.getProperty("linear-gradient");
|
||||
|
||||
if (t.true((linearGradient instanceof Brush))) {
|
||||
t.is((linearGradient as Brush).toString(),
|
||||
"linear-gradient(90deg, rgba(63, 135, 166, 255) 0%, rgba(235, 248, 225, 255) 50%, rgba(246, 157, 60, 255) 100%)");
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
import test from 'ava';
|
||||
|
||||
import { Brush, Color, ArrayModel, Timer } from '../index'
|
||||
import { Brush, ArrayModel, Timer, private_api } from '../index'
|
||||
|
||||
test('Color from fromRgb', (t) => {
|
||||
let color = Color.fromRgb(100, 110, 120);
|
||||
let color = private_api.SlintColor.fromRgb(100, 110, 120);
|
||||
|
||||
t.deepEqual(color.red, 100);
|
||||
t.deepEqual(color.green, 110);
|
||||
|
@ -14,7 +14,7 @@ test('Color from fromRgb', (t) => {
|
|||
})
|
||||
|
||||
test('Color from fromArgb', (t) => {
|
||||
let color = Color.fromArgb(120, 100, 110, 120);
|
||||
let color = private_api.SlintColor.fromArgb(120, 100, 110, 120);
|
||||
|
||||
t.deepEqual(color.red, 100);
|
||||
t.deepEqual(color.green, 110);
|
||||
|
@ -23,7 +23,7 @@ test('Color from fromArgb', (t) => {
|
|||
})
|
||||
|
||||
test('Color from fromArgbEncoded', (t) => {
|
||||
let color = Color.fromArgbEncoded(2019847800);
|
||||
let color = private_api.SlintColor.fromArgbEncoded(2019847800);
|
||||
|
||||
t.deepEqual(color.red, 100);
|
||||
t.deepEqual(color.green, 110);
|
||||
|
@ -31,7 +31,7 @@ test('Color from fromArgbEncoded', (t) => {
|
|||
})
|
||||
|
||||
test('Color brighter', (t) => {
|
||||
let color = Color.fromRgb(100, 110, 120).brighter(0.1);
|
||||
let color = private_api.SlintColor.fromRgb(100, 110, 120).brighter(0.1);
|
||||
|
||||
t.deepEqual(color.red, 110);
|
||||
t.deepEqual(color.green, 121);
|
||||
|
@ -39,7 +39,7 @@ test('Color brighter', (t) => {
|
|||
})
|
||||
|
||||
test('Color darker', (t) => {
|
||||
let color = Color.fromRgb(100, 110, 120).darker(0.1);
|
||||
let color = private_api.SlintColor.fromRgb(100, 110, 120).darker(0.1);
|
||||
|
||||
t.deepEqual(color.red, 91);
|
||||
t.deepEqual(color.green, 100);
|
||||
|
@ -47,11 +47,20 @@ test('Color darker', (t) => {
|
|||
})
|
||||
|
||||
test('Brush from Color', (t) => {
|
||||
let brush = Brush.fromColor(Color.fromRgb(100, 110, 120));
|
||||
let brush = new Brush({ red: 100, green: 110, blue: 120, alpha: 255 });
|
||||
|
||||
t.deepEqual(brush.color.red, 100);
|
||||
t.deepEqual(brush.color.green, 110);
|
||||
t.deepEqual(brush.color.blue, 120);
|
||||
|
||||
t.throws(() => {
|
||||
new Brush({ red: -100, green: 110, blue: 120, alpha: 255 })
|
||||
},
|
||||
{
|
||||
code: "GenericFailure",
|
||||
message: "A channel of Color cannot be negative"
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
test('ArrayModel push', (t) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { private_api, Window } from '../index'
|
|||
|
||||
test('Window constructor', (t) => {
|
||||
t.throws(() => {
|
||||
new Window()
|
||||
new private_api.Window()
|
||||
},
|
||||
{
|
||||
code: "GenericFailure",
|
||||
|
@ -30,9 +30,9 @@ test('Window show / hide', (t) => {
|
|||
t.not(instance, null);
|
||||
|
||||
let window = instance!.window();
|
||||
t.is(window.is_visible, false);
|
||||
t.is(window.isVisible, false);
|
||||
window.show();
|
||||
t.is(window.is_visible, true);
|
||||
t.is(window.isVisible, true);
|
||||
window.hide();
|
||||
t.is(window.is_visible, false);
|
||||
t.is(window.isVisible, false);
|
||||
})
|
|
@ -127,7 +127,7 @@ export component MyComponent inherits Window {
|
|||
}
|
||||
```
|
||||
|
||||
The callbacks in JavaScript are exposed as property that has a setHandler function, and that can be called as a function.
|
||||
The callbacks in JavaScript are exposed as property and that can be called as a function.
|
||||
|
||||
**`main.js`**
|
||||
|
||||
|
@ -138,7 +138,7 @@ let ui = slint.loadFile("ui/my-component.slint");
|
|||
let component = new ui.MyComponent();
|
||||
|
||||
// connect to a callback
|
||||
component.clicked.setHandler(function() { console.log("hello"); })
|
||||
component.clicked = function() { console.log("hello"); };
|
||||
// emit a callback
|
||||
component.clicked();
|
||||
```
|
||||
|
|
|
@ -4,40 +4,78 @@
|
|||
import * as path from "path";
|
||||
|
||||
import * as napi from "./rust-module";
|
||||
export { Diagnostic, DiagnosticLevel, Window, Brush, Color, ImageData, Point, Size, SlintModelNotify } from "./rust-module";
|
||||
export { Diagnostic, DiagnosticLevel, Brush, Color, SlintModelNotify } from "./rust-module";
|
||||
|
||||
/**
|
||||
* ModelPeer is the interface that the run-time implements. An instance is
|
||||
* set on dynamic {@link Model} instances and can be used to notify the run-time
|
||||
* of changes in the structure or data of the model.
|
||||
* Represents a two-dimensional point.
|
||||
*/
|
||||
export interface ModelPeer {
|
||||
export interface Point {
|
||||
x: number,
|
||||
y: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a two-dimensional size.
|
||||
*/
|
||||
export interface Size {
|
||||
width: number,
|
||||
height: number
|
||||
}
|
||||
|
||||
/**
|
||||
* This type represents a window towards the windowing system, that's used to render the
|
||||
* scene of a component. It provides API to control windowing system specific aspects such
|
||||
* as the position on the screen.
|
||||
*/
|
||||
export interface Window {
|
||||
/**
|
||||
* Call this function from our own model to notify that fields of data
|
||||
* in the specified row have changed.
|
||||
* @argument row
|
||||
* Shows the window on the screen. An additional strong reference on the
|
||||
* associated component is maintained while the window is visible.
|
||||
*/
|
||||
rowDataChanged(row: number): void;
|
||||
/**
|
||||
* Call this function from your own model to notify that one or multiple
|
||||
* rows were added to the model, starting at the specified row.
|
||||
* @param row
|
||||
* @param count
|
||||
*/
|
||||
rowAdded(row: number, count: number): void;
|
||||
/**
|
||||
* Call this function from your own model to notify that one or multiple
|
||||
* rows were removed from the model, starting at the specified row.
|
||||
* @param row
|
||||
* @param count
|
||||
*/
|
||||
rowRemoved(row: number, count: number): void;
|
||||
show(): void;
|
||||
|
||||
/** Hides the window, so that it is not visible anymore. */
|
||||
hide(): void;
|
||||
|
||||
/**
|
||||
* Call this function from your own model to notify that the model has been
|
||||
* changed and everything must be reloaded
|
||||
* Returns the visibility state of the window. This function can return false even if you previously called show()
|
||||
* on it, for example if the user minimized the window.
|
||||
*/
|
||||
reset(): void;
|
||||
get isVisible(): boolean;
|
||||
|
||||
/** Gets or sets the logical position of the window on the screen. */
|
||||
logicalPosition: Point;
|
||||
|
||||
/** Gets or sets the physical position of the window on the screen. */
|
||||
physicalPosition: Point;
|
||||
|
||||
/** Gets or sets the logical size of the window on the screen, */
|
||||
logicalSize: Size;
|
||||
|
||||
/** Gets or sets the physical size of the window on the screen, */
|
||||
physicalSize: Size;
|
||||
}
|
||||
|
||||
/**
|
||||
* An image data type that can be displayed by the Image element.
|
||||
*
|
||||
* This interface is inspired by the web [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) interface.
|
||||
*/
|
||||
export interface ImageData {
|
||||
/**
|
||||
* Returns the image as buffer.
|
||||
*/
|
||||
get data(): Uint8Array;
|
||||
|
||||
/**
|
||||
* Returns the width of the image in pixels.
|
||||
*/
|
||||
get width(): number;
|
||||
|
||||
/**
|
||||
* Returns the height of the image in pixels.
|
||||
*/
|
||||
get height(): number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,11 +91,10 @@ export interface ModelPeer {
|
|||
* ```js
|
||||
* export class ArrayModel<T> implements Model<T> {
|
||||
* private a: Array<T>
|
||||
* notify: ModelPeer;
|
||||
*
|
||||
* constructor(arr: Array<T>) {
|
||||
* super();
|
||||
* this.a = arr;
|
||||
* this.notify = new NullPeer();
|
||||
* }
|
||||
*
|
||||
* rowCount() {
|
||||
|
@ -98,34 +135,38 @@ export interface ModelPeer {
|
|||
*}
|
||||
* ```
|
||||
*/
|
||||
export interface Model<T> {
|
||||
export abstract class Model<T> {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
notify: NullPeer;
|
||||
|
||||
constructor() {
|
||||
this.notify = new NullPeer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementations of this function must return the current number of rows.
|
||||
*/
|
||||
rowCount(): number;
|
||||
abstract rowCount(): number;
|
||||
/**
|
||||
* Implementations of this function must return the data at the specified row.
|
||||
* @param row
|
||||
*/
|
||||
rowData(row: number): T | undefined;
|
||||
abstract rowData(row: number): T | undefined;
|
||||
/**
|
||||
* Implementations of this function must store the provided data parameter
|
||||
* in the model at the specified row.
|
||||
* @param row
|
||||
* @param data
|
||||
*/
|
||||
setRowData(row: number, data: T): void;
|
||||
/**
|
||||
* This public member is set by the run-time and implementation must use this
|
||||
* to notify the run-time of changes in the model.
|
||||
*/
|
||||
notify: ModelPeer;
|
||||
abstract setRowData(row: number, data: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
class NullPeer implements ModelPeer {
|
||||
class NullPeer {
|
||||
rowDataChanged(row: number): void { }
|
||||
rowAdded(row: number, count: number): void { }
|
||||
rowRemoved(row: number, count: number): void { }
|
||||
|
@ -136,12 +177,11 @@ class NullPeer implements ModelPeer {
|
|||
* ArrayModel wraps a JavaScript array for use in `.slint` views. The underlying
|
||||
* array can be modified with the [[ArrayModel.push]] and [[ArrayModel.remove]] methods.
|
||||
*/
|
||||
export class ArrayModel<T> implements Model<T> {
|
||||
export class ArrayModel<T> extends Model<T> {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private a: Array<T>
|
||||
notify: ModelPeer;
|
||||
|
||||
/**
|
||||
* Creates a new ArrayModel.
|
||||
|
@ -149,8 +189,8 @@ export class ArrayModel<T> implements Model<T> {
|
|||
* @param arr
|
||||
*/
|
||||
constructor(arr: Array<T>) {
|
||||
super();
|
||||
this.a = arr;
|
||||
this.notify = new NullPeer();
|
||||
}
|
||||
|
||||
rowCount() {
|
||||
|
@ -176,9 +216,7 @@ export class ArrayModel<T> implements Model<T> {
|
|||
// FIXME: should this be named splice and have the splice api?
|
||||
/**
|
||||
* Removes the specified number of element from the array that's backing
|
||||
* the model, starting at the specified index. This is equivalent to calling
|
||||
* Array.slice() on the array and notifying the run-time about the removed
|
||||
* rows.
|
||||
* the model, starting at the specified index.
|
||||
* @param index
|
||||
* @param size
|
||||
*/
|
||||
|
@ -225,7 +263,7 @@ export interface ComponentHandle {
|
|||
* Returns the {@link Window} associated with this component instance.
|
||||
* The window API can be used to control different aspects of the integration into the windowing system, such as the position on the screen.
|
||||
*/
|
||||
get window(): napi.Window;
|
||||
get window(): Window;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,7 +291,7 @@ class Component implements ComponentHandle {
|
|||
this.instance.window().hide();
|
||||
}
|
||||
|
||||
get window(): napi.Window {
|
||||
get window(): Window {
|
||||
return this.instance.window();
|
||||
}
|
||||
|
||||
|
@ -265,13 +303,6 @@ class Component implements ComponentHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
interface Callback {
|
||||
(): any;
|
||||
setHandler(cb: any): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an errors that can be emitted by the compiler.
|
||||
|
@ -292,17 +323,65 @@ export class CompileError extends Error {
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads the given slint file and returns a constructor to create an instance of the exported component.
|
||||
* LoadFileOptions are used to defines different optional parameters that can be used to configure the compiler.
|
||||
*/
|
||||
export function loadFile(filePath: string): Object {
|
||||
export interface LoadFileOptions {
|
||||
/**
|
||||
* If set to true warnings from the compiler will not be printed to the console.
|
||||
*/
|
||||
quiet?: boolean,
|
||||
|
||||
/**
|
||||
* Sets the widget style the compiler is currently using when compiling .slint files.
|
||||
*/
|
||||
style?: string
|
||||
|
||||
/**
|
||||
* Sets the include paths used for looking up `.slint` imports to the specified vector of paths.
|
||||
*/
|
||||
includePaths?: Array<string>,
|
||||
|
||||
/**
|
||||
* Sets library paths used for looking up `@library` imports to the specified map of library names to paths.
|
||||
*/
|
||||
libraryPaths?: Record<string, string>
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given slint file and returns an objects that contains a functions to construct the exported
|
||||
* component of the slint file.
|
||||
*
|
||||
* ```js
|
||||
* import * as slint from "slint-ui";
|
||||
* let ui = slint.loadFile(".ui/main.slint");
|
||||
* let main = new ui.Main();
|
||||
* ```
|
||||
*/
|
||||
export function loadFile(filePath: string, options?: LoadFileOptions) : Object {
|
||||
let compiler = new napi.ComponentCompiler;
|
||||
|
||||
if (typeof options !== 'undefined') {
|
||||
if (typeof options.style !== 'undefined') {
|
||||
compiler.style = options.style;
|
||||
}
|
||||
if (typeof options.includePaths !== 'undefined') {
|
||||
compiler.includePaths = options.includePaths;
|
||||
}
|
||||
if (typeof options.libraryPaths !== 'undefined') {
|
||||
compiler.libraryPaths = options.libraryPaths;
|
||||
}
|
||||
}
|
||||
|
||||
let definition = compiler.buildFromPath(filePath);
|
||||
|
||||
let diagnostics = compiler.diagnostics;
|
||||
|
||||
if (diagnostics.length > 0) {
|
||||
let warnings = diagnostics.filter((d) => d.level == napi.DiagnosticLevel.Warning);
|
||||
warnings.forEach((w) => console.log("Warning: " + w));
|
||||
|
||||
if (typeof options !== 'undefined' && options.quiet !== true) {
|
||||
warnings.forEach((w) => console.warn("Warning: " + w));
|
||||
}
|
||||
|
||||
let errors = diagnostics.filter((d) => d.level == napi.DiagnosticLevel.Error);
|
||||
|
||||
|
@ -343,9 +422,10 @@ export function loadFile(filePath: string): Object {
|
|||
instance!.definition().callbacks.forEach((cb) => {
|
||||
Object.defineProperty(componentHandle, cb.replace(/-/g, '_') , {
|
||||
get() {
|
||||
let callback = function () { return instance!.invoke(cb, Array.from(arguments)); } as Callback;
|
||||
callback.setHandler = function (callback) { instance!.setCallback(cb, callback) };
|
||||
return callback;
|
||||
return function () { return instance!.invoke(cb, Array.from(arguments)); };
|
||||
},
|
||||
set(callback) {
|
||||
instance!.setCallback(cb, callback);
|
||||
},
|
||||
enumerable: true,
|
||||
})
|
||||
|
@ -375,6 +455,9 @@ export namespace private_api {
|
|||
export import ComponentDefinition = napi.ComponentDefinition;
|
||||
export import ComponentInstance = napi.ComponentInstance;
|
||||
export import ValueType = napi.ValueType;
|
||||
export import Window = napi.Window;
|
||||
export import ImageData = napi.ImageData;
|
||||
export import SlintColor = napi.SlintColor;
|
||||
|
||||
export function send_mouse_click(component: Component, x: number, y: number) {
|
||||
component.component_instance.sendMouseClick(x, y);
|
||||
|
|
|
@ -71,6 +71,17 @@ impl JsComponentCompiler {
|
|||
self.internal.set_library_paths(library_paths);
|
||||
}
|
||||
|
||||
#[napi(getter)]
|
||||
pub fn library_paths(&self) -> HashMap<String, String> {
|
||||
let mut library_paths = HashMap::new();
|
||||
|
||||
for (key, path) in self.internal.library_paths() {
|
||||
library_paths.insert(key.clone(), path.to_str().unwrap_or_default().to_string());
|
||||
}
|
||||
|
||||
library_paths
|
||||
}
|
||||
|
||||
#[napi(setter)]
|
||||
pub fn set_style(&mut self, style: String) {
|
||||
self.internal.set_style(style);
|
||||
|
|
|
@ -35,14 +35,14 @@ pub struct JsDiagnostic {
|
|||
/// Message for this diagnostic.
|
||||
pub message: String,
|
||||
|
||||
/// The line number in the .slint source file.
|
||||
/// The line number in the .slint source file. The line number starts with 1.
|
||||
pub line_number: u32,
|
||||
|
||||
// The column in the .slint source file
|
||||
pub column: u32,
|
||||
// The column in the .slint source file. The column number starts with 1.
|
||||
pub column_number: u32,
|
||||
|
||||
/// The path of the source file where this diagnostic occurred.
|
||||
pub source_file: Option<String>,
|
||||
pub file_name: Option<String>,
|
||||
}
|
||||
|
||||
impl From<Diagnostic> for JsDiagnostic {
|
||||
|
@ -52,8 +52,8 @@ impl From<Diagnostic> for JsDiagnostic {
|
|||
level: internal_diagnostic.level().into(),
|
||||
message: internal_diagnostic.message().into(),
|
||||
line_number: line_number as u32,
|
||||
column: column as u32,
|
||||
source_file: internal_diagnostic
|
||||
column_number: column as u32,
|
||||
file_name: internal_diagnostic
|
||||
.source_file()
|
||||
.and_then(|path| path.to_str())
|
||||
.map(|str| str.into()),
|
||||
|
|
|
@ -50,7 +50,7 @@ impl JsWindow {
|
|||
|
||||
/// Returns the visibility state of the window. This function can return false even if you previously called show()
|
||||
/// on it, for example if the user minimized the window.
|
||||
#[napi(getter, js_name = "is_visible")]
|
||||
#[napi(getter)]
|
||||
pub fn is_visible(&self) -> bool {
|
||||
self.inner.window().is_visible()
|
||||
}
|
||||
|
|
|
@ -1,23 +1,39 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
use i_slint_core::{Brush, Color};
|
||||
use napi::bindgen_prelude::External;
|
||||
use i_slint_core::{graphics::GradientStop, Brush, Color};
|
||||
use napi::{bindgen_prelude::External, Error, Result};
|
||||
|
||||
/// Color represents a color in the Slint run-time, represented using 8-bit channels for red, green, blue and the alpha (opacity).
|
||||
#[napi(js_name = Color)]
|
||||
#[napi(object, js_name = "Color")]
|
||||
pub struct JsColor {
|
||||
/// Represents the red channel of the color as u8 in the range 0..255.
|
||||
pub red: f64,
|
||||
|
||||
/// Represents the green channel of the color as u8 in the range 0..255.
|
||||
pub green: f64,
|
||||
|
||||
/// Represents the blue channel of the color as u8 in the range 0..255.
|
||||
pub blue: f64,
|
||||
|
||||
/// Represents the alpha channel of the color as u8 in the range 0..255.
|
||||
pub alpha: f64,
|
||||
}
|
||||
|
||||
/// Color represents a color in the Slint run-time, represented using 8-bit channels for red, green, blue and the alpha (opacity).
|
||||
#[napi(js_name = SlintColor)]
|
||||
pub struct JsSlintColor {
|
||||
inner: Color,
|
||||
}
|
||||
|
||||
impl From<Color> for JsColor {
|
||||
impl From<Color> for JsSlintColor {
|
||||
fn from(color: Color) -> Self {
|
||||
Self { inner: color }
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl JsColor {
|
||||
impl JsSlintColor {
|
||||
/// Creates a new transparent color.
|
||||
#[napi(constructor)]
|
||||
pub fn new() -> Self {
|
||||
|
@ -80,8 +96,8 @@ impl JsColor {
|
|||
/// So for example `brighter(0.2)` will increase the brightness by 20%, and
|
||||
/// calling `brighter(-0.5)` will return a color that's 50% darker.
|
||||
#[napi]
|
||||
pub fn brighter(&self, factor: f64) -> JsColor {
|
||||
JsColor::from(self.inner.brighter(factor as f32))
|
||||
pub fn brighter(&self, factor: f64) -> JsSlintColor {
|
||||
JsSlintColor::from(self.inner.brighter(factor as f32))
|
||||
}
|
||||
|
||||
/// Returns a new version of this color that has the brightness decreased
|
||||
|
@ -90,29 +106,29 @@ impl JsColor {
|
|||
/// result is converted back to RGB and the alpha channel is unchanged.
|
||||
/// So for example `darker(0.3)` will decrease the brightness by 30%.
|
||||
#[napi]
|
||||
pub fn darker(&self, factor: f64) -> JsColor {
|
||||
JsColor::from(self.inner.darker(factor as f32))
|
||||
pub fn darker(&self, factor: f64) -> JsSlintColor {
|
||||
JsSlintColor::from(self.inner.darker(factor as f32))
|
||||
}
|
||||
|
||||
/// Returns a new version of this color with the opacity decreased by `factor`.
|
||||
///
|
||||
/// The transparency is obtained by multiplying the alpha channel by `(1 - factor)`.
|
||||
#[napi]
|
||||
pub fn transparentize(&self, amount: f64) -> JsColor {
|
||||
JsColor::from(self.inner.transparentize(amount as f32))
|
||||
pub fn transparentize(&self, amount: f64) -> JsSlintColor {
|
||||
JsSlintColor::from(self.inner.transparentize(amount as f32))
|
||||
}
|
||||
|
||||
/// Returns a new color that is a mix of `self` and `other`, with a proportion
|
||||
/// factor given by `factor` (which will be clamped to be between `0.0` and `1.0`).
|
||||
#[napi]
|
||||
pub fn mix(&self, other: &JsColor, factor: f64) -> JsColor {
|
||||
JsColor::from(self.inner.mix(&other.inner, factor as f32))
|
||||
pub fn mix(&self, other: &JsSlintColor, factor: f64) -> JsSlintColor {
|
||||
JsSlintColor::from(self.inner.mix(&other.inner, factor as f32))
|
||||
}
|
||||
|
||||
/// Returns a new version of this color with the opacity set to `alpha`.
|
||||
#[napi]
|
||||
pub fn with_alpha(&self, alpha: f64) -> JsColor {
|
||||
JsColor::from(self.inner.with_alpha(alpha as f32))
|
||||
pub fn with_alpha(&self, alpha: f64) -> JsSlintColor {
|
||||
JsSlintColor::from(self.inner.with_alpha(alpha as f32))
|
||||
}
|
||||
|
||||
/// Returns the color as string in hex representation e.g. `#000000` for black.
|
||||
|
@ -137,30 +153,38 @@ impl From<Brush> for JsBrush {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<JsColor> for JsBrush {
|
||||
fn from(color: JsColor) -> Self {
|
||||
impl From<JsSlintColor> for JsBrush {
|
||||
fn from(color: JsSlintColor) -> Self {
|
||||
Self::from(Brush::from(color.inner))
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
impl JsBrush {
|
||||
/// Creates a new transparent brush.
|
||||
#[napi(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Self { inner: Brush::default() }
|
||||
pub fn new_with_color(color: JsColor) -> Result<Self> {
|
||||
if color.red < 0. || color.green < 0. || color.blue < 0. || color.alpha < 0. {
|
||||
return Err(Error::from_reason("A channel of Color cannot be negative"));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
inner: Brush::SolidColor(Color::from_argb_u8(
|
||||
color.alpha.floor() as u8,
|
||||
color.red.floor() as u8,
|
||||
color.green.floor() as u8,
|
||||
color.blue.floor() as u8,
|
||||
)),
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a brush form a `Color`.
|
||||
#[napi(factory)]
|
||||
pub fn from_color(color: &JsColor) -> Self {
|
||||
pub fn from_slint_color(color: &JsSlintColor) -> Self {
|
||||
Self { inner: Brush::SolidColor(color.inner) }
|
||||
}
|
||||
|
||||
/// If the brush is SolidColor, the contained color is returned.
|
||||
/// If the brush is a LinearGradient, the color of the first stop is returned.
|
||||
/// @hidden
|
||||
#[napi(getter)]
|
||||
pub fn color(&self) -> JsColor {
|
||||
pub fn color(&self) -> JsSlintColor {
|
||||
self.inner.color().into()
|
||||
}
|
||||
|
||||
|
@ -217,11 +241,52 @@ impl JsBrush {
|
|||
/// It is only implemented for solid color brushes.
|
||||
#[napi]
|
||||
pub fn to_string(&self) -> String {
|
||||
if let Brush::SolidColor(_) = self.inner {
|
||||
match &self.inner {
|
||||
Brush::SolidColor(_) => {
|
||||
return self.color().to_string();
|
||||
}
|
||||
|
||||
println!("toString() is not yet implemented for gradient brushes.");
|
||||
String::default()
|
||||
Brush::LinearGradient(gradient) => {
|
||||
return format!(
|
||||
"linear-gradient({}deg, {})",
|
||||
gradient.angle(),
|
||||
gradient_stops_to_string(gradient.stops())
|
||||
);
|
||||
}
|
||||
Brush::RadialGradient(gradient) => {
|
||||
return format!(
|
||||
"radial-gradient(circle, {})",
|
||||
gradient_stops_to_string(gradient.stops())
|
||||
);
|
||||
}
|
||||
_ => String::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gradient_stops_to_string<'a>(stops: impl Iterator<Item = &'a GradientStop>) -> String {
|
||||
let stops: Vec<String> = stops
|
||||
.map(|s| {
|
||||
format!(
|
||||
"rgba({}, {}, {}, {}) {}%",
|
||||
s.color.red(),
|
||||
s.color.green(),
|
||||
s.color.blue(),
|
||||
s.color.alpha(),
|
||||
s.position * 100.
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut stops_string = String::default();
|
||||
let len = stops.len();
|
||||
|
||||
for i in 0..len {
|
||||
stops_string.push_str(stops[i].as_str());
|
||||
|
||||
if i < len - 1 {
|
||||
stops_string.push_str(", ");
|
||||
}
|
||||
}
|
||||
|
||||
stops_string
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ for (let i = tiles.length - 1; i > 0; i--) {
|
|||
let model = new slint.ArrayModel(tiles);
|
||||
mainWindow.memory_tiles = model;
|
||||
|
||||
mainWindow.check_if_pair_solved.setHandler(function () {
|
||||
mainWindow.check_if_pair_solved = function () {
|
||||
let flipped_tiles = [];
|
||||
tiles.forEach((tile, index) => {
|
||||
if (tile.image_visible && !tile.solved) {
|
||||
|
@ -60,7 +60,7 @@ mainWindow.check_if_pair_solved.setHandler(function () {
|
|||
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
mainWindow.run();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ for (let i = tiles.length - 1; i > 0; i--) {
|
|||
let model = new slint.ArrayModel(tiles);
|
||||
window.memory_tiles = model;
|
||||
|
||||
window.check_if_pair_solved.setHandler(function () {
|
||||
window.check_if_pair_solved = function () {
|
||||
let flipped_tiles = [];
|
||||
tiles.forEach((tile, index) => {
|
||||
if (tile.image_visible && !tile.solved) {
|
||||
|
@ -58,6 +58,6 @@ window.check_if_pair_solved.setHandler(function () {
|
|||
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
window.run();
|
||||
|
|
|
@ -12,12 +12,12 @@ window.ink_levels = [
|
|||
{ color: "#ffff00", level: 0.60 },
|
||||
{ color: "#000000", level: 0.90 }];
|
||||
|
||||
window.fax_number_erase.setHandler(function () {
|
||||
window.fax_number_erase = function () {
|
||||
window.fax_number = window.fax_number.substring(0, window.fax_number.length - 1);
|
||||
})
|
||||
window.fax_send.setHandler(function () {
|
||||
};
|
||||
window.fax_send = function () {
|
||||
console.log("Send fax to " + window.fax_number);
|
||||
window.fax_number = "";
|
||||
})
|
||||
};
|
||||
|
||||
window.run();
|
||||
|
|
|
@ -43,11 +43,11 @@ let model = new slint.ArrayModel([
|
|||
]);
|
||||
app.todo_model = model;
|
||||
|
||||
app.todo_added.setHandler(function (text) {
|
||||
app.todo_added = function (text) {
|
||||
model.push({ title: text, checked: false })
|
||||
})
|
||||
};
|
||||
|
||||
app.remove_done.setHandler(function () {
|
||||
app.remove_done = function () {
|
||||
let offset = 0;
|
||||
const length = model.length;
|
||||
for (let i = 0; i < length; ++i) {
|
||||
|
@ -56,6 +56,6 @@ app.remove_done.setHandler(function () {
|
|||
offset++;
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
app.run();
|
||||
|
|
|
@ -84,11 +84,11 @@ try {
|
|||
assert.equal(instance.callback_emission_count, 0);
|
||||
|
||||
|
||||
/// also test setHandler
|
||||
instance.test_callback2.setHandler(function(a) {
|
||||
/// also test assigning with a function
|
||||
instance.test_callback2 = function(a) {
|
||||
callback_3_emitted += 100;
|
||||
callback_3_string_value = a;
|
||||
});
|
||||
};
|
||||
instance.test_callback2("salùt")
|
||||
assert.equal(callback_3_emitted, 101);
|
||||
assert.equal(callback_3_string_value, "salùt");
|
||||
|
|
|
@ -204,11 +204,11 @@ assert!(!instance.window().is_visible());
|
|||
|
||||
```js
|
||||
var instance = new slint.Hello();
|
||||
assert(!instance.window.is_visible);
|
||||
assert(!instance.window.isVisible);
|
||||
instance.window.show();
|
||||
assert(instance.window.is_visible);
|
||||
assert(instance.window.isVisible);
|
||||
instance.window.hide();
|
||||
assert(!instance.window.is_visible);
|
||||
assert(!instance.window.isVisible);
|
||||
```
|
||||
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue