summaryrefslogtreecommitdiff
path: root/appl/wm/samtk.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/wm/samtk.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/wm/samtk.b')
-rw-r--r--appl/wm/samtk.b688
1 files changed, 688 insertions, 0 deletions
diff --git a/appl/wm/samtk.b b/appl/wm/samtk.b
new file mode 100644
index 00000000..31eea9fb
--- /dev/null
+++ b/appl/wm/samtk.b
@@ -0,0 +1,688 @@
+implement Samtk;
+
+include "sys.m";
+sys: Sys;
+sprint, FD: import sys;
+
+include "draw.m";
+draw: Draw;
+
+include "samterm.m";
+Context, Flayer, Text, Section: import Samterm;
+
+include "tkclient.m";
+
+include "samtk.m";
+
+ctxt: ref Context;
+
+tk: Tk;
+tkclient: Tkclient;
+
+tksam1 := array[] of {
+ "frame .w",
+ "scrollbar .w.s -command {send scroll}",
+ "text .w.t -width 80w -height 8h",
+ "pack .w.s -side left -fill y",
+ "pack .w.t -fill both -expand 1",
+ "pack .Wm_t -fill x",
+ "pack .w -fill both -expand 1",
+ "pack propagate . 0",
+};
+
+tkwork1 := array[] of {
+ "frame .w",
+ "scrollbar .w.s -command {send scroll}",
+ "text .w.t -width 80w -height 20h",
+ "pack .w.s -side left -fill y",
+ "pack .w.t -fill both -expand 1",
+ "pack .Wm_t -fill x",
+ "pack .w -fill both -expand 1",
+ "pack propagate . 0",
+};
+
+tkcmdlist := array[] of {
+ "bind .w.t <Key> {send keys {%A}}",
+ "bind .w.t <Key-\b> {send keys {%A}}",
+ "bind .w.s <ButtonRelease-1> +{send scroll %s %b %y}",
+ "bind .w.t <ButtonPress-1> +{send button1 %s %b %x %y}",
+ "bind .w.t <ButtonRelease-1> +{send button1 %s %b %x %y}",
+ "bind .w.t <Double-ButtonPress-1> {send button1 2 %b %x %y}",
+ "bind .w.t <Double-ButtonRelease-1> {send button1 3 %b %x %y}",
+ "bind .w.t <ButtonPress-2> {.m2 post %x %y; grab set .m2}",
+ "bind .w.t <ButtonPress-3> {.m3 post %x %y; grab set .m3}",
+ "bind . <Configure> {send titlesel resize}",
+ "focus .w.t",
+ "update"
+};
+
+menuidx := array[2] of {"0","0"};
+
+init(c: ref Context)
+{
+ ctxt = c;
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ tk = load Tk Tk->PATH;
+
+ tkclient = load Tkclient Tkclient->PATH;
+ tkclient->init();
+
+ scrollpos = scrolllines = 0;
+}
+
+x := 10;
+y := 10;
+
+newflayer(tag, tp: int): ref Flayer
+{
+ if (ctxt.which != nil) {
+ tk->cmd(ctxt.which.t,
+ ".Wm_t.title configure -background blue; update");
+ }
+ (t, cmdc) := tkclient->toplevel(ctxt.ctxt.screen, "-borderwidth 1 -relief raised", "SamTerm", Tkclient->Appl);
+ tk->cmd(t, ". configure -x "+string x+" -y "+string y+"; update");
+
+ if (x == 10 && y == 10) {
+ y = 200;
+ } else {
+ x += 40;
+ y += 40;
+ }
+
+ n := chanadd();
+ ctxt.titlesel[n] = cmdc;
+ tk->namechan(t, ctxt.menu3sel[n], "menu3");
+ tk->namechan(t, ctxt.menu2sel[n], "menu2");
+ tk->namechan(t, ctxt.buttonsel[n], "button1");
+ tk->namechan(t, ctxt.keysel[n], "keys");
+ tk->namechan(t, ctxt.scrollsel[n], "scroll");
+ tk->namechan(t, ctxt.titlesel[n], "titlesel");
+
+ lines: int;
+ if (tp) {
+ lines = 8;
+ tkclient->tkcmds(t, tksam1);
+ mkmenu2c(t);
+ } else {
+ lines = 20;
+ tkclient->tkcmds(t, tkwork1);
+ mkmenu2(t);
+ }
+ mkmenu3(t);
+ tkclient->tkcmds(t, tkcmdlist);
+
+ f := ref Flayer(
+ tag, # tag
+ t, # t
+ "SamTerm", # tkwin
+ (0, 0), # scope
+ (0, 0), # dot
+ int tk->cmd(t, ".w.t cget actwidth"), # screen width
+ int tk->cmd(t, ".w.t cget actheight") / lines, # lineheigth
+ lines, # lines
+ (0, 1), # scrollbar
+ -1 # typepoint
+ );
+ ctxt.flayers[n] = f;
+ return f;
+}
+
+menu2str := array [] of {
+ "cut",
+ "paste",
+ "snarf",
+ "look",
+# "exch",
+ "send", # storage for last pattern
+};
+
+menu3str := array [] of {
+ "new",
+ "zerox",
+ "close",
+ "write",
+};
+
+mkmenu2c(t: ref Tk->Toplevel)
+{
+ menus := array [NMENU2+1] of string;
+
+ menus[0] = "menu .m2";
+ for (i := 0; i < NMENU2; i++) {
+ menus[i+1] = addmenuitem(2, "menu2", menu2str[i]);
+ }
+ tkclient->tkcmds(t, menus);
+}
+
+mkmenu2(t: ref Tk->Toplevel)
+{
+ menus := array [NMENU2+1] of string;
+
+ menus[0] = "menu .m2";
+ for (i := 0; i < NMENU2-1; i++) {
+ menus[i+1] = addmenuitem(2, "menu2", menu2str[i]);
+ }
+ menus[NMENU2] = addmenuitem(2, "edit", "/");
+ tkclient->tkcmds(t, menus);
+}
+
+mkmenu3(t: ref Tk->Toplevel)
+{
+ menus := array [NMENU3+len ctxt.menus+1] of string;
+
+ menus[0] = "menu .m3";
+ for (i := 0; i < NMENU3; i++) {
+ menus[i+1] = addmenuitem(3, "menu3", menu3str[i]);
+ }
+ for (i = 0; i < len ctxt.menus; i++) {
+ menus[i+NMENU3+1] = addmenuitem(3, "menu3", ctxt.menus[i].name);
+ }
+ tkclient->tkcmds(t, menus);
+}
+
+addmenuitem(d: int, m, s: string): string
+{
+ return sprint(".m%d add command -text %s -command {send %s %s}",
+ d, s, m, s);
+}
+
+menuins(pos: int, s: string)
+{
+ for (i := 0; i < len ctxt.flayers; i++)
+ tk->cmd(ctxt.flayers[i].t,
+ sprint(".m3 insert %d command -text %s -command {send menu3 %s}",
+ pos + NMENU3, s, s));
+}
+
+menudel(pos: int)
+{
+ for (i := 0; i < len ctxt.flayers; i++)
+ tk->cmd(ctxt.flayers[i].t, sprint(".m3 delete %d", pos + NMENU3));
+}
+
+hsetpat(s: string)
+{
+ for (i := 0; i < len ctxt.flayers; i++) {
+ fl := ctxt.flayers[i];
+ if (fl.tag != ctxt.cmd.tag) {
+ tk->cmd(fl.t, ".m2 entryconfigure "
+ + string Search
+ + " -command {send menu2 search} -text '/" + s);
+ }
+ }
+}
+
+lastsearchstring := "//";
+
+setmenu(num : int,c : string){
+ fl := ctxt.flayers[num];
+ (nil, l) := sys->tokenize(c, " ");
+ x1 := int hd l - 50;
+ y1 := int hd tl l - int tk->cmd(fl.t, ".m"+string num+" yposition "+menuidx[num-2])
+ - 10;
+ tk->cmd(fl.t, ".m"+string num+" activate "+menuidx[num-2]+
+ "; .m"+string num+" post "+string x1+" "+string y1+
+ "; grab set .m"+string num+"; update");
+}
+
+titlectl(win: int, menu: string)
+{
+ tkclient->wmctl(ctxt.flayers[win].t, menu);
+}
+
+flraise(t: ref Text, fl: ref Flayer)
+{
+ nfls: list of ref Flayer;
+
+ nfls = nil;
+ t.flayers = fl :: dellist(t.flayers, fl);
+ tk->cmd(fl.t, "raise .; focus .w.t; update");
+}
+
+dellist(fls: list of ref Flayer, fl: ref Flayer): list of ref Flayer
+{
+ if (fls == nil) return nil;
+ if (hd fls == fl) return dellist(tl fls, fl);
+ return hd fls :: dellist(tl fls, fl);
+}
+
+append(fls: list of ref Flayer, fl: ref Flayer): list of ref Flayer
+{
+ if (fls == nil) return fl :: nil;
+ return hd fls :: append(tl fls, fl);
+}
+
+focus(fl: ref Flayer)
+{
+ tk->cmd(fl.t, "focus .w.t; update");
+}
+
+newcur(t: ref Text, fl: ref Flayer)
+{
+ if (ctxt.which == fl) return;
+ flraise(t, fl);
+ ctxt.which = fl;
+ if (t != ctxt.cmd)
+ ctxt.work = fl;
+}
+
+settitle(t: ref Text, s: string)
+{
+ sd := "";
+ sz := "";
+ if (t.state & Samterm->Dirty) sd = " (Dirty)";
+ if (t != ctxt.cmd && (t.state & Samterm->LDirty)) sd = " (Modified)";
+ if (len t.flayers > 1) sz = " (Zeroxed)";
+ for (fls := t.flayers; fls != nil; fls = tl fls) {
+ fl := hd fls;
+ fl.tkwin = s;
+ tkclient->settitle(fl.t, s + sd + sz);
+ tk->cmd(fl.t, "update");
+ }
+}
+
+resize(fl: ref Flayer)
+{
+ fl.lines = int tk->cmd(fl.t, ".w.t cget actheight") / fl.lineheigth;
+}
+
+allflayers(s: string)
+{
+ for (i := 0; i < len ctxt.texts; i++)
+ for (fls := ctxt.texts[i].flayers; fls != nil; fls = tl fls) {
+ fl := hd fls;
+ tk->cmd(fl.t, s);
+ }
+}
+
+setdot(fl: ref Flayer, l1, l2: int)
+{
+ tk->cmd(fl.t, ".w.t tag remove sel 0.0 end");
+
+ fl.dot.first = l1;
+ fl.dot.last = l2;
+ if (l2 <= fl.scope.first)
+ tk->cmd(fl.t, ".w.t mark set insert 0.0");
+ else if (fl.scope.last <= l1)
+ tk->cmd(fl.t, ".w.t mark set insert end");
+ else {
+ tk->cmd(fl.t, sprint(".w.t mark set insert 0.0+%dchars",
+ l1-fl.scope.first));
+ if (l1 != l2)
+ tk->cmd(fl.t, sprint(".w.t tag add sel 0.0+%dchars 0.0+%dchars",
+ l1-fl.scope.first,
+ l2-fl.scope.first));
+ }
+ tk->cmd(fl.t, "update");
+}
+
+panic(s: string)
+{
+ stderr := sys->fildes(2);
+ sys->fprint(stderr, "Panic: %s\n", s);
+ f := sys->sprint("#p/%d/ctl", ctxt.pgrp);
+ if ((fd := sys->open(f, sys->OWRITE)) != nil)
+ sys->write(fd, array of byte "killgrp\n", 8);
+ exit;
+}
+
+whichmenu(tag: int): int
+{
+ for (i := 0; i < len ctxt.menus; i++)
+ if (ctxt.menus[i].tag == tag)
+ return i;
+ return -1;
+}
+
+whichtext(tag: int): int
+{
+ for (i := 0; i < len ctxt.texts; i++)
+ if (ctxt.texts[i].tag == tag)
+ return i;
+ return -1;
+}
+
+setscrollbar(t: ref Text, fl: ref Flayer)
+{
+ ll := real t.nrunes;
+ f1 := 0.0; f2 := 1.0;
+ if (ll != 0.0) {
+ f1 = real fl.scope.first / ll;
+ if (fl.scope.last > t.nrunes)
+ f2 = 1.0;
+ else
+ f2 = real fl.scope.last / ll;
+ }
+ fl.scrollbar = fl.scope;
+ tk->cmd(fl.t, sprint(".w.s set %f %f; update", f1, f2));
+}
+
+buttonselect(fl: ref Flayer, s: string): int
+{
+ tag := fl.tag;
+ if ((i := whichtext(tag)) < 0) panic("buttonselect: whichtext");
+ t := ctxt.texts[i];
+
+ (n, l) := sys->tokenize(s, " ");
+ if (n != 4) panic("buttonselect");
+
+ # ignore mouse down -- wait for mouse up
+ if (hd l == "1" || hd l == "3") return 0;
+
+ if (ctxt.which != fl) {
+ if (ctxt.menus[i].text != ctxt.cmd)
+ ctxt.work = fl;
+ newcur(t, fl);
+# setdot(fl, fl.dot.first, fl.dot.first);
+ return 0;
+ }
+
+ if (hd l == "2") {
+ # Double click
+ l = tl tl l;
+ s = tk->cmd(fl.t, ".w.t index @" + hd l + "," + hd tl l);
+ fl.dot.first = fl.dot.last = coord2pos(t, fl, s);
+ return 1;
+ }
+
+ rg := tk->cmd(fl.t, ".w.t tag ranges sel");
+ if (rg == "") {
+ # Nothing selected, find insertion point
+ l = tl tl l;
+ s = tk->cmd(fl.t, ".w.t index @" + hd l + "," + hd tl l);
+ fl.dot.first = fl.dot.last = coord2pos(t, fl, s);
+ } else {
+ (n, l) = sys->tokenize(rg, " ");
+ #if (n == 4 && hd tl l == hd tl tl l)
+ # lst := hd tl tl tl l;
+ #else if (n != 2) panic("buttonselect: tag ranges");
+ #else lst = hd tl l;
+ # We only have one contiguous selection, so, take the
+ # first as dot.first and the last as dot.last
+ fst:=hd l;
+ lst:=fst;
+ while(l!=nil){
+ lst=hd l;
+ l = tl l;
+ }
+ fl.dot.first = coord2pos(t, fl, fst);
+ fl.dot.last = coord2pos(t, fl, lst);
+ tk->cmd(fl.t, ".w.t mark set insert " + fst);
+ tk->cmd(fl.t, "update");
+ }
+ return 0;
+}
+
+coord2pos(t: ref Text, fl: ref Flayer, s: string): int
+{
+ x, y: int;
+
+ (n, l) := sys->tokenize(s, ".");
+ if (n != 2) panic("coord2pos");
+ y = (int hd l) - 1;
+ x = int hd tl l;
+ if (x == 0 && y == 0) return fl.scope.first;
+ first := fl.scope.first;
+ for (scts := t.sects; scts != nil; scts = tl scts) {
+ sct := hd scts;
+ if (first >= sct.nrunes) {
+ first -= sct.nrunes;
+ continue;
+ }
+ if (first > 0) i := first; else i = 0;
+ while (i < len sct.text) {
+ if (y) {
+ if (sct.text[i++] == '\n') y--;
+ } else {
+ if (x <= 1)
+ return fl.scope.first - first + i + x;
+ if (sct.text[i++] == '\n') panic("coord2pos");
+ x--;
+ }
+ }
+ if (len sct.text < sct.nrunes) panic("coord2pos: hole");
+ first -= sct.nrunes;
+ }
+ if (x <= 0 && y == 0) return t.nrunes;
+ panic("coord2pos: can't find");
+ return(-1);
+}
+
+scrollpos, scrolllines: int;
+
+scroll(fl: ref Flayer, s: string): (int, int)
+{
+ tag := fl.tag;
+ if ((i := whichtext(tag)) < 0) panic("scroll: whichtext");
+ t := ctxt.texts[i];
+ (n, l) := sys->tokenize(s, " ");
+ height := fl.scrollbar.last - fl.scrollbar.first;
+ length := t.nrunes;
+ case (hd l) {
+ "0" =>
+ if (n != 3) panic("scroll: format");
+ return (scrollpos, scrolllines);
+ "moveto" =>
+ if (n != 2) panic("scroll: format");
+ f := real hd tl l;
+ if (f < 0.0) f = 0.0;
+ if (f > 1.0) f = 1.0;
+ scrollpos = int (f * real length) - height/2;
+ scrolllines = 1;
+ "scroll" =>
+ if (n != 3) panic("scroll: format");
+ l = tl l;
+ n = int hd l;
+ case(hd tl l) {
+ "page" =>
+ if (n < 0) {
+ scrollpos = fl.scrollbar.first;
+ scrolllines = fl.lines;
+ break;
+ }
+ scrollpos = fl.scrollbar.last;
+ scrolllines = 0;
+ "unit" =>
+ if (n < 0) {
+ scrollpos = fl.scrollbar.first - 1;
+ scrolllines = 1;
+ break;
+ }
+ (p, q) := rasplines(t.sects, fl.scrollbar.first, 1);
+ if (p > 0) {
+ scrollpos = p;
+ scrolllines = 0;
+ } else {
+ scrollpos = fl.scrollbar.first;
+ scrolllines = 0;
+ }
+ }
+ * =>
+ panic("scroll: input");
+ }
+ if (scrollpos > length)
+ scrollpos = length;
+ if (scrollpos < 0) {
+ scrollpos = 0;
+ scrolllines = 0;
+ }
+ if (length != 0)
+ tk->cmd(fl.t, sprint(".w.s set %f %f",
+ real scrollpos / real length,
+ real (scrollpos + height) / real length));
+ else
+ tk->cmd(fl.t, ".w.s set 0.0 1.0");
+ tk->cmd(fl.t, "update");
+ return (-1, -1);
+}
+
+flclear(fl: ref Flayer)
+{
+ tk->cmd(fl.t, ".w.t delete 0.0 end");
+ tk->cmd(fl.t, "update");
+}
+
+flinsert(fl: ref Flayer, l: int, s: string)
+{
+ offset := l-fl.scope.first;
+ tk->cmd(fl.t, ".w.t insert 0.0+" + string offset + "chars '" + s);
+ setdot(fl, fl.dot.first, fl.dot.last);
+}
+
+fldelexcess(fl: ref Flayer)
+{
+ tk->cmd(fl.t, ".w.t delete " + string (fl.lines+1) + ".0 end");
+}
+
+fldelete(fl: ref Flayer, l1, l2: int)
+{
+ s: string;
+ if (l1 <= fl.scope.first) {
+ if (l2 >= fl.scope.last) {
+ s = sprint(".w.t delete 0.0 end");
+ fl.scope.first = fl.scope.last = l1;
+ } else {
+ s = sprint(".w.t delete 0.0 0.0+%dchars",
+ l2 - fl.scope.first);
+ fl.scope.last -= l2 - l1;
+ fl.scope.first = l1;
+ }
+ } else {
+ if (l2 >= fl.scope.last) {
+ s = sprint(".w.t delete 0.0+%dchars end",
+ l1 - fl.scope.first);
+ fl.scope.last = l1;
+ } else {
+ s = sprint(".w.t delete 0.0+%dchars 0.0+%dchars",
+ l1 - fl.scope.first, l2 - fl.scope.first);
+ fl.scope.last -= l2 - l1;
+ }
+ }
+ if (fl.dot.first >= l2) fl.dot.first -= l2-l1;
+ else if (fl.dot.first > l1) fl.dot.first = l1;
+ if (fl.dot.last >= l2) fl.dot.last -= l2-l1;
+ else if (fl.dot.last > l1) fl.dot.last = l1;
+ tk->cmd(fl.t, s);
+ setdot(fl, fl.dot.first, fl.dot.last);
+ tk->cmd(fl.t, "update");
+}
+
+# Calculate position forward or backward nlines lines from pos.
+# If lines > 0 count forward, if lines < 0 count backward.\
+# Returns a pair, (position, nlines). Nlines is the remaining
+# number of lines to be found. If non-zero, beginning or end of
+# rasp was encountered while still counting, or a hole was
+# encountered. In the former case, position will be 0 or nrunes,
+# in the latter case, position will be set to -1.
+# To search to the beginning of the current line, set nlines to -1;
+
+rasplines(scts: list of ref Section, pos, nlines: int): (int, int)
+{
+ p, i: int;
+ if (nlines < 0) {
+ if (scts != nil) {
+ sct := hd scts; scts = tl scts;
+ if (pos > sct.nrunes) {
+ (p, nlines) =
+ rasplines(scts, pos - sct.nrunes, nlines);
+ if (p < 0) return (p, nlines);
+ pos = p + sct.nrunes;
+ if (nlines == 0) return (pos, 0);
+ }
+ if (pos > len sct.text) return (-1, nlines);
+ for (p = pos-1; p >= 0; p--) {
+ if (sct.text[p] == '\n') nlines++;
+ if (nlines == 0) return (p+1, 0);
+ }
+ }
+ return (0, nlines);
+ } else {
+ p = 0;
+ while (scts != nil) {
+ sct := hd scts; scts = tl scts;
+ if (pos < sct.nrunes) {
+ for (i = pos; i < len sct.text; i++) {
+ if (sct.text[i] == '\n') nlines--;
+ if (nlines == 0) return (p+i+1, 0);
+ }
+ if (i < sct.nrunes) return (-1, nlines);
+ }
+ pos -= sct.nrunes;
+ if (pos < 0) pos = 0;
+ p += sct.nrunes;
+ }
+ return (p, nlines);
+ }
+}
+
+chanadd(): int
+{
+ l := len ctxt.flayers;
+
+ keysel := array [l+1] of chan of string;
+ keysel[0:] = ctxt.keysel;
+ keysel[l] = chan of string;
+ ctxt.keysel = keysel;
+ scrollsel := array [l+1] of chan of string;
+ scrollsel[0:] = ctxt.scrollsel;
+ scrollsel[l] = chan of string;
+ ctxt.scrollsel = scrollsel;
+ buttonsel := array [l+1] of chan of string;
+ buttonsel[0:] = ctxt.buttonsel;
+ buttonsel[l] = chan of string;
+ ctxt.buttonsel = buttonsel;
+ menu2sel := array [l+1] of chan of string;
+ menu2sel[0:] = ctxt.menu2sel;
+ menu2sel[l] = chan of string;
+ ctxt.menu2sel = menu2sel;
+ menu3sel := array [l+1] of chan of string;
+ menu3sel[0:] = ctxt.menu3sel;
+ menu3sel[l] = chan of string;
+ ctxt.menu3sel = menu3sel;
+ titlesel := array [l+1] of chan of string;
+ titlesel[0:] = ctxt.titlesel;
+ titlesel[l] = chan of string;
+ ctxt.titlesel = titlesel;
+ flayers := array [l+1] of ref Flayer;
+ flayers[0:] = ctxt.flayers;
+ flayers[l] = nil;
+ ctxt.flayers = flayers;
+ return l;
+}
+
+chandel(n: int)
+{
+ l := len ctxt.flayers;
+ if (n >= l)
+ panic("chandel");
+
+ keysel := array [l-1] of chan of string;
+ keysel[0:] = ctxt.keysel[0:n];
+ keysel[n:] = ctxt.keysel[n+1:];
+ ctxt.keysel = keysel;
+ scrollsel := array [l-1] of chan of string;
+ scrollsel[0:] = ctxt.scrollsel[0:n];
+ scrollsel[n:] = ctxt.scrollsel[n+1:];
+ ctxt.scrollsel = scrollsel;
+ buttonsel := array [l-1] of chan of string;
+ buttonsel[0:] = ctxt.buttonsel[0:n];
+ buttonsel[n:] = ctxt.buttonsel[n+1:];
+ ctxt.buttonsel = buttonsel;
+ menu2sel := array [l-1] of chan of string;
+ menu2sel[0:] = ctxt.menu2sel[0:n];
+ menu2sel[n:] = ctxt.menu2sel[n+1:];
+ ctxt.menu2sel = menu2sel;
+ menu3sel := array [l-1] of chan of string;
+ menu3sel[0:] = ctxt.menu3sel[0:n];
+ menu3sel[n:] = ctxt.menu3sel[n+1:];
+ ctxt.menu3sel = menu3sel;
+ titlesel := array [l-1] of chan of string;
+ titlesel[0:] = ctxt.titlesel[0:n];
+ titlesel[n:] = ctxt.titlesel[n+1:];
+ ctxt.titlesel = titlesel;
+ flayers := array [l-1] of ref Flayer;
+ flayers[0:] = ctxt.flayers[0:n];
+ flayers[n:] = ctxt.flayers[n+1:];
+ ctxt.flayers = flayers;
+}