@usman404/crowjs 1.0.3 → 1.1.0

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/Frames/Frame.js CHANGED
@@ -22,6 +22,8 @@ export class Frame extends FrameComponent{
22
22
  * @param {number} pady - Vertical padding
23
23
  * @param {boolean} alwaysShowBanner - Whether to always show the banner
24
24
  * @param {number} bannerHeight - Height of the top banner
25
+ * @param {p5.Color|string} bannerColor - Banner background color
26
+ * @param {p5.Color|string} bannerDotColor - Banner dot indicator color
25
27
  * @param {number} nearestBorderThreshold - Distance threshold for border detection
26
28
  * @param {Component|null} parent - Parent component
27
29
  * @param {string} type - Component type
@@ -30,15 +32,24 @@ export class Frame extends FrameComponent{
30
32
  * @param {boolean} enableResizing - Allow resizing
31
33
  * @param {boolean} enableOptimisedResizing - Use optimized resizing
32
34
  * @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
35
+ * @param {string} shadowColor - Shadow color (CSS color string)
36
+ * @param {number} shadowBlur - Shadow blur radius
37
+ * @param {number} shadowOffsetX - Shadow offset on X axis
38
+ * @param {number} shadowOffsetY - Shadow offset on Y axis
39
+ * @param {Object} marginOptions - Margin options
40
+ * @param {number} marginOptions.margin - General margin for all sides
41
+ * @param {number} marginOptions.marginx - Horizontal margin (left and right)
42
+ * @param {number} marginOptions.marginy - Vertical margin (top and bottom)
43
+ * @param {number} marginOptions.marginl - Left margin
44
+ * @param {number} marginOptions.marginr - Right margin
45
+ * @param {number} marginOptions.margint - Top margin
46
+ * @param {number} marginOptions.marginb - Bottom margin
37
47
  */
38
48
  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});
