ButtonGrid -- command buttons array
Background
Sometimes during J data analysis session, certain commands need to be executed over and over. Notable examples would be pd 'clip', pd 'keypos rti;show', etc. This application allows to assign a j phrase to a command button and execute this phrase (in base locale) with one button click.
cocurrent 'jzbg' «utilities» «data» «access» «form» «command_handlers» «event_handlers» «locale_cover»
Utilities
controlgrid=:(,~"0/&([: +/\ }:@(0&,)) ,"1 ,~"0/)&,
moveby=:+/@,:"1
ltrb=:0 1 _2 _1{(<./ , >./) ,/ (2&{. , [: +/ _2 ]\ ])"1
NB. turn any array of rectangles into a list of rectangles (2d array)
rravel=:(, $~ (*/@}: , {:)@$)
NB. bounding rectangle of the list of rectangles
runion=:[: (<./ ([ , -~) >./) [: ,/ ([: +/\ _2 ]\ ])"1
rexpand=:4 : '((-x)+2{.y),(2*x)+2}.y'
NB. top left point
rnw=:rtl=:2 & {.
NB. bottom right point
rse=:rbr=:[: +/ _2 ]\ ]
NB. top right point
rne=:rtr=:0 2&(+/@:{) , 1&{
NB. bottom left point
rsw=:rbl=:0&{ , 1 3&(+/@:{)
NB. place rectangle identical to y next to y
rxnext=:(+ 2&{ 0} 0">)
require 'regex'
template=:(4 : 0)"1
m=. '%(\d+)%?' rxmatches x
i=.(#y) <. (1&{"2 m) ".@>@rxfrom x
<(i{(":each y),<,'?') (0&{"2 m) rxmerge x
)
once=: [: ".^:((('=:'&-:)@>@{: *. (0>4!:0)@{.)@(2 {. ;:)) ;._2 ,&LF
These are copied from elswhere. Most of these verbs manipulate rectangles for programmatic GUI generation. once executes assignment unless the name is already defined.
Actions and Labels
once 'ACTION=:0 0 2$ a:'
get_action=:0&{"1
get_label=:1&{"1
Program stores actions and labels in boxed 3d array ACTION. It has shape m×n×2. Each "1 item contains j expression (action) and arbitrary string (label) in that order
Form
NB. --- Default and initial values of configuration parameters
once 'COCREATOR=:<''base'''
The form is executed in its own locale, jzbg. Right now there can only be one command button array per session. I considered making it a class (like plot or adjust), but I never seem to want more than one command button array at a time anyway.
bg_makeform=:3 : 0
y=.$ID
FID=:'bg'
wd 'pc ',FID,';pn "ButtonGrid (',(>COCREATOR),')"'
«button_array»
«worktext»
«shift_switches»
«service_switches»
wd 'pas ',(":2$MARGIN),';pshow'
BForm=:wd 'qhwndp'
wd 'pmovex ',":(2{.LASTPOS),2}.".wd 'qformx'
)
This form should look something like this:
s=.BUTTON+MARGIN
xywh=.<"1 (2$MARGIN) moveby BUTTON,~"1 s*"1 |."1 (#: i.) y
wd&> 'xywh %0%;cc %1% button;cn "%2%"' template xywh ,"_2 ID ,"_2 get_label ACTION
The main functional component of a form is an aray of command buttons. When user clicks on a button, event handler executes j phrase associated with this button. As a feedback the executed phrase is placed into editbox (named worktext in the code).
tb=.(0,MARGIN) moveby (rbl , 2&{ , EH"_) runion rravel >xywh
wd 'xywh ',(":tb),';cc worktext edit es_autohscroll;cn ""'
cb0=.(_1 1*MARGIN) moveby (rbl tb), 0,RBH
cb1r=. 25 (2}) (MARGIN,0) moveby rxnext cb0
cb2r=. 25 (2}) (MARGIN,0) moveby rxnext cb1r
cb3r=. 20 (2}) (MARGIN,0) moveby rxnext cb2r
t=.'xywh %0%;cc %1% radiobutton group;cn "%2%"'
wd > t template cb1r;'cblabel';'label'
wd > t template cb2r;'cbview';'view'
wd > t template cb3r;'cbsetexec';'set'
Radio buttons below the text box work kind of like calculator shift keys. User selects one of the radio buttons and then clicks one of the buttons on the command button array. This will modify appropriate setting for the button or display pertinent information. After this radio button is turned off and command buttons return to their normal "execute j phrase" mode.
label -- text from worktext becomes label on a command button
view -- j phrase associated with the button is copied into worktext
set -- worktext becomes new j phrase associated with a button
r=.+/0 2{tb
t=.1{cb3r
cbt=.(r-CBW),t,CBW,RBH
cbq=.(r-CBW+MARGIN+CBW),t,CBW,RBH
t=.'xywh %0%;cc %1% checkbox;cn "%2%"'
wd >t template cbq;'cbq';'&Q'
wd >t template cbt;'cbt';'&T'
Two checkboxes modify the default behavior of the form. "Quiet" (Q) does not display the expression and its result in .ijx window. "On top" (T) makes form "always on top". They are placed in the same row as shift switches and aligned to the right edge of workbox. If workbox is not wide enough, the 2 areas may overlap.
bg_cbt_button=:3 : 0 wd 'ptop ',cbt )
Configuration
All defining globals must be set by the time bg_makeform verb is run. They are:
once 'BUTTON=:30 30'
Each command button size.
once 'MARGIN=:3'
Intervals between buttons and extra space around the entire array.
once 'EH=:14'
Heigh of a textbox where user enters J command or button label. This is a single line textbox. Changing its height makes sense when font is smaller or larger than anticipated.
once 'RBH=:12'
Radio button height. Ditto.
once 'CBW=:15'
Service checkbox width. Should be able to accomodate single character plus checkbox itself.
Commands
bg_cmd=:3 : 0
'cmd rest'=.y({.~ ; (}.~ >:))y i. ' '
if. 3=nc :: _1: <'bgc_' (, :: [)cmd do.
('bgc_',cmd)~ rest
return.
end.
if. 0=nc :: _1: <toupper cmd do.
(toupper cmd)=:0".rest
y=.''
NB. KLUDGE: to iduce redraw
ACTION=:({.~ 1+2{.$)ACTION
end.
NB. *** numeric or empty argument -- build as needed and show
if. ''-:y do. y=.2{.$ACTION end.
if. 0=*/y do. y=.3 4 end.
ID=:('b' <@, ":)">i. y
if. -. ACTION -:&(2 {. $) ID do.
bg_close ''
ACTION=:y {. ACTION
bg_makeform ''
end.
bgc_show ''
)
bg_cmd is an interface to entire command button array functionality. It has cover verb bg in z locale for convenience. It does several things.
If input (y) is numeric 2 element vector, it is interpreted as a number of rows and columns in the command button array. bg_cmd resizes internal storage structures for j phrases and button labels, generates necessary GUI elements and assigns id's to them.
If input is empty vector, bg_cmd activates the form with current paramters. If form was accidentally or intentionally closed, empty argument will restore it.
If input is a string, it is considered a command. It is split into first word and rest of the string.
If first word after capitalization becomes one of the internal noun names, te command means "chnage the name and regenerate form". For example:
bg 'button 40 20'
sets button size noun BUTTON to 40 20 and regenerates form with buttons of this new size.
Otherwise, program looks for a verb named bgc_first-word. If found, program runs this verb and passes the rest of the string as a y parameter.
bgc_help
bgc_help=:3 : 0
NB. list allcaps nouns
l=.(#~ (-: toupper)&>) nl 0
NB. list bgc_* named verbs
l=.l,(#~ ('bgc_' -: 4&{.)&>) nl 3
list l
)
bgc_help is a handler for help command.
Right now
bg 'help'
will list all internal command handlers and calibration variables.
bgc_show
bgc_show=:3 : 0
try.
wd 'psel ',FID,';pactive;pshow'
bg_savepos ''
catch.
bg_makeform ''
end.
wd 'pmovex ',":(2{.LASTPOS),2}.".wd 'qformx'
)
bgc_save
bgc_save=:3 : 0
s=.(CRLF,~ [ , '=:' , [: 5!:5 <)
if. ''-:PREDEFINEDLOCATION do.
self=.(>(4!:3 ''){~(4!:4 <'bg_save_jzbg_'))
else.
self=.PREDEFINEDLOCATION
end.
r=. 'require ''',self,'''',CRLF
r=.r,'cocurrent ''',(>coname''),'''',CRLF
r=. r,;s&.> 'VERSION';'ACTION';'BUTTON';'MARGIN';'LASTPOS'
r=.r,'bg ''''',CRLF
(1!:2&(<y))^:(-.''-:y) r
)
bg 'save'
generates j script that loads command button array and initializes it with currently set-up parameters, including all sizes, button labels and j phrases attached to them.
PREDEFINEDLOCATION=:'bg'
Script generated by bgc_save needs to load this script first. The location of this script may be specified in PREDEFINEDLOCATION configuration noun. (I made a PUBLIC_j_ alias bg for this script on my system.) If PREDEFINEDLOCATION is left empty, it will attempt to make a guess using 4!:3 and 4!:4 (list of scripts and index in a list of scripts) foreigns.
bg 'save filename.ijs'
saves this sript to a file so that
load 'filename.ijs'
creates same form again.
bgc_compact
bgc_compact=:3 : 0
wd 'psel ',FID
if. (''-:y) +. 0~: 0".y do.
wd 'pas ',":MARGIN,-+/EH,MARGIN,RBH
else.
wd 'pas ',":2#MARGIN
end.
)
Hide worktext, shift and service switches, leave only buttons visible.
bg 'comapact 0'
turns this off and restores service area.
bgc_exch
bgc_exch=:3 : 0
y=.4({.!._) _".y
assert. (4=#y) *. *./,_2 (0&<:*.(2{.$ACTION)>])\ y
i=._2 <\ y
ACTION=:(i{ACTION) (|.i)}ACTION
bg_close ''
bg_makeform ''
bgc_show''
)
Exchange contents and labels of 2 buttons with given row and column coordinates.
Event handlers
bg_default=:3 : 0
exec=.''
if. -.'button'-:'systype' wdget wdq do. return. end.
ind=.<"1 ($ #: I.@,) (<'syschild' wdget wdq) = ID
if. 1~:#ind do. return. end.
ind=.{.ind
NB. --- "shifted" keys (radio buttons) processings
if. ".cblabel do.
ACTION=: (<worktext) (ind,&.>1)} ACTION
wd 'setcaption ',(>ind{ID),' *',worktext
elseif. ".cbview do.
wd 'set worktext *',(>ind{get_action ACTION)
elseif. ".cbsetexec do.
ACTION=: (<worktext) (ind,&.>0)} ACTION
if. (ind{get_label ACTION)-:a: do.
ACTION=: (<worktext) (ind,&.>1)} ACTION
wd 'setcaption ',(>ind{ID),' *',worktext
end.
elseif. 1 do.
exec=.>ind{get_action ACTION
wd 'set worktext *',exec
end.
wd 'set cblabel 0'
wd 'set cbview 0'
wd 'set cbsetexec 0'
if. -.''-:exec do.
r=.do__COCREATOR exec
if. -. ".cbq do. NB. -.0 0-:$r
smoutput ' ',exec
smoutput r
end.
end.
)
Since the number of buttons is not known beforehand, all processing is performed in default form handler. Events from radio buttons could have been processed separately, but i found it easier to keep everything in one place.
once 'LASTPOS=:16 16 0 0'
bg_savepos=: 3 : 0 wd 'psel bg' LASTPOS=:".wd 'qformx' )
Form stores its last know position in LASTPOS noun and tries to keep it up to date at every opportunity.
bg_close=:3 : 0
try.
bg_savepos ''
catch.
end.
wd 'pclose'
)
Close event needs to be processed to capture last known position to be able to restore it at next start.
Epilogue
bg_z_=:bg_cmd_jzbg_
Cover verb for main command processor placed in z locale to simplify typing.
NB. --- end of configuration section VERSION=:'$Revision: 1.8 $'
See also: adjust.lit
Tips and tricks
A button can be assigned to a command of saving current button configuration to a predefined file:
bg 'save C:\Data\p\ttqtopos\2012-02-08-11p99583\buttons.ijs'
To make a button that makes current window permanent on top, assign:
wd 'ptop 1'
A button to restore normal status:
wd 'ptop 0'
To hide radiobuttons and worktext use:
wd 'psel bg;pas ',":do_jzbg_ 'MARGIN,-+/EH,MARGIN,RBH'
To restore use
wd 'psel bg;pas ',":2#MARGIN_jzbg_
Some pretty unicode symbols to use in button labels (copy and paste)
← ↓ ↑ → ◄ ▼ ▲ ► ∑ ∏ σ √ ∫ ∂ ∆ ∞ ∩ ∪
Ideas for further improvements
I try to keep both interface and operation as simple as possible. Most of these ideas defeat this goal and therefor unlikely to be implemented. Nevertheless, I list them here is food for thought.
multiline button lables
There seems to be no way to do it in wd
Coloring buttons
Buttons may have color. Static coloring enhances button gouping by function. Dynamic cooring may indicate "state" of some variable that this button affects.
Moving recatngular blocks of buttons around
Expanding button array to fit more buttons often requires existing buttons to be slightly rearranged. 'exch' command allows to do it on small scale. Direct manipulation of ACTION global does it on larger scale, but is inconvenient due to lack of convenient multidimensional indexing in J.
Tabs
The whole point is to have all commands available one click away. Having them on different tabs makes it two clicks away.
