Skip to content

Commit dd4d67e

Browse files
committedNov 17, 2024
Implemented: Import images in bulk #532
1 parent d8fe5b2 commit dd4d67e

File tree

3 files changed

+124
-14
lines changed

3 files changed

+124
-14
lines changed
 

‎packages/project-editor/features/bitmap/bitmap.tsx

+48-12
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import { getThemedColor } from "project-editor/features/style/theme";
4141

4242
import { showGenericDialog } from "project-editor/core/util";
4343

44-
import { AbsoluteFileInput } from "project-editor/ui-components/FileInput";
44+
import { MultipleAbsoluteFileInput } from "project-editor/ui-components/FileInput";
4545
import { getProject, findStyle } from "project-editor/project/project";
4646

4747
import { ProjectEditor } from "project-editor/project-editor-interface";
@@ -241,12 +241,18 @@ export class Bitmap extends EezObject {
241241
validators.required,
242242
validators.invalidCharacters("."),
243243
validators.unique({}, parent)
244-
]
244+
],
245+
visible: (values: any) => {
246+
return !(
247+
values.imageFilePaths &&
248+
values.imageFilePaths.length > 1
249+
);
250+
}
245251
},
246252
{
247-
name: "imageFilePath",
253+
name: "imageFilePaths",
248254
displayName: "Image",
249-
type: AbsoluteFileInput,
255+
type: MultipleAbsoluteFileInput,
250256
validators: [validators.required],
251257
options: {
252258
filters: [
@@ -287,16 +293,46 @@ export class Bitmap extends EezObject {
287293
}
288294
});
289295

290-
const name: string = result.values.name;
291296
const bpp: number = result.values.bpp;
292297

293-
return createBitmap(
294-
projectStore,
295-
result.values.imageFilePath,
296-
undefined,
297-
name,
298-
bpp
299-
);
298+
if (result.values.imageFilePaths.length == 1) {
299+
const name: string = result.values.name;
300+
301+
return createBitmap(
302+
projectStore,
303+
result.values.imageFilePaths[0],
304+
undefined,
305+
name,
306+
bpp
307+
);
308+
} else {
309+
projectStore.undoManager.setCombineCommands(true);
310+
311+
for (let i = 0; i < result.values.imageFilePaths.length; i++) {
312+
const filePath = result.values.imageFilePaths[i];
313+
314+
let name = getUniquePropertyValue(
315+
projectStore.project.bitmaps,
316+
"name",
317+
path.parse(filePath).name
318+
) as string;
319+
320+
const bitmap = await createBitmap(
321+
projectStore,
322+
filePath,
323+
undefined,
324+
name,
325+
bpp
326+
);
327+
if (bitmap) {
328+
projectStore.addObject(parent, bitmap);
329+
}
330+
}
331+
332+
projectStore.undoManager.setCombineCommands(false);
333+
334+
return undefined;
335+
}
300336
},
301337
icon: "material:image",
302338
afterLoadHook: (bitmap: Bitmap, project) => {

‎packages/project-editor/lvgl/widgets/Base.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -1054,8 +1054,10 @@ export class LVGLWidget extends Widget {
10541054
referencedObjectCollectionPath: "lvglGroups/groups",
10551055
propertyGridGroup: generalGroup,
10561056
hideInPropertyGrid: (widget: LVGLWidget) =>
1057-
ProjectEditor.getProject(widget).lvglGroups.groups.length ==
1058-
0 || widget instanceof LVGLScreenWidget
1057+
(ProjectEditor.getProject(widget).lvglGroups.groups
1058+
.length == 0 &&
1059+
!widget.group) ||
1060+
widget instanceof LVGLScreenWidget
10591061
},
10601062
{
10611063
name: "groupIndex",

‎packages/project-editor/ui-components/FileInput.tsx

+72
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,78 @@ export class AbsoluteFileInput extends FieldComponent {
133133

134134
////////////////////////////////////////////////////////////////////////////////
135135

136+
export class MultipleAbsoluteFileInput extends FieldComponent {
137+
static contextType = ProjectContext;
138+
declare context: React.ContextType<typeof ProjectContext>;
139+
140+
onClear = () => {
141+
this.props.onChange(undefined);
142+
};
143+
144+
onSelect = async () => {
145+
const result = await dialog.showOpenDialog({
146+
properties: ["openFile", "multiSelections"],
147+
filters: this.props.fieldProperties.options.filters
148+
});
149+
150+
if (result.filePaths && result.filePaths.length > 0) {
151+
this.props.onChange(result.filePaths);
152+
}
153+
};
154+
155+
get value() {
156+
const value = this.props.values[this.props.fieldProperties.name];
157+
if (!value) {
158+
return "";
159+
}
160+
161+
if (value.length > 1) {
162+
return `${value.length} images selected`;
163+
}
164+
165+
return value;
166+
}
167+
168+
render() {
169+
let clearButton: JSX.Element | undefined;
170+
171+
if (this.props.values[this.props.fieldProperties.name]) {
172+
clearButton = (
173+
<button
174+
className="btn btn-default"
175+
type="button"
176+
onClick={this.onClear}
177+
>
178+
<Icon icon="material:close" size={17} />
179+
</button>
180+
);
181+
}
182+
183+
return (
184+
<div className="input-group">
185+
<input
186+
type="text"
187+
className="form-control"
188+
value={this.value}
189+
readOnly
190+
/>
191+
<>
192+
{clearButton}
193+
<button
194+
className="btn btn-secondary"
195+
type="button"
196+
onClick={this.onSelect}
197+
>
198+
&hellip;
199+
</button>
200+
</>
201+
</div>
202+
);
203+
}
204+
}
205+
206+
////////////////////////////////////////////////////////////////////////////////
207+
136208
export class AbsoluteFileSaveInput extends FieldComponent {
137209
static contextType = ProjectContext;
138210
declare context: React.ContextType<typeof ProjectContext>;

0 commit comments

Comments
 (0)