49
+ cornerRadius, padx, pady, alwaysShowBanner, bannerHeight, bannerColor, bannerDotColor, nearestBorderThreshold, parent, type,
50
+ enableReposition, enableOptimisedReposition, enableResizing, enableOptimisedResizing, enableShadow, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY,
51
+ {margin=0, marginx=null, marginy=null, marginl=null, marginr=null, margint=null, marginb=null, minWidth=0, minHeight=0, showDebugOverlay=false} = {}){
52
+ super(x, y, width, height, {parent: parent, type: type, id: id, margin: margin, marginx: marginx, marginy: marginy, marginl: marginl, marginr: marginr, margint: margint, marginb: marginb, minWidth: minWidth, minHeight: minHeight, showDebugOverlay: showDebugOverlay});
42
53
 
43
54
  this.backgroundColor = backgroundColor;
44
55
  this.borderColor = borderColor;
@@ -47,6 +58,7 @@ export class Frame extends FrameComponent{
47
58
  this.cornerRadius = cornerRadius;
48
59
  this.padx = padx;
49
60
  this.pady = pady;
61
+ this.pad = (this.padx === this.pady) ? this.padx : null;
50
62
 
51
63
  this.enableShadow = enableShadow;
52
64
  this.enableReposition = enableReposition;
@@ -57,6 +69,8 @@ export class Frame extends FrameComponent{
57
69
 
58
70
  if(this.enableReposition || this.alwaysShowBanner){
59
71
  this.bannerHeight = bannerHeight;
72
+ this.bannerColor = bannerColor;
73
+ this.bannerDotColor = bannerDotColor;
60
74
 
61
75
  if(this.enableReposition){
62
76
  this.isBannerShown = false;
@@ -74,13 +88,14 @@ export class Frame extends FrameComponent{
74
88
  if(this.enableResizing){
75
89
  this.nearestBorder = null;
76
90
  this.nearestBorderThreshold = nearestBorderThreshold;
91
+ this._isResizing = false;
77
92
  }
78
93
 
79
94
  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
95
+ this.shadowColor = shadowColor;
96
+ this.shadowBlur = shadowBlur;
97
+ this.shadowOffsetX = shadowOffsetX;
98
+ this.shadowOffsetY = shadowOffsetY;
84
99
  }
85
100
 
86
101
  this.addEventListener("hover", (event) => this.onMouseHover(event));
@@ -92,12 +107,21 @@ export class Frame extends FrameComponent{
92
107
  this.addEventListener("reposition", (event) => this.onRepos(event));
93
108
  }
94
109
 
110
+ /**
111
+ * Sets a unified padding value for both axes
112
+ * @param {number} pad - Padding value to apply to both axes
113
+ */
114
+ setPad(pad){
115
+ this.pad = pad;
116
+ this.padx = pad;
117
+ this.pady = pad;
118
+ }
119
+
95
120
  /**
96
121
  * Handles frame resize events
97
122
  * @param {GUIEvent} event - The resize event
98
123
  */
99
124
  onResize(event){
100
- console.log("resizing...");
101
125
  event.stopPropagation();
102
126
  }
103
127
 
@@ -106,7 +130,6 @@ export class Frame extends FrameComponent{
106
130
  * @param {GUIEvent} event - The reposition event
107
131
  */
108
132
  onRepos(event){
109
- console.log("repositioning...");
110
133
  }
111
134
 
112
135
  /**
@@ -114,6 +137,10 @@ export class Frame extends FrameComponent{
114
137
  * @param {GUIEvent} event - The release event
115
138
  */
116
139
  onMouseRelease(event){
140
+ if(this.enableResizing){
141
+ this._isResizing = false;
142
+ }
143
+
117
144
  if(!this.isOverBannerArea()){
118
145
  cursor("");
119
146
  }
@@ -144,7 +171,9 @@ export class Frame extends FrameComponent{
144
171
  onMouseHover(event){
145
172
  // console.log("mouse hovering...");
146
173
  if(this.enableResizing) {
147
- this.checkAndFindNearestBorder();
174
+ if(!this._isResizing){
175
+ this.checkAndFindNearestBorder();
176
+ }
148
177
  if(this.isNearBorder()){
149
178
  if(this.isBannerShown){
150
179
  this.clearHoverCache({clearResizingCache:false});
@@ -182,6 +211,8 @@ export class Frame extends FrameComponent{
182
211
  */
183
212
  onMouseBtnPress(event) {
184
213
  if(this.enableResizing && this.isNearBorder()){
214
+ this._isResizing = true;
215
+
185
216
  //dummy resize frame
186
217
  if(this.enableOptimisedResizing){
187
218
  this.createDummyFrame(DummyFrame.RESIZE_DF);
@@ -218,16 +249,14 @@ export class Frame extends FrameComponent{
218
249
  */
219
250
  onMouseDrag(event){
220
251
  if(this.enableResizing){
221
- if(this.isNearBorder() && !this.isRepositioning()){
252
+ if((this.isNearBorder() || this._isResizing) && !this.isRepositioning()){
222
253
  this.updateDimensions();
223
- this.dispatchTrickleDownEvent(new GUIEvent(event.x, event.y, "resize", this));
224
254
  return;
225
255
  }
226
256
  }
227
257
 
228
258
  if(this.enableReposition && this.isRepositioning()){
229
259
  this.updatePosition();
230
- this.dispatchTrickleDownEvent(new GUIEvent(event.x, event.y, "reposition", this));
231
260
  }
232
261
  }
233
262
 
@@ -358,14 +387,17 @@ export class Frame extends FrameComponent{
358
387
  * Updates frame dimensions during resizing
359
388
  */
360
389
  updateDimensions(){
390
+ const effMinW = this.getEffectiveMinWidth();
391
+ const effMinH = this.getEffectiveMinHeight();
392
+
361
393
  if(this.nearestBorder=="left" || this.nearestBorder=="right"){
362
394
  if( this.nearestBorder=="left"){
363
- if(this.x+this.width-mouseX>=this.bannerHeight){
395
+ if(this.x+this.width-mouseX>=effMinW){
364
396
  this.width = this.x + this.width - mouseX;
365
397
  this.x = mouseX;
366
398
  }
367
399
  } else {
368
- if(mouseX-this.x>=this.bannerHeight){
400
+ if(mouseX-this.x>=effMinW){
369
401
  this.width = mouseX - this.x;
370
402
  }
371
403
  }
@@ -378,12 +410,12 @@ export class Frame extends FrameComponent{
378
410
 
379
411
  } else if(this.nearestBorder=="top"||this.nearestBorder=="bottom"){
380
412
  if(this.nearestBorder=="top"){
381
- if(this.y+this.height-mouseY>=this.bannerHeight){
413
+ if(this.y+this.height-mouseY>=effMinH){
382
414
  this.height =this.y + this.height - mouseY;
383
415
  this.y = mouseY;
384
416
  }
385
417
  } else {
386
- if(mouseY-this.y>=this.bannerHeight){
418
+ if(mouseY-this.y>=effMinH){
387
419
  this.height = mouseY - this.y;
388
420
  }
389
421
  }
@@ -400,39 +432,39 @@ export class Frame extends FrameComponent{
400
432
 
401
433
  } else {
402
434
  if(this.nearestBorder=="top-left"){
403
- if(this.x+this.width-mouseX>=50){
435
+ if(this.x+this.width-mouseX>=effMinW){
404
436
  this.width = this.x + this.width - mouseX;
405
437
  this.x = mouseX;
406
438
  }
407
439
 
408
- if(this.y+this.height-mouseY>=50){
440
+ if(this.y+this.height-mouseY>=effMinH){
409
441
  this.height =this.y + this.height - mouseY;
410
442
  this.y = mouseY;
411
443
  }
412
444
  } else if(this.nearestBorder=="top-right"){
413
- if(mouseX-this.x>=50){
445
+ if(mouseX-this.x>=effMinW){
414
446
  this.width = mouseX - this.x;
415
447
  }
416
448
 
417
- if(this.y+this.height-mouseY>=50){
449
+ if(this.y+this.height-mouseY>=effMinH){
418
450
  this.height =this.y + this.height - mouseY;
419
451
  this.y = mouseY;
420
452
  }
421
453
  } else if(this.nearestBorder=="bottom-left"){
422
- if(this.x+this.width-mouseX>=50){
454
+ if(this.x+this.width-mouseX>=effMinW){
423
455
  this.width = this.x + this.width - mouseX;
424
456
  this.x = mouseX;
425
457
  }
426
458
 
427
- if(mouseY-this.y>=50){
459
+ if(mouseY-this.y>=effMinH){
428
460
  this.height = mouseY - this.y;
429
461
  }
430
462
  } else if(this.nearestBorder=="bottom-right"){
431
- if(mouseX-this.x>=50){
463
+ if(mouseX-this.x>=effMinW){
432
464
  this.width = mouseX - this.x;
433
465
  }
434
466
 
435
- if(mouseY-this.y>=50){
467
+ if(mouseY-this.y>=effMinH){
436
468
  this.height = mouseY - this.y;
437
469
  }
438
470
  }
@@ -455,13 +487,14 @@ export class Frame extends FrameComponent{
455
487
  this.x = mouseX - abs(this.xDist);
456
488
  this.y = mouseY - abs(this.yDist);
457
489
 
458
- if(this.prevX-this.x==0 && this.prevY-this.y==0){
490
+ let xDiff = this.prevX - this.x;
491
+ let yDiff = this.prevY - this.y;
492
+
493
+ if(xDiff === 0 && yDiff === 0){
459
494
  return;
460
495
  }
461
496
 
462
- //console.log("(",this.x,",",this.y,")");
463
-
464
- this.updatePosUtil(this.prevX-this.x, this.prevY-this.y);
497
+ this.updatePosUtil(xDiff, yDiff);
465
498
  }
466
499
  /**
467
500
  * Clears hover and interaction cache
@@ -485,47 +518,74 @@ export class Frame extends FrameComponent{
485
518
 
486
519
  if(clearResizingCache && this.enableResizing){
487
520
  this.nearestBorder=null;
521
+ this._isResizing = false;
488
522
  // console.log("resizing cache removed...");
489
523
  }
490
524
 
491
525
  // console.log("");
492
526
  }
493
527
  /**
494
- * Converts RGB color string to array
495
- * @param {string} shadowColor - RGB color string
496
- * @returns {number[]|null} Array of RGB values or null
528
+ * Updates shadow color
529
+ * @param {string} shadowColor - Shadow color (CSS color string)
497
530
  */
498
- rgbToArray(shadowColor) {
499
- let match = shadowColor.match(/\d+/g);
500
- return match ? match.map(Number) : null;
531
+ setShadowColor(shadowColor){
532
+ this.shadowColor = shadowColor;
533
+ }
534
+
535
+ /**
536
+ * Updates shadow blur radius
537
+ * @param {number} shadowBlur - Shadow blur
538
+ */
539
+ setShadowBlur(shadowBlur){
540
+ this.shadowBlur = shadowBlur;
541
+ }
542
+
543
+ /**
544
+ * Updates shadow X offset
545
+ * @param {number} shadowOffsetX - Shadow offset on X axis
546
+ */
547
+ setShadowOffsetX(shadowOffsetX){
548
+ this.shadowOffsetX = shadowOffsetX;
549
+ }
550
+
551
+ /**
552
+ * Updates shadow Y offset
553
+ * @param {number} shadowOffsetY - Shadow offset on Y axis
554
+ */
555
+ setShadowOffsetY(shadowOffsetY){
556
+ this.shadowOffsetY = shadowOffsetY;
501
557
  }
502
558
  /**
503
559
  * Renders shadow effect around the frame
504
560
  * @param {Object} options - Shadow options
505
561
  */
506
562
  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)");
563
+ if(this.width<=0 || this.height<=0){
510
564
  return;
511
565
  }
512
566
 
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
- }
567
+ let blur = Math.max(0, this.shadowBlur ?? 0);
568
+ let offsetX = this.shadowOffsetX ?? 0;
569
+ let offsetY = this.shadowOffsetY ?? 0;
570
+ let resolvedShadowColor = (typeof this.shadowColor === "string")
571
+ ? this.shadowColor
572
+ : (this.shadowColor && this.shadowColor.toString ? this.shadowColor.toString() : "rgba(0,0,0,0.35)");
520
573
 
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();
574
+ if(blur===0 && offsetX===0 && offsetY===0){
575
+ return;
529
576
  }
577
+
578
+ let baseFill = this.backgroundColor ?? color(0, 0, 0, 0);
579
+
580
+ push();
581
+ let ctx = drawingContext;
582
+ ctx.shadowColor = resolvedShadowColor;
583
+ ctx.shadowBlur = blur;
584
+ ctx.shadowOffsetX = offsetX;
585
+ ctx.shadowOffsetY = offsetY;
586
+ noStroke();
587
+ fill(baseFill);
588
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
589
+ pop();
530
590
  }
531
591
  }
@@ -11,9 +11,16 @@ export class FrameComponent extends Component{
11
11
  * @param {Component|null} options.parent - Parent component
12
12
  * @param {string} options.type - Component type
13
13
  * @param {string|null} options.id - Component ID
14
+ * @param {number} options.margin - General margin for all sides
15
+ * @param {number} options.marginx - Horizontal margin (left and right)
16
+ * @param {number} options.marginy - Vertical margin (top and bottom)
17
+ * @param {number} options.marginl - Left margin
18
+ * @param {number} options.marginr - Right margin
19
+ * @param {number} options.margint - Top margin
20
+ * @param {number} options.marginb - Bottom margin
14
21
  */
15
- constructor(x, y, width, height, {parent=null, type="", id=null} = {}){
16
- super(x, y, width, height, {parent: parent, type: type, id: id,});
22
+ constructor(x, y, width, height, {parent=null, type="", id=null, margin=0, marginx=null, marginy=null, marginl=null, marginr=null, margint=null, marginb=null, minWidth=0, minHeight=0, showDebugOverlay=false} = {}){
23
+ super(x, y, width, height, {parent: parent, type: type, id: id, margin: margin, marginx: marginx, marginy: marginy, marginl: marginl, marginr: marginr, margint: margint, marginb: marginb, minWidth: minWidth, minHeight: minHeight, showDebugOverlay: showDebugOverlay});
17
24
  }
18
25
 
19
26
  /**
@@ -14,6 +14,7 @@ export class GridFrame extends Frame{
14
14
  * @param {p5.Color} options.highlightedBorderColor - Highlighted border color
15
15
  * @param {number} options.borderWidth - Border width
16
16
  * @param {number} options.cornerRadius - Corner radius
17
+ * @param {number} options.pad - Unified padding for both axes
17
18
  * @param {number} options.padx - Horizontal padding
18
19
  * @param {number} options.pady - Vertical padding
19
20
  * @param {boolean} options.alwaysShowBanner - Always show banner
@@ -21,47 +22,83 @@ export class GridFrame extends Frame{
21
22
  * @param {number} options.cols - Number of columns in grid
22
23
  * @param {number} options.nearestBorderThreshold - Border detection threshold
23
24
  * @param {number} options.bannerHeight - Banner height
25
+ * @param {p5.Color|string} options.bannerColor - Banner background color
26
+ * @param {p5.Color|string} options.bannerDotColor - Banner dot indicator color
24
27
  * @param {Component|null} options.parent - Parent component
25
28
  * @param {boolean} options.enableReposition - Allow dragging
26
29
  * @param {boolean} options.enableOptimisedReposition - Optimized repositioning
27
30
  * @param {boolean} options.enableResizing - Allow resizing
28
31
  * @param {boolean} options.enableOptimisedResizing - Optimized resizing
29
32
  * @param {boolean} options.enableShadow - Enable shadow
30
- * @param {string} options.shadowColor - Shadow color
31
- * @param {number} options.shadowIntensity - Shadow opacity
32
- * @param {number} options.shadowSpread - Shadow spread
33
- * @param {number} options.shadowDetail - Shadow layers
33
+ * @param {string} options.shadowColor - Shadow color (CSS color string)
34
+ * @param {number} options.shadowBlur - Shadow blur radius
35
+ * @param {number} options.shadowOffsetX - Shadow offset on X axis
36
+ * @param {number} options.shadowOffsetY - Shadow offset on Y axis
37
+ * @param {number} options.margin - General margin for all sides
38
+ * @param {number} options.marginx - Horizontal margin (left and right)
39
+ * @param {number} options.marginy - Vertical margin (top and bottom)
40
+ * @param {number} options.marginl - Left margin
41
+ * @param {number} options.marginr - Right margin
42
+ * @param {number} options.margint - Top margin
43
+ * @param {number} options.marginb - Bottom margin
34
44
  */
35
45
  constructor(x, y, width, height, {
36
46
  id=null,
37
- backgroundColor = color(255),
38
- borderColor = color(0),
39
- highlightedBorderColor = color(0),
47
+ backgroundColor = color('#1e1e2e'),
48
+ borderColor = color('#3a3a4d'),
49
+ highlightedBorderColor = color('#5a5a7a'),
40
50
  borderWidth = 1,
41
- cornerRadius = 0,
42
- padx=0,
43
- pady=0,
51
+ cornerRadius = 8,
52
+ pad=null,
53
+ padx=null,
54
+ pady=null,
44
55
  alwaysShowBanner = false,
45
56
  rows=1,
46
57
  cols=1,
47
58
  nearestBorderThreshold=8,
48
59
  bannerHeight=35,
60
+ bannerColor='#2a2a3d',
61
+ bannerDotColor='#6a6a8a',
49
62
  parent=null,
50
63
  enableReposition=false,
51
64
  enableOptimisedReposition=false,
52
65
  enableResizing=false,
53
66
  enableOptimisedResizing=false,
54
67
  enableShadow=false,
55
- shadowColor= 'rgb(0,0,0)',
56
- shadowIntensity = 0.3,
57
- shadowSpread = 1,
58
- shadowDetail = 10,
68
+ shadowColor= 'rgba(0,0,0,0.5)',
69
+ shadowBlur = 12,
70
+ shadowOffsetX = 0,
71
+ shadowOffsetY = 4,
72
+ margin = 0,
73
+ marginx = null,
74
+ marginy = null,
75
+ marginl = null,
76
+ marginr = null,
77
+ margint = null,
78
+ marginb = null,
79
+ minWidth = 0,
80
+ minHeight = 0,
81
+ showDebugOverlay = false,
59
82
  }
60
83
  ){
84
+ if (pad !== null && pad !== undefined) {
85
+ padx = pad;
86
+ pady = pad;
87
+ }
88
+
89
+ if (padx === null || padx === undefined) {
90
+ padx = 0;
91
+ }
92
+
93
+ if (pady === null || pady === undefined) {
94
+ pady = 0;
95
+ }
96
+
61
97
  bannerHeight = bannerHeight%height;
62
98
  super(x, y, width, height, id, backgroundColor, borderColor, highlightedBorderColor, borderWidth,
63
- cornerRadius, padx, pady, alwaysShowBanner, bannerHeight, nearestBorderThreshold, parent, "Frame",
64
- enableReposition, enableOptimisedReposition, enableResizing, enableOptimisedResizing, enableShadow, shadowColor, shadowIntensity, shadowSpread, shadowDetail);
99
+ cornerRadius, padx, pady, alwaysShowBanner, bannerHeight, bannerColor, bannerDotColor, nearestBorderThreshold, parent, "Frame",
100
+ enableReposition, enableOptimisedReposition, enableResizing, enableOptimisedResizing, enableShadow, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY,
101
+ {margin, marginx, marginy, marginl, marginr, margint, marginb, minWidth, minHeight, showDebugOverlay});
65
102
 
66
103
  //for storing child elements
67
104
  this.rows=rows;
@@ -224,6 +261,62 @@ export class GridFrame extends Frame{
224
261
  this.colWeights[colNum] = weight;
225
262
  this.totalColWeight+=weight;
226
263
  }
264
+
265
+ /**
266
+ * Computes the effective minimum width from children's constraints.
267
+ * @returns {number}
268
+ */
269
+ getEffectiveMinWidth() {
270
+ let minW = this.minWidth;
271
+ if (!this.grid) return minW;
272
+
273
+ let maxNeeded = 0;
274
+ for (let i = 0; i < this.cols; i++) {
275
+ for (let j = 0; j < this.rows; j++) {
276
+ if (this.grid[j][i] != null && this.grid[j][i] != "taken") {
277
+ let curr = this.grid[j][i];
278
+ let childMin = curr[0].getEffectiveMinWidth();
279
+ if (childMin <= 0) continue;
280
+ let childNeeded = childMin + curr[3] + curr[4] + curr[0].marginl + curr[0].marginr;
281
+ let spanWeight = 0;
282
+ for (let k = 0; k < curr[2]; k++) spanWeight += this.colWeights[i + k];
283
+ let needed = childNeeded * this.totalColWeight / spanWeight + 2 * this.padx;
284
+ maxNeeded = Math.max(maxNeeded, needed);
285
+ }
286
+ }
287
+ }
288
+
289
+ return Math.max(minW, maxNeeded);
290
+ }
291
+
292
+ /**
293
+ * Computes the effective minimum height from children's constraints.
294
+ * @returns {number}
295
+ */
296
+ getEffectiveMinHeight() {
297
+ let minH = this.minHeight;
298
+ if (!this.grid) return minH;
299
+
300
+ let bannerH = (this.alwaysShowBanner || this.enableReposition) ? (this.bannerHeight || 0) : 0;
301
+
302
+ let maxNeeded = 0;
303
+ for (let i = 0; i < this.rows; i++) {
304
+ for (let j = 0; j < this.cols; j++) {
305
+ if (this.grid[i][j] != null && this.grid[i][j] != "taken") {
306
+ let curr = this.grid[i][j];
307
+ let childMin = curr[0].getEffectiveMinHeight();
308
+ if (childMin <= 0) continue;
309
+ let childNeeded = childMin + curr[5] + curr[6] + curr[0].margint + curr[0].marginb;
310
+ let spanWeight = 0;
311
+ for (let k = 0; k < curr[1]; k++) spanWeight += this.rowWeights[i + k];
312
+ let needed = childNeeded * this.totalRowWeight / spanWeight + 2 * this.pady + bannerH;
313
+ maxNeeded = Math.max(maxNeeded, needed);
314
+ }
315
+ }
316
+ }
317
+
318
+ return Math.max(minH, maxNeeded);
319
+ }
227
320
 
228
321
  /**
229
322
  * Initializes the grid structure with specified rows and columns
@@ -266,14 +359,17 @@ export class GridFrame extends Frame{
266
359
  if(this.grid && this.grid[j][i]!=null && this.grid[j][i]!="taken"){
267
360
  let curr = this.grid[j][i];
268
361
 
269
- curr[0].x = x + curr[3];
362
+ curr[0].x = x + curr[3] + curr[0].marginl;
270
363
  curr[0].width = 0;
271
364
 
272
365
  for(let k=0; k<curr[2]; k++){
273
366
  curr[0].width += (this.colWeights[i+k]/this.totalColWeight) * w;
274
367
  }
275
368
 
276
- curr[0].width -= curr[3] + curr[4];
369
+ curr[0].width -= curr[3] + curr[4] + curr[0].marginl + curr[0].marginr;
370
+
371
+ // Clamp to child's effective minimum width
372
+ curr[0].width = Math.max(curr[0].width, curr[0].getEffectiveMinWidth());
277
373
 
278
374
  if(curr[0].type=="Frame"){
279
375
  curr[0].adjustWidth(curr[0].x + curr[0].padx, curr[0].width - 2*curr[0].padx);
@@ -300,15 +396,18 @@ export class GridFrame extends Frame{
300
396
  if(this.grid && this.grid[i][j]!=null && this.grid[i][j]!="taken"){
301
397
  let curr = this.grid[i][j];
302
398
 
303
- curr[0].y = y + curr[5];
399
+ curr[0].y = y + curr[5] + curr[0].margint;
304
400
  curr[0].height = 0;
305
401
 
306
402
  for(let k=0; k<curr[1]; k++){
307
403
  curr[0].height += (this.rowWeights[i+k]/this.totalRowWeight) * h;
308
404
  }
309
405
 
310
- curr[0].height -= curr[5] + curr[6];
406
+ curr[0].height -= curr[5] + curr[6] + curr[0].margint + curr[0].marginb;
311
407
 
408
+ // Clamp to child's effective minimum height
409
+ curr[0].height = Math.max(curr[0].height, curr[0].getEffectiveMinHeight());
410
+
312
411
  //console.log("curr[0].type:"+curr[0].type);
313
412
 
314
413
  if(curr[0].type=="Frame"){
@@ -353,8 +452,8 @@ export class GridFrame extends Frame{
353
452
  y += (this.rowWeights[i]/this.totalRowWeight) * h;
354
453
  }
355
454
 
356
- this.grid[row][col][0].x = x + this.grid[row][col][3];
357
- this.grid[row][col][0].y = y + this.grid[row][col][5];
455
+ this.grid[row][col][0].x = x + this.grid[row][col][3] + this.grid[row][col][0].marginl;
456
+ this.grid[row][col][0].y = y + this.grid[row][col][5] + this.grid[row][col][0].margint;
358
457
 
359
458
  this.expandElement(row, col, rowSpan, colSpan);
360
459
 
@@ -445,8 +544,13 @@ export class GridFrame extends Frame{
445
544
  }
446
545
  }
447
546
 
448
- this.grid[row][col][0].width = w - this.grid[row][col][3] - this.grid[row][col][4];
449
- this.grid[row][col][0].height = h - this.grid[row][col][5] - this.grid[row][col][6];
547
+ this.grid[row][col][0].width = w - this.grid[row][col][3] - this.grid[row][col][4] - this.grid[row][col][0].marginl - this.grid[row][col][0].marginr;
548
+ this.grid[row][col][0].height = h - this.grid[row][col][5] - this.grid[row][col][6] - this.grid[row][col][0].margint - this.grid[row][col][0].marginb;
549
+
550
+ // Clamp to child's effective min dimensions
551
+ this.grid[row][col][0].width = Math.max(this.grid[row][col][0].width, this.grid[row][col][0].getEffectiveMinWidth());
552
+ this.grid[row][col][0].height = Math.max(this.grid[row][col][0].height, this.grid[row][col][0].getEffectiveMinHeight());
553
+
450
554
  this.grid[row][col][1] = yLimit+1;
451
555
  this.grid[row][col][2] = xLimit+1;
452
556
  }
@@ -523,10 +627,10 @@ export class GridFrame extends Frame{
523
627
  //showing the top banner
524
628
  if(this.alwaysShowBanner || (this.enableReposition && this.isBannerShown==true)){
525
629
  noStroke();
526
- fill(0);
527
- rect(this.x, this.y, this.width, this.bannerHeight);
630
+ fill(this.bannerColor);
631
+ rect(this.x, this.y, this.width, this.bannerHeight, this.cornerRadius, this.cornerRadius, 0, 0);
528
632
 
529
- fill(255);
633
+ fill(this.bannerDotColor);
530
634
  ellipse(this.x+this.width/2,
531
635
  this.y+(this.bannerHeight)/2,
532
636
  (this.bannerHeight)/4,