1implement Cardlib; 2include "sys.m"; 3 sys: Sys; 4include "draw.m"; 5include "sets.m"; 6 sets: Sets; 7 Set, set, A, B, All, None: import sets; 8include "../spree.m"; 9 spree: Spree; 10 Attributes, Range, Object, Clique, Member, rand: import spree; 11include "objstore.m"; 12 objstore: Objstore; 13include "cardlib.m"; 14 15MAXPLAYERS: con 4; 16 17Layobject: adt { 18 lay: ref Object; 19 name: string; 20 packopts: int; 21 pick { 22 Obj => 23 obj: ref Object; # nil if it's a frame 24 Frame => 25 facing: int; # only valid if for frames 26 } 27}; 28 29clique: ref Clique; 30cmembers: array of ref Cmember; 31cpids := array[8] of list of ref Cmember; 32 33# XXX first string is unnecessary as it's held in the Layobject anyway? 34layouts := array[17] of list of (string, ref Layout, ref Layobject); 35maxlayid := 1; 36cmemberid := 1; 37 38archiveobjs: array of list of (string, ref Object); 39 40defaultrank := array[13] of {12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 41defaultsuitrank := array[] of {CLUBS => 0, DIAMONDS => 1, HEARTS => 2, SPADES => 3}; 42 43table := array[] of { 44 0 => array[] of { 45 (-1, dTOP|EXPAND, dBOTTOM, dTOP), 46 }, 47 1 => array [] of { 48 (0, dBOTTOM|FILLX, dBOTTOM, dTOP), 49 (-1, dTOP|EXPAND, dBOTTOM, dTOP), 50 }, 51 2 => array[] of { 52 (0, dBOTTOM|FILLX, dBOTTOM, dTOP), 53 (1, dTOP|FILLX, dTOP, dBOTTOM), 54 (-1, dTOP|EXPAND, dBOTTOM, dTOP) 55 }, 56 3 => array[] of { 57 (2, dRIGHT|FILLY, dRIGHT, dLEFT), 58 (0, dBOTTOM|FILLX, dBOTTOM, dTOP), 59 (1, dTOP|FILLX, dTOP, dBOTTOM), 60 (-1, dRIGHT|EXPAND, dBOTTOM, dTOP) 61 }, 62 4 => array[] of { 63 (1, dLEFT|FILLY, dLEFT, dRIGHT), 64 (3, dRIGHT|FILLY, dRIGHT, dLEFT), 65 (0, dBOTTOM|FILLX, dBOTTOM, dTOP), 66 (2, dTOP|FILLX, dTOP, dBOTTOM), 67 (-1, dRIGHT|EXPAND, dBOTTOM, dTOP) 68 }, 69}; 70 71 72init(mod: Spree, g: ref Clique) 73{ 74 sys = load Sys Sys->PATH; 75 sets = load Sets Sets->PATH; 76 if (sets == nil) 77 panic(sys->sprint("cannot load %s: %r", Sets->PATH)); 78 objstore = load Objstore Objstore->PATH; 79 if (objstore == nil) 80 panic(sys->sprint("cannot load %s: %r", Objstore->PATH)); 81 objstore->init(mod, g); 82 clique = g; 83 spree = mod; 84} 85 86archive(): ref Object 87{ 88 for (i := 0; i < len cmembers; i++) { 89 cp := cmembers[i]; 90 setarchivename(cp.obj, "member" + string i); 91 setarchivename(cp.layout.lay, "layout" + string i); 92 sel := cp.sel; 93 if (sel.stack != nil) 94 setarchivename(sel.stack, "sel" + string i); 95 } 96 for (i = 0; i < len layouts; i++) { 97 for (ll := layouts[i]; ll != nil; ll = tl ll) { 98 (name, lay, layobj) := hd ll; 99 if (name != nil) 100 layobj.lay.setattr("layname", name, None); 101 pick l := layobj { 102 Frame => 103 l.lay.setattr("facing", sides[l.facing], None); 104 Obj => 105 setarchivename(l.obj, "layid" + l.obj.getattr("layid")); 106 } 107 } 108 } 109 # XXX should archive layouts that aren't particular to a member. 110 archiveobj := clique.newobject(nil, None, "archive"); 111 setarchivename(archiveobj, "archive"); 112 archiveobj.setattr("maxlayid", string maxlayid, None); 113 archiveobj.setattr("cmemberid", string cmemberid, None); 114 return archiveobj; 115} 116 117setarchivename(o: ref Object, name: string) 118{ 119 objstore->setname(o, name); 120} 121 122getarchiveobj(name: string): ref Object 123{ 124 return objstore->get(name); 125} 126 127archivearray(a: array of ref Object, name: string) 128{ 129 for (i := 0; i < len a; i++) 130 objstore->setname(a[i], name + string i); 131} 132 133getarchivearray(name: string): array of ref Object 134{ 135 l: list of ref Object; 136 for (i := 0; ; i++) { 137 o := objstore->get(name + string i); 138 if (o == nil) 139 break; 140 l = o :: l; 141 } 142 a := array[i] of ref Object; 143 for (; l != nil; l = tl l) 144 a[--i] = hd l; 145 return a; 146} 147 148unarchive(): ref Object 149{ 150 objstore->unarchive(); 151 archiveobj := getarchiveobj("archive"); 152 cpl: list of ref Cmember; 153 for (i := 0; (o := getarchiveobj("member" + string i)) != nil; i++) { 154 cp := ref Cmember( 155 i, 156 int o.getattr("id"), 157 clique.membernamed(o.getattr("name")), 158 o, 159 ref Layout(getarchiveobj("layout" + string i)), 160 ref Selection(getarchiveobj("sel" + string i), -1, 1, (0, 0), nil) 161 ); 162 cp.sel.ownerid = cp.id; 163 sel := cp.sel; 164 if (sel.stack != nil && (selstr := sel.stack.getattr("sel")) != nil) { 165 (n, val) := sys->tokenize(selstr, " "); 166 if (tl val != nil && hd tl val == "-") 167 (sel.r.start, sel.r.end) = (int hd val, int hd tl tl val); 168 else { 169 idxl: list of int; 170 sel.isrange = 0; 171 for (; val != nil; val = tl val) 172 idxl = int hd val :: idxl; 173 sel.idxl = idxl; 174 } 175 } 176 lay := cp.layout.lay; 177 # there should be exactly one child, of type "layframe" 178 if (len lay.children != 1 || lay.children[0].objtype != "layframe") 179 panic("invalid layout"); 180 x := strhash(nil, len layouts); 181 layouts[x] = (nil, cp.layout, obj2layobj(lay.children[0])) :: layouts[x]; 182 unarchivelayoutobj(cp.layout, lay.children[0]); 183 cpl = cp :: cpl; 184 } 185 cmembers = array[len cpl] of ref Cmember; 186 for (; cpl != nil; cpl = tl cpl) { 187 cp := hd cpl; 188 cmembers[cp.ord] = cp; 189 idx := cp.id % len cpids; 190 cpids[idx] = cp :: cpids[idx]; 191 } 192 193 maxlayid = int archiveobj.getattr("maxlayid"); 194 cmemberid = int archiveobj.getattr("cmemberid"); 195 return archiveobj; 196} 197 198unarchivelayoutobj(layout: ref Layout, o: ref Object) 199{ 200 for (i := 0; i < len o.children; i++) { 201 child := o.children[i]; 202 layobj := obj2layobj(child); 203 if (layobj.name != nil) { 204 x := strhash(layobj.name, len layouts); 205 layouts[x] = (layobj.name, layout, layobj) :: layouts[x]; 206 } 207 if (tagof(layobj) == tagof(Layobject.Frame)) 208 unarchivelayoutobj(layout, child); 209 } 210} 211 212obj2layobj(o: ref Object): ref Layobject 213{ 214 case o.objtype { 215 "layframe" => 216 return ref Layobject.Frame( 217 o, 218 o.getattr("layname"), 219 s2packopts(o.getattr("opts")), 220 searchopt(sides, o.getattr("facing")) 221 ); 222 "layobj" => 223 return ref Layobject.Obj( 224 o, 225 o.getattr("layname"), 226 s2packopts(o.getattr("opts")), 227 getarchiveobj("layid" + o.getattr("layid")) 228 ); 229 * => 230 panic("invalid layobject found, of type '" + o.objtype + "'"); 231 return nil; 232 } 233} 234 235Cmember.join(member: ref Member, ord: int): ref Cmember 236{ 237 cmembers = (array[len cmembers + 1] of ref Cmember)[0:] = cmembers; 238 if (ord == -1) 239 ord = len cmembers - 1; 240 else { 241 cmembers[ord + 1:] = cmembers[ord:len cmembers - 1]; 242 for (i := ord + 1; i < len cmembers; i++) 243 cmembers[i].ord = i; 244 } 245 cp := cmembers[ord] = ref Cmember(ord, cmemberid++, member, nil, nil, nil); 246 cp.obj = clique.newobject(nil, All, "member"); 247 cp.obj.setattr("id", string cp.id, All); 248 cp.obj.setattr("name", member.name, All); 249 cp.obj.setattr("you", string cp.id, None.add(member.id)); 250 cp.obj.setattr("cliquetitle", clique.fname, All); 251 cp.layout = newlayout(cp.obj, None.add(member.id)); 252 cp.sel = ref Selection(nil, cp.id, 1, (0, 0), nil); 253 254 idx := cp.id % len cpids; 255 cpids[idx] = cp :: cpids[idx]; 256 return cp; 257} 258 259Cmember.find(p: ref Member): ref Cmember 260{ 261 id := p.id; 262 for (i := 0; i < len cmembers; i++) 263 if (cmembers[i].p.id == id) 264 return cmembers[i]; 265 return nil; 266} 267 268Cmember.index(ord: int): ref Cmember 269{ 270 if (ord < 0 || ord >= len cmembers) 271 return nil; 272 return cmembers[ord]; 273} 274 275Cmember.next(cp: self ref Cmember, fwd: int): ref Cmember 276{ 277 if (!fwd) 278 return cp.prev(1); 279 x := cp.ord + 1; 280 if (x >= len cmembers) 281 x = 0; 282 return cmembers[x]; 283} 284 285Cmember.prev(cp: self ref Cmember, fwd: int): ref Cmember 286{ 287 if (!fwd) 288 return cp.next(1); 289 x := cp.ord - 1; 290 if (x < 0) 291 x = len cmembers - 1; 292 return cmembers[x]; 293} 294 295Cmember.leave(cp: self ref Cmember) 296{ 297 ord := cp.ord; 298 cmembers[ord] = nil; 299 cmembers[ord:] = cmembers[ord + 1:]; 300 cmembers[len cmembers - 1] = nil; 301 cmembers = cmembers[0:len cmembers - 1]; 302 for (i := ord; i < len cmembers; i++) 303 cmembers[i].ord = i; 304 cp.obj.delete(); 305 dellayout(cp.layout); 306 cp.layout = nil; 307 idx := cp.id % len cpids; 308 l: list of ref Cmember; 309 ll := cpids[idx]; 310 for (; ll != nil; ll = tl ll) 311 if (hd ll != cp) 312 l = hd ll :: l; 313 cpids[idx] = l; 314 cp.ord = -1; 315} 316 317Cmember.findid(id: int): ref Cmember 318{ 319 for (l := cpids[id % len cpids]; l != nil; l = tl l) 320 if ((hd l).id == id) 321 return hd l; 322 return nil; 323} 324 325newstack(parent: ref Object, owner: ref Member, spec: Stackspec): ref Object 326{ 327 vis := All; 328 if (spec.conceal) { 329 vis = None; 330 if (owner != nil) 331 vis = vis.add(owner.id); 332 } 333 o := clique.newobject(parent, vis, "stack"); 334 o.setattr("maxcards", string spec.maxcards, All); 335 o.setattr("style", spec.style, All); 336 337 # XXX provide some means for this to contain the member's name? 338 o.setattr("title", spec.title, All); 339 return o; 340} 341 342makecard(deck: ref Object, c: Card, rear: string): ref Object 343{ 344 card := clique.newobject(deck, None, "card"); 345 card.setattr("face", string c.face, All); 346 vis := None; 347 if(c.face) 348 vis = All; 349 card.setattr("number", string (c.number * 4 + c.suit), vis); 350 if (rear != nil) 351 card.setattr("rear", rear, All); 352 return card; 353} 354 355makecards(deck: ref Object, r: Range, rear: string) 356{ 357 for (i := r.start; i < r.end; i++) 358 for(suit := 0; suit < 4; suit++) 359 makecard(deck, (suit, i, 0), rear); 360} 361 362# deal n cards to each member, if possible. 363# deal in chunks for efficiency. 364# if accuracy is required (e.g. dealing from an unshuffled 365# deck containing known cards) then this'll have to change. 366deal(deck: ref Object, n: int, stacks: array of ref Object, first: int) 367{ 368 ncards := len deck.children; 369 ord := 0; 370 permember := n; 371 leftover := 0; 372 if (n * len stacks > ncards) { 373 # if trying to deal more cards than we've got, 374 # deal all that we've got, distributing the remainder fairly. 375 permember = ncards / len stacks; 376 leftover = ncards % len stacks; 377 } 378 for (i := 0; i < len stacks; i++) { 379 n = permember; 380 if (leftover > 0) { 381 n++; 382 leftover--; 383 } 384 priv := stacks[(first + i) % len stacks]; 385 deck.transfer((ncards - n, ncards), priv, len priv.children); 386 priv.setattr("n", string (int priv.getattr("n") + n), All); 387 # make cards visible to member 388 for (j := len priv.children - n; j < len priv.children; j++) 389 setface(priv.children[j], 1); 390 391 ncards -= n; 392 } 393} 394 395setface(card: ref Object, face: int) 396{ 397 # XXX check parent stack style and if it's a pile, 398 # only expose a face up card at the top. 399 400 card.setattr("face", string face, All); 401 if (face) 402 card.setattrvisibility("number", All); 403 else 404 card.setattrvisibility("number", None); 405} 406 407nmembers(): int 408{ 409 return len cmembers; 410} 411 412getcard(card: ref Object): Card 413{ 414 n := int card.getattr("number"); 415 (suit, num) := (n % 4, n / 4); 416 return Card(suit, num, int card.getattr("face")); 417} 418 419getcards(stack: ref Object): array of Card 420{ 421 a := array[len stack.children] of Card; 422 for (i := 0; i < len a; i++) 423 a[i] = getcard(stack.children[i]); 424 return a; 425} 426 427discard(stk, pile: ref Object, facedown: int) 428{ 429 n := len stk.children; 430 if (facedown) 431 for (i := 0; i < n; i++) 432 setface(stk.children[i], 0); 433 stk.transfer((0, n), pile, len pile.children); 434} 435 436# shuffle children into a random order. first we make all the children 437# invisible (which will cause them to be deleted in the clients) then 438# shuffle to our heart's content, and make visible again... 439shuffle(o: ref Object) 440{ 441 ovis := o.visibility; 442 o.setvisibility(None); 443 a := o.children; 444 n := len a; 445 for (i := 0; i < n; i++) { 446 j := i + rand(n - i); 447 (a[i], a[j]) = (a[j], a[i]); 448 } 449 o.setvisibility(ovis); 450} 451 452sort(o: ref Object, rank, suitrank: array of int) 453{ 454 if (rank == nil) 455 rank = defaultrank; 456 if (suitrank == nil) 457 suitrank = defaultsuitrank; 458 ovis := o.visibility; 459 o.setvisibility(None); 460 cardmergesort(o.children, array[len o.children] of ref Object, rank, suitrank); 461 o.setvisibility(ovis); 462} 463 464cardcmp(a, b: ref Object, rank, suitrank: array of int): int 465{ 466 c1 := getcard(a); 467 c2 := getcard(b); 468 if (suitrank[c1.suit] != suitrank[c2.suit]) 469 return suitrank[c1.suit] - suitrank[c2.suit]; 470 return rank[c1.number] - rank[c2.number]; 471} 472 473cardmergesort(a, b: array of ref Object, rank, suitrank: array of int) 474{ 475 r := len a; 476 if (r > 1) { 477 m := (r-1)/2 + 1; 478 cardmergesort(a[0:m], b[0:m], rank, suitrank); 479 cardmergesort(a[m:], b[m:], rank, suitrank); 480 b[0:] = a; 481 for ((i, j, k) := (0, m, 0); i < m && j < r; k++) { 482 if (cardcmp(b[i], b[j], rank, suitrank) > 0) 483 a[k] = b[j++]; 484 else 485 a[k] = b[i++]; 486 } 487 if (i < m) 488 a[k:] = b[i:m]; 489 else if (j < r) 490 a[k:] = b[j:r]; 491 } 492} 493 494# reverse and flip all cards in stack. 495flip(stack: ref Object) 496{ 497 ovis := stack.visibility; 498 stack.setvisibility(None); 499 a := stack.children; 500 (n, m) := (len a, len a / 2); 501 for (i := 0; i < m; i++) { 502 j := n - i - 1; 503 (a[i], a[j]) = (a[j], a[i]); 504 } 505 for (i = 0; i < n; i++) 506 setface(a[i], !int a[i].getattr("face")); 507 stack.setvisibility(ovis); 508} 509 510selection(stack: ref Object): ref Selection 511{ 512 if ((owner := stack.getattr("owner")) != nil && 513 (cp := Cmember.findid(int owner)) != nil) 514 return cp.sel; 515 return nil; 516} 517 518Selection.set(sel: self ref Selection, stack: ref Object) 519{ 520 if (stack == sel.stack) 521 return; 522 if (stack != nil) { 523 oldowner := stack.getattr("owner"); 524 if (oldowner != nil) { 525 oldcp := Cmember.findid(int oldowner); 526 if (oldcp != nil) 527 oldcp.sel.set(nil); 528 } 529 } 530 if (sel.stack != nil) 531 sel.stack.setattr("owner", nil, All); 532 sel.stack = stack; 533 sel.isrange = 1; 534 sel.r = (0, 0); 535 sel.idxl = nil; 536 setsel(sel); 537} 538 539Selection.setexcl(sel: self ref Selection, stack: ref Object): int 540{ 541 if (stack != nil && (oldowner := stack.getattr("owner")) != nil) 542 if ((cp := Cmember.findid(int oldowner)) != nil && !cp.sel.isempty()) 543 return 0; 544 sel.set(stack); 545 return 1; 546} 547 548Selection.owner(sel: self ref Selection): ref Cmember 549{ 550 return Cmember.findid(sel.ownerid); 551} 552 553Selection.setrange(sel: self ref Selection, r: Range) 554{ 555 if (!sel.isrange) { 556 sel.idxl = nil; 557 sel.isrange = 1; 558 } 559 sel.r = r; 560 setsel(sel); 561} 562 563Selection.addindex(sel: self ref Selection, i: int) 564{ 565 if (sel.isrange) { 566 sel.r = (0, 0); 567 sel.isrange = 0; 568 } 569 ll: list of int; 570 for (l := sel.idxl; l != nil; l = tl l) { 571 if (hd l >= i) 572 break; 573 ll = hd l :: ll; 574 } 575 if (l != nil && hd l == i) 576 return; 577 l = i :: l; 578 for (; ll != nil; ll = tl ll) 579 l = hd ll :: l; 580 sel.idxl = l; 581 setsel(sel); 582} 583 584Selection.delindex(sel: self ref Selection, i: int) 585{ 586 if (sel.isrange) { 587 sys->print("cardlib: delindex from range-type selection\n"); 588 return; 589 } 590 ll: list of int; 591 for (l := sel.idxl; l != nil; l = tl l) { 592 if (hd l == i) { 593 l = tl l; 594 break; 595 } 596 ll = hd l :: ll; 597 } 598 for (; ll != nil; ll = tl ll) 599 l = hd ll :: l; 600 sel.idxl = l; 601 setsel(sel); 602} 603 604Selection.isempty(sel: self ref Selection): int 605{ 606 if (sel.stack == nil) 607 return 1; 608 if (sel.isrange) 609 return sel.r.start == sel.r.end; 610 return sel.idxl == nil; 611} 612 613Selection.isset(sel: self ref Selection, index: int): int 614{ 615 if (sel.isrange) 616 return index >= sel.r.start && index < sel.r.end; 617 for (l := sel.idxl; l != nil; l = tl l) 618 if (hd l == index) 619 return 1; 620 return 0; 621} 622 623Selection.transfer(sel: self ref Selection, dst: ref Object, index: int) 624{ 625 if (sel.isempty()) 626 return; 627 src := sel.stack; 628 if (sel.isrange) { 629 r := sel.r; 630 sel.set(nil); 631 src.transfer(r, dst, index); 632 } else { 633 if (sel.stack == dst) { 634 sys->print("cardlib: cannot move multisel to same stack\n"); 635 return; 636 } 637 xl := l := sel.idxl; 638 sel.set(nil); 639 rl: list of Range; 640 for (; l != nil; l = tl l) { 641 r := Range(hd l, hd l); 642 last := l; 643 # concatenate adjacent items, for efficiency. 644 for (l = tl l; l != nil; (last, l) = (l, tl l)) { 645 if (hd l != r.end + 1) 646 break; 647 r.end = hd l; 648 } 649 rl = (r.start, r.end + 1) :: rl; 650 l = last; 651 } 652 # do ranges in reverse, so that later ranges 653 # aren't affected by earlier ones. 654 if (index == -1) 655 index = len dst.children; 656 for (; rl != nil; rl = tl rl) 657 src.transfer(hd rl, dst, index); 658 } 659} 660 661setsel(sel: ref Selection) 662{ 663 if (sel.stack == nil) 664 return; 665 s := ""; 666 if (sel.isrange) { 667 if (sel.r.end > sel.r.start) 668 s = string sel.r.start + " - " + string sel.r.end; 669 } else { 670 if (sel.idxl != nil) { 671 s = string hd sel.idxl; 672 for (l := tl sel.idxl; l != nil; l = tl l) 673 s += " " + string hd l; 674 } 675 } 676 if (s != nil) 677 sel.stack.setattr("owner", string sel.owner().id, All); 678 else 679 sel.stack.setattr("owner", nil, All); 680 vis := None.add(sel.owner().p.id); 681 sel.stack.setattr("sel", s, vis); 682 sel.stack.setattrvisibility("sel", vis); 683} 684 685newlayout(parent: ref Object, vis: Set): ref Layout 686{ 687 l := ref Layout(clique.newobject(parent, vis, "layout")); 688 x := strhash(nil, len layouts); 689 layobj := ref Layobject.Frame(nil, "", dTOP|EXPAND|FILLX|FILLY, dTOP); 690 layobj.lay = clique.newobject(l.lay, All, "layframe"); 691 layobj.lay.setattr("opts", packopts2s(layobj.packopts), All); 692 layouts[x] = (nil, l, layobj) :: layouts[x]; 693# sys->print("[%d] => ('%s', %ux, %ux) (new layout)\n", x, "", l, layobj); 694 return l; 695} 696 697addlayframe(name, parent: string, layout: ref Layout, packopts: int, facing: int) 698{ 699# sys->print("addlayframe('%s', %ux, name: %s\n", parent, layout, name); 700 addlay(parent, layout, ref Layobject.Frame(nil, name, packopts, facing)); 701} 702 703addlayobj(name, parent: string, layout: ref Layout, packopts: int, obj: ref Object) 704{ 705# sys->print("addlayobj('%s', %ux, name: %s, obj %d\n", parent, layout, name, obj.id); 706 addlay(parent, layout, ref Layobject.Obj(nil, name, packopts, obj)); 707} 708 709addlay(parent: string, layout: ref Layout, layobj: ref Layobject) 710{ 711 a := layouts; 712 name := layobj.name; 713 x := strhash(name, len a); 714 added := 0; 715 for (nl := a[strhash(parent, len a)]; nl != nil; nl = tl nl) { 716 (s, lay, parentlay) := hd nl; 717 if (s == parent && (layout == nil || layout == lay)) { 718 pick p := parentlay { 719 Obj => 720 sys->fprint(sys->fildes(2), 721 "cardlib: cannot add layout to non-frame: %d\n", p.obj.id); 722 Frame => 723 nlayobj := copylayobj(layobj); 724 nlayobj.packopts = packoptsfacing(nlayobj.packopts, p.facing); 725 o: ref Object; 726 pick lo := nlayobj { 727 Obj => 728 o = clique.newobject(p.lay, All, "layobj"); 729 id := lo.obj.getattr("layid"); 730 if (id == nil) { 731 id = string maxlayid++; 732 lo.obj.setattr("layid", id, All); 733 } 734 o.setattr("layid", id, All); 735 Frame => 736 o = clique.newobject(p.lay, All, "layframe"); 737 lo.facing = (lo.facing + p.facing) % 4; 738 } 739 o.setattr("opts", packopts2s(nlayobj.packopts), All); 740 nlayobj.lay = o; 741 if (name != nil) 742 a[x] = (name, lay, nlayobj) :: a[x]; 743 added++; 744 } 745 } 746 } 747 if (added == 0) 748 sys->print("no parent found, adding '%s', parent '%s', layout %ux\n", 749 layobj.name, parent, layout); 750# sys->print("%d new entries\n", added); 751} 752 753maketable(parent: string) 754{ 755 # make a table for all current members. 756 plcount := len cmembers; 757 packopts := table[plcount]; 758 for (i := 0; i < plcount; i++) { 759 layout := cmembers[i].layout; 760 for (j := 0; j < len packopts; j++) { 761 (ord, outer, inner, facing) := packopts[j]; 762 name := "public"; 763 if (ord != -1) 764 name = "p" + string ((ord + i) % plcount); 765 addlayframe("@" + name, parent, layout, outer, dTOP); 766 addlayframe(name, "@" + name, layout, inner, facing); 767 } 768 } 769} 770 771dellay(name: string, layout: ref Layout) 772{ 773 a := layouts; 774 x := strhash(name, len a); 775 rl: list of (string, ref Layout, ref Layobject); 776 for (nl := a[x]; nl != nil; nl = tl nl) { 777 (s, lay, layobj) := hd nl; 778 if (s != name || (layout != nil && layout != lay)) 779 rl = hd nl :: rl; 780 } 781 a[x] = rl; 782} 783 784dellayout(layout: ref Layout) 785{ 786 for (i := 0; i < len layouts; i++) { 787 ll: list of (string, ref Layout, ref Layobject); 788 for (nl := layouts[i]; nl != nil; nl = tl nl) { 789 (s, lay, layobj) := hd nl; 790 if (lay != layout) 791 ll = hd nl :: ll; 792 } 793 layouts[i] = ll; 794 } 795} 796 797copylayobj(obj: ref Layobject): ref Layobject 798{ 799 pick o := obj { 800 Frame => 801 return ref *o; 802 Obj => 803 return ref *o; 804 } 805 return nil; 806} 807 808packoptsfacing(opts, facing: int): int 809{ 810 if (facing == dTOP) 811 return opts; 812 nopts := 0; 813 814 # 4 directions 815 nopts |= (facing + (opts & dMASK)) % 4; 816 817 # 2 orientations 818 nopts |= ((facing + ((opts & oMASK) >> oSHIFT)) % 4) << oSHIFT; 819 820 # 8 anchorpoints (+ centre) 821 a := (opts & aMASK); 822 if (a != aCENTRE) 823 a = ((((a >> aSHIFT) - 1 + facing * 2) % 8) + 1) << aSHIFT; 824 nopts |= a; 825 826 # two fill options 827 if (facing % 2) { 828 if (opts & FILLX) 829 nopts |= FILLY; 830 if (opts & FILLY) 831 nopts |= FILLX; 832 } else 833 nopts |= (opts & (FILLX | FILLY)); 834 835 nopts |= (opts & EXPAND); 836 return nopts; 837} 838 839# these arrays are dependent on the ordering of 840# the relevant constants defined in cardlib.m 841 842sides := array[] of {"top", "left", "bottom", "right"}; 843anchors := array[] of {"centre", "n", "nw", "w", "sw", "s", "se", "e", "ne"}; 844orientations := array[] of {"right", "up", "left", "down"}; 845fills := array[] of {"none", "x", "y", "both"}; 846 847packopts2s(opts: int): string 848{ 849 s := orientations[(opts & oMASK) >> oSHIFT] + 850 " -side " + sides[opts & dMASK]; 851 if ((opts & aMASK) != aCENTRE) 852 s += " -anchor " + anchors[(opts & aMASK) >> aSHIFT]; 853 if (opts & EXPAND) 854 s += " -expand 1"; 855 if (opts & (FILLX | FILLY)) 856 s += " -fill " + fills[(opts & FILLMASK) >> FILLSHIFT]; 857 return s; 858} 859 860searchopt(a: array of string, s: string): int 861{ 862 for (i := 0; i < len a; i++) 863 if (a[i] == s) 864 return i; 865 panic("unknown pack option '" + s + "'"); 866 return 0; 867} 868 869s2packopts(s: string): int 870{ 871 (nil, toks) := sys->tokenize(s, " "); 872 if (toks == nil) 873 panic("invalid packopts: " + s); 874 p := searchopt(orientations, hd toks) << oSHIFT; 875 for (toks = tl toks; toks != nil; toks = tl tl toks) { 876 if (tl toks == nil) 877 panic("invalid packopts: " + s); 878 arg := hd tl toks; 879 case hd toks { 880 "-anchor" => 881 p |= searchopt(anchors, arg) << aSHIFT; 882 "-fill" => 883 p |= searchopt(fills, arg) << FILLSHIFT; 884 "-side" => 885 p |= searchopt(sides, arg) << dSHIFT; 886 "-expand" => 887 if (int hd tl toks) 888 p |= EXPAND; 889 * => 890 panic("unknown pack option: " + hd toks); 891 } 892 } 893 return p; 894} 895 896panic(e: string) 897{ 898 sys->fprint(sys->fildes(2), "cardlib panic: %s\n", e); 899 raise "panic"; 900} 901 902assert(b: int, err: string) 903{ 904 if (b == 0) 905 raise "parse:" + err; 906} 907 908# from Aho Hopcroft Ullman 909strhash(s: string, n: int): int 910{ 911 h := 0; 912 m := len s; 913 for(i := 0; i<m; i++){ 914 h = 65599 * h + s[i]; 915 } 916 return (h & 16r7fffffff) % n; 917} 918