public class Listbox // REMOVE GUIDO DEPENDENCY HERE?
{
    float x, y, width, height;
    
    ArrayList<String> items;
    int itemHeight;
    int listStartAt;
    int hoverItem;
    int selectorId;
    
    float valueY;
    boolean hasSlider;
    
    String lastItemClicked;
    
    Listbox ( float xx, float yy, float ww, float hh, int itemHeight, String[] fileTypes, int selectorId ) 
    {
        x = xx; y = yy;
        valueY = y;
        
        this.width = ww; this.height = hh;
        this.selectorId = selectorId;
        this.itemHeight = itemHeight;
        this.listStartAt = 0;
        this.hoverItem = -1;
        this.hasSlider = false;
        this.items = new ArrayList<String>();
        
        for (String type : fileTypes) {
          this.addItem(type);
        }
        
        // register it
        Interactive.add( this );
    }
    
    public void addItem ( String item )
    {
        items.add( item );
        hasSlider = items.size() * itemHeight > this.height;
    }
    
    public void mouseMoved ( float mx, float my )
    {
        if (!selectingFileType) { return; }
        if ( hasSlider && mx > this.width-20 ) return;
        
        hoverItem = listStartAt + int((my-y) / itemHeight);
    }
    
    public void mouseExited ( float mx, float my )
    {
        hoverItem = -1;
    }
    
    // For slider
    void mouseDragged ( float mx, float my, float dx, float dy )
    {
        if (!selectingFileType) { return; }
        if (!hasSlider) return;
        if ( mx < x+this.width-20 ) return;
        
        valueY = my-10;
        valueY = constrain( valueY, y, y+this.height-20 );
        
        update();
    }
    
    // Called from manager
    void mouseScrolled ( float step )
    {
        if (!selectingFileType) { return; }
        valueY += step;
        valueY = constrain( valueY, y, y+this.height-20 );
        
        update();
    }
    
    void update ()
    {
        if (!selectingFileType) { return; }
        float totalHeight = items.size() * itemHeight;
        float itemsInView = this.height / itemHeight;
        float listOffset = map( valueY, y, y+this.height-20, 0, totalHeight-this.height );
        
        listStartAt = int( listOffset / itemHeight );
    }
    
    void mousePressed ( float mx, float my )
    {
        if (!selectingFileType) { return; }
        if ( hasSlider && mx > this.width-20 ) return;
        
        int item = listStartAt + int( (my-y) / itemHeight );
        lastItemClicked = items.get(item);
        if (debugPrints) { println(lastItemClicked); }
    }

    void draw ()
    {
        if (!selectingFileType || selectorId != displaySelectorId) { return; }
        noStroke();
        fill(#FFFFFF);
        rectMode(CORNER);
        rect( x, y, this.width, this.height );
        strokeWeight(2);
        if ( items != null )
        {
          for ( int i = 0; i < int(this.height/itemHeight) && i < items.size(); ++i )
          {
            String currentItem = items.get(i+listStartAt);
            stroke( ds.GUIColor );
            if (currentItem.equals(lastItemClicked)) {
              fill(#000000);
            } else {
              fill(#FFFFFF);
            }
            
            if ((i+listStartAt) == hoverItem) { fill(#FFF8AD); }
            rect( x, y + (i*itemHeight), this.width, itemHeight );
            
            noStroke();
            if (currentItem.equals(lastItemClicked)) {
              if ((i+listStartAt) == hoverItem) {
                fill(#0052FF);
              } else {
                fill(#FFFFFF);
              }
            } else {
              fill(#000000);
            }
            textSize(itemHeight * .75);
            textAlign(LEFT);
            text( currentItem, x+5, y+(i+1)*itemHeight-5 );
          }
        }
        
        if ( hasSlider )
        {
            rectMode(CORNER);
            stroke( 80 ); // TODO: change color
            fill( 100 );
            rect( x+this.width-20, y, 20, this.height );
            fill( 120 );
            rect( x+this.width-20, valueY, 20, 20 );
        }
    }
}