@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.
@@ -0,0 +1,764 @@
1
+ import {Frame} from './Frame.js';
2
+
3
+ export class ScrollFrame extends Frame{
4
+ /**
5
+ * Creates a scrollable container for child components
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 {string|null} options.id - Component ID
12
+ * @param {p5.Color} options.backgroundColor - Background color
13
+ * @param {p5.Color} options.borderColor - Border color
14
+ * @param {p5.Color} options.highlightedBorderColor - Highlighted border color
15
+ * @param {number} options.borderWidth - Border width
16
+ * @param {number} options.cornerRadius - Corner radius
17
+ * @param {number} options.padx - Horizontal padding
18
+ * @param {number} options.pady - Vertical padding
19
+ * @param {boolean} options.alwaysShowBanner - Always show banner
20
+ * @param {boolean} options.enableVScroll - Enable vertical scrolling
21
+ * @param {boolean} options.enableHScroll - Enable horizontal scrolling
22
+ * @param {number} options.scrollSensitivity - Scroll speed
23
+ * @param {number} options.bannerHeight - Banner height
24
+ * @param {string} options.alignment - Layout alignment ("v" or "h")
25
+ * @param {number} options.nearestBorderThreshold - Border detection threshold
26
+ * @param {Component|null} options.parent - Parent component
27
+ * @param {boolean} options.enableReposition - Allow dragging
28
+ * @param {boolean} options.enableOptimisedReposition - Optimized repositioning
29
+ * @param {boolean} options.enableResizing - Allow resizing
30
+ * @param {boolean} options.enableOptimisedResizing - Optimized resizing
31
+ * @param {boolean} options.enableShadow - Enable shadow
32
+ * @param {string} options.shadowColor - Shadow color
33
+ * @param {number} options.shadowIntensity - Shadow opacity
34
+ * @param {number} options.shadowSpread - Shadow spread
35
+ * @param {number} options.shadowDetail - Shadow layers
36
+ */
37
+ constructor(x, y, width, height, {
38
+ id=null,
39
+ backgroundColor = color(255),
40
+ borderColor = color(0),
41
+ highlightedBorderColor = color(0),
42
+ borderWidth = 1,
43
+ cornerRadius = 0,
44
+ padx=0,
45
+ pady=0,
46
+ alwaysShowBanner = false,
47
+ enableVScroll=false,
48
+ enableHScroll=false,
49
+ scrollSensitivity=20,
50
+ bannerHeight=35,
51
+ alignment="v", //v for vertical, h for horizontal
52
+ nearestBorderThreshold=8,
53
+ parent=null,
54
+ enableReposition=false,
55
+ enableOptimisedReposition=false,
56
+ enableResizing=false,
57
+ enableOptimisedResizing=false,
58
+ enableShadow=false,
59
+ shadowColor= 'rgb(0,0,0)',
60
+ shadowIntensity= 0.3,
61
+ shadowSpread= 1,
62
+ shadowDetail=10,
63
+ } = {}) {
64
+ bannerHeight = bannerHeight%height;
65
+ super(x, y, width, height, id, backgroundColor, borderColor, highlightedBorderColor, borderWidth,
66
+ cornerRadius, padx, pady, alwaysShowBanner, bannerHeight, nearestBorderThreshold, parent, "Frame",
67
+ enableReposition, enableOptimisedReposition, enableResizing, enableOptimisedResizing, enableShadow, shadowColor, shadowIntensity, shadowSpread, shadowDetail);
68
+
69
+ this.preferences = [];
70
+ //used for calculating weighted dimensions of child elements
71
+ this.totalWeight = 0;
72
+ //flags for scroll on/off
73
+ this.enableVScroll=enableVScroll;
74
+ this.enableHScroll=enableHScroll;
75
+ //for internal alignment of elements
76
+ this.alignment = alignment;
77
+
78
+ if(this.alignment=="vertical"){
79
+ this.alignment="v";
80
+ }
81
+
82
+ if(this.alignment=="horizontal"){
83
+ this.alignment="h";
84
+ }
85
+
86
+ if(this.alignment!="v" && this.alignment!="h"){
87
+ this.alignment="v";
88
+ }
89
+
90
+ //sets the amount in % to scroll in any direction
91
+ if(this.enableHScroll || this.enableVScroll){
92
+ this.scrollSensitivity=scrollSensitivity;
93
+ }
94
+
95
+ if(this.enableVScroll){
96
+ this.topper=-1;
97
+ this.deepest=-1;
98
+ }
99
+
100
+ if(this.enableHScroll){
101
+ this.leftist=-1;
102
+ this.rightist=-1;
103
+ }
104
+
105
+ //default event listeners
106
+ this.addEventListener("keyDown", (event) => this.onKeyDown(event));
107
+ }
108
+
109
+ /**
110
+ * Handles keyboard navigation for scrolling
111
+ * @param {KeyboardEvent} event - The key down event
112
+ */
113
+ onKeyDown(event) {
114
+ // console.log("key is pressed...");
115
+ if(keyIsDown(LEFT_ARROW)){
116
+ this.scrollLeft();
117
+ } else if(keyIsDown(RIGHT_ARROW)){
118
+ this.scrollRight();
119
+ } else if(keyIsDown(UP_ARROW)){
120
+ this.scrollUp();
121
+ } else if(keyIsDown(DOWN_ARROW)){
122
+ this.scrollDown();
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Renders the scroll frame and child components
128
+ */
129
+ show() {
130
+ //shadow
131
+ if(this.enableShadow){
132
+ this.drawShadow();
133
+ }
134
+
135
+ //coloring the background
136
+ if(this.backgroundColor!=null){
137
+ push();
138
+ noStroke();
139
+ fill(this.backgroundColor);
140
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
141
+ pop();
142
+ }
143
+
144
+ //applying clipping mask
145
+ push();
146
+ beginClip();
147
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
148
+ endClip();
149
+
150
+ //displaying child elements
151
+ for (let child of this.children) {
152
+ child.show();
153
+ }
154
+
155
+ //show the top banner
156
+ if(this.alwaysShowBanner || (this.enableReposition && this.isBannerShown)){
157
+ noStroke();
158
+ fill(0);
159
+ rect(this.x, this.y, this.width, this.bannerHeight);
160
+
161
+ fill(255);
162
+ ellipse(this.x+this.width/2, this.y+(this.bannerHeight)/2, (this.bannerHeight)/4, (this.bannerHeight)/4);
163
+ ellipse(this.x+this.width/2 - (this.bannerHeight)/2, this.y+(this.bannerHeight)/2, (this.bannerHeight)/4, (this.bannerHeight)/4);
164
+ ellipse(this.x+this.width/2 + (this.bannerHeight)/2, this.y+(this.bannerHeight)/2, (this.bannerHeight)/4, (this.bannerHeight)/4);
165
+ }
166
+
167
+ pop();
168
+
169
+ //displaying the outline/border
170
+ if(this.borderColor!=null){
171
+ push();
172
+ stroke(this.borderColor);
173
+ strokeWeight(this.borderWidth);
174
+ noFill();
175
+ rect(this.x, this.y, this.width, this.height, this.cornerRadius);
176
+ pop();
177
+ }
178
+
179
+ //highlight the relevant border if cursor is sufficiently near to it
180
+ // if(this.enableResizing && this.nearestBorder!=null){
181
+ // this.showHighlightedBorder();
182
+ // }
183
+ }
184
+
185
+ /**
186
+ * Adds a component to the scroll frame with weighted sizing
187
+ * @param {Component} element - The component to add
188
+ * @param {Object} options - Placement options
189
+ * @param {number} options.weight - Proportional weight for sizing
190
+ * @param {number} options.padL - Left padding
191
+ * @param {number} options.padR - Right padding
192
+ * @param {number} options.padT - Top padding
193
+ * @param {number} options.padB - Bottom padding
194
+ */
195
+ add(element,
196
+ {
197
+ weight=1,
198
+ padL=0,
199
+ padR=0,
200
+ padT=0,
201
+ padB=0
202
+ }={})
203
+ {
204
+ if(element==null){
205
+ console.log("element to add can't be null");
206
+ return;
207
+ }
208
+
209
+ if(this.findElement(element)){
210
+ console.log(`the component (id: ${element.id}) is already added to the scrollframe (${this.id})`);
211
+ console.log("component: ", element, "\nScrollFrame: ", this);
212
+ return;
213
+ }
214
+
215
+ if(weight<=0){
216
+ console.log("weight can't be non-positive");
217
+ return;
218
+ }
219
+
220
+ if(this.getElementById(element.id)){
221
+ console.log(`component with duplicate id (${element.id}) found in ${this.constructor.name}; component (${element.constructor.name}) can't be added!`);
222
+ console.log(this);
223
+ console.log("");
224
+ return;
225
+ }
226
+
227
+ element.turnResizingAndRepositionOff();
228
+ element.parent=this;
229
+ this.children.push(element);
230
+ // 0 , 1 , 2 , 3 , 4 , 5
231
+ //old: element, weight, padL, padR, padT, padB
232
+ // 0 , 1 , 2 , 3 , 4
233
+ //new: weight, padL, padR, padT, padB
234
+ this.preferences.push([weight, padL, padR, padT, padB]);
235
+ this.totalWeight+=weight;
236
+ this.redraw();
237
+
238
+ if(this.enableHScroll==true){
239
+ this.findLeftist();
240
+ this.findRightist();
241
+ }
242
+
243
+ if(this.enableVScroll==true){
244
+ this.findTopper();
245
+ this.findDeepest();
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Removes a component from the scroll frame
251
+ * @param {Component} element - The component to remove
252
+ */
253
+ remove(element){
254
+ let index = this.findIndexOfElement(element);
255
+ if(index==-1){
256
+ console.log(`element (id: ${element.id}) can't be removed from ScrollFrame (id: ${this.id})
257
+ because it was not found in immediate children!`);
258
+ return;
259
+ }
260
+
261
+ this.children[index].parent = null;
262
+ this.totalWeight -= this.preferences[index][0];
263
+ this.preferences = this.preferences.filter((_, i) => i!==index);
264
+ this.removeChild(element);
265
+ this.redraw();
266
+
267
+ console.log(`element (id: ${element.id}) successfully removed from ${this.constructor.name} (id: ${this.id})!`);
268
+ }
269
+
270
+ /**
271
+ * Sets the weight of a child component
272
+ * @param {number} index - Child index
273
+ * @param {number} weight - New weight value
274
+ */
275
+ setWeight(index, weight){
276
+ if(index<0 || index>this.children.length-1){
277
+ console.log("index out of range! can't set new weight");
278
+ return;
279
+ }
280
+
281
+ if(weight<1){
282
+ console.log("weight to set must be >= 1");
283
+ return;
284
+ }
285
+
286
+ this.totalWeight -= this.preferences[index][0];
287
+ this.totalWeight += weight;
288
+ this.preferences[index][0] = weight;
289
+ }
290
+
291
+ /**
292
+ * Gets the weight of a child component
293
+ * @param {number} index - Child index
294
+ * @returns {number} The weight value
295
+ */
296
+ getWeight(index){
297
+ if(index<0 || index>this.children.length-1){
298
+ console.log("index out of range! can't set new weight");
299
+ return;
300
+ }
301
+
302
+ return this.preferences[index][0];
303
+ }
304
+
305
+ /**
306
+ * Sets left padding for a child component
307
+ * @param {number} index - Child index
308
+ * @param {number} padL - Left padding value
309
+ */
310
+ setPadL(index, padL){
311
+ if(index<0 || index>this.children.length-1){
312
+ console.log("index out of range! can't set new padL");
313
+ return;
314
+ }
315
+
316
+ if(padL<0){
317
+ console.log("padL to set must be >= 0");
318
+ return;
319
+ }
320
+
321
+ this.preferences[index][1] = padL;
322
+ }
323
+
324
+ /**
325
+ * Gets left padding of a child component
326
+ * @param {number} index - Child index
327
+ * @returns {number} Left padding value
328
+ */
329
+ getPadL(index){
330
+ if(index<0 || index>this.children.length-1){
331
+ console.log("index out of range! can't set new padL");
332
+ return;
333
+ }
334
+
335
+ return this.preferences[index][1];
336
+ }
337
+
338
+ /**
339
+ * Sets right padding for a child component
340
+ * @param {number} index - Child index
341
+ * @param {number} padR - Right padding value
342
+ */
343
+ setPadR(index, padR){
344
+ if(index<0 || index>this.children.length-1){
345
+ console.log("index out of range! can't set new padR");
346
+ return;
347
+ }
348
+
349
+ if(padR<0){
350
+ console.log("padR to set must be >= 0");
351
+ return;
352
+ }
353
+
354
+ this.preferences[index][2] = padR;
355
+ }
356
+
357
+ /**
358
+ * Gets right padding of a child component
359
+ * @param {number} index - Child index
360
+ * @returns {number} Right padding value
361
+ */
362
+ getPadR(index){
363
+ if(index<0 || index>this.children.length-1){
364
+ console.log("index out of range! can't set new padR");
365
+ return;
366
+ }
367
+
368
+ return this.preferences[index][2];
369
+ }
370
+
371
+ /**
372
+ * Sets top padding for a child component
373
+ * @param {number} index - Child index
374
+ * @param {number} padT - Top padding value
375
+ */
376
+ setPadT(index, padT){
377
+ if(index<0 || index>this.children.length-1){
378
+ console.log("index out of range! can't set new padT");
379
+ return;
380
+ }
381
+
382
+ if(padT<0){
383
+ console.log("padT to set must be >= 0");
384
+ return;
385
+ }
386
+
387
+ this.preferences[index][3] = padT;
388
+ }
389
+
390
+ /**
391
+ * Gets top padding of a child component
392
+ * @param {number} index - Child index
393
+ * @returns {number} Top padding value
394
+ */
395
+ getPadT(index){
396
+ if(index<0 || index>this.children.length-1){
397
+ console.log("index out of range! can't set new padT");
398
+ return;
399
+ }
400
+
401
+ return this.preferences[index][3];
402
+ }
403
+
404
+ /**
405
+ * Sets bottom padding for a child component
406
+ * @param {number} index - Child index
407
+ * @param {number} padB - Bottom padding value
408
+ */
409
+ setPadB(index, padB){
410
+ if(index<0 || index>this.children.length-1){
411
+ console.log("index out of range! can't set new padB");
412
+ return;
413
+ }
414
+
415
+ if(padB<0){
416
+ console.log("padB to set must be >= 0");
417
+ return;
418
+ }
419
+
420
+ this.preferences[index][4] = padB;
421
+ }
422
+
423
+ /**
424
+ * Gets bottom padding of a child component
425
+ * @param {number} index - Child index
426
+ * @returns {number} Bottom padding value
427
+ */
428
+ getPadB(index){
429
+ if(index<0 || index>this.children.length-1){
430
+ console.log("index out of range! can't set new padB");
431
+ return;
432
+ }
433
+
434
+ return this.preferences[index][4];
435
+ }
436
+
437
+ //the following find methods find the relevant subjects by maintaing a
438
+ //reference variable. This variable is conditionally updated by comparing
439
+ //it to the most recently added element in the list. Therefore, there is
440
+ //no need to loop over all the elements every single time any element is added.
441
+
442
+ //finds the element nearest to the top
443
+ /**
444
+ * Finds the topmost child component
445
+ */
446
+ findTopper(){
447
+ if(this.topper==-1){
448
+ this.topper=0;
449
+ return;
450
+ }
451
+
452
+ let i = this.preferences.length-1;
453
+ if(this.children[i].y +
454
+ this.preferences[i][3] <
455
+ this.children[this.topper].y +
456
+ this.preferences[this.topper][3]){
457
+ this.topper = i;
458
+ }
459
+ }
460
+
461
+ //finds the element that is farther down than any other element
462
+ /**
463
+ * Finds the bottommost child component
464
+ */
465
+
466
+ findDeepest(){
467
+ if(this.deepest==-1){
468
+ this.deepest=0;
469
+ return;
470
+ }
471
+
472
+ let i = this.preferences.length-1;
473
+ if(this.children[i].y +
474
+ this.children[i].height -
475
+ this.preferences[i][4] >
476
+ this.children[this.deepest].y +
477
+ this.children[this.deepest].height -
478
+ this.preferences[this.deepest][4]){
479
+ this.deepest = i;
480
+ }
481
+ }
482
+
483
+ //finds the element nearest to the left boundary
484
+ /**
485
+ * Finds the leftmost child component
486
+ */
487
+ findLeftist(){
488
+ if(this.leftist==-1){
489
+ this.leftist=0;
490
+ return;
491
+ }
492
+
493
+ let i = this.preferences.length-1;
494
+ if(this.children[i].x +
495
+ this.preferences[i][1] <
496
+ this.children[this.leftist].x +
497
+ this.preferences[this.leftist][1]){
498
+ this.leftist = i
499
+ }
500
+ }
501
+
502
+ //finds the element farthest to the right
503
+ /**
504
+ * Finds the rightmost child component
505
+ */
506
+ findRightist(){
507
+ if(this.rightist==-1){
508
+ this.rightist=0;
509
+ return;
510
+ }
511
+
512
+ let i = this.preferences.length-1;
513
+ if(this.children[i].x +
514
+ this.children[i].width -
515
+ this.preferences[i][2] >
516
+ this.children[this.rightist].x +
517
+ this.children[this.rightist].width -
518
+ this.preferences[this.rightist][2]){
519
+ this.rightist = i;
520
+ }
521
+ }
522
+ /**
523
+ * Scrolls content downward
524
+ */
525
+ scrollDown(){
526
+ if(!this.enableVScroll || this.children.length==0){
527
+ return;
528
+ }
529
+
530
+ if(this.alignment=="v"){
531
+ let last_elem = this.children[this.children.length-1];
532
+ if(last_elem.y + last_elem.height > this.y + this.height - this.pady - this.preferences[this.preferences.length-1][4]){
533
+ this.vScrollUtil(-1);
534
+ }
535
+ } else {
536
+ //need to find the one that extends the longest
537
+ if(this.children[this.deepest].y + this.children[this.deepest].height > this.y + this.height - this.pady- this.preferences[this.deepest][4]){
538
+ this.vScrollUtil(-1);
539
+ }
540
+ }
541
+ }
542
+ /**
543
+ * Scrolls content upward
544
+ */
545
+ scrollUp(){
546
+ if(!this.enableVScroll || this.children.length==0){
547
+ return;
548
+ }
549
+
550
+ if(this.alignment=="v"){
551
+ let first_elem = this.children[0];
552
+ if(first_elem.y + this.preferences[0][3] <this.y + this.pady){
553
+ this.vScrollUtil(1);
554
+ }
555
+ } else {
556
+ //need to find the element that is nearest to the top
557
+ if(this.children[this.topper].y + this.preferences[this.topper][3] <this.y + this.pady){
558
+ this.vScrollUtil(1);
559
+ }
560
+ }
561
+ }
562
+ /**
563
+ * Utility method for vertical scrolling
564
+ * @param {number} multiple - Scroll direction and multiplier
565
+ */
566
+ vScrollUtil(multiple){
567
+ for(let i=0; i<this.children.length; i++){
568
+ let elem = this.children[i];
569
+
570
+ if(elem.constructor.name=="ScrollFrame"){
571
+ elem.vScrollUtil(multiple);
572
+ }
573
+
574
+ elem.y+=multiple*this.scrollSensitivity;
575
+ }
576
+ }
577
+ /**
578
+ * Scrolls content to the left
579
+ */
580
+ scrollLeft(){
581
+ if(!this.enableHScroll || this.children.length==0){
582
+ return;
583
+ }
584
+
585
+ if(this.alignment=="v"){
586
+ //do something about the loop
587
+ if(this.children[this.leftist].x-this.preferences[this.leftist][1]<this.x+this.padx){
588
+ this.hScrollUtil(1);
589
+ }
590
+
591
+ } else {
592
+ //first element
593
+ if(this.children[0].x-this.preferences[0][1]<this.x+this.padx){
594
+ this.hScrollUtil(1);
595
+ }
596
+ }
597
+ }
598
+ /**
599
+ * Scrolls content to the right
600
+ */
601
+ scrollRight(){
602
+ if(!this.enableHScroll || this.children.length==0){
603
+ return;
604
+ }
605
+
606
+ if(this.alignment=="v"){
607
+ if(this.children[this.rightist].x+this.children[this.rightist].width+this.preferences[this.rightist][2]>this.x+this.width-this.padx){
608
+ this.hScrollUtil(-1);
609
+ }
610
+
611
+ } else {
612
+ let last_elem = this.children[this.children.length-1];
613
+ if(last_elem.x+last_elem.width+this.preferences[this.preferences.length-1][2]>this.x+this.width-this.padx){
614
+ this.hScrollUtil(-1);
615
+ }
616
+ }
617
+ }
618
+ /**
619
+ * Utility method for horizontal scrolling
620
+ * @param {number} multiple - Scroll direction and multiplier
621
+ */
622
+ hScrollUtil(multiple){
623
+ for(let i=0; i<this.children.length; i++){
624
+ let elem = this.children[i];
625
+
626
+ if(elem.constructor.name=="ScrollFrame"){
627
+ elem.hScrollUtil(multiple);
628
+ }
629
+
630
+ elem.x+=multiple*this.scrollSensitivity;
631
+ }
632
+ }
633
+ /**
634
+ * Shows banner and adjusts content position
635
+ */
636
+ showBanner(){
637
+ if(this.enableVScroll==true){
638
+ this.BannerUtil(1, this.bannerHeight);
639
+ } else {
640
+ this.adjustHeight(this.y + (this.bannerHeight) + this.pady, this.height - (this.bannerHeight) - 2*(this.pady));
641
+ }
642
+ this.isBannerShown=true;
643
+ }
644
+ /**
645
+ * Hides banner and adjusts content position
646
+ */
647
+ hideBanner(){
648
+ if(this.enableReposition && this.isBannerShown){
649
+ if(this.enableVScroll==true){
650
+ this.BannerUtil(-1, this.bannerHeight);
651
+ } else {
652
+ this.adjustHeight(this.y + this.pady, this.height-2*(this.pady));
653
+ }
654
+ this.isBannerShown=false;
655
+ }
656
+ }
657
+ /**
658
+ * Utility for banner visibility changes
659
+ * @param {number} dir - Direction (1 for show, -1 for hide)
660
+ * @param {number} heightAdjustment - Height adjustment amount
661
+ */
662
+ BannerUtil(dir, heightAdjustment){
663
+ for(let i=0; i<this.children.length; i++){
664
+ let curr = this.children[i];
665
+ curr.y += dir*heightAdjustment;
666
+
667
+ if(curr.constructor.name=="ScrollFrame"){
668
+ curr.BannerUtil(dir, heightAdjustment);
669
+ }
670
+ }
671
+ }
672
+ /**
673
+ * Adjusts child component heights based on weights and alignment
674
+ * @param {number} y - Starting y position
675
+ * @param {number} h - Available height
676
+ */
677
+ adjustHeight(y, h){
678
+ //[element, weight, padL, padR, padT, padB]
679
+ for(let i=0; i<this.children.length; i++){
680
+
681
+ let curr = this.children[i];
682
+
683
+ if(i-1>=0){
684
+ let prev = this.children[i-1];
685
+ if(this.alignment=="v"){
686
+ curr.y = prev.y + prev.height + this.preferences[i-1][4] + this.preferences[i][3];
687
+ } else {
688
+ curr.y = y + this.preferences[i][3];
689
+ }
690
+ } else {
691
+ curr.y = y + this.preferences[i][3];
692
+ }
693
+
694
+ if(this.enableVScroll==false){
695
+ if(this.alignment=="v"){
696
+ curr.height = (this.preferences[i][0]/(this.totalWeight))*(h) - this.preferences[i][3] - this.preferences[i][4];
697
+ } else {
698
+ curr.height = h - this.preferences[i][3] - this.preferences[i][4];
699
+ }
700
+ }
701
+
702
+ if(curr.type=="Frame"){
703
+ curr.adjustHeight(curr.y + curr.pady, curr.height - 2*(curr.pady));
704
+ } else {
705
+ if(this.enableVScroll==false){
706
+ curr.updateHeight();
707
+ }
708
+ }
709
+
710
+ }
711
+ }
712
+ /**
713
+ * Adjusts child component widths based on weights and alignment
714
+ * @param {number} x - Starting x position
715
+ * @param {number} w - Available width
716
+ */
717
+ adjustWidth(x, w){
718
+ //[element, weight, padL, padR, padT, padB]
719
+ for(let i=0; i<this.children.length; i++){
720
+ let curr = this.children[i];
721
+ if(i-1>=0){
722
+ let prev = this.children[i-1];
723
+ if(this.alignment!="v"){
724
+ curr.x = prev.x + prev.width + this.preferences[i-1][2] + this.preferences[i][1];
725
+ } else {
726
+ curr.x = x + this.preferences[i][1];
727
+ }
728
+ } else {
729
+ curr.x = x + this.preferences[i][1];
730
+ }
731
+
732
+ if(this.enableHScroll==false){
733
+ if(this.alignment=="v"){
734
+ curr.width = w - this.preferences[i][1] - this.preferences[i][2];
735
+ } else {
736
+ curr.width = (this.preferences[i][0]/(this.totalWeight))*(w) - this.preferences[i][1] - this.preferences[i][2];
737
+ }
738
+ }
739
+
740
+ if(curr.type=="Frame"){
741
+ curr.adjustWidth(curr.x + curr.padx, curr.width - 2*(curr.padx));
742
+ } else {
743
+ if(this.enableHScroll==false){
744
+ curr.updateWidth();
745
+ }
746
+ }
747
+
748
+ }
749
+ }
750
+ /**
751
+ * Updates child positions during frame movement
752
+ * @param {number} xDiff - X position difference
753
+ * @param {number} yDiff - Y position difference
754
+ */
755
+ updatePosUtil(xDiff, yDiff){
756
+ for(let i=0; i<this.children.length; i++){
757
+ this.children[i].x -= xDiff;
758
+ this.children[i].y -= yDiff;
759
+ if(this.children[i].type=="Frame"){
760
+ this.children[i].updatePosUtil(xDiff, yDiff);
761
+ }
762
+ }
763
+ }
764
+ }