📄 grid.class
字号:
/* grid
spanfit(...) will expand into empty cells, but will NOT back
up if other cells later invade space that it has captured.
*/
*! version 1.0.5 21nov2004
version 8
class {
instance:
style = .plotregionstyle.new
subview = .yesno.new , style(no)
gmetric_mult = 1
fixed_xsize = (.)
fixed_ysize = (.)
xoffset = 0
yoffset = 0
maxrow = 0 /* max row number */
maxcol = 0 /* max column number */
array rowpos = { 1 } /* array of row positions */
array colpos = { 1 } /* array of column positions */
double shared_rowsz /* size of shared stretch rows */
double shared_colsz /* size of shared stretch cols */
array fitcells /* cells who span by fitting */
cells = .null.new /* cell information that aligns *
* with dynamically declared view */
draw_view = .yesno.new, style(yes)
fill_if_undrawn = .yesno.new, style(no)
_hold_scaling = (.)
_hold_gmetric_mult = (.)
} , inherit(container)
/* -------------------------------------------------------------------------*/
program define new
syntax [, Style(string) SUBVIEW GMETricmult(integer 1) * ]
if `gmetricmult' <= 0 {
di as error "gmetricmult() invalid, must be > 0"
exit 198
}
.gmetric_mult = `gmetricmult'
if "`subview'" != "" {
.subview.set_true
}
if "`style'" == "" {
local style scheme graph
}
.style.setstyle, style(`style') /* uses schemes */
.xstretch.set free
.ystretch.set free
/* ... more ? ... */
.Super.new , `options'
end
/* -------------------------------------------------------------------------*/
/* Move an existing view
Usage: .move <view_name> location_syntax_from_insert_below
*/
program move
gettoken view location : 0
if !(0`.`view'.isofclass view' | 0`.`view'.isofclass subview') {
di in white "May only move dynamically declared views"
exit 198
}
tempname holdview
.`holdview' = .`view'.ref
.delete `view'
.insert (`view' = .`holdview'.ref) `location'
end
/* -------------------------------------------------------------------------*/
/* Insert a view into the grid above, below, leftof, or rightof of the named
view. A new row or column is created to hold the view.
Usage:
insert (<new_view>) [overlay] {A|B|L|R|N...} {baseview|rc} [, Span(...) ]
{A|B|L|R|N|O} := Above name|#_r #_c
Below name|#_r #_c
Leftof name|#_r #_c
Rightof name|#_r #_c
On
AT row column
Top (very top)
Bottom (very bottom)
FULLLeft (far left)
FULLRight (far right)
New
<new_view> := name = rvalue (returning a view)
class viewclass [name]
*/
program define insert
gettoken new_dec 0 : 0, match(par)
if "`par'" == "" {
di as error "grid.insert, (new_view) not found"
exit 198
}
gettoken direct 0 : 0 , parse(" ,")
local overlay = "`direct'" == "overlay"
if `overlay' {
gettoken direct 0 : 0 , parse(" ,")
}
._set_direction direct : `direct' /* set the direction */
/* handle "new" location */
if "`direct'" == "new" {
if "`.dynamicmv.arrnels'" != "" {
di as error "may not insert using new when " /*
*/ "grid already contains view"
exit 198
}
.maxrow = 3
.maxcol = 3
._add_view `"`new_dec'"' 2 2 `"`0"'
exit /* EXIT */
}
/* handle "at" location */
if "`direct'" == "at" {
gettoken row 0 : 0
gettoken col 0 : 0 , parse(" ,")
capture confirm integer number `row'
local rc = _rc
capture confirm integer number `col'
if _rc | `rc' {
di as error "grid.insert: at row col, row and col " /*
*/ "must be integers"
}
if `row' < 1 | `col' < 1 {
di as error "grid.insert: at row col, row and col " /*
*/ "must be positive integers"
local row = max(`row', 1)
local col = max(`col', 1)
}
if 0`.maxrow' <= `row' {
.maxrow = `row' + 1
}
if 0`.maxcol' <= `col' {
.maxcol = `col' + 1
}
._add_view `"`new_dec'"' `row' `col' `"`0'"'
exit /* EXIT */
}
/* handle relative locations and
* extreme positions */
if ! inlist("`direct'", "fullleft", "fullright", "top", "bottom") {
syntax [anything] [ , RING(real -1) * ]
capture numlist "`anything'" , min(2) max(2) integer range(>0)
if ! _rc { // #_r #_c
tokenize `r(numlist)'
local ins_row `1'
local ins_col `2'
local 0 , ring(`ring') `options'
}
else { // obj name
gettoken basename 0 : 0 , parse(" ,")
local cellname cells.`basename'
if "`.`cellname'.isa'" == "array" {
local cellname `cellname'[1] // 1st element
}
// check errors */
if "`.`cellname'.isa'" == "" {
di as error `"grid.insert: `basename' not found"'
exit 198
}
if "`.`cellname'.minrow'" == "" | ///
"`.`cellname'.mincol'" == "" {
di in red "`basename' not in grid, may " ///
"not use grid.insert"
exit 198
}
/* hold insertion row and col */
if "`direct'" == "above" {
local ins_row = `.`cellname'.maxrow' + 1
}
else {
local ins_row = `.`cellname'.minrow'
}
if "`direct'" == "rightof" {
local ins_col = `.`cellname'.maxcol' + 1
}
else {
local ins_col = `.`cellname'.mincol'
}
}
if 0`ring' > 0 & "`direct'" != "on" {
if "`direct'" == "above" | "`direct'" == "below" {
._find_ringrow ins_row f_ring : ///
`ins_row' `ins_col' `ring' `direct'
}
else {
._find_ringcol ins_col f_ring : ///
`ins_row' `ins_col' `ring' `direct'
}
local overlay = `ring' == 0`f_ring'
}
// local ins_row = `.`cellname'.minrow' + ("`direct'" == "above")
// local ins_col = `.`cellname'.mincol' + ("`direct'" == "rightof")
}
else { /* extreme position */
local ins_row = cond("`direct'" == "top", /*
*/ max(2, `.maxrow'), 2)
local ins_col = cond("`direct'" == "fullright", /*
*/ max(2, `.maxcol'), 2)
}
/* handle "on" location */
if "`direct'" == "on" {
._add_view `"`new_dec'"' `ins_row' `ins_col' `"`0'"'
exit /* EXIT */
}
/* handle insertion locations */
local shift_on = cond( /*
*/ index("`direct'", "left") | index("`direct'", "right"), /*
*/ "col", "row")
if `overlay' {
local ins_`shift_on' = `ins_`shift_on'' - /*
*/ ("`direct'" == "below" | "`direct'" == "leftof")
if `ins_`shift_on'' > 0 {
if `ins_`shift_on'' > `.max`shift_on'' {
.max`shift_on' = `ins_`shift_on''
}
._add_view `"`new_dec'"' `ins_row' `ins_col' `"`0'"'
exit /* EXIT */
}
else local ins_`shift_on' = 1
}
/* shift current views */
local shift_at `ins_`shift_on''
forvalues i = 1/0`.cells.dynamicmv.arrnels' {
if "`.cells.dynamicmv[`i'].isa'" != "array" {
._shift_at cells.dynamicmv[`i'] `shift_on' `shift_at'
continue /* CONTINUE */
}
/* loop over any that are arrays */
forvalues j = 1/0`.cells.dynamicmv[`i'].arrnels' {
._shift_at cells.dynamicmv[`i'][`j'] ///
`shift_on' `shift_at'
}
}
/* track largest row and col */
.max`shift_on' = `.max`shift_on'' + 1
/* insert the new view */
._add_view `"`new_dec'"' `ins_row' `ins_col' `"`0'"'
end
program define _set_direction
args lname colon
mac shift 2
local 0 `", `*'"'
syntax [ , Above Below Leftof Rightof On AT New Top BOttom /*
*/ FULLLeft FULLRight ]
/*
if _rc {
di as error "{p 0 6} grid.insert: `lname' not " /*
*/ "allowed, first argument must be above, " /*
*/ "below, leftof, rightof, on, at, or new"
exit 198
}
*/
c_local `lname' `above'`below'`leftof'`rightof'`on'`at'`new'/*
*/`top'`bottom'`fullright'`fullleft'
end
program _find_ringrow
args imac rmac colon irow icol ring dir
if "`dir'" == "above" {
local mm max
local test >=
local above_shift 1
}
else {
local mm min
local test <
local above_shift 0
}
forvalues i = 1/0`.cells.dynamicmv.arrnels' {
local cell cells.dynamicmv[`i']
if 0`.`cell'.mincol' <= `icol' & 0`.`cell'.maxcol' >= `icol' {
if `.`cell'.`mm'row' `test' `irow' {
if 0`.`cell'.ring' < `ring' {
local irow = `.`cell'.`mm'row' + `above_shift'
c_local `rmac' `.`cell'.ring'
}
else {
if 0`.`cell'.ring' == `ring' {
local irow = `.`cell'.`mm'row'
c_local `rmac' `.`cell'.ring'
continue , break
}
}
}
}
}
c_local `imac' `irow'
end
program _find_ringcol
args imac rmac colon irow icol ring dir
if "`dir'" == "rightof" {
local mm max
local test >=
local right_shift 1
}
else {
local mm min
local test <
local right_shift 0
}
forvalues i = 1/0`.cells.dynamicmv.arrnels' {
local cell cells.dynamicmv[`i']
if 0`.`cell'.minrow' <= `irow' & 0`.`cell'.maxrow' >= `irow' {
if `.`cell'.`mm'col' `test' `icol' {
if 0`.`cell'.ring' < `ring' {
local icol = `.`cell'.`mm'col' + `right_shift'
c_local `rmac' `.`cell'.ring'
}
else {
if 0`.`cell'.ring' == `ring' {
c_local `rmac' `.`cell'.ring'
}
}
}
}
}
c_local `imac' `icol'
end
program define _add_view
args new_dec row col options
gettoken name rvalue : new_dec , parse(" =")
.cells.Declare `name' = .cell.new /* aligned cell */
local cell cells.`r(name)'
._declare_view `name' `rvalue' /* new view */
local view `r(name)'
.`cell'.minrow = `row'
.`cell'.maxrow = `row'
.`cell'.mincol = `col'
.`cell'.maxcol = `col'
.`cell'._prse_set_span `view' `.maxrow' `.maxcol' `"`options'"'
if "`.`cell'.fitspan'" != "" {
.fitcells[`.fitcells.arrnels'+1] = .`cell'.ref
}
if `.fitcells.arrnels' > 0 {
_fill_fitgaps
}
end
program define _declare_view
/* this exists so that, lgrid can shadow it
* with one that logs the key */
gettoken name 0 : 0
.Declare `name' `0'
end
/* internal
program define _shift_at
args cell shift_on shift_at
if "`.`cell'.isa'" == "" {
exit /* empty view */
}
if ".`cell'.`shift_on'" == "" {
exit
}
if `.`cell'.min`shift_on'' >= `shift_at' {
.`cell'.min`shift_on' = `.`cell'.min`shift_on'' + 1
}
if `.`cell'.max`shift_on'' >= `shift_at' {
.`cell'.max`shift_on' = `.`cell'.max`shift_on'' + 1
}
end
*/
program define _fill_fitgaps
_set_fitgaps
forvalues i = 1/`.fitcells.arrnels' {
local 0 ", `.fitcells[`i'].fitspan'"
syntax [, Left Right Above Below ]
if "`left'" != "" {
_fitgaps_goleft "fitcells[`i']"
}
if "`right'" != "" {
_fitgaps_goright "fitcells[`i']"
}
if "`above'" != "" {
_fitgaps_goabove "fitcells[`i']"
}
if "`below'" != "" {
_fitgaps_gobelow "fitcells[`i']"
}
}
_clear_fitgaps
end
program define _set_fitgaps
if `.maxcol' > 80 {
di as error "grid: maximum grid columns exceeded"
error 198
}
global T_one "11111111111111111111111111111111111111111111111111111111111111111111111111111111"
global T_zero "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
/* initialize matrix */
forvalues r = 1/`.maxrow' {
global T_gaprow`r' = substr("$T_zero", 1, `.maxcol')
}
/* set filled values to 0 */
forvalues i = 1/0`.dynamicmv.arrnels' {
if "`.cells.dynamicmv[`i'].isa'" != "array" {
_set_cell_gap "cells.dynamicmv[`i']"
continue /* CONTINUE */
}
/* loop over any arrays */
forvalues j = 1/`.cells.dynamicmv[`i'].arrnels' {
_set_cell_gap "cells.dynamicmv[`i'][`j']"
}
}
end
program define _set_cell_gap
args cell
local cmin = max(1, 0`.`cell'.mincol')
local cmax 0`.`cell'.maxcol'
local rmin 0`.`cell'.minrow'
local rmax 0`.`cell'.maxrow'
_fitgaps_blot `rmin' `rmax' `cmin' `cmax'
end
program define _fitgaps_blot
args rmin rmax cmin cmax
if `rmin' < 1 {
exit
}
forvalues r = `rmin'/`rmax' {
global T_gaprow`r' = /*
*/ substr("${T_gaprow`r'}", 1, `cmin'-1) + /*
*/ substr("$T_one" , 1, `cmax'-`cmin'+1) + /*
*/ substr("${T_gaprow`r'}", `cmax'+1, `.maxcol')
}
end
program define _fitgaps_check_n_blot
args clear_mac colon rmin rmax cmin cmax
local len = `cmax' - `cmin' + 1
local rng `cmin' , `len'
forvalues r = `rmin'/`rmax' {
if substr("${T_gaprow`r'}", `rng') != substr("$T_zero", `rng') {
c_local `clear_mac' 0
exit
}
}
_fitgaps_blot `rmin' `rmax' `cmin' `cmax'
c_local `clear_mac' 1
end
program define _fitgaps_goabove
args cell
local cmin `.`cell'.mincol'
local cmax `.`cell'.maxcol'
local r = `.`cell'.maxrow' + 1
while `r' < `.maxrow' {
._fitgaps_check_n_blot clear : `r' `r' `cmin' `cmax'
if ! `clear' {
continue, break /* BREAK */
}
.`cell'.maxrow = `r'
local r = `r' + 1
}
end
program define _fitgaps_gobelow
args cell
local cmin `.`cell'.mincol'
local cmax `.`cell'.maxcol'
local m = `.`cell'.minrow' - 1
forvalues r = `m'(-1)1 {
._fitgaps_check_n_blot clear : `r' `r' `cmin' `cmax'
if ! `clear' {
continue, break /* BREAK */
}
.`cell'.minrow = `r'
}
end
program define _fitgaps_goleft
args cell
local rmin `.`cell'.minrow'
local rmax `.`cell'.maxrow'
local m = `.`cell'.mincol' - 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -