@usman404/crowjs 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +1 -0
- package/Core/Component.js +426 -0
- package/Core/GUIEvent/GUIEvent.js +23 -0
- package/Core/GUIEvent/KeyboardEvent.js +14 -0
- package/Core/GUIEvent/MouseEvent.js +22 -0
- package/Core/Root.js +558 -0
- package/Frames/DummyFrame.js +185 -0
- package/Frames/Frame.js +531 -0
- package/Frames/FrameComponent.js +54 -0
- package/Frames/GridFrame.js +574 -0
- package/Frames/ScrollFrame.js +764 -0
- package/LICENSE +21 -0
- package/README.md +130 -0
- package/UIComponents/Input.js +78 -0
- package/UIComponents/Label.js +234 -0
- package/UIComponents/TextField.js +551 -0
- package/UIComponents/UIComponent.js +97 -0
- package/crowjs-01-01.png +0 -0
- package/index.html +15 -0
- package/package.json +23 -0
- package/sketch.js +65 -0
package/Frames/Frame.js
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import { GUIEvent } from '../Core/GUIEvent/GUIEvent.js';
|
|
2
|
+
import { DummyFrame } from './DummyFrame.js';
|
|
3
|
+
import { FrameComponent } from './FrameComponent.js';
|
|
4
|
+
|
|
5
|
+
//frame should allow, closing off -> remove it and all of its childern from the root array
|
|
6
|
+
//frames should also allow docking -> adding frames in frames
|
|
7
|
+
|
|
8
|
+
export class Frame extends FrameComponent{
|
|
9
|
+
/**
|
|
10
|
+
* Creates a resizable and draggable frame container
|
|
11
|
+
* @param {number} x - The x-coordinate
|
|
12
|
+
* @param {number} y - The y-coordinate
|
|
13
|
+
* @param {number} width - The width
|
|
14
|
+
* @param {number} height - The height
|
|
15
|
+
* @param {string|null} id - Component ID
|
|
16
|
+
* @param {p5.Color} backgroundColor - Background color
|
|
17
|
+
* @param {p5.Color} borderColor - Border color
|
|
18
|
+
* @param {p5.Color} highlightedBorderColor - Highlighted border color
|
|
19
|
+
* @param {number} borderWidth - Border width
|
|
20
|
+
* @param {number} cornerRadius - Corner radius
|
|
21
|
+
* @param {number} padx - Horizontal padding
|
|
22
|
+
* @param {number} pady - Vertical padding
|
|
23
|
+
* @param {boolean} alwaysShowBanner - Whether to always show the banner
|
|
24
|
+
* @param {number} bannerHeight - Height of the top banner
|
|
25
|
+
* @param {number} nearestBorderThreshold - Distance threshold for border detection
|
|
26
|
+
* @param {Component|null} parent - Parent component
|
|
27
|
+
* @param {string} type - Component type
|
|
28
|
+
* @param {boolean} enableReposition - Allow dragging
|
|
29
|
+
* @param {boolean} enableOptimisedReposition - Use optimized repositioning
|
|
30
|
+
* @param {boolean} enableResizing - Allow resizing
|
|
31
|
+
* @param {boolean} enableOptimisedResizing - Use optimized resizing
|
|
32
|
+
* @param {boolean} enableShadow - Enable shadow rendering
|
|
33
|
+
* @param {string} shadowColor - Shadow color
|
|
34
|
+
* @param {number} shadowIntensity - Shadow opacity
|
|
35
|
+
* @param {number} shadowSpread - Shadow spread
|
|
36
|
+
* @param {number} shadowDetail - Number of shadow layers
|
|
37
|
+
*/
|
|
38
|
+
constructor(x, y, width, height, id, backgroundColor, borderColor, highlightedBorderColor, borderWidth,
|
|
39
|
+
cornerRadius, padx, pady, alwaysShowBanner, bannerHeight, nearestBorderThreshold, parent, type,
|
|
40
|
+
enableReposition, enableOptimisedReposition, enableResizing, enableOptimisedResizing, enableShadow, shadowColor, shadowIntensity, shadowSpread, shadowDetail){
|
|
41
|
+
super(x, y, width, height, {parent: parent, type: type, id: id});
|
|
42
|
+
|
|
43
|
+
this.backgroundColor = backgroundColor;
|
|
44
|
+
this.borderColor = borderColor;
|
|
45
|
+
this.highlightedBorderColor = highlightedBorderColor;
|
|
46
|
+
this.borderWidth = borderWidth;
|
|
47
|
+
this.cornerRadius = cornerRadius;
|
|
48
|
+
this.padx = padx;
|
|
49
|
+
this.pady = pady;
|
|
50
|
+
|
|
51
|
+
this.enableShadow = enableShadow;
|
|
52
|
+
this.enableReposition = enableReposition;
|
|
53
|
+
this.enableOptimisedReposition = enableOptimisedReposition;
|
|
54
|
+
this.enableResizing = enableResizing;
|
|
55
|
+
this.enableOptimisedResizing = enableOptimisedResizing;
|
|
56
|
+
this.alwaysShowBanner = alwaysShowBanner;
|
|
57
|
+
|
|
58
|
+
if(this.enableReposition || this.alwaysShowBanner){
|
|
59
|
+
this.bannerHeight = bannerHeight;
|
|
60
|
+
|
|
61
|
+
if(this.enableReposition){
|
|
62
|
+
this.isBannerShown = false;
|
|
63
|
+
this.xDist = null;
|
|
64
|
+
this.yDist = null;
|
|
65
|
+
this.prevX = null;
|
|
66
|
+
this.prevY = null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if(this.alwaysShowBanner){
|
|
70
|
+
this.isBannerShown = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if(this.enableResizing){
|
|
75
|
+
this.nearestBorder = null;
|
|
76
|
+
this.nearestBorderThreshold = nearestBorderThreshold;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if(this.enableShadow){
|
|
80
|
+
this.shadowColor = shadowColor;//rgb value
|
|
81
|
+
this.shadowIntensity = shadowIntensity;//opacity value between 0 and 1
|
|
82
|
+
this.shadowSpread = shadowSpread;//stroke width of each of those rectangles
|
|
83
|
+
this.shadowDetail = shadowDetail;//number of rectangles that will be drawn around the component
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.addEventListener("hover", (event) => this.onMouseHover(event));
|
|
87
|
+
this.addEventListener("mouseLeave", (event)=> this.onMouseLeave(event));
|
|
88
|
+
this.addEventListener("drag", (event)=> this.onMouseDrag(event));
|
|
89
|
+
this.addEventListener("press", (event) => this.onMouseBtnPress(event));
|
|
90
|
+
this.addEventListener("release", (event) => this.onMouseRelease(event));
|
|
91
|
+
this.addEventListener("resize", (event) => this.onResize(event));
|
|
92
|
+
this.addEventListener("reposition", (event) => this.onRepos(event));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Handles frame resize events
|
|
97
|
+
* @param {GUIEvent} event - The resize event
|
|
98
|
+
*/
|
|
99
|
+
onResize(event){
|
|
100
|
+
console.log("resizing...");
|
|
101
|
+
event.stopPropagation();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Handles frame reposition events
|
|
106
|
+
* @param {GUIEvent} event - The reposition event
|
|
107
|
+
*/
|
|
108
|
+
onRepos(event){
|
|
109
|
+
console.log("repositioning...");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Handles mouse button release events
|
|
114
|
+
* @param {GUIEvent} event - The release event
|
|
115
|
+
*/
|
|
116
|
+
onMouseRelease(event){
|
|
117
|
+
if(!this.isOverBannerArea()){
|
|
118
|
+
cursor("");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Handles mouse leave events
|
|
124
|
+
* @param {GUIEvent} event - The mouse leave event
|
|
125
|
+
*/
|
|
126
|
+
onMouseLeave(event){
|
|
127
|
+
// console.log("mouse left...");
|
|
128
|
+
this.clearHoverCache();
|
|
129
|
+
cursor("");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Checks if cursor is near any border for resizing
|
|
134
|
+
* @returns {boolean} True if cursor is near a border
|
|
135
|
+
*/
|
|
136
|
+
isNearBorder(){
|
|
137
|
+
return this.nearestBorder!==null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Handles mouse hover events for banner and cursor changes
|
|
142
|
+
* @param {GUIEvent} event - The hover event
|
|
143
|
+
*/
|
|
144
|
+
onMouseHover(event){
|
|
145
|
+
// console.log("mouse hovering...");
|
|
146
|
+
if(this.enableResizing) {
|
|
147
|
+
this.checkAndFindNearestBorder();
|
|
148
|
+
if(this.isNearBorder()){
|
|
149
|
+
if(this.isBannerShown){
|
|
150
|
+
this.clearHoverCache({clearResizingCache:false});
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if(this.enableReposition && this.isOverBannerArea() && !mouseIsPressed){
|
|
157
|
+
cursor("grab");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if(!this.isOverBannerArea()){
|
|
161
|
+
cursor("");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if(this.isOverBannerArea() && (this.enableReposition && !this.isBannerShown)) {
|
|
165
|
+
this.showBanner();
|
|
166
|
+
} else {
|
|
167
|
+
if(!this.isOverBannerArea()) {
|
|
168
|
+
if(this.enableReposition && this.isBannerShown){
|
|
169
|
+
this.clearHoverCache({clearResizingCache:false});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if(!this.alwaysShowBanner){
|
|
173
|
+
this.hideBanner();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Handles mouse button press events for dragging and resizing
|
|
181
|
+
* @param {GUIEvent} event - The press event
|
|
182
|
+
*/
|
|
183
|
+
onMouseBtnPress(event) {
|
|
184
|
+
if(this.enableResizing && this.isNearBorder()){
|
|
185
|
+
//dummy resize frame
|
|
186
|
+
if(this.enableOptimisedResizing){
|
|
187
|
+
this.createDummyFrame(DummyFrame.RESIZE_DF);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if(this.isOverBannerArea()){
|
|
194
|
+
if(this.enableReposition) {
|
|
195
|
+
cursor("grabbing");
|
|
196
|
+
this.xDist = mouseX - this.x;
|
|
197
|
+
this.yDist = mouseY - this.y;
|
|
198
|
+
|
|
199
|
+
//dummy reposition frame
|
|
200
|
+
if(this.enableOptimisedReposition){
|
|
201
|
+
this.createDummyFrame(DummyFrame.REPOSITION_DF);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Checks if the frame is currently being repositioned
|
|
209
|
+
* @returns {boolean} True if repositioning is in progress
|
|
210
|
+
*/
|
|
211
|
+
isRepositioning(){
|
|
212
|
+
return (this.xDist!=null && this.yDist!=null);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Handles mouse drag events for resizing and repositioning
|
|
217
|
+
* @param {GUIEvent} event - The drag event
|
|
218
|
+
*/
|
|
219
|
+
onMouseDrag(event){
|
|
220
|
+
if(this.enableResizing){
|
|
221
|
+
if(this.isNearBorder() && !this.isRepositioning()){
|
|
222
|
+
this.updateDimensions();
|
|
223
|
+
this.dispatchTrickleDownEvent(new GUIEvent(event.x, event.y, "resize", this));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if(this.enableReposition && this.isRepositioning()){
|
|
229
|
+
this.updatePosition();
|
|
230
|
+
this.dispatchTrickleDownEvent(new GUIEvent(event.x, event.y, "reposition", this));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Creates a temporary dummy frame for smooth resizing/repositioning
|
|
236
|
+
* @param {string} type - Type of dummy frame (RESIZE_DF or REPOSITION_DF)
|
|
237
|
+
*/
|
|
238
|
+
createDummyFrame(type){
|
|
239
|
+
let DF = new DummyFrame(this.x, this.y, this.width, this.height, type);
|
|
240
|
+
DF.parent = this;
|
|
241
|
+
DF.root = this.root;
|
|
242
|
+
|
|
243
|
+
if(type === DummyFrame.RESIZE_DF){
|
|
244
|
+
DF.nearestBorder = this.nearestBorder;
|
|
245
|
+
} else if(type === DummyFrame.REPOSITION_DF){
|
|
246
|
+
DF.xDist = this.xDist;
|
|
247
|
+
DF.yDist = this.yDist;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.root.add(DF);
|
|
251
|
+
this.root.activeElement = DF;
|
|
252
|
+
|
|
253
|
+
// console.log(DF);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Checks if mouse is over the banner area
|
|
258
|
+
* @returns {boolean} True if mouse is over the banner
|
|
259
|
+
*/
|
|
260
|
+
isOverBannerArea(){
|
|
261
|
+
return (mouseX>this.x && mouseX<this.x+this.width && mouseY>this.y && mouseY<this.y+(this.bannerHeight));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Utility method for position updates (to be overridden)
|
|
266
|
+
*/
|
|
267
|
+
updatePosUtil(){};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Handles mouse release events for repositioning
|
|
271
|
+
*/
|
|
272
|
+
mouseReleasedEventListener(){
|
|
273
|
+
if(this.enableReposition && this.isRepositioning()){
|
|
274
|
+
this.xDist=null;
|
|
275
|
+
this.yDist=null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Detects which border is nearest to the cursor for resizing
|
|
281
|
+
*/
|
|
282
|
+
checkAndFindNearestBorder(){
|
|
283
|
+
if(mouseX>=this.x && mouseX<=this.x+this.nearestBorderThreshold && mouseY>=this.y+this.cornerRadius && mouseY<=this.y+this.height-this.cornerRadius){
|
|
284
|
+
this.nearestBorder = "left";
|
|
285
|
+
cursor("ew-resize");
|
|
286
|
+
} else if(mouseX>=this.x + this.width - this.nearestBorderThreshold && mouseX<=this.x + this.width && mouseY>=this.y+this.cornerRadius && mouseY<=this.y+this.height-this.cornerRadius){
|
|
287
|
+
this.nearestBorder = "right";
|
|
288
|
+
cursor("ew-resize");
|
|
289
|
+
} else if(mouseY>=this.y && mouseY<=this.y+this.nearestBorderThreshold && mouseX>=this.x+this.cornerRadius && mouseX<=this.x+this.width-this.cornerRadius){
|
|
290
|
+
this.nearestBorder = "top";
|
|
291
|
+
cursor("ns-resize");
|
|
292
|
+
} else if(mouseY>=this.y +this.height - this.nearestBorderThreshold && mouseY<=this.y + this.height && mouseX>=this.x+this.cornerRadius && mouseX<=this.x+this.width-this.cornerRadius){
|
|
293
|
+
this.nearestBorder = "bottom";
|
|
294
|
+
cursor("ns-resize");
|
|
295
|
+
} else if(abs(mouseX-this.x)<=this.nearestBorderThreshold && abs(mouseY-this.y)<=this.nearestBorderThreshold){
|
|
296
|
+
this.nearestBorder = "top-left";
|
|
297
|
+
cursor("nwse-resize");
|
|
298
|
+
} else if(abs(mouseX-(this.x+this.width))<=this.nearestBorderThreshold && abs(mouseY-this.y)<=this.nearestBorderThreshold){
|
|
299
|
+
this.nearestBorder = "top-right";
|
|
300
|
+
cursor("nesw-resize");
|
|
301
|
+
} else if(abs(mouseX-this.x)<=this.nearestBorderThreshold && abs(mouseY - (this.y+this.height))<=this.nearestBorderThreshold){
|
|
302
|
+
this.nearestBorder = "bottom-left";
|
|
303
|
+
cursor("nesw-resize");
|
|
304
|
+
} else if(abs(mouseX-(this.x+this.width))<=this.nearestBorderThreshold && abs(mouseY - (this.y+this.height))<=this.nearestBorderThreshold){
|
|
305
|
+
this.nearestBorder = "bottom-right";
|
|
306
|
+
cursor("nwse-resize");
|
|
307
|
+
} else {
|
|
308
|
+
this.nearestBorder = null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Draws highlighted borders when cursor is near them
|
|
314
|
+
*/
|
|
315
|
+
showHighlightedBorder(){
|
|
316
|
+
push();
|
|
317
|
+
stroke(this.highlightedBorderColor);
|
|
318
|
+
strokeWeight(this.borderWidth+2);
|
|
319
|
+
if(this.nearestBorder=="left"){
|
|
320
|
+
line(this.x, this.y+this.cornerRadius, this.x, this.y+this.height-this.cornerRadius);
|
|
321
|
+
} else if(this.nearestBorder=="right"){
|
|
322
|
+
line(this.x+this.width, this.y+this.cornerRadius, this.x+this.width, this.y+this.height-this.cornerRadius);
|
|
323
|
+
} else if(this.nearestBorder=="top"){
|
|
324
|
+
line(this.x+this.cornerRadius, this.y, this.x+this.width-this.cornerRadius, this.y);
|
|
325
|
+
} else if(this.nearestBorder=="bottom"){
|
|
326
|
+
line(this.x+this.cornerRadius, this.y+this.height, this.x+this.width-this.cornerRadius, this.y+this.height);
|
|
327
|
+
} else {
|
|
328
|
+
noFill();
|
|
329
|
+
strokeWeight(6);
|
|
330
|
+
if(this.nearestBorder=="top-left"){
|
|
331
|
+
arc(this.x+this.cornerRadius, this.y+this.cornerRadius, 2*this.cornerRadius, 2*this.cornerRadius, PI, PI+HALF_PI);
|
|
332
|
+
} else if(this.nearestBorder=="top-right"){
|
|
333
|
+
arc(this.x+this.width-this.cornerRadius, this.y+this.cornerRadius, 2*this.cornerRadius, 2*this.cornerRadius, PI+HALF_PI, TWO_PI);
|
|
334
|
+
} else if(this.nearestBorder=="bottom-left"){
|
|
335
|
+
arc(this.x+this.cornerRadius, this.y+this.height-this.cornerRadius, 2*this.cornerRadius, 2*this.cornerRadius, HALF_PI, PI);
|
|
336
|
+
} else if(this.nearestBorder=="bottom-right"){
|
|
337
|
+
arc(this.x+this.width-this.cornerRadius, this.y+this.height-this.cornerRadius, 2*this.cornerRadius, 2*this.cornerRadius, 0, HALF_PI);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
pop();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
//corrects position and dimensions of all the child elements so that
|
|
344
|
+
//they fit right in the parent frame
|
|
345
|
+
/**
|
|
346
|
+
* Adjusts child components to fit within the frame's new dimensions
|
|
347
|
+
*/
|
|
348
|
+
redraw(){
|
|
349
|
+
if(this.alwaysShowBanner || (this.isOverBannerArea() && this.enableReposition && !this.isBannerShown)){
|
|
350
|
+
this.adjustHeight(this.y + (this.bannerHeight) + this.pady, this.height - (this.bannerHeight) - 2*(this.pady));
|
|
351
|
+
} else {
|
|
352
|
+
this.adjustHeight(this.y+this.pady, this.height-2*this.pady);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
this.adjustWidth(this.x+this.padx, this.width-2*this.padx);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Updates frame dimensions during resizing
|
|
359
|
+
*/
|
|
360
|
+
updateDimensions(){
|
|
361
|
+
if(this.nearestBorder=="left" || this.nearestBorder=="right"){
|
|
362
|
+
if( this.nearestBorder=="left"){
|
|
363
|
+
if(this.x+this.width-mouseX>=this.bannerHeight){
|
|
364
|
+
this.width = this.x + this.width - mouseX;
|
|
365
|
+
this.x = mouseX;
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
if(mouseX-this.x>=this.bannerHeight){
|
|
369
|
+
this.width = mouseX - this.x;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if(this.nearestBorder=="right" && this.xScroll==true){
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
this.adjustWidth(this.x + this.padx, this.width - 2*(this.padx));
|
|
378
|
+
|
|
379
|
+
} else if(this.nearestBorder=="top"||this.nearestBorder=="bottom"){
|
|
380
|
+
if(this.nearestBorder=="top"){
|
|
381
|
+
if(this.y+this.height-mouseY>=this.bannerHeight){
|
|
382
|
+
this.height =this.y + this.height - mouseY;
|
|
383
|
+
this.y = mouseY;
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
if(mouseY-this.y>=this.bannerHeight){
|
|
387
|
+
this.height = mouseY - this.y;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if(this.yScroll==true && this.nearestBorder=="bottom"){
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if(this.alwaysShowBanner){
|
|
396
|
+
this.adjustHeight(this.y + (this.bannerHeight) + this.pady, this.height - (this.bannerHeight) - 2*(this.pady));
|
|
397
|
+
} else {
|
|
398
|
+
this.adjustHeight(this.y+this.pady, this.height-2*this.pady);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
} else {
|
|
402
|
+
if(this.nearestBorder=="top-left"){
|
|
403
|
+
if(this.x+this.width-mouseX>=50){
|
|
404
|
+
this.width = this.x + this.width - mouseX;
|
|
405
|
+
this.x = mouseX;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if(this.y+this.height-mouseY>=50){
|
|
409
|
+
this.height =this.y + this.height - mouseY;
|
|
410
|
+
this.y = mouseY;
|
|
411
|
+
}
|
|
412
|
+
} else if(this.nearestBorder=="top-right"){
|
|
413
|
+
if(mouseX-this.x>=50){
|
|
414
|
+
this.width = mouseX - this.x;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if(this.y+this.height-mouseY>=50){
|
|
418
|
+
this.height =this.y + this.height - mouseY;
|
|
419
|
+
this.y = mouseY;
|
|
420
|
+
}
|
|
421
|
+
} else if(this.nearestBorder=="bottom-left"){
|
|
422
|
+
if(this.x+this.width-mouseX>=50){
|
|
423
|
+
this.width = this.x + this.width - mouseX;
|
|
424
|
+
this.x = mouseX;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if(mouseY-this.y>=50){
|
|
428
|
+
this.height = mouseY - this.y;
|
|
429
|
+
}
|
|
430
|
+
} else if(this.nearestBorder=="bottom-right"){
|
|
431
|
+
if(mouseX-this.x>=50){
|
|
432
|
+
this.width = mouseX - this.x;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if(mouseY-this.y>=50){
|
|
436
|
+
this.height = mouseY - this.y;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
this.adjustWidth(this.x + this.padx, this.width - 2*(this.padx));
|
|
441
|
+
if(this.alwaysShowBanner){
|
|
442
|
+
this.adjustHeight(this.y + (this.bannerHeight) + this.pady, this.height - (this.bannerHeight) - 2*(this.pady));
|
|
443
|
+
} else {
|
|
444
|
+
this.adjustHeight(this.y+this.pady, this.height-2*this.pady);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Updates frame position during dragging
|
|
450
|
+
*/
|
|
451
|
+
updatePosition(){
|
|
452
|
+
this.prevX = this.x;
|
|
453
|
+
this.prevY = this.y;
|
|
454
|
+
|
|
455
|
+
this.x = mouseX - abs(this.xDist);
|
|
456
|
+
this.y = mouseY - abs(this.yDist);
|
|
457
|
+
|
|
458
|
+
if(this.prevX-this.x==0 && this.prevY-this.y==0){
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
//console.log("(",this.x,",",this.y,")");
|
|
463
|
+
|
|
464
|
+
this.updatePosUtil(this.prevX-this.x, this.prevY-this.y);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Clears hover and interaction cache
|
|
468
|
+
* @param {Object} options - Clear options
|
|
469
|
+
* @param {boolean} options.clearRepositionCache - Clear reposition cache
|
|
470
|
+
* @param {boolean} options.clearResizingCache - Clear resizing cache
|
|
471
|
+
*/
|
|
472
|
+
clearHoverCache({clearRepositionCache=true, clearResizingCache=true}={}){
|
|
473
|
+
// console.log("Hover cache cleared...");
|
|
474
|
+
if(clearRepositionCache && this.enableReposition){
|
|
475
|
+
if(!this.alwaysShowBanner){
|
|
476
|
+
this.hideBanner();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
this.xDist=null;
|
|
480
|
+
this.yDist=null;
|
|
481
|
+
this.prevX=null;
|
|
482
|
+
this.prevY=null;
|
|
483
|
+
// console.log("reposition cache removed...");
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if(clearResizingCache && this.enableResizing){
|
|
487
|
+
this.nearestBorder=null;
|
|
488
|
+
// console.log("resizing cache removed...");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// console.log("");
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Converts RGB color string to array
|
|
495
|
+
* @param {string} shadowColor - RGB color string
|
|
496
|
+
* @returns {number[]|null} Array of RGB values or null
|
|
497
|
+
*/
|
|
498
|
+
rgbToArray(shadowColor) {
|
|
499
|
+
let match = shadowColor.match(/\d+/g);
|
|
500
|
+
return match ? match.map(Number) : null;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Renders shadow effect around the frame
|
|
504
|
+
* @param {Object} options - Shadow options
|
|
505
|
+
*/
|
|
506
|
+
drawShadow({}={}){
|
|
507
|
+
let color = this.rgbToArray(this.shadowColor);
|
|
508
|
+
if(color==null){
|
|
509
|
+
console.log("shadow color value is not in the correct format: rgb(0,0,0)");
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if(this.shadowIntensity>1){
|
|
514
|
+
this.shadowIntensity=1;
|
|
515
|
+
console.log("shadow intensity should be between 0 and 1 inclusive.\nAny value given outside of the range will be clipped to the ends.");
|
|
516
|
+
} else if(this.shadowIntensity<0){
|
|
517
|
+
console.log("shadow intensity should be between 0 and 1 inclusive.\nAny value given outside of the range will be clipped to the ends.");
|
|
518
|
+
this.shadowIntensity=0;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
for(let i=1; i<=this.shadowDetail; i++){
|
|
522
|
+
push();
|
|
523
|
+
noFill();
|
|
524
|
+
let alpha = this.shadowIntensity * pow(1 - i / this.shadowDetail, 2);
|
|
525
|
+
stroke(`rgba(${color[0]}, ${color[1]}, ${color[2]}, ${alpha})`);
|
|
526
|
+
strokeWeight(this.shadowSpread);
|
|
527
|
+
rect(this.x-((i*this.shadowSpread)/2), this.y-((i*this.shadowSpread)/2), this.width+(i*this.shadowSpread), this.height+(i*this.shadowSpread), this.cornerRadius);
|
|
528
|
+
pop();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Component } from "../Core/Component.js";
|
|
2
|
+
|
|
3
|
+
export class FrameComponent extends Component{
|
|
4
|
+
/**
|
|
5
|
+
* Creates a base frame component for container elements
|
|
6
|
+
* @param {number} x - The x-coordinate
|
|
7
|
+
* @param {number} y - The y-coordinate
|
|
8
|
+
* @param {number} width - The width
|
|
9
|
+
* @param {number} height - The height
|
|
10
|
+
* @param {Object} options - Configuration options
|
|
11
|
+
* @param {Component|null} options.parent - Parent component
|
|
12
|
+
* @param {string} options.type - Component type
|
|
13
|
+
* @param {string|null} options.id - Component ID
|
|
14
|
+
*/
|
|
15
|
+
constructor(x, y, width, height, {parent=null, type="", id=null} = {}){
|
|
16
|
+
super(x, y, width, height, {parent: parent, type: type, id: id,});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Adjusts the height of child components (abstract method)
|
|
21
|
+
* @abstract
|
|
22
|
+
*/
|
|
23
|
+
adjustHeight(){};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Adjusts the width of child components (abstract method)
|
|
27
|
+
* @abstract
|
|
28
|
+
*/
|
|
29
|
+
adjustWidth(){};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Shows the frame banner (abstract method)
|
|
33
|
+
* @abstract
|
|
34
|
+
*/
|
|
35
|
+
showBanner(){};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Hides the frame banner (abstract method)
|
|
39
|
+
* @abstract
|
|
40
|
+
*/
|
|
41
|
+
hideBanner(){};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Updates the position during dragging (abstract method)
|
|
45
|
+
* @abstract
|
|
46
|
+
*/
|
|
47
|
+
updatePosition(){};//for dragging
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Adds a child component (abstract method)
|
|
51
|
+
* @abstract
|
|
52
|
+
*/
|
|
53
|
+
add(){};
|
|
54
|
+
}
|