TabbedView an array of CompositeViews (or ScrollViews) with tabs for switching

by jostM, June11, 2009 version 1.25

Change history at bottom.

Class Methods

*new(parent,bounds,labels,colors,name,scroll) returns a TabbedView object

parent a parent view. if nil, then a new window is created

bounds Rect . if nil then the parent Rect is used

labels an array of strings. determines how many tabs there are. default ["tab1", "tab2", "tab3"]

colors an array of colors. if the array is smaller than the amount of labels, the color series repeats.

For convenience, a color scheme is automatically created using these colors.

You cannot use gradients here, because the tabs are drawn with Pen.

Gradients only work with background_;

Custom color schemes and shapes can be controlled with instance variables

or with the *new variations below.

name a name for the window if a new window is created (view==nil) -- default " "

scroll boolean defaults to false. It substitutes the CompositeView with a ScrollView.

Convenience method variations on *new for quick styling :

*newBasic

*newColor

*newColorLabels

*newFlat

*newTall

*newTransparent

*newPacked

Methods/Variables:

view returns the container for all the views

views returns an array of Composite/Scroll Views

add ( label ) string adds a tab with label ; returns the Composite/Scroll View

insert ( index , label ) int, string inserts a tab at index with label string ; returns the Composite/Scroll View

removeAt( index ) int remove tab at Index.

focus ( index ) int selects one of the tabs

activeTab returns the index of the focused tab

focusActions_(array) an Array of user onFocus functions.

unfocusActions_ (array) an Array of user onUnfocus functions.

tabPosition_ ( symbol ) \left, \top, \right, or \bottom.

followEdges_ ( bool ) default true. Set tabs parallel or perpendicular to container edges.

resize_ ( val ) int sets the resize flag (1-9 ). default 1. ;

labelColors_ ( colorarray ) Array of Colors for the tabs.

unfocusedColors_ (colorarray ) Array of Colors for the unfocused tabs

focusFrameColor_(color ) Color of the focus frame of the tabs. Cocoa only.

unfocusTabs_(boolean ) Unfocuses the UserView which draws the tabs after a tab is clicked.

