Release 0.7.13-alpha
This commit is contained in:
commit
42bdab988d
10
Changelog.md
10
Changelog.md
|
|
@ -1,7 +1,17 @@
|
||||||
|
# 0.7.13-alpha:
|
||||||
|
Changes:
|
||||||
|
- changed file MIME type from text/plain to application/lightningbeam to prevent editor woes on Linux
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Port several live fixes to version control
|
||||||
|
- Fix opening files on macOS
|
||||||
|
- Improve rendering speed by 10x or more when multiple layers are present
|
||||||
|
|
||||||
# 0.7.12-alpha:
|
# 0.7.12-alpha:
|
||||||
New features:
|
New features:
|
||||||
- Add "New Window" command
|
- Add "New Window" command
|
||||||
- Enable files to be opened with Lightningbeam
|
- Enable files to be opened with Lightningbeam
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- Fix error when an object is deleted from a frame
|
- Fix error when an object is deleted from a frame
|
||||||
- Fix parent references being lost
|
- Fix parent references being lost
|
||||||
|
|
|
||||||
|
|
@ -126,87 +126,94 @@ fn handle_file_associations(app: AppHandle, files: Vec<PathBuf>) {
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
let pkg_name = env!("CARGO_PKG_NAME").to_string();
|
let pkg_name = env!("CARGO_PKG_NAME").to_string();
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.setup(|app| {
|
.manage(Mutex::new(AppState::default()))
|
||||||
{
|
.setup(|app| {
|
||||||
app.manage(Mutex::new(AppState::default()));
|
#[cfg(any(windows, target_os = "linux"))] // Windows/Linux needs different handling from macOS
|
||||||
}
|
{
|
||||||
#[cfg(any(windows, target_os = "linux"))] // Windows/Linux needs different handling from macOS
|
let mut files = Vec::new();
|
||||||
{
|
|
||||||
let mut files = Vec::new();
|
|
||||||
|
|
||||||
// NOTICE: `args` may include URL protocol (`your-app-protocol://`)
|
// NOTICE: `args` may include URL protocol (`your-app-protocol://`)
|
||||||
// or arguments (`--`) if your app supports them.
|
// or arguments (`--`) if your app supports them.
|
||||||
// files may aslo be passed as `file://path/to/file`
|
// files may also be passed as `file://path/to/file`
|
||||||
for maybe_file in std::env::args().skip(1) {
|
for maybe_file in std::env::args().skip(1) {
|
||||||
// skip flags like -f or --flag
|
// skip flags like -f or --flag
|
||||||
if maybe_file.starts_with('-') {
|
if maybe_file.starts_with('-') {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// handle `file://` path urls and skip other urls
|
|
||||||
if let Ok(url) = Url::parse(&maybe_file) {
|
|
||||||
// if let Ok(url) = url::Url::parse(&maybe_file) {
|
|
||||||
if let Ok(path) = url.to_file_path() {
|
|
||||||
files.push(path);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
files.push(PathBuf::from(maybe_file))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_file_associations(app.handle().clone(), files);
|
// handle `file://` path urls and skip other urls
|
||||||
}
|
if let Ok(url) = Url::parse(&maybe_file) {
|
||||||
#[cfg(debug_assertions)] // only include this code on debug builds
|
// if let Ok(url) = url::Url::parse(&maybe_file) {
|
||||||
{
|
if let Ok(path) = url.to_file_path() {
|
||||||
let window = app.get_webview_window("main").unwrap();
|
files.push(path);
|
||||||
window.open_devtools();
|
}
|
||||||
window.close_devtools();
|
} else {
|
||||||
}
|
files.push(PathBuf::from(maybe_file))
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.plugin(
|
|
||||||
tauri_plugin_log::Builder::new()
|
|
||||||
.timezone_strategy(tauri_plugin_log::TimezoneStrategy::UseLocal)
|
|
||||||
.format(|out, message, record| {
|
|
||||||
let date = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
|
||||||
out.finish(format_args!(
|
|
||||||
"{}[{}] {}",
|
|
||||||
date,
|
|
||||||
record.level(),
|
|
||||||
message
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.targets([
|
|
||||||
Target::new(TargetKind::Stdout),
|
|
||||||
// LogDir locations:
|
|
||||||
// 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),
|
|
||||||
])
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.plugin(tauri_plugin_dialog::init())
|
|
||||||
.plugin(tauri_plugin_fs::init())
|
|
||||||
.plugin(tauri_plugin_shell::init())
|
|
||||||
.invoke_handler(tauri::generate_handler![greet, trace, debug, info, warn, error, create_window])
|
|
||||||
// .manage(window_counter)
|
|
||||||
.build(tauri::generate_context!())
|
|
||||||
.expect("error while running tauri application")
|
|
||||||
.run(
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
|app, event| {
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
|
||||||
if let tauri::RunEvent::Opened { urls } = event {
|
|
||||||
let files = urls
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|url| url.to_file_path().ok())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
handle_file_associations(app.clone(), files);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
|
||||||
|
handle_file_associations(app.handle().clone(), files);
|
||||||
|
}
|
||||||
|
#[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(())
|
||||||
|
})
|
||||||
|
.plugin(
|
||||||
|
tauri_plugin_log::Builder::new()
|
||||||
|
.timezone_strategy(tauri_plugin_log::TimezoneStrategy::UseLocal)
|
||||||
|
.format(|out, message, record| {
|
||||||
|
let date = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
|
||||||
|
out.finish(format_args!(
|
||||||
|
"{}[{}] {}",
|
||||||
|
date,
|
||||||
|
record.level(),
|
||||||
|
message
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.targets([
|
||||||
|
Target::new(TargetKind::Stdout),
|
||||||
|
// LogDir locations:
|
||||||
|
// 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),
|
||||||
|
])
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.plugin(tauri_plugin_fs::init())
|
||||||
|
.plugin(tauri_plugin_shell::init())
|
||||||
|
.invoke_handler(tauri::generate_handler![greet, trace, debug, info, warn, error, create_window])
|
||||||
|
// .manage(window_counter)
|
||||||
|
.build(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application")
|
||||||
|
.run(
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
|app, event| {
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
if let tauri::RunEvent::Opened { urls } = event {
|
||||||
|
let app = app.clone();
|
||||||
|
let files = urls
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|url| url.to_file_path().ok())
|
||||||
|
.map(|f| {
|
||||||
|
let file = f.to_string_lossy().replace('\\', "\\\\"); // escape backslash
|
||||||
|
format!("\"{file}\"",) // wrap in quotes for JS array
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
for path in files {
|
||||||
|
create_window(app.clone(), Some(path)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
tracing_subscriber::fmt().with_env_filter(EnvFilter::new(format!("{}=trace", pkg_name))).init();
|
tracing_subscriber::fmt().with_env_filter(EnvFilter::new(format!("{}=trace", pkg_name))).init();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Lightningbeam",
|
"productName": "Lightningbeam",
|
||||||
"version": "0.7.12-alpha",
|
"version": "0.7.13-alpha",
|
||||||
"identifier": "org.lightningbeam.core",
|
"identifier": "org.lightningbeam.core",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../src"
|
"frontendDist": "../src"
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
"ext": [
|
"ext": [
|
||||||
"beam"
|
"beam"
|
||||||
],
|
],
|
||||||
"mimeType": "text/plain"
|
"mimeType": "application/lightningbeam"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
src/icon.js
45
src/icon.js
|
|
@ -3,28 +3,43 @@ class Icon {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.svgContent = '';
|
this.svgContent = '';
|
||||||
this.svgLoaded = false;
|
this.svgLoaded = false;
|
||||||
this.load()
|
this.cacheCanvas = null; // Offscreen canvas for caching
|
||||||
|
this.cacheContext = null;
|
||||||
|
this.cacheColor = null;
|
||||||
|
this.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
return fetch(this.url)
|
try {
|
||||||
.then(response => response.text())
|
const response = await fetch(this.url);
|
||||||
.then(svgContent => {
|
this.svgContent = await response.text();
|
||||||
this.svgContent = svgContent;
|
this.svgLoaded = true;
|
||||||
this.svgLoaded = true;
|
} catch (error) {
|
||||||
})
|
console.error('Error loading SVG:', error);
|
||||||
.catch(error => {
|
this.svgLoaded = false;
|
||||||
console.error('Error loading SVG:', error);
|
}
|
||||||
this.svgLoaded = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(ctx, x, y, w, h, color) {
|
render(ctx, x, y, w, h, color) {
|
||||||
if (this.svgLoaded) {
|
if (!this.svgLoaded) return; // Do nothing if SVG is not loaded
|
||||||
ctx.fillStyle = color
|
|
||||||
ctx.drawSvg(this.svgContent, x, y, w, h)
|
if (!this.cacheCanvas || this.cacheCanvas.width !== w || this.cacheCanvas.height !== h || this.cacheColor !== color) {
|
||||||
|
// Create or update the offscreen canvas for caching
|
||||||
|
this.cacheCanvas = document.createElement('canvas');
|
||||||
|
this.cacheCanvas.width = w;
|
||||||
|
this.cacheCanvas.height = h;
|
||||||
|
this.cacheContext = this.cacheCanvas.getContext('2d');
|
||||||
|
|
||||||
|
// Draw the SVG onto the offscreen canvas
|
||||||
|
this.cacheContext.clearRect(0, 0, w, h); // Clear previous contents
|
||||||
|
this.cacheContext.fillStyle = color;
|
||||||
|
this.cacheColor = color
|
||||||
|
this.cacheContext.drawSvg(this.svgContent, 0, 0, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw the cached result onto the main canvas
|
||||||
|
ctx.drawImage(this.cacheCanvas, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Icon };
|
export { Icon };
|
||||||
|
|
|
||||||
122
src/main.js
122
src/main.js
|
|
@ -93,7 +93,7 @@ function forwardConsole(fnName, dest) {
|
||||||
const stackLines = error.stack.split("\n");
|
const stackLines = error.stack.split("\n");
|
||||||
|
|
||||||
let message = args.join(" "); // Join all arguments into a single string
|
let message = args.join(" "); // Join all arguments into a single string
|
||||||
const location = stackLines[1].match(/([a-zA-Z0-9_-]+\.js:\d+)/);
|
const location = stackLines.length>1 ? stackLines[1].match(/([a-zA-Z0-9_-]+\.js:\d+)/) : stackLines.toString();
|
||||||
|
|
||||||
if (fnName === "error") {
|
if (fnName === "error") {
|
||||||
// Send the full stack trace for errors
|
// Send the full stack trace for errors
|
||||||
|
|
@ -350,7 +350,6 @@ let context = {
|
||||||
let config = {
|
let config = {
|
||||||
shortcuts: {
|
shortcuts: {
|
||||||
playAnimation: " ",
|
playAnimation: " ",
|
||||||
// undo: "<ctrl>+z"
|
|
||||||
undo: "<mod>z",
|
undo: "<mod>z",
|
||||||
redo: "<mod>Z",
|
redo: "<mod>Z",
|
||||||
new: "<mod>n",
|
new: "<mod>n",
|
||||||
|
|
@ -379,6 +378,7 @@ let config = {
|
||||||
recentFiles: [],
|
recentFiles: [],
|
||||||
scrollSpeed: 1,
|
scrollSpeed: 1,
|
||||||
debug: false,
|
debug: false,
|
||||||
|
reopenLastSession: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function getShortcut(shortcut) {
|
function getShortcut(shortcut) {
|
||||||
|
|
@ -421,13 +421,8 @@ async function saveConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addRecentFile(filePath) {
|
async function addRecentFile(filePath) {
|
||||||
if (!config.recentFiles.includes(filePath)) {
|
config.recentFiles = [filePath, ...config.recentFiles.filter(file => file !== filePath)].slice(0, 10);
|
||||||
config.recentFiles.unshift(filePath);
|
await saveConfig(config);
|
||||||
if (config.recentFiles.length > 10) {
|
|
||||||
config.recentFiles = config.recentFiles.slice(0, 10);
|
|
||||||
}
|
|
||||||
await saveConfig(config);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointers to all objects
|
// Pointers to all objects
|
||||||
|
|
@ -1327,12 +1322,14 @@ let actions = {
|
||||||
for (let frameObj of action.selectedFrames) {
|
for (let frameObj of action.selectedFrames) {
|
||||||
let layer = object.layers[frameObj.layer];
|
let layer = object.layers[frameObj.layer];
|
||||||
let frame = layer.frames[frameObj.frameNum];
|
let frame = layer.frames[frameObj.frameNum];
|
||||||
frameBuffer.push({
|
if (frameObj) {
|
||||||
frame: frame,
|
frameBuffer.push({
|
||||||
frameNum: frameObj.frameNum,
|
frame: frame,
|
||||||
layer: frameObj.layer,
|
frameNum: frameObj.frameNum,
|
||||||
});
|
layer: frameObj.layer,
|
||||||
layer.deleteFrame(frame.idx, undefined, frameObj.replacementUuid);
|
});
|
||||||
|
layer.deleteFrame(frame.idx, undefined, frameObj.replacementUuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (let frameObj of frameBuffer) {
|
for (let frameObj of frameBuffer) {
|
||||||
const layer_idx = frameObj.layer + action.offset.layers;
|
const layer_idx = frameObj.layer + action.offset.layers;
|
||||||
|
|
@ -1448,6 +1445,7 @@ let actions = {
|
||||||
let serializableShapes = [];
|
let serializableShapes = [];
|
||||||
let serializableObjects = [];
|
let serializableObjects = [];
|
||||||
let bbox;
|
let bbox;
|
||||||
|
const frame = context.activeObject.currentFrame
|
||||||
for (let shape of context.shapeselection) {
|
for (let shape of context.shapeselection) {
|
||||||
serializableShapes.push(shape.idx);
|
serializableShapes.push(shape.idx);
|
||||||
if (bbox == undefined) {
|
if (bbox == undefined) {
|
||||||
|
|
@ -1457,12 +1455,14 @@ let actions = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let object of context.selection) {
|
for (let object of context.selection) {
|
||||||
serializableObjects.push(object.idx);
|
if (object.idx in frame.keys) {
|
||||||
// TODO: rotated bbox
|
serializableObjects.push(object.idx);
|
||||||
if (bbox == undefined) {
|
// TODO: rotated bbox
|
||||||
bbox = object.bbox();
|
if (bbox == undefined) {
|
||||||
} else {
|
bbox = object.bbox();
|
||||||
growBoundingBox(bbox, object.bbox());
|
} else {
|
||||||
|
growBoundingBox(bbox, object.bbox());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.shapeselection = [];
|
context.shapeselection = [];
|
||||||
|
|
@ -1472,7 +1472,7 @@ let actions = {
|
||||||
objects: serializableObjects,
|
objects: serializableObjects,
|
||||||
groupUuid: uuidv4(),
|
groupUuid: uuidv4(),
|
||||||
parent: context.activeObject.idx,
|
parent: context.activeObject.idx,
|
||||||
frame: context.activeObject.currentFrame.idx,
|
frame: frame.idx,
|
||||||
layer: context.activeObject.activeLayer.idx,
|
layer: context.activeObject.activeLayer.idx,
|
||||||
position: {
|
position: {
|
||||||
x: (bbox.x.min + bbox.x.max) / 2,
|
x: (bbox.x.min + bbox.x.max) / 2,
|
||||||
|
|
@ -2637,14 +2637,14 @@ class Layer extends Widget {
|
||||||
ctx.setTransform(transform)
|
ctx.setTransform(transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (this.activeShape) {
|
||||||
if (this.activeShape) {
|
this.activeShape.draw(cxt)
|
||||||
this.activeShape.draw(cxt)
|
}
|
||||||
}
|
if (context.activeCurve) {
|
||||||
if (context.activeCurve) {
|
if (frame.shapes.indexOf(context.activeCurve.shape) != -1) {
|
||||||
if (frame.shapes.indexOf(context.activeCurve.shape) != -1) {
|
cxt.selected = true
|
||||||
cxt.selected = true
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2965,20 +2965,22 @@ class BaseShape {
|
||||||
ctx.lineCap = "round";
|
ctx.lineCap = "round";
|
||||||
|
|
||||||
// Create a repeating pattern for indicating selected shapes
|
// Create a repeating pattern for indicating selected shapes
|
||||||
let patternCanvas = document.createElement('canvas');
|
if (!this.patternCanvas) {
|
||||||
patternCanvas.width = 2;
|
this.patternCanvas = document.createElement('canvas');
|
||||||
patternCanvas.height = 2;
|
this.patternCanvas.width = 2;
|
||||||
let patternCtx = patternCanvas.getContext('2d');
|
this.patternCanvas.height = 2;
|
||||||
// Draw the pattern:
|
let patternCtx = this.patternCanvas.getContext('2d');
|
||||||
// black, transparent,
|
// Draw the pattern:
|
||||||
// transparent, white
|
// black, transparent,
|
||||||
patternCtx.fillStyle = 'black';
|
// transparent, white
|
||||||
patternCtx.fillRect(0, 0, 1, 1);
|
patternCtx.fillStyle = 'black';
|
||||||
patternCtx.clearRect(1, 0, 1, 1);
|
patternCtx.fillRect(0, 0, 1, 1);
|
||||||
patternCtx.clearRect(0, 1, 1, 1);
|
patternCtx.clearRect(1, 0, 1, 1);
|
||||||
patternCtx.fillStyle = 'white';
|
patternCtx.clearRect(0, 1, 1, 1);
|
||||||
patternCtx.fillRect(1, 1, 1, 1);
|
patternCtx.fillStyle = 'white';
|
||||||
let pattern = ctx.createPattern(patternCanvas, 'repeat'); // repeat the pattern across the canvas
|
patternCtx.fillRect(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
let pattern = ctx.createPattern(this.patternCanvas, 'repeat'); // repeat the pattern across the canvas
|
||||||
|
|
||||||
// for (let region of this.regions) {
|
// for (let region of this.regions) {
|
||||||
// // if (region.filled) continue;
|
// // if (region.filled) continue;
|
||||||
|
|
@ -4114,7 +4116,9 @@ class GraphicsObject extends Widget {
|
||||||
for (let layer of this.layers) {
|
for (let layer of this.layers) {
|
||||||
layer.children = layer.children.filter(child => child.idx !== idx);
|
layer.children = layer.children.filter(child => child.idx !== idx);
|
||||||
for (let frame of layer.frames) {
|
for (let frame of layer.frames) {
|
||||||
delete frame[idx];
|
if (frame) {
|
||||||
|
delete frame[idx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this.children.splice(this.children.indexOf(childObject), 1);
|
// this.children.splice(this.children.indexOf(childObject), 1);
|
||||||
|
|
@ -5069,6 +5073,19 @@ async function setupVideoExport(ext, path, canvas, exportContext) {
|
||||||
|
|
||||||
// audioEncoder.configure(audioConfig)
|
// audioEncoder.configure(audioConfig)
|
||||||
|
|
||||||
|
async function finishEncoding() {
|
||||||
|
const progressText = document.getElementById('progressText');
|
||||||
|
progressText.innerText = 'Finalizing...';
|
||||||
|
const progressBar = document.getElementById('progressBar');
|
||||||
|
progressBar.value = 100;
|
||||||
|
await videoEncoder.flush();
|
||||||
|
muxer.finalize();
|
||||||
|
await writeFile(path, new Uint8Array(target.buffer));
|
||||||
|
const modal = document.getElementById('progressModal');
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.querySelector("body").style.cursor = "default";
|
||||||
|
}
|
||||||
|
|
||||||
const processFrame = async (currentFrame) => {
|
const processFrame = async (currentFrame) => {
|
||||||
if (currentFrame < root.maxFrame) {
|
if (currentFrame < root.maxFrame) {
|
||||||
// Update progress bar
|
// Update progress bar
|
||||||
|
|
@ -5971,7 +5988,7 @@ function stage() {
|
||||||
for (let child of context.selection) {
|
for (let child of context.selection) {
|
||||||
if (!context.activeObject.currentFrame) continue;
|
if (!context.activeObject.currentFrame) continue;
|
||||||
if (!context.activeObject.currentFrame.keys) continue;
|
if (!context.activeObject.currentFrame.keys) continue;
|
||||||
if (!child.idx in context.activeObject.currentFrame.keys) continue;
|
if (!(child.idx in context.activeObject.currentFrame.keys)) continue;
|
||||||
context.activeObject.currentFrame.keys[child.idx].x +=
|
context.activeObject.currentFrame.keys[child.idx].x +=
|
||||||
mouse.x - context.lastMouse.x;
|
mouse.x - context.lastMouse.x;
|
||||||
context.activeObject.currentFrame.keys[child.idx].y +=
|
context.activeObject.currentFrame.keys[child.idx].y +=
|
||||||
|
|
@ -6729,8 +6746,12 @@ function outliner(object = undefined) {
|
||||||
async function startup() {
|
async function startup() {
|
||||||
await loadConfig();
|
await loadConfig();
|
||||||
createNewFileDialog(_newFile, _open, config);
|
createNewFileDialog(_newFile, _open, config);
|
||||||
if (!window.openedFiles) {
|
if (!window.openedFiles?.length) {
|
||||||
showNewFileDialog(config);
|
if (config.reopenLastSession && config.recentFiles?.length) {
|
||||||
|
_open(config.recentFiles[0])
|
||||||
|
} else {
|
||||||
|
showNewFileDialog(config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7896,6 +7917,11 @@ async function renderMenu() {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
action: () => {},
|
action: () => {},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: "Close Window",
|
||||||
|
enabled: true,
|
||||||
|
action: quit,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: "Quit Lightningbeam",
|
text: "Quit Lightningbeam",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
@ -8349,4 +8375,4 @@ if (window.openedFiles?.length>0) {
|
||||||
for (let i=1; i<window.openedFiles.length; i++) {
|
for (let i=1; i<window.openedFiles.length; i++) {
|
||||||
newWindow(window.openedFiles[i])
|
newWindow(window.openedFiles[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue