Skip to content
Open
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
177 changes: 156 additions & 21 deletions build/uil.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,10 +641,10 @@
/*
// esta era la funcion original
loop: function () {
if( R.isLoop ) requestAnimationFrame( R.loop );
if( R.isLoop ) requestAnimationFrame( R.loop );
R.update();
},
*/
},
*/

loop: function () {
// modified by Fedemarino
Expand Down Expand Up @@ -889,9 +889,9 @@
//https://developer.mozilla.org/fr/docs/Web/CSS/css_flexible_box_layout/aligning_items_in_a_flex_container

/*cloneColor: function () {
let cc = Object.assign({}, T.colors );
let cc = Object.assign({}, T.colors );
return cc;
},*/
},*/

// intern function

Expand Down Expand Up @@ -936,7 +936,7 @@
T.set(dom, obj);

/* } else if ( type === 'use' ) {
dom = document.createElementNS( T.svgns, 'use' );
dom = document.createElementNS( T.svgns, 'use' );
T.set( dom, obj );
*/
} else {
Expand Down Expand Up @@ -1160,7 +1160,7 @@
}
},
/*makeGraph: function () {
let w = 128;
let w = 128;
let radius = 34;
let svg = T.dom( 'svg', T.css.basic , { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
T.dom( 'path', '', { d:'', stroke:T.colors.text, 'stroke-width':4, fill:'none', 'stroke-linecap':'butt' }, svg );//0
Expand All @@ -1170,7 +1170,7 @@
//T.dom( 'circle', '', { cx:64, cy:64, r:radius+7, stroke:'rgba(0,0,0,0.3)', 'stroke-width':7 , fill:'none'}, svg );//2
//T.dom( 'path', '', { d:'', stroke:'rgba(255,255,255,0.3)', 'stroke-width':2, fill:'none', 'stroke-linecap':'round', 'stroke-opacity':0.5 }, svg );//3
T.graph = svg;
},*/
},*/

makePad: function (model) {
let ww = 256;
Expand Down Expand Up @@ -3340,8 +3340,8 @@
// ----------------------

/*mode: function ( mode ) {
let s = this.s;
switch(mode){
let s = this.s;
switch(mode){
case 0: // base
s[1].color = this.colors.text;
//s[1].background = 'none';
Expand All @@ -3354,7 +3354,7 @@
s[1].color = this.colors.text;
//s[1].background = UIL.SELECTDOWN;
break;
}
}
},*/

tick(v) {
Expand Down Expand Up @@ -4601,7 +4601,7 @@
/*if(this.hideCurrent){
//items = [...this.items]
items = this.items.slice(this.tmpId)
}*/
}*/

let i = items.length,
item,
Expand Down Expand Up @@ -4867,7 +4867,7 @@
//item.style.marginLeft = (this.imageSize[0]+8)+'px'

/*let c = document.createElement('canvas')
c.width = this.imageSize[0]
c.width = this.imageSize[0]
c.height = this.imageSize[1]
let ctx = c.getContext("2d")
ctx.fillStyle = this.canvasBg
Expand Down Expand Up @@ -5983,7 +5983,7 @@
/*rSize () {

super.rSize();
}*/
}*/

mode(n) {
let change = false;
Expand Down Expand Up @@ -6033,7 +6033,7 @@
super(o);

/*this.values = o.values || [];
if( typeof this.values === 'string' ) this.values = [ this.values ];*/
if( typeof this.values === 'string' ) this.values = [ this.values ];*/

this.values = [];
if (o.values) {
Expand Down Expand Up @@ -6288,9 +6288,9 @@
this.bounds.x2 = o.x2 || 1;
this.bounds.y1 = o.y1 || -1;
this.bounds.y2 = o.y2 || 1;
this.lerpX = this.lerp( this.margin, this.w - this.margin , this.bounds.x1, this.bounds.x2 );
this.lerpX = this.lerp( this.margin, this.w - this.margin , this.bounds.x1, this.bounds.x2 );
this.lerpY = this.lerp( this.margin, this.w - this.margin , this.bounds.y1, this.bounds.y2 );
this.alerpX = this.lerp( this.bounds.x1, this.bounds.x2, this.margin, this.w - this.margin );
this.alerpX = this.lerp( this.bounds.x1, this.bounds.x2, this.margin, this.w - this.margin );
this.alerpY = this.lerp( this.bounds.y1, this.bounds.y2, this.margin, this.w - this.margin );*/

this.value = Array.isArray(o.value) && o.value.length == 2 ? o.value : [0, 0];
Expand Down Expand Up @@ -6450,13 +6450,145 @@
}

/*lerp( s1, s2, d1, d2, c = true ) {
let s = ( d2 - d1 ) / ( s2 - s1 );
return c ? ( v ) => {
let s = ( d2 - d1 ) / ( s2 - s1 );
return c ? ( v ) => {
return ( ( v < s1 ? s1 : v > s2 ? s2 : v ) - s1 ) * s + d1
} : ( v ) => {
return ( v - s1 ) * s + d1
}
}*/
}*/
}