Defaut on Cocoa is false, otherwise true. (because Swing can't hide focus frames);

backgrounds_ (colorarray ) Array of Colors for the CompositeViews

stringColor_ ( color ) a Color

stringFocusColor_ ( col ) a Color

labelPadding_ ( int ) if autosizing is on, then this determines left and right padding from th label text

tabWidth_ (int ) int or \auto ; a fixed tab width, or "auto" for automatic tab width (default "auto", unless using themes)

tabHeight_ ( int ) int or \auto ; a fixed tab height, or "auto" for automatic tab height (default "auto", unless using themes)

tabCurve_ ( int ) ; the radius in pixels of the rounded tab corners

swingFactor_( point ) Point ; a multiplication factor for a string/tab width for GUI.swing only. default Point(0.52146,1.25)

Usage:

use CompositeView style GUI

(

t=TabbedView(name:"** this is a mock preferences pane **");

ActionButton(t.views[0],"go to next tab ",{t.focus(1)}).bounds_(Rect(50,50,200,100));

)

use FlowView style GUI

(

t=TabbedView(); // use Flow Style

t.views[0].flow({|w|

GUI.button.new(w,Rect(50,50,250,50))

.states_([["control the tab with method 'focus' -->"]]).action_({t.focus(1)})

});

t.views[1].flow({|w|

GUI.button.new(w,Rect(50,50,200,100))

.states_([["go to last tab"]]).action_({t.focus(2)})

});

)

quick styling with variations on *new:

(There are some color differences for swing)

TabbedView.newBasic

TabbedView.newColor

TabbedView.newColorLabels

TabbedView.newFlat

TabbedView.newTall

TabbedView.newTransparent

TabbedView.newPacked(nil,nil,Array.fill(20,{|i| i.asString})); //very good for tons of tabs :

set tabPosition and followEdges:

live switching adjusts positions of contents if you use .flow .

(

v=TabbedView.newColorLabels(nil,nil,Array.fill(5,{arg i; var q="aa"; i.do{q=q++"a"}; q })); //default

v.views[0].flow({arg w;

ActionButton(w,"tabs top",{v.tabPosition_(\top)},300,50);

w.startRow;

ActionButton(w,"tabs left",{v.tabPosition_(\left)},148,50);

ActionButton(w,"tabs right",{v.tabPosition_(\right)},148,50);

w.startRow;

ActionButton(w,"tabs bottom",{v.tabPosition_(\bottom)},300,50);

GUI.button.new(w,300@50)

.states_([["set followEdges=false",Color.black,Color.red.alpha_(0.2)],

["set followEdges=true",Color.black,Color.green.alpha_(0.2)]])

.action_({arg b;(b.value==1).if{v.followEdges_(false)}{v.followEdges_(true)};});

});

)

TabbedView.newColorLabels(nil,nil,Array.fill(25,{|i| "tab"++i.asString})).tabPosition_(\right).followEdges_(false);

TabbedView.newTall(nil,nil,Array.fill(5,{|i| "tab"++i.asString})).tabPosition_(\left);

TabbedView.newTall(nil,Rect(100,500,400,100),Array.fill(5,{|i| "tab"++i.asString})).tabPosition_(\bottom);

Drag objects from one tab to another (under cocoa only at the moment):

(

v=TabbedView.newColorLabels;

n = GUI.dragSource.new(v.views[0], Rect(50, 50, 140, 24));

n.object = "Drag me to Tab2";

GUI.textView.new (v.views[1], Rect(50, 50, 140, 80));

)

add, removeAt, insert tabs

defaults on *new, but other thems use fixedwidths:

v=TabbedView.newColor

v.add("I am last")

v.insert(2,"squeeze me in")

v.removeAt(2)

resize_()

(

w=GUI.window.new.front;

v=TabbedView.newColorLabels(w,Rect(40,40,280,280),Array.fill(12,{|i| "tab"++i.asString})).tabPosition_(\right).followEdges_(false);

v.resize_(5);

GUI.slider.new(v.views[0],Rect(10,80,200,30)).resize_(2);

)

nest TabbedViews & use scrolling

uses scroll:true in the inner tab

(

v=TabbedView.newPacked(nil,Rect(200,200,600,400).insetBy(20,20),["1","2","3"])

.tabHeight_(40).tabPosition_(\right).followEdges_(false);

q=TabbedView.newColorLabels(v.views[0],nil,["tab1.1","tab1.2","tab1.3"], scroll: true)

.tabPosition_(\right).resize_(5).followEdges_(false);

q.views[0].flow({ arg w;

78.do({ arg i;

b = GUI.button.new(w, Rect(rrand(20,300),rrand(20,300), 75, 24));

b.states = [["Start "++i, Color.black, Color.rand],

["Stop "++i, Color.white, Color.red]];

});

});

GUI.slider.new(q.views[1],q.views[1].bounds.insetBy(50,50));

)

user functions: focus and unfocus

turn on/off scopes , e.g.

(

v=TabbedView.new();

v.focusActions[1]={"tab2 is focused".postln};

v.unfocusActions[1]={"tab2 just unfocused".postln};

)

focusFrameColor_(color) and unfocusTabs_(bool)

The tabs are drawn with user view which have a clear focus frame on Cocoa. On Swing, the frame cannot be made clear, so vy default the tabs are unfocused after clicking. You can change this if it interferes with you tabbing scheme.

(

v=TabbedView.new();

v.focusFrameColor_(Color.red);

)

v.unfocusTabs_(true); // default is false on Cocoa, true otherwise;

default autosizing tabs

defaults to auto on *new, but other themes use fixedwidths:

(

TabbedView.new(nil,Rect(150,100,400,500),["1","two","threeeeeeeeeeee","four","5"]);

)

(

v=TabbedView.newFlat(nil,Rect(150,100,400,300),["1","two","threeeeeeeeeee","four","5"]);

v.tabWidth_(\auto);

)

fixed tab sizes

(

TabbedView(nil,nil,["1","two","three","four","5"]).tabWidth_(70);

)

set font

Swing fonts only work within certain limits for now.

(

v=TabbedView.newBasic.font_(GUI.font.new("Monaco",9)).tabHeight_(18);

)

(

v=TabbedView.newBasic.font_(GUI.font.new("Monaco",36));

)

(

v=TabbedView.newBasic.font_(GUI.font.new("Helvetica",14)).tabHeight_(\auto);

)

(

v=TabbedView.newTall.font_(GUI.font.new("Helvetica",18)).tabPosition_(\left);

)

(

v=TabbedView.newTall.font_(GUI.font.new("Helvetica",36)).tabPosition_(\left).tabHeight_(\auto).tabWidth_(\auto);

)

set colors with an argument to .new

Colors can wrap around if there are less than there are labels.

Unfocused colors are calculated automatically.

(

v=TabbedView(nil,nil,Array.fill(8,{|i| i.asString}),

[Color.rand,Color.rand,Color.rand]);

//Colors can wrap around

)

set colors very specifically to your own taste using set methods

(

v=TabbedView.new(nil,nil,["one","two","three"]);

//Colors can wrap around

v.labelColors_([Color.rand,Color.rand,Color.rand]);

)

(

v=TabbedView.new(nil,nil,["one","two","three"]);

v.labelColors_([Color.red,Color.blue,Color.yellow]);

v.unfocusedColors_([Color.red.alpha_(0.1),Color.blue.alpha_(0.1),Color.yellow.alpha_(0.1)]);

v.backgrounds_([Color.red.alpha_(0.1),Color.blue.alpha_(0.1),Color.yellow.alpha_(0.1)]);

)

adjust padding and curves for small autowidth

labelPadding only has an effect on autowidth

(

v=TabbedView(nil,nil,Array.fill(20,{|i| i.asString}));

v.labelPadding_(8); //tighter padding

v.tabCurve_(3); //sharper curves

v.stringColor_(Color.black);

v.backgrounds_([Color.white.alpha_(0.3)]);

)

or simply use *newPacked:

(

v=TabbedView.newPacked(nil,nil,Array.fill(20,{|i| i.asString}));

)

adjust tab height and curves

super flat and elegant

(

v=TabbedView(nil,nil,["1","two","three","four","5"]).tabWidth_(70).tabHeight_(13).tabCurve_(3);

)

super tall and clear

(

TabbedView(nil,nil,["1","two","three","four","5"]).tabWidth_(70).tabHeight_(30).tabCurve_(3);

)

Change History:

Aug 27, 2007 : code optimized; instanceVar tabPosition. Version 1.0;

Aug 24, 2007 : small code optimizations Version 1.01;

Aug 23, 2007 : fixed small bug when bounds=nil Version 1.02;

Aug 30, 2007 : added scroll option. Convenience new methods can now take arguments of form arg:value Version 1.03;

Sep 2, 2007 : FlowView contents will now reposition in real time if tab position is changed. tabPosition getter. Version 1.04;

Tabs can switch during drags(cocoa only);

Feb 12, 2008 : relativeOrigin variable added to adjust to new SCCompositeView behavior. Swing compatibility. Version 1.10;

Feb 16, 2008 : Version 1.11; Swing themes adjusted to use no transparency.

deprecated: newRGB and newRGBLabels ;

use new methods: newColor and newColorLabels instead.

swingFactor defaults to 7 (integers work better than floats,

Feb 19, 2008 : Version 1.12;

focus_() deprecated; use focus(index) instead.

focused added.

Feb 19, 2008 : Version 1.13;

focused removed and changed to activeTab.

All variables that had a double s in "focussed", changed to singel s;

Feb 20, 2008 : Version 1.14; Fixed returned tab on add and insert methods

Feb 20, 2008 : Version 1.15; added font variable. other bug fixes

Feb 26, 2008 : Version 1.20; added followEdges option.

July 9, 2008 : Version 1.21; updates for SC3.21

Dec 15, 2008 : Version 1.22; changed swing font calculation

Dec 19, 2008 : Version 1.23; changed swing font calculation

Jan 28, 2008 : Version 1.24; fixed loop bug. relativeOrigin deprecated (always use r/o)

Jun 11, 2009 : Version 1.25; removed all calls to relativeOrigin. focusFrameColor_(color) and unfocusTabs_(bool).

arg w changed to parent