Skip to content

Commit

Permalink
text widget. can now intercept file drops on a per node basis
Browse files Browse the repository at this point in the history
  • Loading branch information
EliCDavis committed Oct 7, 2024
1 parent be6b339 commit f3a37ca
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 21 deletions.
17 changes: 17 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,23 @@
type: "color"
}
]
},
"widgets/text": {
title: "Text Node",
widgets: [
{
type: "text",
config: {
value: "Arbitrary Text"
}
}
],
outputs: [
{
name: "out",
type: "color"
}
]
}
}
},
Expand Down
13 changes: 13 additions & 0 deletions src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ class GraphView {
}
}

fileDrop(file: File): boolean {
for (let i = this.#subsystems.length - 1; i >= 0; i--) {
if (this.#subsystems[i].fileDrop(file)) {
return true;
}
}
return false;
}

openContextMenu(ctx: CanvasRenderingContext2D, position: Vector2): ContextMenuConfig {
let finalConfig: ContextMenuConfig = {};

Expand Down Expand Up @@ -220,6 +229,10 @@ export class NodeFlowGraph {

#fileDrop(file: File): void {

if (this.currentView().fileDrop(file)) {
return;
}

const contents = file.name.split('.');
const extension = contents[contents.length - 1];
if (extension !== "jpg" && extension !== "jpeg" && extension !== "png") {
Expand Down
2 changes: 2 additions & 0 deletions src/graphSubsystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ export interface GraphSubsystem {

mouseDragEvent(delta: Vector2, scale: number): boolean;

fileDrop(file: File): boolean;

clickEnd(): void;
}
70 changes: 56 additions & 14 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface FlowNodeConfig {
onRelease?: () => void;
onSelect?: () => void;
onUnselect?: () => void;
onFileDrop?: (file: File) => void;

// Widgets
widgets?: Array<WidgetConfig>;
Expand Down Expand Up @@ -110,9 +111,11 @@ export class FlowNode {

// Callbacks

#onSelect?: () => void;
#onSelect: Array<() => void>;

#onUnselect?: () => void;
#onUnselect: Array<() => void>;

#onFiledrop: Array<(file: File) => void>;

// Styling ================================================================

Expand Down Expand Up @@ -160,8 +163,21 @@ export class FlowNode {
this.#contextMenu = config?.contextMenu === undefined ? null : config.contextMenu;

this.#selected = false;
this.#onSelect = config?.onSelect;
this.#onUnselect = config?.onUnselect;
this.#onSelect = new Array<() => void>;
this.#onUnselect = new Array<() => void>;
this.#onFiledrop = new Array<(file: File) => void>;

if (config?.onSelect) {
this.#onSelect.push(config?.onSelect);
}

if (config?.onUnselect) {
this.#onUnselect.push(config?.onUnselect);
}

if (config?.onFileDrop) {
this.#onFiledrop.push(config?.onFileDrop);
}

this.#position = config?.position === undefined ? { x: 0, y: 0 } : config.position;
this.#title = new Text(
Expand Down Expand Up @@ -237,8 +253,8 @@ export class FlowNode {
return;
}
this.#selected = true;
if (this.#onSelect) {
this.#onSelect();
for (let i = 0; i < this.#onSelect.length; i++) {
this.#onSelect[i]();
}
}

Expand Down Expand Up @@ -390,9 +406,9 @@ export class FlowNode {
],
onUpdate: (data: Array<any>) => {
this.addWidget(new ImageWidget({
image: data[0],
maxWidth: data[1],
maxHeight: data[2],
image: data[0],
maxWidth: data[1],
maxHeight: data[2],
}));
}
}).Show();
Expand Down Expand Up @@ -510,11 +526,29 @@ export class FlowNode {
return;
}
this.#selected = false;
if (this.#onUnselect) {
this.#onUnselect();
for (let i = 0; i < this.#onUnselect.length; i++) {
this.#onUnselect[i]();
}
}

public addUnselectListener(callback: () => void): void {
this.#onUnselect.push(callback);
}

public addSelectListener(callback: () => void): void {
this.#onSelect.push(callback);
}

public dropFile(file: File): void {
for(let i = 0; i < this.#onFiledrop.length; i ++) {
this.#onFiledrop[i](file);
}
}

public addFileDropListener(callback: (file: File) => void): void {
this.#onFiledrop.push(callback);
}

public locked(): boolean {
return this.#locked;
}
Expand Down Expand Up @@ -601,6 +635,14 @@ export class FlowNode {
this.#widgets.push(widget);
}

getWidget(index: number): Widget {
return this.#widgets[index];
}

widgetCount(): number {
return this.#widgets.length;
}

translate(delta: Vector2): void {
this.#position.x += delta.x;
this.#position.y += delta.y;
Expand Down Expand Up @@ -653,9 +695,9 @@ export class FlowNode {
}

setTitle(newTitle: string): void {
if (!this.#canEdit) {
console.warn("setTitle instruction ignored, as node has been marked un-editable");
}
// if (!this.#canEdit) {
// console.warn("setTitle instruction ignored, as node has been marked un-editable");
// }
this.#title.set(newTitle);
}

Expand Down
9 changes: 8 additions & 1 deletion src/nodes/subsystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { RenderResults } from "../graphSubsystem";
import { FlowNode, NodeState } from "../node";
import { Organize } from "../organize";
import { TimeExecution } from "../performance";
import { SetStringPopup } from "../popups/string";
import { Port } from "../port";
import { CursorStyle } from "../styles/cursor";
import { List } from "../types/list";
Expand Down Expand Up @@ -311,6 +310,14 @@ export class NodeSubsystem {
this.#nodes.push(node);
}

fileDrop(file: File): boolean {
if (this.#nodeHovering === -1) {
return false;
}
this.#nodes[this.#nodeHovering].dropFile(file);
return true;
}

#removeNodeConnections(nodeIndex: number): void {
if (nodeIndex >= this.#nodes.length || nodeIndex < 0) {
console.error("invalid node connection");
Expand Down
4 changes: 4 additions & 0 deletions src/notes/subsystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ export class NoteSubsystem {
return true;
}

fileDrop(file: File): boolean {
return false;
}

#removeNote(note: FlowNote): void {
const index = this.#notes.indexOf(note);
if (index > -1) {
Expand Down
7 changes: 5 additions & 2 deletions src/popups/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ interface Config {
export function FormPopup(config: Config): Popup {
let input = new Array<HTMLInputElement | null>();

const setOption = "Set";
const cancelOption = "Cancel";

return new Popup({
title: config.title,
options: ["Set", "Cancel"],
options: [setOption, cancelOption],
content: () => {
const container = document.createElement('div');
container.style.flexDirection = "column";
Expand All @@ -43,7 +46,7 @@ export function FormPopup(config: Config): Popup {
return container;
},
onClose: (button: string | null): void => {
if (button !== "Set" || input === null) {
if (button !== setOption || input === null) {
if (config.onCancel) {
config.onCancel();
}
Expand Down
2 changes: 2 additions & 0 deletions src/widgets/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { StringWidget, StringWidgetConfig } from './string';
import { ToggleWidget, ToggleWidgetConfig } from './toggle';
import { FlowNode } from "../node";
import { ImageWidget, ImageWidgetConfig } from "./image";
import { TextWidget, TextWidgetConfig } from "./text";

export type WidgetBuilder = (node: FlowNode, confg?: any) => Widget;

Expand Down Expand Up @@ -40,5 +41,6 @@ GlobalWidgetFactory.register("slider", (node: FlowNode, config?: SliderWidgetCon
GlobalWidgetFactory.register("string", (node: FlowNode, config?: StringWidgetConfig) => new StringWidget(node, config));
GlobalWidgetFactory.register("toggle", (node: FlowNode, config?: ToggleWidgetConfig) => new ToggleWidget(node, config));
GlobalWidgetFactory.register("image", (node: FlowNode, config?: ImageWidgetConfig) => new ImageWidget(config));
GlobalWidgetFactory.register("text", (node: FlowNode, config?: TextWidgetConfig) => new TextWidget(node, config));

export { GlobalWidgetFactory };
8 changes: 5 additions & 3 deletions src/widgets/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class NumberWidget {
}

// https://stackoverflow.com/questions/5765398/whats-the-best-way-to-convert-a-number-to-a-string-in-javascript
this.#text = '' + this.#value;
this.#text = '' + parseFloat(this.#value.toPrecision(6));
}

ClickStart(): void {
Expand All @@ -99,9 +99,11 @@ export class NumberWidget {
ClickEnd(): void {
let input: HTMLInputElement | null = null;

const setOption = "Set";
const cancelOption = "Cancel";
const popup = new Popup({
title: "Set Number",
options: ["Set", "Cancel"],
options: [setOption, cancelOption],
content: () => {
const container = document.createElement('div');
input = document.createElement('input')
Expand All @@ -111,7 +113,7 @@ export class NumberWidget {
return container;
},
onClose: (button: string | null): void => {
if (button !== "Set" || input === null) {
if (button !== setOption || input === null) {
return;
}

Expand Down
1 change: 0 additions & 1 deletion src/widgets/string.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Theme } from "../theme";
import { Popup } from "../popup";
import { TextBoxStyle, TextBoxStyleConfig, TextBoxStyleWithFallback } from "../styles/textBox";
import { Box, InBox } from "../types/box";
import { Vector2 } from "../types/vector2";
Expand Down
91 changes: 91 additions & 0 deletions src/widgets/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Theme } from "../theme";
import { Box, InBox } from "../types/box";
import { Vector2 } from "../types/vector2";
import { FlowNode } from '../node';
import { Text } from "../types/text";
import { TextStyle, TextStyleConfig, TextStyleFallback } from "../styles/text";

export interface TextWidgetConfig {
property?: string;

value?: string;

textBoxStyle?: TextStyleConfig;

callback?: (newString: string) => void;
}

export class TextWidget {

#value: Text;

#callback?: (newString: string) => void;

#node: FlowNode

#nodeProperty: string | undefined;

#size: Vector2;

constructor(node: FlowNode, config?: TextWidgetConfig) {
this.#size = { x: 0, y: 0 };
this.#node = node;
this.#nodeProperty = config?.property;
this.#value = new Text("", TextStyleFallback(config?.textBoxStyle, {
font: Theme.FontFamily,
color: Theme.Widget.FontColor,
size: Theme.Note.FontSize,
}))

this.Set(config?.value === undefined ? "" : config?.value);
this.#callback = config?.callback;
if (this.#nodeProperty !== undefined) {
this.#node.subscribeToProperty(this.#nodeProperty, (oldVal, newVal) => {
this.Set(newVal);
});
}
}

Size(): Vector2 {
return this.#size;
}

Set(value: string): void {
if (this.#value.get() === value) {
return;
}
this.#value.set(value);

if (this.#nodeProperty !== undefined) {
this.#node.setProperty(this.#nodeProperty, value)
}

if (this.#callback !== undefined) {
this.#callback(value);
}
}

ClickStart(): void {
// Left blank for implementing Widget interface
}

ClickEnd(): void {
// Left blank for implementing Widget interface
}


Draw(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, mousePosition: Vector2 | undefined): Box {
this.#value.size(ctx, scale, this.#size);
const box = {
Position: position,
Size: this.#size
};
this.#value.size(ctx, 1, this.#size);

ctx.textAlign = "left";
this.#value.render(ctx, scale, box.Position);
// this.#idleStyle.DrawUnderline(ctx, box, scale, fitString(ctx, this.#value, box.Size.x - (20 * scale)))

return box;
}
}

0 comments on commit f3a37ca

Please sign in to comment.