1############################################################################# 2## 3#W poset.gi XGAP library Max Neunhoeffer 4## 5## 6#Y Copyright 1998, Max Neunhoeffer, Aachen, Germany 7## 8## This file contains the implementations for graphs and posets 9## 10 11 12############################################################################# 13## 14## Declarations of representations: 15## 16############################################################################# 17 18 19############################################################################# 20## 21#R IsGraphicGraphRep . . . . . . . . . . . . . . . representation for graph 22## 23if not IsBound(IsGraphicGraphRep) then 24 DeclareRepresentation( "IsGraphicGraphRep", 25 IsComponentObjectRep and IsAttributeStoringRep and IsGraphicSheet and 26 IsGraphicSheetRep, 27# we inherit those components from the sheet: 28 [ "name", "width", "height", "gapMenu", "callbackName", "callbackFunc", 29 "menus", "objects", "free", 30# now our own components: 31 "vertices","edges","selectedvertices","menutypes", 32 "menuenabled","rightclickfunction","color"], 33 IsGraphicSheet ); 34fi; 35 36 37 38############################################################################# 39## 40#R IsGraphicPosetRep . . . . . . . . . . . . . . . representation for poset 41## 42if not IsBound(IsGraphicPosetRep) then 43 DeclareRepresentation( "IsGraphicPosetRep", 44 IsComponentObjectRep and IsAttributeStoringRep and 45 IsGraphicSheet and IsGraphicSheetRep and IsGraphicGraphRep, 46# we inherit those components from the sheet: 47 [ "name", "width", "height", "gapMenu", "callbackName", "callbackFunc", 48 "menus", "objects", "free", 49# now our own components: 50 "levels", # list of levels, stores current total ordering 51 "levelparams", # list of level parameters 52 "selectedvertices", # list of selected vertices 53 "menutypes", # one entry per menu which contains list of types 54 "menuenabled", # one entry per menu which contains list of flags 55 "rightclickfunction", # the current function which is called when 56 # user clicks right button 57 "color", # some color infos for the case of different models 58 "levelboxes", # little graphic boxes for the user to handle levels 59 "showlevelparams", # flag, if level parameters are shown 60 "showlevels"], # flag, if levelboxes are shown 61 IsGraphicSheet ); 62fi; 63 64 65############################################################################# 66## 67#R IsGPLevel . . . . . . . . . . . . . . . . . . . representation for level 68## 69if not IsBound(IsGPLevel) then 70 DeclareRepresentation( "IsGPLevel", 71 IsComponentObjectRep, 72 [ "top", # y coordinate of top of level, relative to sheet 73 "height", # height in pixels 74 "classes", # list of classes, which are lists of vertices 75 "classparams", # list of class parameters 76 "poset" # poset to which level belongs 77 ], 78 IsGraphicObject ); 79fi; 80 81############################################################################# 82## 83#R IsGGVertex . . . . . . . . . . . . . . . . . . representation for vertex 84## 85if not IsBound(IsGGVertex) then 86 DeclareRepresentation( "IsGGVertex", 87 IsComponentObjectRep and IsGraphicObject, 88 [ "data", # the mathematical data 89 "obj", # real graphic object 90 "x","y", # coordinates of graphic object within sheet 91 "serial", # a serial number for comparison 92 "label" # the label of the vertex or false 93 ], 94 IsGraphicObject ); 95fi; 96 97 98############################################################################# 99## 100#R IsGPVertex . . . . . . . . . . . . . . . . . . representation for vertex 101## 102if not IsBound(IsGPVertex) then 103 DeclareRepresentation( "IsGPVertex", 104 IsComponentObjectRep and IsGraphicObject, 105 [ "data", # the mathematical data 106 "obj", # real graphic object 107 "levelparam", # level parameter 108 "classparam", # class parameter 109 "maximals", # list of vertices which are maximal subobjects 110 "maximalin", # list of vertices where this one is maximal in 111 "x","y", # coordinates of graphic object within level 112 "serial", # a serial number for comparison 113 "label" # the label of the vertex or false 114 ], 115 IsGraphicObject ); 116fi; 117 118 119############################################################################# 120## 121## Some global things we all need: 122## 123############################################################################# 124 125 126## We count all vertices: 127PosetLastUsedSerialNumber := 0; 128 129 130## The following function is installed as a LeftPBDown in every graph or 131## poset. It calls the operation PosetLeftClick. 132 133PosetLeftClickCallback := function(poset,x,y) 134 PosetLeftClick(poset,x,y); 135end; 136 137## The following function is installed as a RightPBDown in every graph or 138## poset. It calls the operation PosetRightClick. 139 140PosetRightClickCallback := function(poset,x,y) 141 PosetRightClick(poset,x,y); 142end; 143 144## The following function is installed as a CtrlLeftPBDown and 145## ShiftLeftPBDown in every graph or poset. It calls the operation 146## PosetCtrlLeftClick. 147 148PosetCtrlLeftClickCallback := function(poset,x,y) 149 PosetCtrlLeftClick(poset,x,y); 150end; 151 152 153## The following is a for a menu entry and just calls another method: 154PosetDoRedraw := function(poset,menu,entry) 155 DoRedraw(poset); 156end; 157 158 159## Our menu which goes in all poset sheets: 160PosetMenuEntries := 161 ["Redraw","Show Levels","Show Level Parameters",, 162 "Delete Vertices","Delete Edge","Merge Classes",, 163 "Magnify Lattice", "Shrink Lattice", "Resize Lattice", "Resize Sheet", 164 "Move Lattice",, 165 "Change Labels","Average Y Positions","Average X Positions", 166 "Rearrange Classes"]; 167PosetMenuTypes := 168 ["forany","forany","forany",, 169 "forsubset","foredge","forsubset",, 170 "forany","forany","forany","forany","forany",, 171 "forsubset","forany","forsubset","forsubset"]; 172PosetMenuFunctions := 173 [ PosetDoRedraw,PosetShowLevels,PosetShowLevelparams,, 174 UserDeleteVerticesOp, UserDeleteEdgeOp, UserMergeClassesOp,, 175 UserMagnifyLattice,UserShrinkLattice,UserResizeLattice,UserResizeSheet, 176 UserMoveLattice,, 177 UserChangeLabels,UserAverageY,UserAverageX,UserRearrangeClasses]; 178 179 180############################################################################# 181## 182## Constructors: 183## 184############################################################################# 185 186 187## we need this to set up the colors in a sheet: 188 189BindGlobal( "GPMakeColors", 190 function( sheet ) 191 192 # set up color information: 193 if sheet!.color.model = "color" then 194 if COLORS.red <> false then 195 sheet!.color.unselected := COLORS.black; 196 sheet!.color.selected := COLORS.red; 197 else 198 sheet!.color.unselected := COLORS.dimGray; 199 sheet!.color.selected := COLORS.black; 200 fi; 201 if COLORS.green <> false then 202 sheet!.color.result := COLORS.green; 203 else 204 sheet!.color.result := COLORS.black; # COLORS.lightGray; 205 fi; 206 else 207 sheet!.color.selected := COLORS.black; 208 sheet!.color.unselected := COLORS.black; 209 sheet!.color.result := false; 210 fi; 211end); 212 213 214############################################################################# 215## 216#M GraphicGraph( <name>, <width>, <height> ) . . . . . . a new graphic graph 217## 218## creates a new graphic graph which is a graphic sheet representation 219## with knowledge about vertices and edges and infrastructure for user 220## interfaces. 221## 222InstallMethod( GraphicGraph, 223 "for a string, and two integers", 224 true, 225 [ IsString, 226 IsInt, 227 IsInt ], 228 0, 229 230function( name, width, height ) 231 #local ...; 232 233end); 234 235 236############################################################################# 237## 238#M GraphicPoset( <name>, <width>, <height> ) . . . . . . a new graphic poset 239## 240## creates a new graphic poset which is a specialization of a graphic graph 241## mainly because per definition a poset comes in "layers" or "levels". This 242## leads to some algorithms that are more efficient than the general ones 243## for graphs. 244## 245InstallMethod( GraphicPoset, 246 "for a string, and two integers", 247 true, 248 [ IsString, 249 IsInt, 250 IsInt ], 251 0, 252 253function( name, width, height ) 254 local poset, tmpEntries, tmpTypes, tmpFuncs, m; 255 256 poset := GraphicSheet(name,width,height); 257 SetFilterObj(poset,IsGraphicGraphRep); 258 SetFilterObj(poset,IsGraphicPosetRep); 259 poset!.levels := []; 260 poset!.levelparams := []; 261 poset!.selectedvertices := []; 262 # think of the GAP menu: 263 poset!.menutypes := [List(poset!.menus[1]!.entries,x->"forany")]; 264 poset!.menuenabled := [List(poset!.menus[1]!.entries,x->true)]; 265 poset!.rightclickfunction := Ignore; 266 267 # set up color information: 268 poset!.color := rec(); 269 if COLORS.red <> false or COLORS.lightGray <> false then 270 poset!.color.model := "color"; 271 # note: if you rename this, think of the "use black&white" below! 272 else 273 poset!.color.model := "monochrome"; 274 fi; 275 GPMakeColors(poset); 276 277 poset!.levelboxes := []; 278 poset!.showlevels := false; 279 poset!.lptexts := []; 280 poset!.showlevelparams := true; 281 282 InstallCallback(poset,"LeftPBDown",PosetLeftClickCallback); 283 InstallCallback(poset,"ShiftLeftPBDown",PosetCtrlLeftClickCallback); 284 InstallCallback(poset,"CtrlLeftPBDown",PosetCtrlLeftClickCallback); 285 InstallCallback(poset,"RightPBDown",PosetRightClickCallback); 286 287 tmpEntries := ShallowCopy(PosetMenuEntries); 288 tmpTypes := ShallowCopy(PosetMenuTypes); 289 tmpFuncs := ShallowCopy(PosetMenuFunctions); 290 if poset!.color.model = "color" then 291 Append(tmpEntries,["-","Use Black&White"]); 292 Append(tmpTypes,["-","forany"]); 293 Append(tmpFuncs,["-",UserUseBlackWhite]); 294 fi; 295 m := Menu(poset,"Poset",tmpEntries,tmpTypes,tmpFuncs); 296 Check(m,"Show Level Parameters",true); 297 298 return poset; 299end); 300 301 302############################################################################# 303## 304#M CreateLevel(<poset>, <levelparam>) . . . . . . creates new level in poset 305#M CreateLevel(<poset>, <levelparam>, <lptext>) . creates new level in poset 306## 307## A level in a graphic poset can be thought of as a horizontal slice of 308## the poset. It has a y coordinate of the top of the level relatively to 309## the graphic sheet and a height. Every class of vertices in a graphic 310## poset is in a level. The levels are totally ordered by their y 311## coordinate. No two vertices which are included in each other are in the 312## same level. A vertex containing another one is always "higher" on the 313## screen, meaning in a "higher" level. Every level has a unique 314## levelparam, which can be any {\GAP} object. The user is responsible for 315## all methods where a levelparam occurs as parameter and is not just an 316## integer. There is NO {\GAP} object representing a level which is visible 317## for the user of posets. All communication about levels goes via the 318## levelparam. Returns fail if there is already a level with a level 319## parameter which is considered "equal" by CompareLevels or levelparam if 320## everything went well. 321## The second method allows to specify which text appears for the level at 322## the right edge of the sheet. 323## 324InstallMethod( CreateLevel, 325 "for a graphic poset, a level parameter, and a string", 326 true, 327 [ IsGraphicPosetRep, IsObject, IsString ], 328 0, 329 330function( poset, levelparam, lpstr ) 331 local level, box, str, strlen, text, l, firstpos, before, look, 332 compare, i, cl, v; 333 334 # does this level parameter exist already? 335 if Position(poset!.levelparams,levelparam) <> fail then 336 return fail; 337 fi; 338 339 # create a level object: 340 level := rec(classes := [], 341 classparams := [], 342 poset := poset); 343 Objectify(NewType(GraphicObjectFamily,IsGPLevel),level); 344 345 # is it the first level: 346 if poset!.levelparams = [] then 347 poset!.levelparams := [levelparam]; 348 poset!.levels := [level]; 349 level!.top := 0; 350 level!.height := 2 * VERTEX.diameter; 351 352 # make a level box: 353 box := Box(poset,0,level!.top+level!.height-8,8,8); 354 if COLORS.blue <> false then 355 Recolor(box,COLORS.blue); 356 fi; 357 if not poset!.showlevels then 358 Destroy(box); 359 fi; 360 361 poset!.levelboxes := [ box ]; 362 363 # make a text for level parameter: 364 if lpstr <> "" then 365 str := lpstr; 366 else 367 str := String(levelparam); 368 fi; 369 strlen := Length(str); 370 text := Text(poset,FONTS.normal, 371 poset!.width - 24 - strlen*FontInfo(FONTS.normal)[3], 372 level!.top + QuoInt(level!.height,2),str); 373 if COLORS.blue <> false then 374 Recolor(text,COLORS.blue); 375 fi; 376 if not poset!.showlevelparams then 377 Destroy(text); 378 fi; 379 380 poset!.lptexts := [ text ]; 381 382 return levelparam; 383 fi; 384 385 # now find the position, we choose the last position where the new level 386 # can be according to the partial order defined by CompareLevels we do a 387 # binary search, we insert not before "firstpos" and before "before". 388 # Attention: We cannot decide at a level which is not comparable to the 389 # new level, so we have to search linearly for a comparable level! 390 l := Length(poset!.levelparams); 391 firstpos := 1; 392 before := l + 1; 393 while firstpos < before do 394 look := QuoInt(firstpos + before,2); 395 repeat # search first backward up to firstpos, then down 396 compare := CompareLevels(poset,levelparam,poset!.levelparams[look]); 397 if compare = 0 then 398 return fail; 399 elif compare = fail then # not comparable 400 look := look-1; 401 fi; 402 until compare <> fail or look < firstpos; 403 if compare = fail then 404 # search now forward down to before 405 look := QuoInt(firstpos + before,2)+1; 406 if look = before then 407 firstpos := before; # we insert right HERE! 408 compare := 0; 409 fi; 410 while compare = fail do 411 compare := CompareLevels(poset,levelparam,poset!.levelparams[look]); 412 if compare = 0 then 413 return fail; 414 elif compare = fail then # not comparable 415 look := look+1; 416 if look = before then # nothing comparable in between! 417 firstpos := before; # we insert right HERE! 418 compare := 0; # this does exactly that! 419 fi; 420 fi; 421 od; 422 fi; 423 if compare < 0 then 424 before := look; 425 elif compare > 0 then 426 firstpos := look+1; 427 fi; 428 od; 429 430 # we now insert at position firstpos = before: 431 poset!.levelparams{[firstpos+1..l+1]} := poset!.levelparams{[firstpos..l]}; 432 poset!.levelparams[firstpos] := levelparam; 433 poset!.levels{[firstpos+1..l+1]} := poset!.levels{[firstpos..l]}; 434 poset!.levels[firstpos] := level; 435 poset!.levelboxes{[firstpos+1..l+1]} := poset!.levelboxes{[firstpos..l]}; 436 poset!.lptexts{[firstpos+1..l+1]} := poset!.lptexts{[firstpos..l]}; 437 438 if firstpos = 1 then 439 level!.top := 0; 440 else 441 level!.top := poset!.levels[firstpos-1]!.top + 442 poset!.levels[firstpos-1]!.height; 443 fi; 444 level!.height := 2 * VERTEX.diameter; 445 446 # move all lower levels down: 447 FastUpdate(poset,true); 448 for i in [firstpos+1..l+1] do 449 poset!.levels[i]!.top := poset!.levels[i]!.top + level!.height; 450 for cl in poset!.levels[i]!.classes do 451 for v in cl do 452 MoveDelta(v!.obj,0,level!.height); 453 od; 454 od; 455 if poset!.showlevels then 456 MoveDelta(poset!.levelboxes[i],0,level!.height); 457 fi; 458 if poset!.showlevelparams then 459 MoveDelta(poset!.lptexts[i],0,level!.height); 460 fi; 461 od; 462 FastUpdate(poset,false); 463 464 # has the graphic sheet become higher? 465 l := l + 1; # this means: l := Length(poset!.levels); 466 i := poset!.levels[l]!.top + poset!.levels[l]!.height; 467 if i > poset!.height then 468 Resize(poset,poset!.width,i); 469 fi; 470 471 # create a level box: 472 box := Box(poset,0,level!.top+level!.height-8,8,8); 473 if COLORS.blue <> false then 474 Recolor(box,COLORS.blue); 475 fi; 476 if not poset!.showlevels then 477 Destroy(box); 478 fi; 479 poset!.levelboxes[firstpos] := box; 480 481 # create a level parameter text: 482 if lpstr <> "" then 483 str := lpstr; 484 else 485 str := String(levelparam); 486 fi; 487 strlen := Length(str); 488 text := Text(poset,FONTS.normal, 489 poset!.width - 24 - strlen*FontInfo(FONTS.normal)[3], 490 level!.top + QuoInt(level!.height,2),str); 491 if COLORS.blue <> false then 492 Recolor(text,COLORS.blue); 493 fi; 494 if not poset!.showlevelparams then 495 Destroy(text); 496 fi; 497 poset!.lptexts[firstpos] := text; 498 499 return levelparam; 500end); 501 502 503InstallOtherMethod( CreateLevel, 504 "for a graphic poset, and a level parameter", 505 true, 506 [ IsGraphicPosetRep, IsObject ], 507 0, 508function( poset, levelparam ) 509 return CreateLevel(poset,levelparam,""); 510end); 511 512 513############################################################################# 514## 515#M CreateClass(<poset>,<levelparam>,<classparam>) . . . . creates new class 516## 517## A class in a graphic poset is a collection of vertices within a level 518## which belong together in some sense. Every vertex in a graphic poset 519## is in a class, which in turn belongs to a level. Every class in a level 520## has a unique classparam, which can be any {\GAP} object. The user is 521## responsible for all methods where a classparam occurs as parameter and 522## is not just an integer. There is NO {\GAP} object representing a class 523## which is visible to the user of posets. All communication about classes 524## goes via the classparam. Returns fail if there is no level with 525## parameter levelparam or there is already a class in this level with 526## parameter classparam. Returns classparam otherwise. 527## 528InstallMethod( CreateClass, 529 "for a graphic poset, a level parameter, and a class parameter", 530 true, 531 [ IsGraphicPosetRep, IsObject, IsObject ], 532 0, 533 534function( poset, levelparam, classparam ) 535 local nr, level; 536 537 nr := Position(poset!.levelparams,levelparam); 538 if nr = fail then 539 return fail; 540 fi; 541 level := poset!.levels[nr]; 542 543 nr := Position(level!.classparams,classparam); 544 if nr <> fail then 545 return fail; 546 fi; 547 548 Add(level!.classparams,classparam); 549 Add(level!.classes,[]); 550 551 return classparam; 552end); 553 554 555############################################################################# 556## 557#M Vertex(<graph>,<data>[,<inf>]) . . . . . . . . . . . . creates new vertex 558## 559## Creates a new vertex. <inf> is a record in which additional info can be 560## supplied for the new vertex. For general graphic graphs only the 561## "label", "color", "shape", "x" and "y" components are applicable, they 562## contain a short label which will be attached to the vertex, the color, 563## the shape ("circle", "diamond", or "rectangle") and the coordinates 564## relative to the graphic sheet respectively. For graphic posets also the 565## components "levelparam" and "classparam" are evaluated. If the component 566## "hints" is bound it must be a list of x coordinates which will be 567## delivered to ChoosePosition to help placement. Those x coordinates will 568## be the coordinates of other vertices related to the new one. All values of 569## record components which are not specified will be determined by calling 570## some methods for graphic graphs or posets. Those are: 571## ChooseLabel for the label, 572## ChooseColor for the color, 573## ChooseShape for the shape, 574## ChoosePosition for the position, 575## ChooseLevel for the levelparam, and 576## ChooseClass for the classparam. 577## ChooseWidth for the line width of the vertex 578## Returns fail no vertex was created. This happens only, if one of the 579## choose functions return fail or no possible value, for example a 580## non-existing level or class parameter. 581## Returns vertex object if everything went well. 582## 583InstallOtherMethod( Vertex, 584 "for a graphic poset, an object, and a record", 585 true, 586 [ IsGraphicPosetRep, IsObject, IsRecord ], 587 0, 588 589function( poset, data, info ) 590 local lp, lnr, level, cp, cnr, class, vertex, label, shape, 591 color, position, width; 592 593 # first determine levelparam: 594 if not IsBound(info.levelparam) then 595 lp := ChooseLevel(poset,data); 596 else 597 lp := info.levelparam; 598 fi; 599 if lp = fail then 600 return fail; 601 fi; 602 603 # we search for the level: 604 lnr := Position(poset!.levelparams,lp); 605 if lnr = fail then 606 return fail; 607 fi; 608 level := poset!.levels[lnr]; 609 610 # now determine class: 611 if not IsBound(info.classparam) then 612 cp := ChooseClass(poset,data,lp); 613 else 614 cp := info.classparam; 615 fi; 616 if cp = fail then 617 return fail; 618 fi; 619 620 # we search for the class: 621 cnr := Position(level!.classparams,cp); 622 if cnr = fail then 623 return fail; 624 fi; 625 class := level!.classes[cnr]; 626 627 # create a new vertex object: 628 PosetLastUsedSerialNumber := PosetLastUsedSerialNumber + 1; 629 vertex := rec(data := data, 630 levelparam := lp, 631 classparam := cp, 632 maximals := [], 633 maximalin := [], 634 serial := PosetLastUsedSerialNumber); 635 Objectify(NewType(GraphicObjectFamily,IsGPVertex),vertex); 636 SetFilterObj(vertex,IsGGVertex); 637 SetFilterObj(vertex,IsAlive); 638 639 # choose label, shape, color and position: 640 if not IsBound(info.label) then 641 label := ChooseLabel(poset,data); 642 if label = fail then 643 return fail; 644 fi; 645 else 646 label := info.label; 647 fi; 648 if not IsBound(info.shape) then 649 shape := ChooseShape(poset,data); 650 if shape = fail then 651 return fail; 652 fi; 653 else 654 shape := info.shape; 655 fi; 656 if not IsBound(info.color) then 657 color := ChooseColor(poset,data); 658 if color = fail then 659 return fail; 660 fi; 661 else 662 color := info.color; 663 fi; 664 if not (IsBound(info.x) and IsBound(info.y)) then 665 if IsBound(info.hints) then 666 position := ChoosePosition(poset,data,level,class,info.hints); 667 else 668 position := ChoosePosition(poset,data,level,class,[]); 669 fi; 670 if IsBound(info.x) then # this takes precedence! 671 vertex!.x := info.x; 672 else 673 vertex!.x := position[1]; 674 fi; 675 if IsBound(info.y) then # this takes precedence! 676 vertex!.y := info.y; 677 else 678 vertex!.y := position[2]; 679 fi; 680 else 681 vertex!.x := info.x; 682 vertex!.y := info.y; 683 fi; 684 if not IsBound(info.width) then 685 width := ChooseWidth(poset,data); 686 if width = fail then 687 return fail; 688 fi; 689 fi; 690 691 vertex!.label := label; 692 693 # create the graphic object: 694 vertex!.obj := Vertex(poset,vertex!.x,level!.top + vertex!.y, 695 rec(label := label,color := color,width := width)); 696 if shape = "diamond" then 697 Reshape(vertex!.obj,VERTEX.diamond); 698 elif shape = "rectangle" then 699 Reshape(vertex!.obj,VERTEX.rectangle); 700 fi; 701 702 # put it into the class: 703 Add(class,vertex); 704 705 return vertex; 706end); 707 708 709############################################################################# 710## 711## The following function is only internal: 712## 713## Use it on your own risk and only if you know what you are doing! 714## 715GPSearchWay := function(poset,v1,v2,l2) 716 local v, p; 717 for v in v1!.maximals do 718 if v = v2 then 719 return true; 720 fi; 721 722 if Position(poset!.levelparams,v!.levelparam) < l2 then 723 if GPSearchWay(poset,v,v2,l2) then 724 return true; 725 fi; 726 fi; 727 od; 728 return false; 729end; 730 731 732############################################################################# 733## 734#M Edge(<poset>,<vertex1>,<vertex2>) . . . . . . . . . . . . adds a new edge 735#M Edge(<poset>,<vertex1>,<vertex2>,<def>) . . . . . . . . . adds a new edge 736## 737## Adds a new edge from <vertex1> to <vertex2>. For posets this puts one 738## of the vertices into the other as a maximal subvertex. So either 739## <vertex1> must lie in a "higher" level than <vertex2> or the other way 740## round. There must be no vertex "between" <vertex1> and <vertex2>. If 741## the two vertices are in the same level or one is already indirectly 742## included in the other fail is returned, otherwise true. That means, 743## that in the case where one of the two vertices is already a maximal 744## subobject of the other, then the method does nothing and returns true. 745## The variation with a defaults record just hands this over to the lower 746## levels, meaning that the line width and color are modified. 747## 748InstallOtherMethod( Edge, 749 "for a graphic poset, two vertices, and a defaults record", 750 true, 751 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsRecord ], 752 0, 753 754function( poset, v1, v2, def ) 755 local l1, l2, dummy, l, p; 756 757 # we permute v1 and v2 such that v1 is in higher level: 758 if CompareLevels(poset,v1!.levelparam,v2!.levelparam) = 0 then 759 return fail; 760 fi; 761 l1 := Position(poset!.levelparams,v1!.levelparam); 762 l2 := Position(poset!.levelparams,v2!.levelparam); 763 if l1 > l2 then 764 dummy := v1; 765 v1 := v2; 766 v2 := dummy; 767 dummy := l1; 768 l1 := l2; 769 l2 := dummy; 770 fi; 771 772 # first we have to perform a few checks: 773 if Position(v1!.maximals,v2) <> fail then 774 return true; 775 fi; 776 if GPSearchWay(poset,v1,v2,l2) then 777 return fail; 778 fi; 779 780 # let's think about color, label and width: 781 if not IsBound(def.color) then 782 def.color := ChooseColor(poset,v1!.data,v2!.data); 783 if def.color = fail then 784 return fail; 785 fi; 786 fi; 787 if not IsBound(def.label) then 788 def.label := ChooseLabel(poset,v1!.data,v2!.data); 789 if def.label = fail then 790 return fail; 791 fi; 792 fi; 793 if not IsBound(def.width) then 794 def.width := ChooseWidth(poset,v1!.data,v2!.data); 795 if def.width = fail then 796 return fail; 797 fi; 798 fi; 799 800 # now we know that there is no direct or indirect inclusion of v2 in v1. 801 # we can savely put v2 "into" v1. 802 Add(v1!.maximals,v2); 803 Add(v2!.maximalin,v1); 804 Connection(v1!.obj,v2!.obj,def); 805 806 return true; 807 808end); 809 810InstallOtherMethod( Edge, 811 "for a graphic poset, and two vertices", 812 true, 813 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex ], 814 0, 815 816function( poset, v1, v2 ) 817 return Edge(poset,v1,v2,rec()); 818end); 819 820 821############################################################################# 822## 823## Destructors: 824## 825############################################################################# 826 827 828############################################################################# 829## 830## Set this variable temporarily to false if you delete many things! 831## 832GGDeleteModifiesMenu := true; 833 834 835############################################################################# 836## 837#M Delete(<graph>,<obj>) . . . . . . . . . . . . . remove something in graph 838## 839## This operation already exists in {\XGAP} for the graphic objects! 840## Applicable for edges, vertices, classes. 841## 842## The following method applies to an edge, given by two vertices. It returns 843## fail if not one of the vertices is maximal in the other and true 844## otherwise. 845InstallOtherMethod( Delete, 846 "for a graphic poset, and two vertices", 847 true, 848 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex ], 849 0, 850 851function( poset, v1, v2 ) 852 local p, dummy, l; 853 854 # determine which is the "bigger one": 855 p := Position(v2!.maximals,v1); 856 if p = fail then 857 p := Position(v1!.maximals,v2); 858 if p = fail then 859 return fail; 860 fi; 861 # swap the vertices: 862 dummy := v1; 863 v1 := v2; 864 v2 := dummy; 865 fi; 866 # v1 is now maximal in v2 at position p in v2!.maximals 867 868 Disconnect(v1!.obj,v2!.obj); 869 l := Length(v2!.maximals); 870 v2!.maximals[p] := v2!.maximals[l]; 871 Unbind(v2!.maximals[l]); 872 p := Position(v1!.maximalin,v2); 873 # fail is not an option here! If that happens we bomb out! 874 l := Length(v1!.maximalin); 875 v1!.maximalin[p] := v1!.maximalin[l]; 876 Unbind(v1!.maximalin[l]); 877 878 # think about the menus: 879 if GGDeleteModifiesMenu then 880 ModifyEnabled(poset,1,Length(poset!.menus)); 881 fi; 882 883 return true; 884end); 885 886## The following method applies to a vertex. It returns fail if the vertex 887## is not in the poset. The vertex is deleted and all connections to other 888## vertices are also deleted! Returns true if vertex is successfully deleted. 889InstallOtherMethod( Delete, 890 "for a graphic poset, and a vertex", 891 true, 892 [ IsGraphicPosetRep, IsGPVertex ], 893 0, 894 895function( poset, v ) 896 local lp, l, cp, cl, p, savemaximals, savemaximalin, noerror, 897 v1, v2, store; 898 899 lp := Position(poset!.levelparams,v!.levelparam); 900 if lp = fail then 901 return fail; 902 fi; 903 l := poset!.levels[lp]; 904 905 cp := Position(l!.classparams,v!.classparam); 906 if cp = fail then 907 return fail; 908 fi; 909 cl := l!.classes[cp]; 910 911 p := Position(cl,v); 912 if p = fail then 913 return fail; 914 fi; 915 916 # Remember all connections: 917 savemaximals := ShallowCopy(v!.maximals); 918 savemaximalin := ShallowCopy(v!.maximalin); 919 920 # Delete all connections: 921 noerror := true; 922 store := GGDeleteModifiesMenu; 923 GGDeleteModifiesMenu := false; 924 while v!.maximals <> [] do 925 if Delete(poset,v,v!.maximals[1]) = fail then 926 noerror := fail; 927 fi; 928 od; 929 while v!.maximalin <> [] do 930 if Delete(poset,v,v!.maximalin[1]) = fail then 931 noerror := fail; 932 fi; 933 od; 934 GGDeleteModifiesMenu := store; 935 936 # was it selected? 937 RemoveSet(poset!.selectedvertices,v); 938 939 # now delete vertex: 940 Delete(v!.obj); 941 ResetFilterObj(v,IsAlive); 942 943 l := Length(cl); 944 cl[p] := cl[l]; 945 Unbind(cl[l]); 946 947 # now we have to add new inclusions from the maximal subobjects to those 948 # where our vertex was maximal in. We should not do that however, if there is 949 # already a way. This ensures that the diagram will be again a Hasse diagram 950 # of the remaining vertices with the inclusions induced by the poset 951 # before deletion. 952 for v1 in savemaximals do 953 for v2 in savemaximalin do 954 if not GPSearchWay(poset,v2,v1, 955 Position(poset!.levelparams,v1!.levelparam)) then 956 Edge(poset,v2,v1); 957 fi; 958 od; 959 od; 960 961 # think about the menus: 962 if GGDeleteModifiesMenu then 963 ModifyEnabled(poset,1,Length(poset!.menus)); 964 fi; 965 966 return noerror; 967end); 968 969## The following method applies to a class. It returns fail if the class 970## is not in the poset. The class is deleted and all vertices including 971## their connections to other vertices are also deleted! Returns true 972## if class is successfully deleted. 973## The two parameters are a level parameter and a class parameter. 974InstallOtherMethod( Delete, 975 "for a graphic poset, and two objects", 976 true, 977 [ IsGraphicPosetRep, IsObject, IsObject ], 978 0, 979 980function( poset, levelparam, classparam ) 981 local lp, l, cp, noerror, v, store; 982 983 lp := Position(poset!.levelparams,levelparam); 984 if lp = fail then 985 return fail; 986 fi; 987 l := poset!.levels[lp]; 988 989 cp := Position(l!.classparams,classparam); 990 if cp = fail then 991 return fail; 992 fi; 993 994 # delete all vertices: 995 noerror := true; 996 store := GGDeleteModifiesMenu; 997 GGDeleteModifiesMenu := false; 998 for v in l!.classes[cp] do 999 if Delete(poset,v) = fail then 1000 noerror := fail; 1001 fi; 1002 od; 1003 GGDeleteModifiesMenu := store; 1004 1005 lp := Length(l!.classes); 1006 l!.classes[cp] := l!.classes[lp]; 1007 Unbind(l!.classes[lp]); 1008 l!.classparams[cp] := l!.classparams[lp]; 1009 Unbind(l!.classparams[lp]); 1010 1011 # think about the menus: 1012 if GGDeleteModifiesMenu then 1013 ModifyEnabled(poset,1,Length(poset!.menus)); 1014 fi; 1015 1016 return noerror; 1017end); 1018 1019 1020############################################################################# 1021## 1022#M DeleteLevel(<poset>,<levelparam>) . . . . . . . . . remove level in poset 1023## 1024## The following method applies to a level. It returns `fail' if no level 1025## with level parameter <levelparam> is in the poset. Otherwise the level 1026## is deleted and all classes within it are also deleted! `DeleteLevel' 1027## returns `true' if the level is successfully deleted. 1028## 1029InstallOtherMethod( DeleteLevel, 1030 "for a graphic poset, and an object", 1031 true, 1032 [ IsGraphicPosetRep, IsObject ], 1033 0, 1034 1035function( poset, levelparam ) 1036 local lp, noerror, cl, v, l, lev, store; 1037 1038 lp := Position(poset!.levelparams,levelparam); 1039 if lp = fail then 1040 return fail; 1041 fi; 1042 1043 # delete all vertices: 1044 noerror := true; 1045 store := GGDeleteModifiesMenu; 1046 GGDeleteModifiesMenu := false; 1047 for cl in poset!.levels[lp]!.classes do 1048 while cl <> [] do 1049 if Delete(poset,cl[1]) = fail then 1050 noerror := fail; 1051 fi; 1052 od; 1053 od; 1054 GGDeleteModifiesMenu := store; 1055 1056 l := Length(poset!.levels); 1057 # now we have to move all lower levels up: 1058 FastUpdate(poset,true); 1059 for lev in [lp+1..l] do 1060 poset!.levels[lev]!.top := poset!.levels[lev]!.top 1061 - poset!.levels[lp]!.height; 1062 for cl in poset!.levels[lev]!.classes do 1063 for v in cl do 1064 Move(poset,v,v!.x,v!.y); 1065 od; 1066 od; 1067 if IsAlive(poset!.levelboxes[lev]) then 1068 MoveDelta(poset!.levelboxes[lev],0,-poset!.levels[lp]!.height); 1069 fi; 1070 if IsAlive(poset!.lptexts[lev]) then 1071 MoveDelta(poset!.lptexts[lev],0,-poset!.levels[lp]!.height); 1072 fi; 1073 od; 1074 FastUpdate(poset,false); 1075 poset!.levels{[lp..l-1]} := poset!.levels{[lp+1..l]}; 1076 Unbind(poset!.levels[l]); 1077 poset!.levelparams{[lp..l-1]} := poset!.levelparams{[lp+1..l]}; 1078 Unbind(poset!.levelparams[l]); 1079 if IsAlive(poset!.levelboxes[lp]) then 1080 Delete(poset,poset!.levelboxes[lp]); 1081 fi; 1082 poset!.levelboxes{[lp..l-1]} := poset!.levelboxes{[lp+1..l]}; 1083 Unbind(poset!.levelboxes[l]); 1084 if IsAlive(poset!.lptexts[lp]) then 1085 Delete(poset,poset!.lptexts[lp]); 1086 fi; 1087 poset!.lptexts{[lp..l-1]} := poset!.lptexts{[lp+1..l]}; 1088 Unbind(poset!.lptexts[l]); 1089 1090 # think about the menus: 1091 if GGDeleteModifiesMenu then 1092 ModifyEnabled(poset,1,Length(poset!.menus)); 1093 fi; 1094 1095 return noerror; 1096end); 1097 1098 1099############################################################################# 1100## 1101## Modification methods: 1102## 1103############################################################################# 1104 1105 1106############################################################################# 1107## 1108#M ResizeLevel(<poset>,<levelparam>,<height>) . . . change height of level 1109## 1110## Changes the height of a level. The y coordinate can only be changed by 1111## permuting levels, see below. 1112## Attention: can increase the size of the sheet! 1113## Returns fail if no level with parameter levelparam exists and true 1114## otherwise. 1115## 1116InstallOtherMethod( ResizeLevel, 1117 "for a graphic poset, an object, and an integer", 1118 true, 1119 [ IsGraphicPosetRep, IsObject, IsInt ], 1120 0, 1121 1122function( poset, levelparam, height ) 1123 local lp, l, cl, v, dist, len; 1124 1125 lp := Position(poset!.levelparams,levelparam); 1126 if lp = fail then 1127 return fail; 1128 fi; 1129 l := poset!.levels[lp]; 1130 1131 if height < VERTEX.diameter then 1132 height := VERTEX.diameter; 1133 fi; 1134 1135 if height = l!.height then 1136 return true; 1137 elif height < l!.height then 1138 # move all vertices within level into the new range 1139 FastUpdate(poset,true); 1140 for cl in l!.classes do 1141 for v in cl do 1142 if v!.y > height-VERTEX.radius then 1143 v!.y := height-VERTEX.radius; 1144 Move(v!.obj,v!.x,v!.y + l!.top); 1145 fi; 1146 od; 1147 od; 1148 1149 # now move all lower levels up: 1150 dist := height - l!.height; 1151 l!.height := height; 1152 1153 # move level box and text: 1154 if poset!.showlevels then 1155 Move(poset!.levelboxes[lp],0,l!.top + l!.height - 8); 1156 fi; 1157 if poset!.showlevelparams then 1158 Move(poset!.lptexts[lp],poset!.lptexts[lp]!.x, 1159 l!.top + QuoInt(l!.height,2)); 1160 fi; 1161 FastUpdate(poset,false); 1162 1163 else # height > l!.height 1164 dist := height - l!.height; 1165 l!.height := height; 1166 1167 # do we have to increase height of sheet? 1168 len := Length(poset!.levels); 1169 if poset!.levels[len]!.top + poset!.levels[len]!.height + dist 1170 > poset!.height then 1171 Resize(poset,poset!.width, 1172 poset!.levels[len]!.top + poset!.levels[len]!.height + dist); 1173 fi; 1174 1175 if poset!.showlevels then 1176 Move(poset!.levelboxes[lp],0,l!.top + l!.height - 8); 1177 fi; 1178 if poset!.showlevelparams then 1179 Move(poset!.lptexts[lp],poset!.lptexts[lp]!.x, 1180 l!.top + QuoInt(l!.height,2)); 1181 fi; 1182 1183 # next move down all the levels below the increased level: 1184 fi; 1185 1186 FastUpdate(poset,true); 1187 for l in [lp+1..Length(poset!.levels)] do 1188 poset!.levels[l]!.top := poset!.levels[l]!.top + dist; 1189 for cl in poset!.levels[l]!.classes do 1190 for v in cl do 1191 MoveDelta(v!.obj,0,dist); 1192 od; 1193 od; 1194 # move level box: 1195 if poset!.showlevels then 1196 MoveDelta(poset!.levelboxes[l],0,dist); 1197 fi; 1198 if poset!.showlevelparams then 1199 MoveDelta(poset!.lptexts[l],0,dist); 1200 fi; 1201 od; 1202 FastUpdate(poset,false); 1203end); 1204 1205 1206############################################################################# 1207## 1208#M MoveLevel(<poset>,<levelparam>,<position>) move level to another position 1209## 1210## Moves a level to another position. <position> is an absolute index in 1211## the list of levels. The level with parameter <levelparam> will be at the 1212## position <position> after the operation. This is only allowed if the 1213## new ordering is compatible with the partial order given by CompareLevels 1214## and if there is no connection of a vertex in the moving level with 1215## another level with which it is interchanged. 1216## So <levelparam> is compared with all levelparams between the old and 1217## the new position. If there is a contradiction nothing happens and the 1218## method returns fail. If everything works the operation returns true. 1219## This operation already exists in {\XGAP} for graphic objects. 1220## 1221InstallOtherMethod( MoveLevel, 1222 "for a graphic poset, an object, and an integer", 1223 true, 1224 [ IsGraphicPosetRep, IsObject, IsInt ], 1225 0, 1226 1227function( poset, levelparam, position ) 1228 local lp, i, compare, cl, v, v2, p, list; 1229 # nonsense position? 1230 if position < 1 or position > Length(poset!.levels) then 1231 return fail; 1232 fi; 1233 1234 # does level exist? 1235 lp := Position(poset!.levelparams,levelparam); 1236 if lp = fail then 1237 return fail; 1238 fi; 1239 1240 # nothing to do? 1241 if position = lp then 1242 return true; # we are done 1243 fi; 1244 1245 if position < lp then # move level UP 1246 # check with partial ordering: 1247 for i in [position..lp-1] do 1248 compare := CompareLevels(poset,poset!.levelparams[i],levelparam); 1249 if compare <> fail and compare < 0 then 1250 # that would contradict the partial order 1251 return fail; 1252 fi; 1253 od; 1254 1255 # now check vertices: 1256 for cl in poset!.levels[lp]!.classes do 1257 for v in cl do 1258 for v2 in v!.maximalin do 1259 p := Position(poset!.levelparams,v2!.levelparam); 1260 if p >= position then # < lp is a MUST! 1261 return fail; 1262 fi; 1263 od; 1264 od; 1265 od; 1266 1267 # OK, we can do it: 1268 FastUpdate(poset,true); 1269 list := Concatenation([lp],[position..lp-1]); 1270 poset!.levels{[position..lp]} := poset!.levels{list}; 1271 poset!.levelparams{[position..lp]} := poset!.levelparams{list}; 1272 poset!.levelboxes{[position..lp]} := poset!.levelboxes{list}; 1273 poset!.lptexts{[position..lp]} := poset!.lptexts{list}; 1274 poset!.levels[position]!.top := poset!.levels[position+1]!.top; 1275 if poset!.showlevels then 1276 Move(poset!.levelboxes[position],0,poset!.levels[position]!.top 1277 + poset!.levels[position]!.height - 8); 1278 fi; 1279 if poset!.showlevelparams then 1280 Move(poset!.lptexts[position],poset!.lptexts[position]!.x, 1281 poset!.levels[position]!.top + 1282 QuoInt(poset!.levels[position]!.height,2)); 1283 fi; 1284 1285 for cl in poset!.levels[position]!.classes do 1286 for v in cl do 1287 Move(poset,v,v!.x,v!.y); 1288 od; 1289 od; 1290 for i in [position+1..lp] do 1291 poset!.levels[i]!.top := poset!.levels[i]!.top 1292 + poset!.levels[position]!.height; 1293 1294 if poset!.showlevels then 1295 Move(poset!.levelboxes[i],0,poset!.levels[i]!.top 1296 + poset!.levels[i]!.height - 8); 1297 fi; 1298 if poset!.showlevelparams then 1299 Move(poset!.lptexts[i],poset!.lptexts[i]!.x, 1300 poset!.levels[i]!.top + QuoInt(poset!.levels[i]!.height,2)); 1301 fi; 1302 for cl in poset!.levels[i]!.classes do 1303 for v in cl do 1304 Move(poset,v,v!.x,v!.y); 1305 od; 1306 od; 1307 od; 1308 # in case another one has overwritten our box: 1309 if poset!.showlevels then 1310 Draw(poset!.levelboxes[position]); 1311 fi; 1312 if poset!.showlevelparams then 1313 Draw(poset!.lptexts[position]); 1314 fi; 1315 FastUpdate(poset,false); 1316 1317 # we did it. 1318 else # position > lp, move level DOWN 1319 # check with partial ordering: 1320 for i in [lp+1..position] do 1321 compare := CompareLevels(poset,poset!.levelparams[i],levelparam); 1322 if compare <> fail and compare > 0 then 1323 # that would contradict the partial order 1324 return fail; 1325 fi; 1326 od; 1327 1328 # now check vertices: 1329 for cl in poset!.levels[lp]!.classes do 1330 for v in cl do 1331 for v2 in v!.maximals do 1332 p := Position(poset!.levelparams,v2!.levelparam); 1333 if p <= position then # > lp is a MUST! 1334 return fail; 1335 fi; 1336 od; 1337 od; 1338 od; 1339 1340 # OK, we can do it: 1341 FastUpdate(poset,true); 1342 list := Concatenation([lp+1..position],[lp]); 1343 poset!.levels{[lp..position]} := poset!.levels{list}; 1344 poset!.levelparams{[lp..position]} := poset!.levelparams{list}; 1345 poset!.levelboxes{[lp..position]} := poset!.levelboxes{list}; 1346 poset!.lptexts{[lp..position]} := poset!.lptexts{list}; 1347 poset!.levels[position]!.top := poset!.levels[position-1]!.top 1348 - poset!.levels[position]!.height 1349 + poset!.levels[position-1]!.height; 1350 if poset!.showlevels then 1351 Move(poset!.levelboxes[position],0,poset!.levels[position]!.top 1352 + poset!.levels[position]!.height - 8); 1353 fi; 1354 if poset!.showlevelparams then 1355 Move(poset!.lptexts[position],poset!.lptexts[position]!.x, 1356 poset!.levels[position]!.top + 1357 QuoInt(poset!.levels[position]!.height,2)); 1358 fi; 1359 for cl in poset!.levels[position]!.classes do 1360 for v in cl do 1361 Move(poset,v,v!.x,v!.y); 1362 od; 1363 od; 1364 for i in [lp..position-1] do 1365 poset!.levels[i]!.top := poset!.levels[i]!.top 1366 - poset!.levels[position]!.height; 1367 if poset!.showlevels then 1368 Move(poset!.levelboxes[i],0,poset!.levels[i]!.top 1369 + poset!.levels[i]!.height - 8); 1370 fi; 1371 if poset!.showlevelparams then 1372 Move(poset!.lptexts[i],poset!.lptexts[i]!.x, 1373 poset!.levels[i]!.top + QuoInt(poset!.levels[i]!.height,2)); 1374 fi; 1375 for cl in poset!.levels[i]!.classes do 1376 for v in cl do 1377 Move(poset,v,v!.x,v!.y); 1378 od; 1379 od; 1380 od; 1381 # in case another one has overwritten our box: 1382 if poset!.showlevels then 1383 Draw(poset!.levelboxes[position]); 1384 fi; 1385 if poset!.showlevelparams then 1386 Draw(poset!.lptexts[position]); 1387 fi; 1388 FastUpdate(poset,false); 1389 1390 # we did it. 1391 fi; 1392 1393 return true; 1394end); 1395 1396 1397############################################################################# 1398## 1399#M Relabel(<graph>,<vertex>,<label>) . . . . . . . . change label of vertex 1400#M Relabel(<graph>,<vertex>) . . . . . . . . . . . . change label of vertex 1401#M Relabel(<poset>,<vertex1>,<vertex2>,<label>) . . . . change label of edge 1402#M Relabel(<poset>,<vertex1>,<vertex2>) . . . . . . . . change label of edge 1403## 1404## Changes the label of the vertex <vertex> or the edge between <vertex1> 1405## and <vertex2>. This must be a short string. In the method where no 1406## label is specified the new label is chosen functionally: the operation 1407## `ChooseLabel' is called. `Relabel' returns `fail' if an error occurs 1408## and `true' otherwise. This operations already exists in {\XGAP} for 1409## graphic objects. 1410## 1411InstallOtherMethod( Relabel, 1412 "for a graphic graph, a vertex, and a string", 1413 true, 1414 [ IsGraphicGraphRep, IsGGVertex, IsString ], 1415 0, 1416 1417function( graph, vertex, label ) 1418 if label = "" then 1419 label := false; 1420 fi; 1421 # we just call the low level routines: 1422 vertex!.label := label; 1423 Relabel(vertex!.obj,label); 1424end); 1425 1426InstallOtherMethod( Relabel, 1427 "for a graphic graph, and a vertex", 1428 true, 1429 [ IsGraphicGraphRep, IsGGVertex ], 1430 0, 1431 1432function( graph, vertex) 1433 local label; 1434 1435 label := ChooseLabel( graph, vertex!.data ); 1436 if label = "" then 1437 label := false; 1438 fi; 1439 # we just call the low level routines: 1440 vertex!.label := label; 1441 Relabel(vertex!.obj,label); 1442end); 1443 1444InstallOtherMethod( Relabel, 1445 "for a graphic poset, two vertices, and a string", 1446 true, 1447 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsString ], 1448 0, 1449 1450function( poset, v1, v2, label ) 1451 local p; 1452 p := Position(v1!.maximals,v2); 1453 if p = fail then 1454 p := Position(v2!.maximals,v1); 1455 if p = fail then 1456 return fail; 1457 fi; 1458 fi; 1459 # we know now that there is a connection! 1460 p := Position(v1!.obj!.connections,v2!.obj); 1461 1462 if label = "" then 1463 label := false; 1464 fi; 1465 1466 # now we just call the low level routines: 1467 Relabel(v1!.obj!.connectingLines[p],label); 1468end); 1469 1470InstallOtherMethod( Relabel, 1471 "for a graphic poset, and two vertices", 1472 true, 1473 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex ], 1474 0, 1475 1476function( poset, v1, v2) 1477 local label; 1478 1479 label := ChooseLabel( poset, v1!.data, v2!.data ); 1480 if label = "" then 1481 label := false; 1482 fi; 1483 # we just call the low level routines: 1484 Relabel(poset,v1,v2,label); 1485end); 1486 1487 1488############################################################################# 1489## 1490#M Move(<graph>,<vertex>,<x>,<y>) . . . . . . . . . . . . . . . move vertex 1491#M Move(<graph>,<vertex>) . . . . . . . . . . . . . . . . . . . move vertex 1492## 1493## Moves vertex <vertex>. For posets coordinates are relative to the level 1494## of the vertex. <vertex> must be a vertex object in <graph>. If no 1495## coordinates are specified the operation `ChoosePosition' is 1496## called. Returns `fail' if an error occurs and `true' otherwise. This 1497## operations already exists in {\XGAP} for graphic objects. 1498## 1499InstallOtherMethod( Move, 1500 "for a graphic poset, a vertex, and two integers", 1501 true, 1502 [ IsGraphicPosetRep, IsGPVertex, IsInt, IsInt ], 1503 0, 1504 1505function( poset, vertex, x, y ) 1506 local l; 1507 1508 if x < VERTEX.radius then 1509 x := VERTEX.radius; 1510 elif x > poset!.width-VERTEX.radius then 1511 x := poset!.width-VERTEX.radius; 1512 fi; 1513 l := Position(poset!.levelparams,vertex!.levelparam); 1514 l := poset!.levels[l]; 1515 if y < VERTEX.radius then 1516 y := VERTEX.radius; 1517 elif y > l!.height-VERTEX.radius then 1518 y := l!.height-VERTEX.radius; 1519 fi; 1520 1521 vertex!.x := x; 1522 vertex!.y := y; 1523 Move(vertex!.obj,x,y+l!.top); 1524 1525 return true; 1526end); 1527 1528InstallOtherMethod( Move, 1529 "for a graphic poset, and a vertex", 1530 true, 1531 [ IsGraphicPosetRep, IsGPVertex ], 1532 0, 1533 1534function( poset, vertex ) 1535 local position; 1536 1537 position := ChoosePosition(poset, vertex!.data, vertex!.levelparam, 1538 vertex!.classparam); 1539 Move(poset,vertex,position[1],position[2]); 1540end); 1541 1542 1543############################################################################# 1544## 1545#M Reshape(<graph>,<vertex>,<shape>) . . . . . . . . change shape of vertex 1546#M Reshape(<graph>,<vertex>) . . . . . . . . . . . . change shape of vertex 1547## 1548## Changes the shape of the vertex <vertex>. <vertex> must be a vertex 1549## object in the graph or poset <graph>. For the method where no shape is 1550## specified the new shape is chosen functionally: `ChooseShape` is called 1551## for the corresponding data. `Reshape' returns `fail' if an error 1552## occurs and `true' otherwise. This operations already exists in {\XGAP} 1553## for graphic objects. 1554## 1555InstallOtherMethod( Reshape, 1556 "for a graphic graph, a vertex, and a string", 1557 true, 1558 [ IsGraphicGraphRep, IsGGVertex, IsString ], 1559 0, 1560 1561function( graph, vertex, shape ) 1562 if shape = "circle" then 1563 Reshape(vertex!.obj,VERTEX.circle); 1564 elif shape = "diamond" then 1565 Reshape(vertex!.obj,VERTEX.diamond); 1566 else 1567 Reshape(vertex!.obj,VERTEX.rectangle); 1568 fi; 1569 return true; 1570end); 1571 1572InstallOtherMethod( Reshape, 1573 "for a graphic graph, and a vertex", 1574 true, 1575 [ IsGraphicGraphRep, IsGGVertex ], 1576 0, 1577 1578function( graph, vertex ) 1579 local shape; 1580 1581 shape := ChooseShape( graph, vertex!.data ); 1582 Reshape(graph, vertex, shape); 1583 return true; 1584end); 1585 1586 1587############################################################################# 1588## 1589#M Recolor(<graph>,<vertex>,<color>) . . . . . . . . change color of vertex 1590#M Recolor(<graph>,<vertex>) . . . . . . . . . . . . change color of vertex 1591#M Recolor(<poset>,<vertex1>,<vertex2>,<color>) . . change color of an edge 1592#M Recolor(<poset>,<vertex1>,<vertex2>) . . . . . . change color of an edge 1593## 1594## Changes the color of the vertex <vertex> or the edge between <vertex1> 1595## and <vertex2>. <vertex> must be a vertex object in <graph>. For the 1596## method where no color is specified the new color is chosen 1597## functionally: `ChooseColor' is called for the corresponding 1598## data. `Recolor' returns `fail' if an error occurs and `true' 1599## otherwise. This operation already exists in {\XGAP} for graphic objects. 1600## 1601InstallOtherMethod( Recolor, 1602 "for a graphic graph, a vertex, and a color", 1603 true, 1604 [ IsGraphicGraphRep, IsGGVertex, IsColor ], 1605 0, 1606 1607function( graph, vertex, color ) 1608 Recolor(vertex!.obj,color); 1609 return true; 1610end); 1611 1612InstallOtherMethod( Recolor, 1613 "for a graphic graph, and a vertex", 1614 true, 1615 [ IsGraphicGraphRep, IsGGVertex ], 1616 0, 1617 1618function( graph, vertex ) 1619 local color; 1620 1621 color := ChooseColor( graph, vertex!.data ); 1622 Recolor(graph, vertex, color); 1623 return true; 1624end); 1625 1626InstallOtherMethod( Recolor, 1627 "for a graphic poset, two vertices, and a color", 1628 true, 1629 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsColor ], 1630 0, 1631 1632function( poset, vertex1, vertex2, color ) 1633 local p; 1634 p := Position(vertex1!.maximals,vertex2); 1635 if p = fail then 1636 p := Position(vertex2!.maximals,vertex1); 1637 if p = fail then 1638 return fail; 1639 fi; 1640 fi; 1641 # we know now that there is a connection! 1642 p := Position(vertex1!.obj!.connections,vertex2!.obj); 1643 Recolor(vertex1!.obj!.connectingLines[p],color); 1644 return true; 1645end); 1646 1647InstallOtherMethod( Recolor, 1648 "for a graphic poset, and two vertices", 1649 true, 1650 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex ], 1651 0, 1652 1653function( poset, vertex1, vertex2 ) 1654 local color; 1655 1656 color := ChooseColor( poset, vertex1!.data, vertex2!.data ); 1657 return Recolor(poset, vertex1, vertex2, color); 1658end); 1659 1660 1661############################################################################# 1662## 1663#M SetWidth(<graph>,<vertex1>,<vertex2>,<width>) . change line width of edge 1664#M SetWidth(<graph>,<vertex1>,<vertex2>) . . . . . change line width of edge 1665## 1666## Changes the line width of an edge. <vertex1> and <vertex2> must be 1667## vertices in the graph <graph>. For the method where no line width is 1668## specified the width is chosen functionally: `ChooseWidth' is called for 1669## the corresponding data pair. Returns `fail' if an error occurs and 1670## `true' otherwise. This operation already exists in {\XGAP} for graphic 1671## objects. 1672## 1673InstallOtherMethod( SetWidth, 1674 "for a graphic poset, two vertices, and an integer", 1675 true, 1676 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex, IsInt ], 1677 0, 1678 1679function( poset, vertex1, vertex2, width ) 1680 local p; 1681 p := Position(vertex1!.maximals,vertex2); 1682 if p = fail then 1683 p := Position(vertex2!.maximals,vertex1); 1684 if p = fail then 1685 return fail; 1686 fi; 1687 fi; 1688 # we know now that there is a connection! 1689 p := Position(vertex1!.obj!.connections,vertex2!.obj); 1690 SetWidth(vertex1!.obj!.connectingLines[p],width); 1691 return true; 1692end); 1693 1694InstallOtherMethod( SetWidth, 1695 "for a graphic poset, and two vertices", 1696 true, 1697 [ IsGraphicPosetRep, IsGPVertex, IsGPVertex ], 1698 0, 1699 1700function( poset, vertex1, vertex2 ) 1701 local width; 1702 1703 width := ChooseWidth( poset, vertex1!.data, vertex2!.data ); 1704 return SetWidth(poset, vertex1, vertex2, width); 1705end); 1706 1707 1708############################################################################# 1709## 1710#M Highlight(<graph>,<vertex>) . . . . . . . change highlightning of vertex 1711#M Highlight(<graph>,<vertex>,<flag>) . . . . change highlightning of vertex 1712## 1713## Changes the highlighting status of the vertex <vertex>. <vertex> must 1714## be a vertex object in <graph>. For the method where no flag is 1715## specified the new status is chosen functionally: `ChooseHighlight' is 1716## called for the corresponding data. Returns `fail' if an error occurs 1717## and `true' otherwise. This operation already exists in {\XGAP} for 1718## graphic objects. 1719## 1720InstallOtherMethod( Highlight, 1721 "for a graphic graph, a vertex, and a flag", 1722 true, 1723 [ IsGraphicGraphRep, IsGGVertex, IsBool ], 1724 0, 1725 1726function( graph, vertex, flag ) 1727 Highlight(vertex!.obj,flag); 1728 return true; 1729end); 1730 1731InstallOtherMethod( Highlight, 1732 "for a graphic graph, and a vertex", 1733 true, 1734 [ IsGraphicGraphRep, IsGGVertex ], 1735 0, 1736 1737function( graph, vertex ) 1738 local flag; 1739 1740 flag := ChooseHighlight( graph, vertex!.data ); 1741 Highlight(graph, vertex, flag); 1742 return true; 1743end); 1744 1745 1746############################################################################# 1747## 1748## Set this variable temporarily to false if you change many selections! 1749## 1750GGSelectModifiesMenu := true; 1751 1752 1753############################################################################# 1754## 1755#M Select(<graph>,<vertex>,<flag>) . . . . . . . . . . (de-)selects a vertex 1756#M Select(<graph>,<vertex>) . . . . . . . . . . . . . . . selects a vertex 1757## 1758## Changes the selection state of the vertex <vertex>. <vertex> must be a 1759## vertex object in <graph>. The flag determines whether the vertex 1760## should be selected or deselected. This operation already exists in 1761## {\XGAP} for graphic objects. The method without flags assumes `true'. 1762## 1763InstallOtherMethod( Select, 1764 "for a graphic graph, a vertex, and a flag", 1765 true, 1766 [ IsGraphicGraphRep, IsGGVertex, IsBool ], 1767 0, 1768 1769function(graph,vertex,flag) 1770 local p, l; 1771 p := PositionSet(graph!.selectedvertices,vertex); 1772 if flag then 1773 if p <> fail then 1774 return; 1775 fi; 1776 Highlight(graph,vertex,true); 1777 Recolor(graph,vertex,graph!.color.selected); 1778 AddSet(graph!.selectedvertices,vertex); 1779 else 1780 if p = fail then 1781 return; 1782 fi; 1783 Highlight(graph,vertex,false); 1784 Recolor(graph,vertex,graph!.color.unselected); 1785 RemoveSet(graph!.selectedvertices,vertex); 1786 fi; 1787 if GGSelectModifiesMenu then 1788 ModifyEnabled(graph,1,Length(graph!.menus)); 1789 fi; 1790 return; 1791end); 1792 1793InstallOtherMethod( Select, 1794 "for a graphic graph, and a vertex", 1795 true, 1796 [ IsGraphicGraphRep, IsGGVertex ], 1797 0, 1798 1799function(graph,vertex) 1800 Select(graph,vertex,true); 1801end); 1802 1803 1804############################################################################# 1805## 1806#M DeselectAll(<graph>) . . . . . . . . . . . . . . . deselects all vertices 1807## 1808## Deselects all vertices in graph. 1809## 1810InstallOtherMethod( DeselectAll, 1811 "for a graphic graph", 1812 true, 1813 [ IsGraphicGraphRep ], 1814 0, 1815 1816function(graph) 1817 local v; 1818 for v in graph!.selectedvertices do 1819 Highlight(graph,v,false); 1820 Recolor(graph,v,graph!.color.unselected); 1821 od; 1822 graph!.selectedvertices := []; 1823end); 1824 1825 1826############################################################################# 1827## 1828#M Selected(<graph>) . . . . . . . . . returns set of all selected vertices 1829## 1830## Returns a (shallow-)copy of the set of all selected vertices. 1831## 1832InstallOtherMethod( Selected, 1833 "for a graphic graph", 1834 true, 1835 [ IsGraphicGraphRep ], 1836 0, 1837 1838function(graph) 1839 return ShallowCopy(graph!.selectedvertices); 1840end); 1841 1842 1843############################################################################# 1844## 1845## Methods for functional decisions: 1846## 1847############################################################################# 1848 1849 1850############################################################################# 1851## 1852#M CompareLevels(<poset>,<levelp1>,<levelp2>) . . . compares two levelparams 1853## 1854## Compare two levelparams. -1 means that levelp1 is "higher", 1 means 1855## that levelp2 is "higher", 0 means that they are equal. fail means that 1856## they are not comparable. This method is for the case if level 1857## parameters are integers and lower values mean higher levels like in the 1858## case of group lattices and subgroup indices. 1859## 1860InstallMethod( CompareLevels, 1861 "for a graphic poset, and two integers", 1862 true, 1863 [ IsGraphicPosetRep, IsInt, IsInt ], 1864 0, 1865 1866function( poset, l1, l2 ) 1867 if l1 < l2 then 1868 return -1; 1869 elif l1 > l2 then 1870 return 1; 1871 else 1872 return 0; 1873 fi; 1874end); 1875 1876 1877############################################################################# 1878## 1879#M ChooseLabel(<graph>,<data>) . . . . . . . is called while vertex creation 1880#M ChooseLabel(<graph>,<data>,<data>) . . . . is called while edge creation 1881## 1882## This operation is called while vertex or edge creation, if the caller 1883## didn't specify a label for the vertex or edge. It has to return a short 1884## string which will be attached to the vertex. If it returns fail the new 1885## vertex is not generated! This method just returns the empty string, so 1886## no label is generated. 1887## This method is also called in the Relabel method without label parameter. 1888## 1889InstallMethod( ChooseLabel, 1890 "for a graphic graph, and an object", 1891 true, 1892 [ IsGraphicGraphRep, IsObject ], 1893 0, 1894 1895function( graph, data ) 1896 return ""; 1897end); 1898 1899InstallOtherMethod( ChooseLabel, 1900 "for a graphic graph, and two objects", 1901 true, 1902 [ IsGraphicGraphRep, IsObject, IsObject ], 1903 0, 1904 1905function( poset, data1, data2 ) 1906 return ""; 1907end); 1908 1909 1910############################################################################# 1911## 1912#M ChooseLevel(<poset>,<data>) . . . . . . . is called while vertex creation 1913## 1914## This operation is called while vertex creation, if the caller didn't 1915## specify a level where the vertex belongs to. It has to return a 1916## levelparam which exists in the poset. If it returns fail the new vertex 1917## is not generated! 1918## This method just chooses the last, lowest level or fail, if there is no 1919## level in the poset. 1920## 1921InstallMethod( ChooseLevel, 1922 "for a graphic poset, and an object", 1923 true, 1924 [ IsGraphicPosetRep, IsObject ], 1925 0, 1926 1927function( poset, data ) 1928 local l; 1929 l := Length(poset!.levelparams); 1930 if l > 0 then 1931 return poset!.levelparams[Length(poset!.levelparams)]; 1932 else 1933 return fail; 1934 fi; 1935end); 1936 1937 1938############################################################################# 1939## 1940#M ChooseClass(<poset>,<data>,<levelp>) . . is called while vertex creation 1941## 1942## This operation is called while vertex creation, if the caller didn't 1943## specify a class where the vertex belongs to. It has to return a 1944## classparam which exists in the poset in levelp. If it returns fail the 1945## new vertex is not generated! 1946## This method just generates a new class in the level with classparam one 1947## bigger than the maximum of all (integer) classparams. It returns fail if 1948## this maximum is no integer. 1949## 1950InstallMethod( ChooseClass, 1951 "for a graphic graph, and two objects", 1952 true, 1953 [ IsGraphicPosetRep, IsObject, IsObject ], 1954 0, 1955 1956function( poset, data, levelparam ) 1957 local l,m; 1958 1959 l := Position(poset!.levelparams,levelparam); 1960 if l = fail then 1961 return fail; 1962 fi; 1963 l := poset!.levels[l]; 1964 1965 if l!.classparams = [] then 1966 return CreateClass(poset,levelparam,1); 1967 fi; 1968 1969 m := Maximum(l!.classparams); 1970 if not IsInt(m) then 1971 return fail; 1972 fi; 1973 1974 return CreateClass(poset,levelparam,m+1); 1975end); 1976 1977 1978############################################################################# 1979## 1980#M ChooseShape(<graph>,<data>) . . . . . . . is called while vertex creation 1981## 1982## This operation is called while vertex creation. 1983## It has to return a string out of the following list: 1984## "circle", "diamond", "rectangle" 1985## If it returns fail the new vertex is not generated! 1986## This method just returns "circle". 1987## 1988InstallMethod( ChooseShape, 1989 "for a graphic graph, and an object", 1990 true, 1991 [ IsGraphicGraphRep, IsObject ], 1992 0, 1993 1994function( graph, data ) 1995 return "circle"; 1996end); 1997 1998 1999############################################################################# 2000## 2001#M ChooseWidth(<graph>,<data>) . . . . . . . is called while vertex creation 2002#M ChooseWidth(<graph>,<data1>,<data2>) . . . is called while edge creation 2003## 2004## This operation is called while vertex or edge creation. 2005## It has to return a line width. 2006## If it returns fail the new vertex or edge is not generated! 2007## This is also called by the SetWidth operation without width parameter. 2008## This method just returns 1. 2009## 2010InstallOtherMethod( ChooseWidth, 2011 "for a graphic graph, and an object", 2012 true, 2013 [ IsGraphicGraphRep, IsObject ], 2014 0, 2015 2016function( graph, data ) 2017 return 1; 2018end); 2019 2020InstallOtherMethod( ChooseWidth, 2021 "for a graphic graph, and two objects", 2022 true, 2023 [ IsGraphicGraphRep, IsObject, IsObject ], 2024 0, 2025 2026function( graph, data1, data2 ) 2027 return 1; 2028end); 2029 2030 2031############################################################################# 2032## 2033#M ChooseColor(<graph>,<data>) . . . . . . . is called while vertex creation 2034#M ChooseColor(<graph>,<data1>,<data2>). . . . is called while edge creation 2035## 2036## This operation is called while vertex or edge creation. It has to return a 2037## color. If it returns fail the new vertex is not generated! 2038## It is also called in the Recolor method without color parameter. 2039## This method just returns black. 2040## 2041InstallMethod( ChooseColor, 2042 "for a graphic graph, and an object", 2043 true, 2044 [ IsGraphicGraphRep, IsObject ], 2045 0, 2046 2047function( graph, data ) 2048 return COLORS.black; 2049end); 2050 2051InstallOtherMethod( ChooseColor, 2052 "for a graphic graph, and two objects", 2053 true, 2054 [ IsGraphicGraphRep, IsObject, IsObject ], 2055 0, 2056 2057function( graph, data1, data2 ) 2058 return COLORS.black; 2059end); 2060 2061 2062############################################################################# 2063## 2064#M ChooseHighlight(<graph>,<data>) . . . . . is called while vertex creation 2065## 2066## This operation is called while vertex creation. It has to return a 2067## flag which indicates, whether the vertex is highlighted or not. If it 2068## returns fail the new vertex is not generated! 2069## It is also called in the Highlight method without flag parameter. 2070## 2071## The following method just returns false. 2072InstallMethod( ChooseHighlight, 2073 "for a graphic graph, and an object", 2074 true, 2075 [ IsGraphicGraphRep, IsObject ], 2076 0, 2077 2078function( graph, data ) 2079 return false; 2080end); 2081 2082 2083############################################################################# 2084## 2085#M ChoosePosition(<poset>,<data>,<level>,<class>) . . . . . . . . . . . . . 2086#M ChoosePosition(<graph>,<data>) . . . . . is called while vertex creation 2087## 2088## This operation is called while vertex creation. It has to return a 2089## list with two integers: the coordinates. For posets those are relative 2090## to the level the vertex resides in. If it returns fail the new vertex 2091## is not generated! 2092## This method positions a new vertex in a nonempty class next to the last 2093## member in the class and a new vertex in a new class halfway to the 2094## right end of the sheet from the rightmost vertex in the level or 2095## halfway to the left end of the sheet from the leftmost vertex in the 2096## class, depending where there is more space. 2097## 2098InstallMethod( ChoosePosition, 2099 "for a graphic poset, an object, a level object, a list, and a list", 2100 true, 2101 [ IsGraphicPosetRep, IsObject, IsGPLevel, IsList, IsList ], 2102 0, 2103 2104function( poset, data, level, class, hints ) 2105 local position, ranges, cl, gaps, maxindex, i; 2106 2107 position := []; 2108 # not first in class: 2109 if class <> [] then 2110 # just near the others in the class: 2111 position[2] := class[Length(class)]!.y; 2112 position[1] := class[Length(class)]!.x + VERTEX.diameter + 2; 2113 else 2114 # collect all x ranges where classes reside: 2115 ranges := [[0,0]]; 2116 for cl in level!.classes do 2117 if cl <> [] then 2118 Add(ranges,[cl[1]!.x-VERTEX.radius,cl[Length(cl)]!.x+VERTEX.radius]); 2119 fi; 2120 od; 2121 Add(ranges,[poset!.width,poset!.width]); 2122 ranges := Set(ranges); 2123 gaps := List([1..Length(ranges)-1],x->ranges[x+1][1]-ranges[x][2]); 2124 2125 # search largest gap: 2126 maxindex := 1; 2127 for i in [2..Length(gaps)] do 2128 if gaps[i] > gaps[maxindex] then 2129 maxindex := i; 2130 fi; 2131 od; 2132 2133 position[1] := QuoInt(ranges[maxindex][2]+ranges[maxindex+1][1],2); 2134 position[2] := QuoInt(level!.height,2); 2135 fi; 2136 return position; 2137end); 2138 2139 2140 2141############################################################################# 2142## 2143## Methods for getting information: 2144## 2145############################################################################# 2146 2147 2148############################################################################# 2149## 2150#M WhichLevel(<poset>,<y>) . . . . . . determine level in which position is 2151## 2152## Determines level in which position is. Returns levelparam or fail. 2153## 2154InstallMethod( WhichLevel, 2155 "for a graphic poset, and an integer", 2156 true, 2157 [ IsGraphicPosetRep, IsInt ], 2158 0, 2159 2160function( poset, y ) 2161 local left, right, look; 2162 2163 if poset!.levels = [] or y < 0 or y >= poset!.height then 2164 return fail; 2165 fi; 2166 2167 # we do a binary search: 2168 left := 1; 2169 right := Length(poset!.levels); 2170 while left <= right do 2171 look := QuoInt(left+right,2); 2172 if y < poset!.levels[look]!.top then 2173 right := look-1; 2174 elif y >= poset!.levels[look]!.top + poset!.levels[look]!.height then 2175 left := look+1; 2176 else 2177 return poset!.levelparams[look]; 2178 fi; 2179 od; 2180 2181 return fail; 2182end); 2183 2184 2185############################################################################# 2186## 2187#M WhichClass(<poset>,<x>,<y>) . . . . determine class in which position is 2188## 2189## Determines a class with a vertex which contains the position. The first 2190## class found is taken. Returns list with levelparam as first and 2191## classparam as second element. Returns fail if no such class is found. 2192## 2193InstallMethod( WhichClass, 2194 "for a graphic poset, and two integers", 2195 true, 2196 [ IsGraphicPosetRep, IsInt, IsInt ], 2197 0, 2198 2199function(poset, x, y) 2200 local lp, l, cl, v; 2201 2202 # first determine the level: 2203 lp := WhichLevel(poset,y); 2204 l := Position(poset!.levelparam,l); 2205 l := poset!.levels[l]; 2206 2207 # now search classes: 2208 for cl in [1..Length(l!.classes)] do 2209 for v in l!.classes[cl] do 2210 if [x,y] in v!.obj then 2211 return [lp,l!.classparams[cl]]; 2212 fi; 2213 od; 2214 od; 2215 2216 return fail; 2217end); 2218 2219 2220############################################################################# 2221## 2222#M WhichVertex(<graph>,<x>,<y>) . . . determine vertex in which position is 2223#M WhichVertex(<graph>,<data>) . . . . . determine vertex with data <data> 2224#M WhichVertex(<graph>,<data>,<func>) . . . determine vertex functionally 2225## 2226## Determines a vertex which contains the position. Returns vertex. 2227## In the third form the function func must take two parameters "data" and 2228## the data entry of a vertex in question. It must return true or false, 2229## according to the right vertex being found or not. 2230## The function can for example consider just one record component of 2231## data records. 2232## Returns fail in case no vertex is found. 2233## 2234InstallOtherMethod( WhichVertex, 2235 "for a graphic poset, and two integers", 2236 true, 2237 [ IsGraphicPosetRep, IsInt, IsInt ], 2238 0, 2239 2240function(poset, x, y) 2241 local lp, l, cl, v; 2242 2243 # first determine the level: 2244 lp := WhichLevel(poset,y); 2245 l := Position(poset!.levelparams,lp); 2246 if l = fail then 2247 return fail; # not even within a level 2248 fi; 2249 l := poset!.levels[l]; 2250 2251 # now search classes: 2252 for cl in [1..Length(l!.classes)] do 2253 for v in l!.classes[cl] do 2254 if [x,y] in v!.obj then 2255 return v; 2256 fi; 2257 od; 2258 od; 2259 2260 return fail; 2261end); 2262 2263## Method for a data object with comparison function: 2264## 2265InstallOtherMethod( WhichVertex, 2266 "for a graphic poset, an object, and a function", 2267 true, 2268 [ IsGraphicPosetRep, IsObject, IsFunction ], 2269 0, 2270 2271function(poset, data, func) 2272 2273 local lp, l, cl, v; 2274 2275 for lp in [1..Length(poset!.levels)] do 2276 l := poset!.levels[lp]; 2277 for cl in [1..Length(l!.classes)] do 2278 for v in l!.classes[cl] do 2279 if func(data,v!.data) then 2280 return v; 2281 fi; 2282 od; 2283 od; 2284 od; 2285 2286 return fail; 2287end); 2288 2289## Method for a data object: 2290## 2291InstallOtherMethod( WhichVertex, 2292 "for a graphic poset, and an object", 2293 true, 2294 [ IsGraphicPosetRep, IsObject ], 2295 0, 2296 2297function(poset, data) 2298 2299 local lp, l, cl, v; 2300 2301 for lp in [1..Length(poset!.levels)] do 2302 l := poset!.levels[lp]; 2303 for cl in [1..Length(l!.classes)] do 2304 for v in l!.classes[cl] do 2305 if v!.data = data then 2306 return v; 2307 fi; 2308 od; 2309 od; 2310 od; 2311 2312 return fail; 2313end); 2314 2315 2316############################################################################# 2317## 2318#M WhichVertices(<graph>,<x>,<y>) . determine vertices in which position is 2319#M WhichVertices(<graph>,<data>) . . . determine vertices with data <data> 2320#M WhichVertices(<graph>,<data>,<func>) . . determine vertices functionally 2321## 2322## Determines the list of vertices which contain the position. Returns list. 2323## In the third form the function func must take two parameters "data" and 2324## the data entry of a vertex in question. It must return true or false, 2325## according to the vertex belonging into the result or not. 2326## The function can for example consider just one record component of 2327## data records. 2328## Returns the empty list in case no vertex is found. 2329## 2330InstallMethod( WhichVertices, 2331 "for a graphic poset, and two integers", 2332 true, 2333 [ IsGraphicPosetRep, IsInt, IsInt ], 2334 0, 2335 2336function(poset, x, y) 2337 local lp, l, cl, v, res; 2338 2339 # first determine the level: 2340 lp := WhichLevel(poset,y); 2341 l := Position(poset!.levelparams,lp); 2342 if l = fail then 2343 return fail; # not even within a level 2344 fi; 2345 l := poset!.levels[l]; 2346 2347 res := []; 2348 # now search classes: 2349 for cl in [1..Length(l!.classes)] do 2350 for v in l!.classes[cl] do 2351 if [x,y] in v!.obj then 2352 Add(res,v); 2353 fi; 2354 od; 2355 od; 2356 2357 return res; 2358end); 2359 2360## Method for a data object with comparison function: 2361## 2362InstallOtherMethod( WhichVertices, 2363 "for a graphic poset, an object, and a function", 2364 true, 2365 [ IsGraphicPosetRep, IsObject, IsFunction ], 2366 0, 2367 2368function(poset, data, func) 2369 2370 local lp, l, cl, v, res; 2371 2372 res := []; 2373 for lp in [1..Length(poset!.levels)] do 2374 l := poset!.levels[lp]; 2375 for cl in [1..Length(l!.classes)] do 2376 for v in l!.classes[cl] do 2377 if func(data, v!.data) then 2378 Add(res,v); 2379 fi; 2380 od; 2381 od; 2382 od; 2383 2384 return res; 2385end); 2386 2387## Method for a data object: 2388## 2389InstallOtherMethod( WhichVertices, 2390 "for a graphic poset, and an object", 2391 true, 2392 [ IsGraphicPosetRep, IsObject ], 2393 0, 2394 2395function(poset, data) 2396 2397 local lp, l, cl, v, res; 2398 2399 res := []; 2400 for lp in [1..Length(poset!.levels)] do 2401 l := poset!.levels[lp]; 2402 for cl in [1..Length(l!.classes)] do 2403 for v in l!.classes[cl] do 2404 if v!.data = data then 2405 Add(res,v); 2406 fi; 2407 od; 2408 od; 2409 od; 2410 2411 return res; 2412end); 2413 2414 2415############################################################################# 2416## 2417#M Levels(<poset>) . . . . . . . . . . . . . returns the list of levelparams 2418## 2419## Returns the list of levelparams in descending order meaning highest to 2420## lowest. 2421## 2422InstallMethod( Levels, 2423 "for a graphic poset", 2424 true, 2425 [ IsGraphicPosetRep ], 2426 0, 2427 2428function(poset) 2429 return poset!.levelparams; 2430end); 2431 2432 2433############################################################################# 2434## 2435#M Classes(<poset>,<levelparam>) . . . . . . returns the list of classparams 2436## 2437## Returns the list of classparams in level levelparam. Returns fail if no 2438## level with parameter <levelparam> occurs. 2439## 2440InstallMethod( Classes, 2441 "for a graphic poset, and an object", 2442 true, 2443 [ IsGraphicPosetRep, IsObject ], 2444 0, 2445 2446function(poset, levelparam) 2447 local l; 2448 2449 l := Position(poset!.levelparams,levelparam); 2450 if l = fail then 2451 return fail; 2452 fi; 2453 l := poset!.levels[l]; 2454 return l!.classparams; 2455end); 2456 2457 2458############################################################################# 2459## 2460#M Vertices(<poset>,<levelparam>,<classparam>) . . . . . . returns vertices 2461## 2462## Returns the list of vertices in class classparams in level 2463## levelparam. Returns fail no level with paramter <levelparam> or no 2464## class with parameter <classparam> in the level. 2465## 2466InstallMethod( Vertices, 2467 "for a graphic poset, and two objects", 2468 true, 2469 [ IsGraphicPosetRep, IsObject, IsObject ], 2470 0, 2471 2472function(poset, levelparam, classparam) 2473 local l, cl; 2474 2475 l := Position(poset!.levelparams,levelparam); 2476 if l = fail then 2477 return fail; 2478 fi; 2479 l := poset!.levels[l]; 2480 2481 cl := Position(l!.classparams,classparam); 2482 if cl = fail then 2483 return fail; 2484 else 2485 return l!.classes[cl]; 2486 fi; 2487end); 2488 2489 2490############################################################################# 2491## 2492#M Maximals(<poset>,<vertex>) . . . . . . . . . returns maximal subvertices 2493## 2494## Returns the list of maximal subvertices in <vertex>. Returns fail if an 2495## error occurs. 2496## 2497InstallMethod( Maximals, 2498 "for a graphic poset, and an object", 2499 true, 2500 [ IsGraphicPosetRep, IsObject ], 2501 0, 2502 2503function(poset, vertex) 2504 return vertex!.maximals; 2505end); 2506 2507 2508############################################################################# 2509## 2510#M MaximalIn(<poset>,<vertex>) . . returns vertices, in which v. is maximal 2511## 2512## Returns the list of vertices, in which <vertex> is maximal. Returns 2513## fail if an error occurs. 2514## 2515InstallMethod( MaximalIn, 2516 "for a graphic poset, and an object", 2517 true, 2518 [ IsGraphicPosetRep, IsObject ], 2519 0, 2520 2521function(poset, vertex) 2522 return vertex!.maximalin; 2523end); 2524 2525 2526############################################################################# 2527## 2528#M PositionLevel(<poset>,<levelparam>) . . . . . returns y position of level 2529## 2530## Returns the y position of the level relative to the graphic 2531## sheet and the height. Returns fail if no level with parameter 2532## <levelparam> exists. 2533## 2534InstallMethod( PositionLevel, 2535 "for a graphic poset, and an object", 2536 true, 2537 [ IsGraphicPosetRep, IsObject ], 2538 0, 2539 2540function(poset, levelparam) 2541 local l; 2542 2543 l := Position(poset!.levelparams,levelparam); 2544 if l = fail then 2545 return fail; 2546 fi; 2547 return [poset!.levels[l]!.top,poset!.levels[l]!.height]; 2548end); 2549 2550 2551 2552############################################################################# 2553## 2554## Methods for menus and mouseclicks: 2555## 2556############################################################################# 2557 2558 2559############################################################################# 2560## 2561#M InstallPopup(<graph>,<func>) . install function for right click on vertex 2562## 2563## Installs a function that is called if the user clicks with the right 2564## button on a vertex. The function gets as parameters: 2565## poset,vertex,x,y (click position) 2566## 2567InstallMethod( InstallPopup, 2568 "for a graphic graph, and a function", 2569 true, 2570 [ IsGraphicGraphRep, IsFunction ], 2571 0, 2572 2573function(graph, func) 2574 graph!.rightclickfunction := func; 2575end); 2576 2577 2578############################################################################# 2579## 2580#M Menu(<graph>,<title>,<entrylist>,<typelist>,<functionslist>) . . new menu 2581## 2582## This operation already exists in {\XGAP} for GraphicSheets. 2583## Builts a new Menu but with information about the type of the menu entry. 2584## This information describes the relation between the selection state of 2585## the vertices and the parameters supplied to the functions. The following 2586## types are supported: 2587## "forany" : always enabled, generic routines don't change anything 2588## "forone" : enabled iff exactly one vertex is selected 2589## "fortwo" : enabled iff exactly two vertices are selected 2590## "forthree" : enabled iff exactly three vertices are selected 2591## "forsubset" : enabled iff at least one vertex is selected 2592## "foredge" : enabled iff a connected pair of two vertices is selected 2593## "formin2" : enabled iff at least two vertices are selected 2594## "formin3" : enabled iff at least three vertices are selected 2595## The IsMenu object is returned. It is also stored in the sheet. 2596InstallOtherMethod( Menu, 2597 "for a graphic graph, a string, a list of strings, a list of strings, and a list of functions", 2598 true, 2599 [ IsGraphicGraphRep, IsString, IsList, IsList, IsList ], 2600 0, 2601 2602function(graph, title, entrylist, typelist, functionslist) 2603 local l, menu, nr; 2604 2605 l := Filtered([1..Length(entrylist)], 2606 x->IsBound(entrylist[x]) and (entrylist[x][1] <> '-')); 2607 menu := Menu(graph,title,entrylist,functionslist); 2608 Add(graph!.menutypes,typelist{l}); 2609 Add(graph!.menuenabled,List(l,x->true)); 2610 nr := Length(graph!.menuenabled); 2611 2612 ModifyEnabled(graph,nr,nr); 2613 2614 return graph!.menus[nr]; 2615end); 2616 2617 2618############################################################################# 2619## 2620#M ModifyEnabled(<graph>,<from>,<to>) , . . modifies enablednes of entries 2621## 2622## Modifies the "Enabledness" of menu entries according to their type and 2623## number of selected vertices. <from> is the first menu to work on and 2624## <to> the last one (indices). Only IsAlive menus are considered. Returns 2625## nothing. 2626## There are two different methods for graphs and posets: 2627## 2628InstallMethod( ModifyEnabled, 2629 "for a graph, and two integers", 2630 true, 2631 [ IsGraphicGraphRep, IsInt, IsInt ], 2632 0, 2633 2634function(graph, from, to) 2635 local len, i, j, flag; 2636 2637 len := Length(graph!.selectedvertices); 2638 for i in [from..to] do 2639 if IsAlive(graph!.menus[i]) then 2640 for j in [1..Length(graph!.menutypes[i])] do 2641 if graph!.menutypes[i][j] = "forone" then 2642 flag := len = 1; 2643 elif graph!.menutypes[i][j] = "fortwo" then 2644 flag := len = 2; 2645 elif graph!.menutypes[i][j] = "forthree" then 2646 flag := len = 3; 2647 elif graph!.menutypes[i][j] = "forsubset" then 2648 flag := len >= 1; 2649 elif graph!.menutypes[i][j] = "foredge" then 2650 flag := false; 2651 if len = 2 then 2652 if Position(graph!.edges,graph!.selectedvertices) <> fail or 2653 Position(graph!.edges,Reversed(graph!.selectedvertices)) 2654 <> fail then 2655 flag := true; 2656 fi; 2657 fi; 2658 elif graph!.menutypes[i][j] = "formin2" then 2659 flag := len >= 2; 2660 elif graph!.menutypes[i][j] = "formin3" then 2661 flag := len >= 3; 2662 else 2663 flag := true; 2664 fi; 2665 if graph!.menuenabled[i][j] <> flag then 2666 graph!.menuenabled[i][j] := flag; 2667 Enable(graph!.menus[i]!.entries[j],flag); 2668 fi; 2669 od; 2670 fi; 2671 od; 2672end); 2673 2674## Here follows nearly the same but: selected edges are different! 2675InstallMethod( ModifyEnabled, 2676 "for a poset, and two integers", 2677 true, 2678 [ IsGraphicPosetRep, IsInt, IsInt ], 2679 0, 2680 2681function(poset, from, to) 2682 local len, i, j, flag; 2683 2684 len := Length(poset!.selectedvertices); 2685 for i in [from..to] do 2686 if IsAlive(poset!.menus[i]) then 2687 for j in [1..Length(poset!.menutypes[i])] do 2688 if poset!.menutypes[i][j] = "forone" then 2689 flag := len = 1; 2690 elif poset!.menutypes[i][j] = "fortwo" then 2691 flag := len = 2; 2692 elif poset!.menutypes[i][j] = "forthree" then 2693 flag := len = 3; 2694 elif poset!.menutypes[i][j] = "forsubset" then 2695 flag := len >= 1; 2696 elif poset!.menutypes[i][j] = "foredge" then 2697 flag := false; 2698 if len = 2 then 2699 if Position(poset!.selectedvertices[1]!.maximals, 2700 poset!.selectedvertices[2]) <> fail or 2701 Position(poset!.selectedvertices[2]!.maximals, 2702 poset!.selectedvertices[1]) <> fail then 2703 flag := true; 2704 fi; 2705 fi; 2706 elif poset!.menutypes[i][j] = "formin2" then 2707 flag := len >= 2; 2708 elif poset!.menutypes[i][j] = "formin3" then 2709 flag := len >= 3; 2710 else # "forany" 2711 flag := true; 2712 fi; 2713 if poset!.menuenabled[i][j] <> flag then 2714 poset!.menuenabled[i][j] := flag; 2715 Enable(poset!.menus[i],poset!.menus[i]!.entries[j],flag); 2716 fi; 2717 od; 2718 fi; 2719 od; 2720end); 2721 2722 2723############################################################################# 2724## 2725## Methods for actual user interaction: 2726## 2727############################################################################# 2728 2729 2730############################################################################# 2731## 2732#M PosetLeftClick(poset,x,y) . . . . method which is called after left click 2733## 2734## This method is called when the user does a left click in a poset. It lets 2735## the user move, select and deselect vertices or edges. 2736## Edges are selected as pair of vertices. 2737## 2738InstallMethod(PosetLeftClick, 2739 "for a graph, and two integers", 2740 true, 2741 [ IsGraphicGraphRep, IsInt, IsInt ], 2742 0, 2743 2744function(poset,x,y) 2745 2746 local v, lp, lev, cp, cl, list, minx, maxx, storex, storey, v2, 2747 lno, line, limit, box, bx, bw, by, bh; 2748 2749 # is this a click on a vertex? 2750 v := WhichVertex(poset,x,y); 2751 if v <> fail then 2752 2753 # yes! search for level: 2754 lp := v!.levelparam; 2755 lev := poset!.levels[Position(poset!.levelparams,lp)]; 2756 2757 # now we search for the class: 2758 cp := v!.classparam; 2759 cl := lev!.classes[Position(lev!.classparams,cp)]; 2760 2761 # we search for minimum and maximum x coordinates, rel. to mouse: 2762 list := List(cl,v->v!.x); 2763 minx := Minimum(list) - x; 2764 maxx := Maximum(list) - x; 2765 2766 storex := v!.x; 2767 storey := v!.y; 2768 2769 if Drag(poset,x,y,BUTTONS.left, 2770 function(x,y) 2771 if x + minx < VERTEX.radius then 2772 x := VERTEX.radius - minx; 2773 elif x + maxx > poset!.width-VERTEX.radius then 2774 x := poset!.width-VERTEX.radius-maxx; 2775 fi; 2776 if y < lev!.top+VERTEX.radius then 2777 y := lev!.top + VERTEX.radius; 2778 elif y > lev!.top+lev!.height-VERTEX.radius then 2779 y := lev!.top+lev!.height-VERTEX.radius; 2780 fi; 2781 Move(poset,v,x,y-lev!.top); 2782 end) then 2783 for v2 in cl do 2784 if v <> v2 then 2785 Move(poset,v2,v2!.x + v!.x - storex,v2!.y + v!.y - storey); 2786 fi; 2787 od; 2788 # better we redraw: 2789 DoRedraw(poset); 2790 else 2791 DeselectAll(poset); 2792 Select(poset,v,true); 2793 fi; 2794 else # no click on a vertex, so we drag a box: 2795 # if this is a poset then we check if somebody clicked on a level box: 2796 if IsGraphicPosetRep(poset) then 2797 if poset!.showlevels and x < 8 then 2798 lno := First([1..Length(poset!.levelboxes)], 2799 i->([x,y] in poset!.levelboxes[i])); 2800 if lno <> fail then 2801 # user clicked on the levelbox no lno, he can now resize this level 2802 line := Line(poset,0,y,poset!.width,0); 2803 if COLORS.blue <> false then 2804 Recolor(line,COLORS.blue); 2805 fi; 2806 limit := poset!.levels[lno]!.top + VERTEX.diameter; 2807 if Drag(poset,x,y,BUTTONS.left, 2808 function(x,y) 2809 if y < limit then 2810 y := limit; 2811 fi; 2812 Move(line,0,y); 2813 end) then 2814 # the user moved the line! the new y coordinate is the new lower 2815 # limit of the level! 2816 Delete(poset,line); 2817 ResizeLevel(poset,poset!.levelparams[lno],line!.y 2818 - poset!.levels[lno]!.top); 2819 else 2820 Delete(poset,line); 2821 fi; 2822 return; 2823 fi; 2824 fi; 2825 fi; 2826 storex := x; 2827 storey := y; 2828 box := Rectangle(poset,x,y,0,0); 2829 if Drag(poset,x,y,BUTTONS.left, 2830 function(x,y) 2831 local bx,by,bw,bh; 2832 if x < storex then 2833 bx := x; 2834 bw := storex - x; 2835 else 2836 bx := storex; 2837 bw := x - storex; 2838 fi; 2839 if y < storey then 2840 by := y; 2841 bh := storey - y; 2842 else 2843 by := storey; 2844 bh := y - storey; 2845 fi; 2846 if bx <> box!.x or by <> box!.y then 2847 Move(box,bx,by); 2848 fi; 2849 if bw <> box!.w or bh <> box!.h then 2850 Reshape(box,bw,bh); 2851 fi; 2852 end) then 2853 # the box had at one time at least a certain size 2854 if box!.w > 0 and box!.h > 0 then 2855 DeselectAll(poset); 2856 GGSelectModifiesMenu := false; 2857 for lev in poset!.levels do 2858 if lev!.top < box!.y+box!.h and 2859 lev!.top + lev!.height >= box!.y then 2860 for cl in lev!.classes do 2861 for v in cl do 2862 if [v!.x,v!.y+lev!.top] in box then 2863 Select(poset,v,true); 2864 fi; 2865 od; 2866 od; 2867 fi; 2868 od; 2869 GGSelectModifiesMenu := true; 2870 ModifyEnabled(poset,1,Length(poset!.menus)); 2871 fi; 2872 Delete(poset,box); 2873 # better we redraw: 2874 DoRedraw(poset); 2875 else # no moving, so user wants to deselect all vertices 2876 DeselectAll(poset); 2877 ModifyEnabled(poset,1,Length(poset!.menus)); 2878 Delete(poset,box); 2879 fi; # Drag(...) --> true 2880 fi; 2881end); 2882 2883 2884############################################################################# 2885## 2886#M PosetCtrlLeftClick(poset,x,y) . . method which is called after left click 2887## 2888## This operation is called when the user does a left click in a poset while 2889## holding down the control key. It lets the user move, select and deselect 2890## vertices or edges. The difference to the operation without the control 2891## key is, that while selecting the old vertices are NOT deselected. 2892## Moving does not move the whole class but only one vertex. This allows 2893## for permuting the vertices within a class. 2894## Edges are selected as pair of vertices. 2895## 2896InstallMethod(PosetCtrlLeftClick, 2897 "for a graph, and two integers", 2898 true, 2899 [ IsGraphicGraphRep, IsInt, IsInt ], 2900 0, 2901 2902function(poset,x,y) 2903 2904 local v, lp, lev, cp, cl, storex, storey, lno, box, levellen, 2905 pos, bx, bw, by, bh; 2906 2907 # is this a click on a vertex? 2908 v := WhichVertex(poset,x,y); 2909 if v <> fail then 2910 2911 # yes! search for level: 2912 lp := v!.levelparam; 2913 lev := poset!.levels[Position(poset!.levelparams,lp)]; 2914 2915 # now we search for the class: 2916 cp := v!.classparam; 2917 cl := lev!.classes[Position(lev!.classparams,cp)]; 2918 2919 storex := v!.x; 2920 storey := v!.y; 2921 2922 if not Drag(poset,x,y,BUTTONS.left, 2923 function(x,y) 2924 if x < VERTEX.radius then 2925 x := VERTEX.radius; 2926 elif x > poset!.width-VERTEX.radius then 2927 x := poset!.width-VERTEX.radius; 2928 fi; 2929 if y < lev!.top+VERTEX.radius then 2930 y := lev!.top + VERTEX.radius; 2931 elif y > lev!.top+lev!.height-VERTEX.radius then 2932 y := lev!.top+lev!.height-VERTEX.radius; 2933 fi; 2934 Move(poset,v,x,y-lev!.top); 2935 end) then 2936 Select(poset,v,PositionSet(poset!.selectedvertices,v) = fail); 2937 else 2938 # better we redraw: 2939 DoRedraw(poset); 2940 fi; 2941 else # no click on a vertex, so we drag a box: 2942 # if this is a poset then we check if somebody clicked on a level box: 2943 if IsGraphicPosetRep(poset) then 2944 if poset!.showlevels and x < 8 then 2945 lno := First([1..Length(poset!.levelboxes)], 2946 i->([x,y] in poset!.levelboxes[i])); 2947 if lno <> fail then 2948 # user clicked on the levelbox no lno, he can now move this level 2949 box := Box(poset,4,y-8,8,8); 2950 if COLORS.red <> false then 2951 Recolor(box,COLORS.red); 2952 fi; 2953 levellen := Length(poset!.levels); 2954 if Drag(poset,x,y,BUTTONS.left, 2955 function(x,y) 2956 if y < 8 then 2957 y := 8; 2958 elif y > poset!.levels[levellen]!.top 2959 + poset!.levels[levellen]!.height then 2960 y := poset!.levels[levellen]!.top 2961 + poset!.levels[levellen]!.height; 2962 fi; 2963 Move(box,4,y-8); 2964 end) then 2965 # the user moved the box! we have to search in which level lies 2966 # the new y coordinate: 2967 pos := First([levellen,levellen-1..1], 2968 i->box!.y >= poset!.levels[i]!.top); 2969 MoveLevel(poset,poset!.levelparams[lno],pos); 2970 fi; 2971 Delete(poset,box); 2972 return; 2973 fi; 2974 fi; 2975 fi; 2976 storex := x; 2977 storey := y; 2978 box := Rectangle(poset,x,y,0,0); 2979 if Drag(poset,x,y,BUTTONS.left, 2980 function(x,y) 2981 local bx,by,bw,bh; 2982 if x < storex then 2983 bx := x; 2984 bw := storex - x; 2985 else 2986 bx := storex; 2987 bw := x - storex; 2988 fi; 2989 if y < storey then 2990 by := y; 2991 bh := storey - y; 2992 else 2993 by := storey; 2994 bh := y - storey; 2995 fi; 2996 if bx <> box!.x or by <> box!.y then 2997 Move(box,bx,by); 2998 fi; 2999 if bw <> box!.w or bh <> box!.h then 3000 Reshape(box,bw,bh); 3001 fi; 3002 end) then 3003 # the box had at one time at least a certain size 3004 if box!.w > 0 and box!.h > 0 then 3005 GGSelectModifiesMenu := false; 3006 for lev in poset!.levels do 3007 if lev!.top < box!.y+box!.h and 3008 lev!.top + lev!.height >= box!.y then 3009 for cl in lev!.classes do 3010 for v in cl do 3011 if [v!.x,v!.y+lev!.top] in box then 3012 Select(poset,v,true); 3013 fi; 3014 od; 3015 od; 3016 fi; 3017 od; 3018 # better we redraw: 3019 Delete(poset,box); 3020 DoRedraw(poset); 3021 GGSelectModifiesMenu := true; 3022 ModifyEnabled(poset,1,Length(poset!.menus)); 3023 else 3024 Delete(poset,box); 3025 fi; 3026 # Drag(...) --> true 3027 else 3028 Delete(poset,box); 3029 fi; 3030 fi; 3031end); 3032 3033 3034############################################################################# 3035## 3036#M PosetRightClick(graph,x,y) . . . method which is called after right click 3037## 3038## This method is called when the user does a right click in a graph. 3039## This method just finds the vertex under the mouse pointer and calls the 3040## rightclickfunction of the poset. Note that the rightclickfunction 3041## can be called with `fail' if no vertex is hit. 3042## 3043InstallMethod(PosetRightClick, 3044 "for a graph, and two integers", 3045 true, 3046 [ IsGraphicGraphRep, IsInt, IsInt ], 3047 0, 3048 3049function(graph,x,y) 3050 local v; 3051 3052 # is this a click on a vertex? 3053 v := WhichVertex(graph,x,y); 3054 if graph!.rightclickfunction <> false then 3055 graph!.rightclickfunction(graph,v,x,y); 3056 fi; 3057 return; 3058end); 3059 3060 3061############################################################################# 3062## 3063#M UserDeleteVerticesOp . . . is called if the user wants to delete vertices 3064## 3065## This operation is called when the user selects "Delete vertices". 3066## The generic method actually deletes the selected vertices including all 3067## their edges. 3068## 3069InstallMethod( UserDeleteVerticesOp, 3070 "for a graphic poset, a menu, and a menu entry", 3071 true, 3072 [ IsGraphicGraphRep, IsMenu, IsString ], 3073 0, 3074 3075function( graph, menu, entry ) 3076 local v; 3077 3078 # it is guaranteed, that at least one vertex is selected! 3079 while graph!.selectedvertices <> [] do 3080 Delete(graph,graph!.selectedvertices[1]); 3081 od; 3082end); 3083 3084 3085############################################################################# 3086## 3087#M UserDeleteEdgeOp . . . . . is called if the user wants to delete an edge 3088## 3089## This operation is called when the user selects "Delete edge". 3090## The generic method deletes the edge with no further warning! 3091## 3092InstallMethod( UserDeleteEdgeOp, 3093 "for a graphic graph, a menu, and a menu entry", 3094 true, 3095 [ IsGraphicGraphRep, IsMenu, IsString ], 3096 0, 3097 3098function( graph, menu, entry ) 3099 # it is guaranteed, that exactly two connected vertices are selected! 3100 Delete(graph,graph!.selectedvertices[1],graph!.selectedvertices[2]); 3101end); 3102 3103 3104############################################################################# 3105## 3106#M UserMergeClassesOp (<sheet>, <menu>, <entry>) . . . . . . . . . . . . . . 3107## . . . . . . . . . . . . . . is called if the user wants to merge classes 3108## 3109## This operation is called when the user selects `Merge Classes'. 3110## The generic method walks through all levels and merges all classes that 3111## contain a selected vertex. Afterwards `UserRearrangeClasses' is called. 3112## 3113InstallMethod( UserMergeClassesOp, 3114 "for a graphic poset, a menu, and a menu entry", 3115 true, 3116 [ IsGraphicGraphRep and IsGraphicPosetRep, IsMenu, IsString ], 3117 0, 3118 3119function( poset, menu, entry ) 3120 local lps, verts, v, pos, i, level, cps, cpos, cls, j; 3121 3122 # it is guaranteed, that at least one vertex is selected! 3123 # we walk through the selected vertices and sort them according to their 3124 # level parameter: 3125 lps := []; 3126 verts := []; 3127 for v in Selected(poset) do 3128 pos := Position(lps,v!.levelparam); 3129 if pos = fail then 3130 Add(lps,v!.levelparam); 3131 Add(verts,[v]); 3132 else 3133 Add(verts[pos],v); 3134 fi; 3135 od; 3136 3137 # All levels: 3138 for i in [1..Length(lps)] do 3139 # the current level: 3140 level := poset!.levels[Position(poset!.levelparams,lps[i])]; 3141 3142 # Now we collect all classes occuring: 3143 cps := []; 3144 cpos := []; 3145 cls := []; 3146 for v in verts[i] do 3147 pos := Position(cps,v!.classparam); 3148 if pos = fail then 3149 Add(cps,v!.classparam); 3150 pos := Position(level!.classparams,v!.classparam); 3151 Add(cpos,pos); 3152 Add(cls,level!.classes[pos]); 3153 fi; 3154 od; 3155 3156 # now we have a list of classes that should be merged: 3157 # let's move all vertices into the first class: 3158 for j in [2..Length(cls)] do 3159 for v in cls[j] do 3160 v!.classparam := cps[1]; 3161 Add(cls[1],v); 3162 od; 3163 od; 3164 3165 # now we have to delete the other classes (but not their vertices!): 3166 cpos := cpos{[2..Length(cps)]}; 3167 Sort(cpos); 3168 for j in [Length(cpos),Length(cpos)-1..1] do 3169 level!.classes[cpos[j]] := level!.classes[Length(level!.classes)]; 3170 Unbind(level!.classes[Length(level!.classes)]); 3171 level!.classparams[cpos[j]] := 3172 level!.classparams[Length(level!.classparams)]; 3173 Unbind(level!.classparams[Length(level!.classparams)]); 3174 od; 3175 od; 3176 3177 # At last we rearrange those classes: 3178 UserRearrangeClasses( poset, menu, "Rearrange Classes" ); 3179end); 3180 3181 3182############################################################################# 3183## 3184## This is used by the following three methods: 3185## 3186BindGlobal("PosetScaleLattice",function(poset,factorx,factory) 3187 local l, pos, cl, v, newx, newy, diffx, diffy; 3188 3189 FastUpdate(poset,true); 3190 Resize(poset, Int(poset!.width*factorx), Int(poset!.height*factory)); 3191 for l in [1..Length(poset!.levelparams)] do 3192 pos := PositionLevel(poset,poset!.levelparams[l]); 3193 ResizeLevel(poset,poset!.levelparams[l],Int(pos[2]*factory)); 3194 for cl in poset!.levels[l]!.classes do 3195 if cl <> [] then 3196 v := cl[1]; 3197 newx := Int(v!.x*factorx); 3198 newy := Int(v!.y*factory); 3199 diffx := newx - v!.x; 3200 diffy := newy - v!.y; 3201 for v in cl do 3202 Move(poset,v,v!.x + diffx,v!.y + diffy); 3203 od; 3204 fi; 3205 od; 3206 od; 3207 FastUpdate(poset,false); 3208end); 3209 3210 3211############################################################################# 3212## 3213#M UserMagnifyLattice . . . . . . lets the user magnify the graphic lattice 3214## 3215## This operation is called when the user selects "Magnify Lattice". 3216## The generic method scales everything by 144/100 including the sheet, 3217## all heights of levels and positions of vertices. 3218## 3219InstallMethod( UserMagnifyLattice, 3220 "for a graphic poset, a menu, and a string", 3221 true, 3222 [ IsGraphicPosetRep, IsMenu, IsString ], 3223 0, 3224 3225function(poset, menu, entry) 3226 local l, pos, cl, v; 3227 PosetScaleLattice(poset,144/100,144/100); 3228end); 3229 3230 3231############################################################################# 3232## 3233#M UserShrinkLattice . . . . . . . lets the user shrink the graphic lattice 3234## 3235## This operation is called when the user selects "Shrink Lattice". 3236## The generic method scales everything by 100/144 including the sheet, 3237## all heights of levels and positions of vertices. 3238## 3239InstallMethod( UserShrinkLattice, 3240 "for a graphic poset, a menu, and a string", 3241 true, 3242 [ IsGraphicPosetRep, IsMenu, IsString ], 3243 0, 3244 3245function(poset, menu, entry) 3246 local l, pos, cl, v; 3247 PosetScaleLattice(poset,100/144,100/144); 3248end); 3249 3250## 3251## Make a rational number from a string, accept fraction: 3252## 3253BindGlobal("PosetRatString", 3254 function( st ) 3255 local n,d,p; 3256 p := Position( st, '/' ); 3257 if p = fail then 3258 return Int(st); 3259 else 3260 n := Int(st{[1..p-1]}); 3261 d := Int(st{[p+1..Length(st)]}); 3262 if d <> 0 then 3263 return n/d; 3264 else 3265 return infinity; 3266 fi; 3267 fi; 3268 end); 3269 3270## 3271## Extracts two factors out of a string: 3272## 3273BindGlobal("PosetFactorsString", 3274 function( factor ) 3275 local p, x, y; 3276 3277 # find "," 3278 p := Position( factor, ',' ); 3279 if p = fail then 3280 x := PosetRatString(factor); 3281 y := x; 3282 elif p = 1 then 3283 x := 1; 3284 y := PosetRatString(factor{[2..Length(factor)]}); 3285 elif p = Length(factor) then 3286 x := PosetRatString(factor{[1..p-1]}); 3287 y := 1; 3288 else 3289 x := PosetRatString(factor{[1..p-1]}); 3290 y := PosetRatString(factor{[p+1..Length(factor)]}); 3291 fi; 3292 if x <= 0 then x := 1; fi; 3293 if y <= 0 then y := 1; fi; 3294 return [ x, y ]; 3295 end); 3296 3297 3298############################################################################# 3299## 3300#M UserResizeLattice . . . . . . . lets the user resize the graphic lattice 3301## 3302## This operation is called when the user selects "Resize Lattice". 3303## The generic method asks the user for a x and a y factor and scales 3304## everything including the sheet, all heights of levels and positions of 3305## vertices. 3306## 3307InstallMethod( UserResizeLattice, 3308 "for a graphic poset, a menu, and a string", 3309 true, 3310 [ IsGraphicPosetRep, IsMenu, IsString ], 3311 0, 3312 3313function(poset, menu, entry) 3314 local res, fac; 3315 3316 res := Query( Dialog( "OKcancel", "X,Y factors" ) ); 3317 if res = false or 0 = Length(res) then 3318 return; 3319 fi; 3320 fac := PosetFactorsString(res); 3321 if fac[1] <> 1 or fac[2] <> 1 then 3322 PosetScaleLattice(poset,fac[1],fac[2]); 3323 fi; 3324end); 3325 3326 3327############################################################################# 3328## 3329#M UserResizeSheet . . . . . . . . . lets the user resize the graphic sheet 3330## 3331## This operation is called when the user selects "Resize Sheet". 3332## The generic method asks the user for a x and a y pixel number and 3333## changes the width and height of the sheet. No positions of levels and 3334## vertices are changed. If the user asks for trouble he gets it! 3335## 3336InstallMethod( UserResizeSheet, 3337 "for a graphic graph, a menu, and a string", 3338 true, 3339 [ IsGraphicGraphRep, IsMenu, IsString ], 3340 0, 3341 3342function(poset, menu, entry) 3343 local res, pix, oldwidth, t; 3344 res := Query( Dialog( "OKcancel", "New Width,Height" ) ); 3345 if res = false or 0 = Length(res) then 3346 return; 3347 fi; 3348 pix := PosetFactorsString(res); 3349 if pix[1] = 1 then 3350 pix[1] := poset!.width; 3351 fi; 3352 if pix[2] = 1 then 3353 pix[2] := poset!.height; 3354 fi; 3355 3356 oldwidth := poset!.width; 3357 3358 Resize(poset,pix[1],pix[2]); 3359 3360 # we now have to move the texts of levelparameters if it is a poset: 3361 if IsGraphicPosetRep(poset) and poset!.showlevelparams then 3362 for t in [1..Length(poset!.levels)] do 3363 MoveDelta(poset!.lptexts[t],poset!.width-oldwidth,0); 3364 od; 3365 fi; 3366end); 3367 3368 3369############################################################################# 3370## 3371#M UserMoveLattice . . . . . . . . . . . . . lets the user move all vertices 3372## 3373## This operation is called when the user selects "Move Lattice". 3374## The generic method asks the user for a pixel number and 3375## changes the position of all vertices horizontally. No positions of 3376## levels are changed. 3377## 3378InstallMethod( UserMoveLattice, 3379 "for a graphic poset, a menu, and a string", 3380 true, 3381 [ IsGraphicGraphRep and IsGraphicPosetRep, IsMenu, IsString ], 3382 0, 3383 3384function(poset, menu, entry) 3385 local res, pix, l, cl, v; 3386 res := Query( Dialog( "OKcancel", "Move horizontally" ) ); 3387 if res = false or 0 = Length(res) then 3388 return; 3389 fi; 3390 pix := Int(res); 3391 if pix <> 0 then 3392 for l in poset!.levels do 3393 for cl in l!.classes do 3394 for v in cl do 3395 Move(poset,v,v!.x+pix,v!.y); 3396 od; 3397 od; 3398 od; 3399 fi; 3400end); 3401 3402 3403############################################################################# 3404## 3405#M UserChangeLabels . . . . . . . . lets the user change labels of vertices 3406## 3407## This operation is called when the user selects "Change Labels". 3408## The user is prompted for every selected vertex, which label it should 3409## have. 3410## 3411InstallMethod( UserChangeLabels, 3412 "for a graphic graph, a menu, and a string", 3413 true, 3414 [ IsGraphicGraphRep, IsMenu, IsString ], 3415 0, 3416 3417function(graph, menu, entry) 3418 local D, sel, v, res; 3419 3420 D := Dialog("OKcancel", "Label"); 3421 sel := Selected(graph); 3422 for v in sel do 3423 res := Query(D,v!.label); 3424 if res = false then 3425 return; 3426 fi; 3427 if 0 < Length(res) then 3428 Relabel(graph,v,res); 3429 fi; 3430 od; 3431end); 3432 3433 3434############################################################################# 3435## 3436#M UserAverageY . . . . . . . . . average all y positions within all levels 3437## 3438## This operation is called when the user selects ``Average Y Positions''. 3439## In all level the average y coordinate is calculated and all vertices are 3440## moved to this y position. 3441## 3442InstallMethod( UserAverageY, 3443 "for a graphic poset, a menu, and a string", 3444 true, 3445 [ IsGraphicSheet and IsGraphicGraphRep and IsGraphicPosetRep, 3446 IsMenu, IsString ], 3447 0, 3448function( poset, menu, string ) 3449 local lev, av, n, cl, v; 3450 for lev in poset!.levels do 3451 av := 0; 3452 n := 0; 3453 for cl in lev!.classes do 3454 for v in cl do 3455 av := av + v!.y; 3456 n := n + 1; 3457 od; 3458 od; 3459 if n > 0 then 3460 av := QuoInt(av,n); 3461 for cl in lev!.classes do 3462 for v in cl do 3463 Move(poset,v,v!.x,av); 3464 od; 3465 od; 3466 fi; 3467 od; 3468end); 3469 3470 3471############################################################################# 3472## 3473#M UserAverageX . . . . . . . . . . average all x positions of sel. vertices 3474## 3475## This operation is called when the user selects ``Average X Positions''. 3476## The average of all x coordinates of the selected vertices is calculated. 3477## Then all classes with a selected vertex are moved such that the first 3478## selected vertex in this class has the calculated position as x position. 3479## 3480InstallMethod( UserAverageX, 3481 "for a graphic poset, a menu, and a string", 3482 true, 3483 [ IsGraphicSheet and IsGraphicGraphRep and IsGraphicPosetRep, 3484 IsMenu, IsString ], 3485 0, 3486function( poset, menu, string ) 3487 local sel, av, list, v, pair, vertices, diff; 3488 sel := Selected(poset); 3489 # we have at least one selected vertex! 3490 av := 0; 3491 list := []; # we store all levelparam/classparam pairs 3492 for v in sel do 3493 av := av + v!.x; 3494 AddSet(list,[v!.levelparam,v!.classparam]); 3495 od; 3496 av := QuoInt(av,Length(sel)); 3497 3498 FastUpdate(poset,true); 3499 for pair in list do 3500 vertices := Vertices(poset,pair[1],pair[2]); 3501 if vertices <> fail then 3502 v := First(vertices,x->x in sel); 3503 if v <> fail then 3504 diff := av - v!.x; 3505 for v in vertices do 3506 Move(poset,v,v!.x + diff,v!.y); 3507 od; 3508 fi; 3509 fi; 3510 od; 3511 FastUpdate(poset,false); 3512end); 3513 3514 3515############################################################################# 3516## 3517#M UserRearrangesClasses . . . . . . . . . . rearrange vertices within class 3518## 3519## This operation is called when the user selects ``Rearrange Classes''. 3520## All classes with a selected vertex are rearranged: The vertices are 3521## lined up neatly one after the other, sorted according to their current 3522## x position. 3523## 3524InstallMethod( UserRearrangeClasses, 3525 "for a graphic poset, a menu, and a string", 3526 true, 3527 [ IsGraphicSheet and IsGraphicGraphRep and IsGraphicPosetRep, 3528 IsMenu, IsString ], 3529 0, 3530function( poset, menu, string ) 3531 local sel, av, list, v, pair, vlist, xlist, perm, i; 3532 3533 sel := Selected(poset); 3534 # we have at least one selected vertex! 3535 av := 0; 3536 list := []; # we store all levelparam/classparam pairs 3537 for v in sel do 3538 AddSet(list,[v!.levelparam,v!.classparam]); 3539 od; 3540 3541 FastUpdate(poset,true); 3542 for pair in list do 3543 # get the vertices in class: 3544 vlist := Vertices(poset,pair[1],pair[2]); 3545 if vlist <> fail then 3546 xlist := List(vlist,y->y!.x); 3547 perm := Sortex(xlist); 3548 vlist := Permuted(vlist,perm); 3549 for i in [2..Length(vlist)] do 3550 Move(poset,vlist[i],vlist[1]!.x + (i-1)*(VERTEX.diameter+2), 3551 vlist[1]!.y); 3552 od; 3553 fi; 3554 od; 3555 FastUpdate(poset,false); 3556end); 3557 3558 3559############################################################################ 3560## 3561#M UserUseBlackWhite . . . . . . . . . . called if user selects bw in menu 3562## 3563## This is called if the user selects ``Use Black and White'' in the menu. 3564## 3565InstallMethod( UserUseBlackWhite, 3566 "for a graphic graph, a menu, and a string", 3567 true, 3568 [ IsGraphicSheet and IsGraphicGraphRep, IsMenu, IsString ], 3569 0, 3570function( sheet, menu, entry ) 3571 local v; 3572 if sheet!.color.model = "monochrome" then 3573 sheet!.color.model := "color"; 3574 Check(menu,entry,false); 3575 else 3576 sheet!.color.model := "monochrome"; 3577 Check(menu,entry,true); 3578 fi; 3579 GPMakeColors(sheet); 3580 for v in Selected(sheet) do 3581 Recolor(sheet,v,sheet!.color.selected); 3582 od; 3583end); 3584 3585 3586############################################################################# 3587## 3588#M PosetShowLevels . . . . . . . . . . . . . . . . switch display of levels 3589## 3590## This operation is called when the user selects "Show Levels" in the menu. 3591## Switches the display of the little boxes for level handling on and off. 3592## 3593InstallMethod( PosetShowLevels, 3594 "for a graphic poset, a menu, and a menu entry", 3595 true, 3596 [ IsGraphicPosetRep, IsMenu, IsString ], 3597 0, 3598 3599function( poset, menu, entry ) 3600 local b; 3601 poset!.showlevels := not(poset!.showlevels); 3602 if poset!.showlevels then 3603 for b in [1..Length(poset!.levelboxes)] do 3604 Revive(poset!.levelboxes[b]); 3605 Move(poset!.levelboxes[b],0,poset!.levels[b]!.top 3606 +poset!.levels[b]!.height-8); 3607 od; 3608 else 3609 for b in poset!.levelboxes do 3610 Destroy(b); 3611 od; 3612 fi; 3613 Check(menu,entry,poset!.showlevels); 3614end); 3615 3616 3617############################################################################# 3618## 3619#M PosetShowLevelparams . . . . . . . . . switch display of levelparameters 3620## 3621## This operation is called when the user selects "Show Levelparameters" in 3622## the menu. Switches the display of the level parameters at the right of 3623## the screen on and off. 3624## 3625InstallMethod( PosetShowLevelparams, 3626 "for a graphic poset, a menu, and a menu entry", 3627 true, 3628 [ IsGraphicPosetRep, IsMenu, IsString ], 3629 0, 3630 3631function( poset, menu, entry ) 3632 local t; 3633 poset!.showlevelparams := not(poset!.showlevelparams); 3634 if poset!.showlevelparams then 3635 for t in [1..Length(poset!.lptexts)] do 3636 Revive(poset!.lptexts[t]); 3637 Move(poset!.lptexts[t],poset!.lptexts[t]!.x,poset!.levels[t]!.top 3638 +QuoInt(poset!.levels[t]!.height,2)); 3639 od; 3640 else 3641 for t in poset!.lptexts do 3642 Destroy(t); 3643 od; 3644 fi; 3645 Check(menu,entry,poset!.showlevelparams); 3646end); 3647 3648 3649############################################################################# 3650## 3651#M DoRedraw(<graph>). . . . . . . . . . redraws all vertices and connections 3652## 3653## Redraws all vertices and connections. 3654## 3655InstallMethod( DoRedraw, 3656 "for a graphic poset", 3657 true, 3658 [ IsGraphicPosetRep ], 3659 0, 3660 3661function(poset) 3662 local lev, cl, v, v2, pos; 3663 3664 for lev in poset!.levels do 3665 for cl in lev!.classes do 3666 for v in cl do 3667 Draw(v!.obj); 3668 for v2 in v!.maximals do 3669 pos := Position(v!.obj!.connections,v2!.obj); 3670 if pos <> fail then 3671 Draw(v!.obj!.connectingLines[pos]); 3672 fi; 3673 od; 3674 od; 3675 od; 3676 od; 3677end); 3678 3679 3680############################################################################# 3681## 3682## Some things that don't fit in other sections: 3683## 3684############################################################################# 3685 3686## 3687## We want Position and PositionSorted for lists of vertices: 3688## 3689InstallMethod( EQ, "for two vertices", true, [IsGGVertex,IsGGVertex],0, 3690 IsIdenticalObj ); 3691InstallMethod( \<, "for two vertices", true, [IsGGVertex,IsGGVertex],0, 3692 function(a,b) return (a!.serial < b!.serial); end); 3693InstallMethod( EQ, "for two levels", true, [IsGPLevel,IsGPLevel],0, 3694 IsIdenticalObj ); 3695 3696## 3697## ViewObj methods: 3698## 3699InstallMethod( ViewObj,"for a graphic graph",true, 3700 [IsGraphicSheet and IsGraphicSheetRep and IsGraphicGraphRep], 3701 0,function( sheet ) 3702 Print("<"); 3703 if not IsAlive(sheet) then 3704 Print("dead "); 3705 fi; 3706 Print("graphic graph \"",sheet!.name,"\">"); 3707end); 3708 3709InstallMethod( ViewObj,"for a graphic poset",true, 3710 [IsGraphicSheet and IsGraphicSheetRep and IsGraphicGraphRep and 3711 IsGraphicPosetRep], 3712 0,function( sheet ) 3713 Print("<"); 3714 if not IsAlive(sheet) then 3715 Print("dead "); 3716 fi; 3717 Print("graphic poset \"",sheet!.name,"\">"); 3718end); 3719 3720InstallMethod( ViewObj,"for a level",true, 3721 [IsGraphicObject and IsGPLevel], 3722 0,function( level ) 3723 local pos; 3724 pos := Position(level!.poset!.levels,level); 3725 Print("<level of graphic poset \"",level!.poset!.name,"\", Parameter: ", 3726 level!.poset!.levelparams[pos],">"); 3727end); 3728 3729InstallMethod( ViewObj,"for a vertex",true, 3730 [IsGraphicObject and IsGGVertex], 3731 0,function( vertex ) 3732 Print("<vertex of graphic graph, label: \"",vertex!.label,"\", Serial:", 3733 vertex!.serial,">"); 3734end); 3735 3736## FIXME: ... TODO-List for graphs: 3737 3738# comments for GraphicGraphRep 3739# generic Graph Menu with at least Redraw, probably Deletes also 3740#M GraphicGraph( <name>, <width>, <height> ) . . . . . . a new graphic graph 3741#M Vertex(<graph>,<data>[,<inf>]) . . . . . . . . . . . . creates new vertex 3742#M Edge(<graph>,<vertex1>,<vertex2>) . . . . . . . . . . . . adds a new edge 3743#M Edge(<graph>,<vertex1>,<vertex2>,<def>) . . . . . . . . . adds a new edge 3744#M Delete(<graph>,<obj>) . . . . . . . . . . . . . remove something in graph 3745#M Move(<graph>,<vertex>,<x>,<y>) . . . . . . . . . . . . . . . move vertex 3746#M Move(<graph>,<vertex>) . . . . . . . . . . . . . . . . . . . move vertex 3747#M SetWidth(<graph>,<vertex1>,<vertex2>,<width>) . change line width of edge 3748#M SetWidth(<graph>,<vertex1>,<vertex2>) . . . . . change line width of edge 3749#M ChooseLabel(<graph>,<data>,<data>) . . . . is called while edge creation 3750#M ChoosePosition(<graph>,<data>) . . . . . is called while vertex creation 3751#M WhichVertex(<graph>,<x>,<y>) . . . determine vertex in which position is 3752#M WhichVertex(<graph>,<data>) . . . . . determine vertex with data <data> 3753 3754 3755