// Hierarchical tree selector component
class TreeList extends Proto {
constructor(o = {}) {
super(o);
this.tree = o.tree || {};
this.value = o.value || [];
this.focused = o.focused || false;
this.focusPath = o.focusPath || [];
this.focusLevel = o.focusLevel || 0;
this.tabIndex = o.tabIndex || 0;
this.itemIndex = o.itemIndex || 0;
this.onChange = o.onChange || function () {};

// preserve original row height so resizing doesn't affect row layout
this.itemHeight = this.h;
this.maxLeaf = computeMaxLeaf(this.tree);
this.c[2] = this.dom('div', this.css.basic + 'top:0; left:0; width:100%;');
this.c[2].style.pointerEvents = 'auto';
this.init();
this.build();
}
setTree(tree) {
this.tree = tree;
this.maxLeaf = computeMaxLeaf(tree);
this.build();
}
setValue(v) {
this.value = v || [];
this.build();
}
setFocus(path, level) {
this.focusPath = path || [];
this.focusLevel = level || 0;
this.build();
}
build() {
while (this.c[2].firstChild) this.c[2].removeChild(this.c[2].firstChild);
let node = this.tree;
let path = this.focused ? this.focusPath : this.value;
let level = 0;
let total = 0;
while (node) {
const isLeaf = Array.isArray(node);
const options = isLeaf ? node : Object.keys(node);
const unit = this.itemHeight;
const rowHeight = isLeaf ? this.maxLeaf * unit : unit;
const container = this.dom('div', 'position:absolute; display:flex;' + (isLeaf ? 'flex-direction:column;' : 'flex-direction:row;'));
container.style.top = total + 'px';
container.style.height = rowHeight + 'px';
container.style.width = '100%';
container.style.pointerEvents = 'auto';
options.forEach(opt => {
const optDiv = this.dom('div', this.css.item + 'margin:1px; line-height:' + (unit - 4) + 'px;');
optDiv.style.height = unit - 2 + 'px';
optDiv.style.pointerEvents = 'auto';
if (isLeaf) {
optDiv.style.width = '100%';
} else {
optDiv.style.flex = '1 1 0';
}
optDiv.textContent = opt;
if (this.value[level] === opt) optDiv.style.background = this.colors.select;
if (this.focused && this.focusLevel === level && this.focusPath[level] === opt) {
optDiv.style.border = '1px solid ' + this.colors.text;
} else {
optDiv.style.border = '1px solid ' + this.colors.border;
}
optDiv.addEventListener('click', () => this.select(level, opt));
container.appendChild(optDiv);
});
if (isLeaf) {
const diff = this.maxLeaf - options.length;
for (let i = 0; i < diff; i++) {
const spacer = this.dom('div', this.css.basic + 'height:' + (unit - 2) + 'px; width:100%;');
spacer.style.pointerEvents = 'none';
container.appendChild(spacer);
}
}
this.c[2].appendChild(container);
total += rowHeight;
if (isLeaf) break;
const nextKey = path[level];
if (nextKey !== undefined && node.hasOwnProperty(nextKey)) {
node = node[nextKey];
level++;
} else {
break;
}
}
this.s[0].height = total + 'px';
this.s[2].height = total + 'px';
this.zone.h = total + this.margin;
this.rSize();
}
select(level, option) {
let newPath = this.value.slice(0, level);
newPath[level] = option;
let node = this.tree;
for (let i = 0; i <= level; i++) {
if (Array.isArray(node)) {
node = null;
break;
}
node = node[newPath[i]];
}
while (node && !Array.isArray(node)) {
const keys = Object.keys(node);
if (!keys.length) break;
newPath.push(keys[0]);
node = node[keys[0]];
}
this.onChange(this.tabIndex, this.itemIndex, newPath);
this.setValue(newPath);
}
rSize() {
super.rSize();
this.s[2].left = this.sa + 'px';
this.s[2].width = this.sb + 'px';
}
}
function computeMaxLeaf(tree) {
let max = 0;
(function traverse(n) {
if (Array.isArray(n)) {
if (n.length > max) max = n.length;
} else if (n && typeof n === 'object') {
Object.keys(n).forEach(k => traverse(n[k]));
}
})(tree);
return max;
}

const add = function () {
Expand Down Expand Up @@ -6556,6 +6688,9 @@
case 'pad':
n = new Pad2D(o);
break;
case 'treelist':
n = new TreeList(o);
break;
}
if (n !== null) {
Roots.needResize = true;
Expand Down Expand Up @@ -6731,7 +6866,7 @@
}
triggerMouseUp(x, y) {
/*
clientX,clientY are no used when isCanvas==true
clientX,clientY are no used when isCanvas==true
*/
Roots.handleEvent({
type: "pointerup",
Expand Down
2 changes: 1 addition & 1 deletion build/uil.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/uil.module.js

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions examples/uil_treeList.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Uil TreeList Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="shortcut icon" href="./assets/favicon.ico">
</head>
<style>
html{ overflow:hidden; width:100%; height:100%; }
body { font-family: "Lucida Console", Monaco, monospace; background-color:#717b84; font-size:11px; color:#fff; margin: 0px; }
</style>
</head>
<body>
<div id='content'></div>
<script type="module">
import * as UIL from '../build/uil.module.js';

let ui;

const sampleTree = {
fruits: {
citrus: ['orange','lemon'],
berries: ['strawberry','blueberry']
},
vegetables: {
root: ['carrot','beet'],
leaf: ['lettuce','spinach']
}
};

function initGUI(){
ui = new UIL.Gui({ w:300, isCanvas:false });
ui.add('treeList', {
name:'Tree',
tree: sampleTree,
value:['fruits','citrus'],
onChange:(tab,item,path)=>{ console.log('selected path', path); }
});
}

initGUI();
</script>
</body>
</html>
2 changes: 2 additions & 0 deletions src/core/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Empty } from '../proto/Empty.js';
import { Item } from '../proto/Item.js';
import { Grid } from '../proto/Grid.js';
import { Pad2D } from '../proto/Pad2D.js';
import { TreeList } from '../proto/TreeList.js';
import { Roots } from './Roots.js';

export const add = function () {
Expand Down Expand Up @@ -79,6 +80,7 @@ export const add = function () {
case 'item': n = new Item(o); break;
case 'grid': n = new Grid(o); break;
case 'pad2d': case 'pad': n = new Pad2D(o); break;
case 'treelist': n = new TreeList(o); break;

}

Expand Down
Loading