Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/eez-studio-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ export interface IActionComponentDefinition {
migrateProperties?: (component: IActionComponent) => void;

execute?: (context: IDashboardComponentContext) => void;

// If true, the build generates an extern C prototype and a registerComponent()
// call. The user provides the implementation in their firmware project.
// Generated function: void eez_flow_ext_<sanitized_name>(FlowState*, unsigned)
isNative?: boolean;
}

interface IMessageFromWorker {
Expand Down Expand Up @@ -932,11 +937,35 @@ export interface IDashboardComponentContext {
throwError: (errorMessage: string) => void;
}

export interface IStructureField {
name: string;
type: ValueType;
}

export interface IStructureDefinition {
name: string;
fields: IStructureField[];
}

export interface IEnumMember {
name: string;
value: number;
}

export interface IEnumDefinition {
name: string;
members: IEnumMember[];
}

////////////////////////////////////////////////////////////////////////////////

export interface IEezFlowEditor {
registerActionComponent(definition: IActionComponentDefinition): void;

registerStructureVariableType(structure: IStructureDefinition): void;

registerEnumVariableType(enumDef: IEnumDefinition): void;

registerObjectVariableType(
name: string,
objectVariableType: IObjectVariableType
Expand Down
12 changes: 11 additions & 1 deletion packages/project-editor/build/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ export class Assets {
[componentType: number]: string;
} = {};

nativeExtensionComponents: { componentType: number; className: string }[] = [];

isUsingCrypyoSha256: boolean = false;

lvglBuild: LVGLBuild;
Expand Down Expand Up @@ -1808,6 +1810,14 @@ export async function buildAssets(
await assets.lvglBuild.buildActionsDecl();
}

if (
!sectionNames ||
sectionNames.indexOf("LVGL_EXT_COMPONENT_DECL") !== -1
) {
result.LVGL_EXT_COMPONENT_DECL =
await assets.lvglBuild.buildExtComponentDecl();
}

if (
!sectionNames ||
sectionNames.indexOf("LVGL_ACTIONS_ARRAY_DEF") !== -1
Expand Down Expand Up @@ -1873,7 +1883,7 @@ export async function buildAssets(

// build eez-gui-lite source code
if (sectionNames!.indexOf("EEZ_GUI_LITE_DECL") !== -1 || sectionNames!.indexOf("EEZ_GUI_LITE_DEF") !== -1) {
const buildEezGuiLite = new BuildEezGuiLite(assets);
const buildEezGuiLite = new BuildEezGuiLite(assets);
if (sectionNames!.indexOf("EEZ_GUI_LITE_DECL") !== -1) {
result.EEZ_GUI_LITE_DECL = buildEezGuiLite.buildDecl();
}
Expand Down
35 changes: 30 additions & 5 deletions packages/project-editor/build/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ function getComponentIdOfComponent(assets: Assets, component: Component) {
assets.dashboardComponentClassNameToComponentIdMap[name] =
flowComponentId;
assets.dashboardComponentTypeToNameMap[flowComponentId] = name;

if (
classInfo.isNative &&
assets.projectStore.projectTypeTraits.isLVGL &&
!assets.nativeExtensionComponents.find(
c => c.componentType === flowComponentId
)
) {
assets.nativeExtensionComponents.push({
componentType: flowComponentId!,
className: name
});
}
}
} else {
console.error("UNEXPECTED!");
Expand Down Expand Up @@ -755,9 +768,15 @@ export function buildFlowStructs(assets: Assets) {

const defs = [];

// Combine project-defined and imported (extension) structures
const allStructures = [
...assets.projectStore.project.variables.structures,
...assets.projectStore.importedStructureVariableTypes.values()
];

// enum FlowStructures
const structureEnumItems = [];
for (const structure of assets.projectStore.project.variables.structures) {
for (const structure of allStructures) {
structureEnumItems.push(
`${TAB}${getName(
"FLOW_STRUCTURE_",
Expand All @@ -777,7 +796,7 @@ export function buildFlowStructs(assets: Assets) {

// enum FlowArrayOfStructures
const arrayOfStructureEnumItems = [];
for (const structure of assets.projectStore.project.variables.structures) {
for (const structure of allStructures) {
arrayOfStructureEnumItems.push(
`${TAB}${getName(
"FLOW_ARRAY_OF_STRUCTURE_",
Expand All @@ -796,7 +815,7 @@ export function buildFlowStructs(assets: Assets) {
);
}

for (const structure of assets.projectStore.project.variables.structures) {
for (const structure of allStructures) {
const fieldEnumItems = [];
for (const field of structure.fields) {
fieldEnumItems.push(
Expand Down Expand Up @@ -1030,8 +1049,14 @@ export function buildFlowStructValues(assets: Assets) {
);
}

for (const structure of assets.projectStore.project.variables.structures) {
buildStructure(structure);
// Include both project-defined and imported (extension) structures
const allStructuresForValues = [
...assets.projectStore.project.variables.structures,
...assets.projectStore.importedStructureVariableTypes.values()
];

for (const structure of allStructuresForValues) {
buildStructure(structure as Structure);
}

return build.result;
Expand Down
2 changes: 2 additions & 0 deletions packages/project-editor/core/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,8 @@ export interface ClassInfo {

execute?: (context: IDashboardComponentContext) => void;

isNative?: boolean;

findChildIndex?: (parent: IEezObject[], child: IEezObject) => number;

widgetEvents?: WidgetEvents | ((object: IEezObject) => WidgetEvents);
Expand Down
14 changes: 9 additions & 5 deletions packages/project-editor/features/variable/value-type.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ export function registerSystemEnum({
const existingSystemEnum = SystemEnum.SYSTEM_ENUMS.find(
systemEnum => systemEnum.compareTo(name, projectTypes, lvglVersions)
);

if (existingSystemEnum) {
existingSystemEnum.members = members;
existingSystemEnum._membersMap = undefined;
Expand Down Expand Up @@ -682,9 +682,13 @@ export const VariableTypeSelect = observer(
)
: [];

const isLVGL = this.props.project.projectTypeTraits.isLVGL;
const enumTypes = [
...project.variables.enums,
...getSystemEnums(this.props.project._store)
...getSystemEnums(this.props.project._store),
...[...project._store.importedEnumVariableTypes.values()].filter(
e => !isLVGL || e.name.includes("/")
)
];

const enums = enumTypes.map(enumDef => (
Expand All @@ -702,9 +706,9 @@ export const VariableTypeSelect = observer(

const structureTypes = [
...project.variables.structures,
...(this.props.project.projectTypeTraits.isLVGL
? []
: SYSTEM_STRUCTURES)
...(isLVGL ? [] : SYSTEM_STRUCTURES),
...[...project._store.importedStructureVariableTypes.values()].filter(
s => !isLVGL || s.name.includes("/"))
];

const structures = this.props.project.projectTypeTraits
Expand Down
11 changes: 11 additions & 0 deletions packages/project-editor/features/variable/variable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,11 @@ export class ProjectVariables extends EezObject {
for (const enumDef of systemEnums) {
map.set(enumDef.name, enumDef);
}
for (const [name, enumDef] of projectStore.importedEnumVariableTypes) {
if (!map.has(name)) {
map.set(name, enumDef);
}
}
return map;
}

Expand All @@ -1748,6 +1753,12 @@ export class ProjectVariables extends EezObject {
for (const structure of SYSTEM_STRUCTURES) {
map.set(structure.name, structure);
}
const projectStore = ProjectEditor.getProjectStore(this);
for (const [name, structure] of projectStore.importedStructureVariableTypes) {
if (!map.has(name)) {
map.set(name, structure);
}
}
return map;
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/project-editor/flow/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4680,7 +4680,8 @@ export function createActionComponentClass(
componentHeaderColor:
actionComponentDefinition.componentHeaderColor,
componentPaletteGroupName,
execute: actionComponentDefinition.execute
execute: actionComponentDefinition.execute,
isNative: actionComponentDefinition.isNative
});

override makeEditable() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ export function getAllComponentClasses(
isProperSubclassOf(
objectClassInfo.objectClass.classInfo,
ProjectEditor.WidgetClass.classInfo
))
)) ||
// Extension components only for LVGL Project (registered via public API) have "/" in their name
(projectStore.projectTypeTraits.isLVGL &&
objectClassInfo.name.includes("/"))
);
}

Expand Down
38 changes: 38 additions & 0 deletions packages/project-editor/lvgl/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ interface UpdateColorCallbackForUserWidget {
updateColorsForPage: UpdateColorCallbackForPage;
}

// Converts an extension component class nameto a valid C identifier
function extComponentFunctionName(className: string): string {
const sanitized = className.replace(/[^a-zA-Z0-9]/g, "_");
return `eez_flow_ext_${sanitized}`;
}

export class LVGLBuild extends Build {
project: Project;

Expand Down Expand Up @@ -2119,6 +2125,20 @@ export class LVGLBuild extends Build {

build.blockStart("void create_screens() {");

if (
this.assets.projectStore.projectTypeTraits.hasFlowSupport &&
this.assets.nativeExtensionComponents.length > 0
) {
build.line("// Register native extension components");
for (const ext of this.assets.nativeExtensionComponents) {
const fnName = extComponentFunctionName(ext.className);
build.line(
`eez_flow_register_ext_component(${ext.componentType}, ${fnName});`
);
}
build.line("");
}

if (
this.assets.projectStore.projectTypeTraits.hasFlowSupport &&
this.styles.length > 0
Expand Down Expand Up @@ -2678,6 +2698,24 @@ extern ext_font_desc_t fonts[];
return this.result;
}

async buildExtComponentDecl() {
if (!this.project.projectTypeTraits.hasFlowSupport) {
return "";
}

this.startBuild();
const build = this;

for (const ext of this.assets.nativeExtensionComponents) {
const fnName = extComponentFunctionName(ext.className);
build.line(
`extern void ${fnName}(void *flowState, unsigned componentIndex);`
);
}

return this.result;
}

async buildActionsArrayDef() {
if (!this.project.projectTypeTraits.hasFlowSupport) {
return "";
Expand Down
Loading