Merge branch 'main' into release
This commit is contained in:
commit
e65aac496c
15
Changelog.md
15
Changelog.md
|
|
@ -1,3 +1,18 @@
|
|||
# 0.7.0-alpha:
|
||||
New features:
|
||||
- Keyframes can now have both motion and shape tweens on the same frame
|
||||
|
||||
Changes:
|
||||
- Tweens are now indicated with colored lines
|
||||
- Tweens are now attached to keyframes rather than the frames in between them
|
||||
|
||||
Bugfixes:
|
||||
- Fix paint bucket coordinates being incorrect inside of movie clips
|
||||
- Fix paint bucket not working for large shapes and shapes whose internal coordinates crossed 0,0
|
||||
- Fixed dragging frames breaking tweens
|
||||
- Fixed logs being inaccessible on macOS
|
||||
- Fixed right-click causing a menu with "Reload" to appear which would reset the application
|
||||
|
||||
# 0.6.18-alpha:
|
||||
New features:
|
||||
- Errors and debug messages are now logged to a file
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use tauri_plugin_log::{Target, TargetKind};
|
|||
use log::{trace, info, debug, warn, error};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use chrono::Local;
|
||||
use tauri::Manager;
|
||||
|
||||
|
||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||
|
|
@ -50,9 +51,9 @@ pub fn run() {
|
|||
.targets([
|
||||
Target::new(TargetKind::Stdout),
|
||||
// LogDir locations:
|
||||
// Linux: /home/user/.local/share/org.lightningbeam.app/logs
|
||||
// macOS: /Users/user/Library/Logs/org.lightningbeam.app/logs
|
||||
// Windows: C:\Users\user\AppData\Local\org.lightningbeam.app\logs
|
||||
// Linux: /home/user/.local/share/org.lightningbeam.core/logs
|
||||
// macOS: /Users/user/Library/Logs/org.lightningbeam.core/logs
|
||||
// Windows: C:\Users\user\AppData\Local\org.lightningbeam.core\logs
|
||||
Target::new(TargetKind::LogDir { file_name: Some("logs".to_string()) }),
|
||||
Target::new(TargetKind::Webview),
|
||||
])
|
||||
|
|
@ -62,6 +63,15 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.invoke_handler(tauri::generate_handler![greet, trace, debug, info, warn, error])
|
||||
.setup(|app| {
|
||||
#[cfg(debug_assertions)] // only include this code on debug builds
|
||||
{
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
window.open_devtools();
|
||||
window.close_devtools();
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
tracing_subscriber::fmt().with_env_filter(EnvFilter::new(format!("{}=trace", pkg_name))).init();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Lightningbeam",
|
||||
"version": "0.6.18-alpha",
|
||||
"identifier": "org.lightningbeam.app",
|
||||
"version": "0.7.0-alpha",
|
||||
"identifier": "org.lightningbeam.core",
|
||||
"build": {
|
||||
"frontendDist": "../src"
|
||||
},
|
||||
|
|
|
|||
1175
src/main.js
1175
src/main.js
File diff suppressed because it is too large
Load Diff
50
src/utils.js
50
src/utils.js
|
|
@ -145,20 +145,40 @@ function generateWaveform(img, buffer, imgHeight, frameWidth, framesPerSecond) {
|
|||
img.src = dataUrl;
|
||||
}
|
||||
|
||||
function multiplyMatrices(a, b) {
|
||||
let result = [
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]
|
||||
];
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
for (let k = 0; k < 3; k++) {
|
||||
result[i][j] += a[i][k] * b[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function growBoundingBox(bboxa, bboxb) {
|
||||
bboxa.x.min = Math.min(bboxa.x.min, bboxb.x.min);
|
||||
bboxa.y.min = Math.min(bboxa.y.min, bboxb.y.min);
|
||||
bboxa.x.max = Math.max(bboxa.x.max, bboxb.x.max);
|
||||
bboxa.y.max = Math.max(bboxa.y.max, bboxb.y.max);
|
||||
}
|
||||
|
||||
function floodFillRegion(
|
||||
startPoint,
|
||||
epsilon,
|
||||
offset, // TODO: this needs to be a generalized transform
|
||||
fileWidth,
|
||||
fileHeight,
|
||||
context,
|
||||
debugPoints,
|
||||
debugPaintbucket) {
|
||||
// Helper function to check if the point is at the boundary of the region
|
||||
function isBoundaryPoint(point) {
|
||||
return point.x <= offset.x || point.x >= offset.x + fileWidth ||
|
||||
point.y <= offset.y || point.y >= offset.y + fileHeight;
|
||||
}
|
||||
|
||||
let halfEpsilon = epsilon/2
|
||||
|
||||
// Helper function to check if a point is near any curve in the shape
|
||||
|
|
@ -186,6 +206,22 @@ function floodFillRegion(
|
|||
const visited = new Set();
|
||||
const stack = [startPoint];
|
||||
const regionPoints = [];
|
||||
let bbox;
|
||||
if (shapes.length>0) {
|
||||
bbox = shapes[0].boundingBox
|
||||
} else {
|
||||
throw new Error("No shapes in layer")
|
||||
}
|
||||
for (const shape of shapes) {
|
||||
growBoundingBox(bbox, shape.boundingBox)
|
||||
}
|
||||
// Helper function to check if the point is at the boundary of the region
|
||||
function isBoundaryPoint(point) {
|
||||
return point.x <= bbox.x.min - 100 || point.x >= bbox.x.max + 100 ||
|
||||
point.y <= bbox.y.min - 100 || point.y >= bbox.y.max + 100;
|
||||
return point.x <= offset.x || point.x >= offset.x + fileWidth ||
|
||||
point.y <= offset.y || point.y >= offset.y + fileHeight;
|
||||
}
|
||||
|
||||
// Begin the flood fill process
|
||||
while (stack.length > 0) {
|
||||
|
|
@ -872,7 +908,9 @@ export {
|
|||
lerpColor,
|
||||
camelToWords,
|
||||
generateWaveform,
|
||||
growBoundingBox,
|
||||
floodFillRegion,
|
||||
multiplyMatrices,
|
||||
getShapeAtPoint,
|
||||
hslToRgb,
|
||||
hsvToRgb,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,39 @@
|
|||
import { clamp, drawCheckerboardBackground, hslToRgb, hsvToRgb, rgbToHex } from "./utils.js"
|
||||
|
||||
function growBoundingBox(bboxa, bboxb) {
|
||||
bboxa.x.min = Math.min(bboxa.x.min, bboxb.x.min);
|
||||
bboxa.y.min = Math.min(bboxa.y.min, bboxb.y.min);
|
||||
bboxa.x.max = Math.max(bboxa.x.max, bboxb.x.max);
|
||||
bboxa.y.max = Math.max(bboxa.y.max, bboxb.y.max);
|
||||
}
|
||||
|
||||
class Widget {
|
||||
constructor(x, y) {
|
||||
this._globalEvents = new Set()
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.scale_x = 1
|
||||
this.scale_y = 1
|
||||
this.rotation = 0
|
||||
this.children = []
|
||||
}
|
||||
handleMouseEvent(eventType, x, y) {
|
||||
for (let child of this.children) {
|
||||
if (child.hitTest(x, y) || child._globalEvents.has(eventType)) {
|
||||
child.handleMouseEvent(eventType, x-child.x, y-child.y)
|
||||
// Adjust for translation
|
||||
const dx = x - child.x;
|
||||
const dy = y - child.y;
|
||||
|
||||
// Apply inverse rotation
|
||||
const cosTheta = Math.cos(child.rotation);
|
||||
const sinTheta = Math.sin(child.rotation);
|
||||
|
||||
// Rotate coordinates to child's local space
|
||||
const rotatedX = dx * cosTheta + dy * sinTheta;
|
||||
const rotatedY = -dx * sinTheta + dy * cosTheta;
|
||||
|
||||
// First, perform hit test using original (global) coordinates
|
||||
if (child.hitTest(rotatedX, rotatedY) || child._globalEvents.has(eventType)) {
|
||||
child.handleMouseEvent(eventType, rotatedX, rotatedY);
|
||||
}
|
||||
}
|
||||
const eventTypes = [
|
||||
|
|
@ -26,22 +49,45 @@ class Widget {
|
|||
}
|
||||
}
|
||||
hitTest(x, y) {
|
||||
if ((x >= this.x) && (x <= this.x+this.width) &&
|
||||
(y >= this.y) && (y <= this.y+this.height)) {
|
||||
// if ((x >= this.x) && (x <= this.x+this.width) &&
|
||||
// (y >= this.y) && (y <= this.y+this.height)) {
|
||||
if ((x>=0) && (x <= this.width) && (y >= 0) && (y <= this.height)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
bbox() {
|
||||
let bbox;
|
||||
if (this.children.length > 0) {
|
||||
if (!bbox) {
|
||||
bbox = structuredClone(this.children[0].bbox());
|
||||
}
|
||||
for (let child of this.children) {
|
||||
growBoundingBox(bbox, child.bbox());
|
||||
}
|
||||
}
|
||||
if (bbox == undefined) {
|
||||
bbox = { x: { min: 0, max: 0 }, y: { min: 0, max: 0 } };
|
||||
}
|
||||
bbox.x.max *= this.scale_x;
|
||||
bbox.y.max *= this.scale_y;
|
||||
bbox.x.min += this.x;
|
||||
bbox.x.max += this.x;
|
||||
bbox.y.min += this.y;
|
||||
bbox.y.max += this.y;
|
||||
return bbox;
|
||||
}
|
||||
draw(ctx) {
|
||||
for (let child of this.children) {
|
||||
const transform = ctx.getTransform()
|
||||
ctx.translate(child.x, child.y)
|
||||
ctx.scale(child.scale_x, child.scale_y)
|
||||
ctx.rotate(child.rotation)
|
||||
child.draw(ctx)
|
||||
ctx.setTransform(transform)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HueSelectionBar extends Widget {
|
||||
constructor(width, height, x, y, colorCvs) {
|
||||
super(x, y)
|
||||
|
|
|
|||
Loading…
Reference in New Issue