home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / ipl / gprocs / tieedit.icn < prev    next >
Text File  |  2002-01-24  |  23KB  |  877 lines

  1. ############################################################################
  2. #
  3. #    File:     tieedit.icn
  4. #
  5. #    Subject:  Procedures to create and edit binary arrays
  6. #
  7. #    Authors:  Ralph E. Griswold and Gregg M. Townsend
  8. #
  9. #    Date:     January 19, 2002
  10. #
  11. ############################################################################
  12. #
  13. #   This file is in the public domain.
  14. #
  15. ############################################################################
  16. #
  17. #  This package provides a variety of facilities for creating and
  18. #  editing binary arrays.  It is intended for use with weaving tie-ups
  19. #  and liftplans.
  20. #
  21. ############################################################################
  22. #
  23. #  Requires:  Version 9 graphics, /tmp
  24. #
  25. ############################################################################
  26. #
  27. #  Links: interact, patxform, vdialog, vsetup, dialog, wopen
  28. #
  29. ############################################################################
  30.  
  31. link interact
  32. link patxform
  33. link vdialog
  34. link vsetup
  35. link dialog
  36. link wopen
  37.  
  38. global cellsize
  39. global flip_horiz                # icon for horizontal flip
  40. global flip_left                # icon for left flip
  41. global flip_right                # icon for right flip
  42. global flip_vert                # icon for vertical flip
  43. global grid_height
  44. global grid_pane
  45. global grid_root
  46. global grid_rows
  47. global grid_state
  48. global grid_window
  49. global grid_width
  50. global grid_vidgets
  51. global hbits                    # number of bits horizontally
  52. global hi_horiz                    # highlighted icon for h-flip
  53. global hi_ident                    # highlighted icon for identity
  54. global hi_left                    # highlighted icon for l-flip
  55. global hi_right                    # highlighted icon for r-flip
  56. global hi_rot_180                # highlighted icon for 180 rot
  57. global hi_rot_90                # highlighted icon for 90-rot
  58. global hi_rot_m90                # highlighted icon for -90 rot
  59. global hi_vert                    # highlighted icon for v-flip
  60. global ident                    # icon for identity
  61. global maxsize                    # maximum grid dimensions
  62. global mode                    # pattern/tile display mode
  63. global old_pat                    # old pattern for undo
  64. global rotate_180                # icon for 180-degree rotation
  65. global rotate_90                # icon for 90-degree rotation
  66. global rotate_m90                # icon for -90-degree rotation
  67. global subservient                # application status
  68. global sym_image_current            # current drawing images
  69. global sym_image_next                # next drawing images
  70. global sym_state                # drawing state
  71. global symmet_xpos
  72. global symmet_yoff
  73. global symmetries                # general symmetry state
  74. global tile_touched                # tile modification switch
  75. global vbits                    # number of bits veritcally
  76. global xform_xpos
  77. global xform_ypos
  78.  
  79. $define MaxCell        24            # maximum size of grid cell
  80. $define IconSize     16            # size of button icons
  81. $define MaxPatt         32
  82. $define InfoLength     40            # length of lines in info box
  83.  
  84. record pattrec(tile)
  85.  
  86. procedure copy_tile()
  87.    local output
  88.  
  89.    output := open("/tmp/tieclip", "w") | {
  90.       Notice("Cannot copy tile.")
  91.       fail
  92.       }
  93.  
  94.    write(output, rows2pat(grid_rows))
  95.  
  96.    close(output)
  97.  
  98.    return
  99.  
  100. end
  101.  
  102. #  draw editing grid
  103.  
  104. procedure grid()
  105.    local x, y
  106.  
  107.    EraseArea(grid_pane)
  108.    every x := 0 to hbits * cellsize by cellsize do
  109.       DrawLine(grid_pane, x, 0, x, vbits * cellsize)
  110.    every y := 0 to vbits * cellsize by cellsize do
  111.       DrawLine(grid_pane, 0, y, hbits * cellsize, y)
  112.  
  113.    return
  114.  
  115. end
  116.  
  117. #  editing grid
  118.  
  119. procedure grid_cb(vidget, e)
  120.    local x, y, i, j
  121.    static xpos, ypos
  122.  
  123.    initial {
  124.       xpos := grid_vidgets["grid"].ax
  125.       ypos := grid_vidgets["grid"].ay
  126.       }
  127.  
  128.    if e === (&lpress | &rpress | &ldrag | &rdrag) then {
  129.       j := (&x - xpos) / cellsize
  130.       i := (&y - ypos) / cellsize
  131.       if j < 0 | j >= hbits | i < 0 | i >= vbits then return
  132.  
  133.       if e === (&lpress | &ldrag) then setbit(i, j, "1")
  134.       else setbit(i, j, "0")
  135.  
  136.       tile_touched := 1
  137.       }
  138.  
  139.    return
  140.  
  141. end
  142.  
  143. #  file menu
  144.  
  145. procedure grid_file_cb(vidget, menu)
  146.  
  147.    return case menu[1] of {
  148.       "read  @R"  :  read_tile()
  149.       "open  @O"  :  open_gif()
  150.       "ims   @M"  :  open_ims()
  151.       "write @W"  :  write_tile()
  152.       "copy  @C"  :  copy_tile()
  153.       "paste @P"  :  paste_tile()
  154.       "quit  @Q"  :  return_tile()
  155.       "save  @S"  :  save_image()
  156.       }
  157.  
  158.    return
  159.  
  160. end
  161.  
  162. procedure grid_init()
  163.    local e, i, j, x, y, v, h, input, window_save, atts
  164.    local shift_up, shift_left, shift_right, shift_down, pixmap
  165.    local clear, invert, scramble, trim, enlarge, resize, crop
  166.  
  167.    symmetries := 0                # initially no symmetries
  168.  
  169.    sym_state := [                # initially no symmetries
  170.       [1, -1, -1, -1],
  171.       [-1, -1, -1, -1]
  172.       ]
  173.  
  174.    tile_touched := &null
  175.  
  176. #  Set up vidgets
  177.  
  178.    window_save := &window        # save current subject window
  179.    &window := &null            # clear for new subject
  180.    atts := grid_ui_atts()
  181.    put(atts, "canvas=hidden")
  182.    (WOpen ! atts) | stop("*** can't open drawdown editor window")
  183.    grid_vidgets := grid_ui()
  184.    grid_window := &window
  185.    &window := window_save         # restore previous subject window
  186.  
  187.    grid_root := grid_vidgets["root"]
  188.  
  189.    xform_xpos := grid_vidgets["xform"].ux
  190.    xform_ypos := grid_vidgets["xform"].uy
  191.    grid_width := grid_vidgets["grid"].uw
  192.    grid_height := grid_vidgets["grid"].uh
  193.    maxsize := grid_width / 3
  194.  
  195.    grid_pane := Clone(grid_window, "bg=white", "dx=" || grid_vidgets["grid"].ax,
  196.       "dy=" || grid_vidgets["grid"].ay)
  197.  
  198.    Clip(grid_pane, 0, 0, grid_width, grid_height)
  199.  
  200.    symmet_xpos := grid_vidgets["symregion"].ux
  201.    symmet_yoff := grid_vidgets["symregion"].uy
  202.  
  203.    shift_up := "16,#3ffe6003408141c143e140814081408140814081408140_
  204.       81408160033ffe0000"
  205.    shift_left := "16,#3ffe6003400140014001401140195ffd40194011400140_
  206.       01400160033ffe0000"
  207.    shift_right := "16,#3ffe600340014001400144014c015ffd4c014401400140_
  208.       01400160033ffe0000"
  209.    shift_down := "16,#3ffe60034081408140814081408140814081408143e141_
  210.       c1408160033ffe0000"
  211.    flip_left := "16,#3ffe600340014079403940394049408149014e014e014f_
  212.       01400160033ffe0000"
  213.    flip_right := "16,#3ffe600340014f014e014e014901408140494039403940_
  214.       79400160033ffe0000"
  215.    flip_vert := "16,#3ffe6003408141c143e14081408140814081408143e141_
  216.       c1408160033ffe0000"
  217.    flip_horiz := "16,#3ffe600340014001400144114c195ffd4c194411400140_
  218.       01400160033ffe0000"
  219.    rotate_90 := "16,#3ffe6003400140f141014201420142014f814701420140_
  220.       01400160033ffe0000"
  221.    rotate_m90 := "16,#3ffe600340014781404140214021402140f94071402140_
  222.       01400160033ffe0000"
  223.    rotate_180 := "16,#3ffe6003400141c140214011401140114111432147c143_
  224.       01410160033ffe0000"
  225.    clear := "16,#3ffe600340014001400140014001400140014001400140_
  226.       01400160033ffe0000"
  227.    invert := "16,#3ffe60ff40ff40ff40ff40ff40ff7fff7f817f817f817f_
  228.       817f817f833ffe0000"
  229.    scramble := "16,#3ffe60034c014c0d418d41814001403159b1598140194c_
  230.       194c0160033ffe0000"
  231.    trim := "16,#3ffe60134011407d40394011400140fd48854c857e854c_
  232.       8548fd60033ffe0000"
  233.    enlarge := "16,#3ffe6083418143fd418148815c017efd48854885488548_
  234.       8548fd60033ffe0000"
  235.    resize := "16,#3ffe6093419943fd419948915c017efd488548857e855c_
  236.       8548fd60033ffe0000"
  237.    crop := "16,#3ffe60034011401147fd441144114411441144115ff144_
  238.       01440160033ffe0000"
  239.  
  240.    ident := "16,#3ffe6003400140014001400141c141c141c14001400140_
  241.       01400160033ffe0000"
  242.  
  243.    hi_ident := "16,#00001ffc3ffe3ffe3ffe3ffe3e3e3e3e3e3e3ffe3ffe3f_
  244.       fe3ffe1ffc00000000"
  245.    hi_rot_90 := "16,#00001ffc3ffe3f0e3efe3dfe3dfe3dfe307e38fe3dfe3f_
  246.       fe3ffe1ffc00000000"
  247.    hi_rot_m90 := "16,#00001ffc3ffe387e3fbe3fde3fde3fde3f063f8e3fde3f_
  248.       fe3ffe1ffc00000000"
  249.    hi_rot_180 := "16,#00001ffc3ffe3e3e3fde3fee3fee3fee3eee3cde383e3c_
  250.       fe3efe1ffc00000000"
  251.    hi_right := "16,#00001ffc3ffe30fe31fe31fe36fe3f7e3fb63fc63fc63f_
  252.       863ffe1ffc00000000"
  253.    hi_left := "16,#00001ffc3ffe3f863fc63fc63fb63f7e36fe31fe31fe30_
  254.       fe3ffe1ffc00000000"
  255.    hi_vert := "16,#00001ffc3f7e3e3e3c1e3f7e3f7e3f7e3f7e3f7e3c1e3e_
  256.       3e3f7e1ffc00000000"
  257.    hi_horiz := "16,#00001ffc3ffe3ffe3ffe3bee33e6200233e63bee3ffe3f_
  258.       fe3ffe1ffc00000000"
  259.  
  260.    sym_image_next := [
  261.       [ident, hi_rot_90, hi_rot_m90, hi_rot_180],
  262.       [hi_right, hi_left, hi_vert, hi_horiz]
  263.       ]
  264.    sym_image_current := [
  265.       [hi_ident, rotate_90, rotate_m90, rotate_180],
  266.       [flip_right, flip_left, flip_vert, flip_horiz]
  267.       ]
  268.  
  269. #  now place the images
  270.  
  271.    place(xform_xpos, xform_ypos, 1, 0, shift_up)
  272.    place(xform_xpos, xform_ypos, 0, 1, shift_left)
  273.    place(xform_xpos, xform_ypos, 2, 1, shift_right)
  274.    place(xform_xpos, xform_ypos, 1, 2, shift_down)
  275.    place(xform_xpos, xform_ypos, 0, 4, flip_right)
  276.    place(xform_xpos, xform_ypos, 0, 5, flip_left)
  277.    place(xform_xpos, xform_ypos, 1, 4, flip_vert)
  278.    place(xform_xpos, xform_ypos, 1, 5, flip_horiz)
  279.    place(xform_xpos, xform_ypos, 0, 7, rotate_90)
  280.    place(xform_xpos, xform_ypos, 0, 8, rotate_m90)
  281.    place(xform_xpos, xform_ypos, 1, 7, rotate_180)
  282.    place(xform_xpos, xform_ypos, 0, 10, clear)
  283.    place(xform_xpos, xform_ypos, 1, 10, invert)
  284.    place(xform_xpos, xform_ypos, 2, 10, scramble)
  285.    place(xform_xpos, xform_ypos, 0, 12, trim)
  286.    place(xform_xpos, xform_ypos, 1, 12, enlarge)
  287.    place(xform_xpos, xform_ypos, 2, 12, resize)
  288.    place(xform_xpos, xform_ypos, 0, 14, crop)
  289.  
  290.    place(symmet_xpos, symmet_yoff, 0, 0, hi_ident)
  291.    place(symmet_xpos, symmet_yoff, 1, 0, rotate_90)
  292.    place(symmet_xpos, symmet_yoff, 2, 0, rotate_m90)
  293.    place(symmet_xpos, symmet_yoff, 3, 0, rotate_180)
  294.    place(symmet_xpos, symmet_yoff, 0, 1, flip_right)
  295.    place(symmet_xpos, symmet_yoff, 1, 1, flip_left)
  296.    place(symmet_xpos, symmet_yoff, 2, 1, flip_vert)
  297.    place(symmet_xpos, symmet_yoff, 3, 1, flip_horiz)
  298.  
  299.    VSetState(grid_vidgets["symstate"], "none ")
  300.  
  301.    return
  302.  
  303. end
  304.  
  305. #  keyboard shortcuts
  306.  
  307. procedure grid_shortcuts(e)
  308.  
  309.    if (e === "\r") & \subservient then return_tile()    # subservient role
  310.  
  311.    if &meta then case map(e) of {
  312.       "0"  :  read_rows()
  313.       "1"  :  write_rows()
  314.       "c"  :  copy_tile()
  315.       "i"  :  tile_info()
  316.       "m"  :  open_ims()
  317.       "n"  :  new_tile()
  318.       "o"  :  open_gif()
  319.       "p"  :  paste_tile()
  320.       "q"  :  return_tile()
  321.       "r"  :  read_tile()
  322.       "s"  :  save_image()
  323.       "z"  :  undo_xform()
  324.       "w"  :  write_tile()
  325.       }
  326.  
  327.    return
  328.  
  329. end
  330.  
  331. #  check for valid integers
  332.  
  333. procedure icheck(values)
  334.    local i
  335.  
  336.    every i := !values do
  337.       if not(integer(i)) | (i < 0) then {
  338.          Notice("Invalid value")
  339.          fail
  340.          }
  341.  
  342.    return
  343.  
  344. end
  345.  
  346. procedure new_tile()
  347.  
  348.    case Dialog("New:", ["height", "width"], [*grid_rows, *grid_rows[1]], 3,
  349.       ["Okay", "Cancel"]) of {
  350.          "Cancel"  :  fail
  351.          "Okay"    :   {
  352.             icheck(dialog_value) | fail
  353.             grid_rows := list(dialog_value[1], repl("0", dialog_value[2]))
  354.             tile_touched := 1
  355.             return setup()
  356.             }
  357.       }
  358.  
  359.    return
  360.  
  361. end
  362.  
  363. procedure open_gif()
  364.    local win, ims
  365.  
  366.    repeat {
  367.       if OpenDialog("Open image:") == "Cancel" then fail
  368.       win := WOpen("canvas=hidden", "image=" || dialog_value) | {
  369.          Notice("Cannot open image.")
  370.          next
  371.          }
  372.       ims := Capture(win, "g2")
  373.       WClose(win)
  374.       setup_ims(ims)
  375.       return
  376.       }
  377.  
  378. end
  379.  
  380. procedure open_ims()
  381.    local ims, input
  382.  
  383.    repeat {
  384.       if OpenDialog("Open ims:") == "Cancel" then fail
  385.       input := open(dialog_value) | {
  386.          Notice("Cannot open ims file.")
  387.          next
  388.          }
  389.       ims := read(input)
  390.       close(input)
  391.       setup_ims(ims)
  392.       return
  393.       }
  394.  
  395. end
  396.  
  397. procedure setup_ims(ims)
  398.    local width
  399.  
  400.    grid_rows := []
  401.  
  402.    ims ? {
  403.       width := tab(upto(','))
  404.       while tab(upto(',') + 1)
  405. #     while put(grid_rows, map(move(width), "01", "10"))
  406.       while put(grid_rows, move(width))
  407.       }
  408.  
  409.    setup()
  410.  
  411.    return
  412.  
  413. end
  414.  
  415. procedure paste_tile()
  416.    local input, tile
  417.  
  418.    input := open("/tmp/tieclip") | {
  419.          Notice("Cannot paste tie-up file.")
  420.          fail
  421.          }
  422.  
  423.    tile := read_pattern(input) | {
  424.       Notice("Cannot process matrix.")
  425.       close(input)
  426.       fail
  427.       }
  428.  
  429.    close(input)
  430.  
  431.    grid_rows := pat2rows(tile.tile)
  432.  
  433.    return setup()
  434.  
  435. end
  436.  
  437. #  place icon
  438.  
  439. procedure place(xoff, yoff, col, row, pattern)
  440.  
  441.    DrawImage(grid_window, xoff + col * IconSize, 
  442.      yoff + row * IconSize, pattern)
  443.  
  444.    return
  445.  
  446. end
  447.  
  448. #  read pattern specification
  449.  
  450. procedure read_pattern(file)
  451.    local line
  452.  
  453.    line := readpattline(file) | fail
  454.  
  455.    return pattrec(legaltile(getpatt(line)), getpattnote(line))
  456.  
  457. end
  458.  
  459. #  read and add pattern to tile list
  460.  
  461. procedure read_tile()
  462.    local input, tile
  463.    static file, line
  464.  
  465.    initial line := "1"
  466.  
  467.    repeat {
  468.       if TextDialog("Read tile:", ["file", "line"], [file, line], [60, 4]) ==
  469.          "Cancel" then fail
  470.       input := open(dialog_value[1]) | {
  471.          Notice("Cannot open file.")
  472.          next
  473.          }
  474.       file := dialog_value[1]
  475.       line := (0 < integer(dialog_value[2]))
  476.       every 1 to line - 1 do
  477.          read(input) | {
  478.             Notice("Not that many lines in file.")
  479.             close(input)
  480.             next
  481.             }
  482.       tile := read_pattern(input) | {
  483.          Notice("Cannot process matrix.")
  484.          close(input)
  485.          next
  486.          }
  487.       close(input)
  488.       grid_rows := pat2rows(tile.tile)
  489.       return setup()
  490.       }
  491.  
  492. end
  493.  
  494. #  read and add rows to tile list
  495.  
  496. procedure read_rows()
  497.    local input
  498.    static file
  499.  
  500.    repeat {
  501.       if OpenDialog("Read rows:") == "Cancel" then fail
  502.       input := open(dialog_value) | {
  503.          Notice("Cannot open file.")
  504.          next
  505.          }
  506.       file := dialog_value
  507.       grid_rows := []
  508.       while put(grid_rows, read(input))
  509.       close(input)
  510.       return setup()
  511.       }
  512.  
  513. end
  514.  
  515. procedure return_tile()
  516.  
  517.    grid_state := "Done"
  518.  
  519.    return
  520.  
  521. end
  522.  
  523. procedure save_image()
  524.  
  525.    snapshot(grid_pane)
  526.  
  527.    return
  528.  
  529. end
  530.  
  531. #  set bits of tile
  532.  
  533. procedure setbit(i, j, c)
  534.    local x, y, xu, yu, xv, yv, xt, yt, action
  535.    static xpos, ypos
  536.  
  537.    initial {
  538.       xpos := grid_vidgets["grid"].ax
  539.       ypos := grid_vidgets["grid"].ay
  540.       }
  541.  
  542.    if (symmetries = 0) & (grid_rows[i + 1, j + 1] == c) then return    # optimization
  543.  
  544.    x := j * cellsize + 1        # the selected cell itself
  545.    y := i * cellsize + 1
  546.    xt := i * cellsize + 1
  547.    yt := j * cellsize + 1
  548.  
  549.    i +:= 1                # computational convenience
  550.    j +:= 1
  551.  
  552.    xu := (hbits - j) * cellsize + 1    # opposite cells
  553.    yu := (vbits - i) * cellsize + 1
  554.    xv := (hbits - i) * cellsize + 1
  555.    yv := (vbits - j) * cellsize + 1
  556.  
  557.    action := if c = 1 then FillRectangle else EraseArea
  558.  
  559.    if sym_state[1, 1] = 1 then {        # cell itself
  560.       grid_rows[i, j] := c
  561.       action(grid_pane, x, y, cellsize - 1, cellsize - 1)
  562.       }
  563.    if sym_state[1, 2] = 1 then {        # 90 degrees
  564.       if grid_rows[j, -i] := c then            # may be out of bounds
  565.          action(grid_pane, xv, yt, cellsize - 1, cellsize - 1)
  566.       }
  567.    if sym_state[1, 3] = 1 then {        # -90 degrees
  568.       if grid_rows[-j, i] := c then            # may be out of bounds
  569.          action(grid_pane, xt, yv, cellsize - 1, cellsize - 1)
  570.       }
  571.    if sym_state[1, 4] = 1 then {        # 180 degrees
  572.       grid_rows[-i, -j] := c
  573.       action(grid_pane, xu, yu, cellsize - 1, cellsize - 1)
  574.       }
  575.    if sym_state[2, 1] = 1 then {        # left diagonal
  576.       if grid_rows[j, i] := c then            # may be out of bounds
  577.       action(grid_pane, xt, yt, cellsize - 1, cellsize - 1)
  578.       }
  579.    if sym_state[2, 2] = 1 then {        # right diagonal
  580.       if grid_rows[-j, -i] := c then            # may be out of bounds
  581.       action(grid_pane, xv, yv, cellsize - 1, cellsize - 1)
  582.       }
  583.    if sym_state[2, 3] = 1 then {        # vertical
  584.       grid_rows[-i, j] := c
  585.       action(grid_pane, x, yu, cellsize - 1, cellsize - 1)
  586.       }
  587.    if sym_state[2, 4] = 1 then {        # horizontal
  588.       grid_rows[i, -j] := c
  589.       action(grid_pane, xu, y, cellsize - 1, cellsize - 1)
  590.       }
  591.  
  592.    return
  593.  
  594. end
  595.  
  596. #  set up editing grid and view area
  597.  
  598. procedure setup()
  599.    local i, j
  600.  
  601.    hbits := *grid_rows[1]
  602.    vbits := *grid_rows
  603.  
  604.    if (hbits | vbits) > maxsize then {        # based on cell size >= 3
  605.       Notice("Dimensions too large.")
  606.       fail
  607.       }
  608.  
  609.    if hbits > MaxPatt then mode := &null    # too large for pattern
  610.  
  611.    cellsize := MaxCell                # cell size on window
  612.    cellsize >:= grid_width / (vbits + 4)
  613.    cellsize >:= grid_height / (hbits + 4)
  614.  
  615.    grid()
  616.  
  617.    every i := 1 to hbits do
  618.       every j := 1 to vbits do
  619.          if grid_rows[j, i] == "1" then
  620.             FillRectangle(grid_pane, (i - 1) * cellsize,
  621.                (j - 1) * cellsize, cellsize, cellsize)
  622.  
  623.    return
  624.  
  625. end
  626.  
  627. procedure symstate_cb(vidget, value)
  628.    local row, col
  629.  
  630.    #  Note:  the blanks at the end of these radio-button labels are
  631.    #  for interface formatting.
  632.  
  633.    sym_state := case value of {
  634.       "none "  :  [[1, -1, -1, -1], [-1, -1, -1, -1]]
  635.       "all  "   :  [[1, 1, 1, 1], [1, 1, 1, 1]]
  636.       }
  637.  
  638.    sym_image_next := [
  639.       [ident, hi_rot_90, hi_rot_m90, hi_rot_180],
  640.       [hi_right, hi_left, hi_vert, hi_horiz]
  641.       ]
  642.    sym_image_current := [
  643.       [hi_ident, rotate_90, rotate_m90, rotate_180],
  644.       [flip_right, flip_left, flip_vert, flip_horiz]
  645.       ]
  646.  
  647.    if value == "all  " then sym_image_next :=: sym_image_current
  648.  
  649.    every col := 1 to 4 do
  650.       every row := 1 to 2 do
  651.          place(symmet_xpos, symmet_yoff, col - 1, row - 1,
  652.             sym_image_current[row, col])
  653.    return
  654.  
  655. end
  656.  
  657. #  symmetry buttons
  658.  
  659. procedure symmet_cb(vidget, e)
  660.    local col, row, symcount
  661.  
  662.    if e === (&lpress | &rpress | &mpress) then {
  663.       col := (&x - symmet_xpos) / IconSize + 1
  664.       row := (&y - symmet_yoff) / IconSize + 1
  665.       sym_state[row, col] *:= -1
  666.       sym_image_current[row, col] :=: sym_image_next[row, col]
  667.       place(symmet_xpos, symmet_yoff, col - 1, row - 1,
  668.          sym_image_current[row, col])
  669.       symcount := 0
  670.       every symcount +:= !!sym_state
  671.       if symcount = -8 then
  672.          Notice("No drawing mode enabled; pattern cannot be edited")
  673.       else if (sym_state[1, 1] = 1) & (symcount = -6) then symmetries := 0
  674.       else symmetries := 1
  675.  
  676.       return
  677.       }
  678.  
  679.    fail
  680.  
  681. end
  682.  
  683. #  tile menu
  684.  
  685. procedure tile_cb(vidget, value)
  686.    local result
  687.  
  688.    case value[1] of {
  689.       "new  @N"  :  new_tile()
  690.       "info @I"  :  tile_info()
  691.       }
  692.  
  693.    return
  694.  
  695. end
  696.  
  697. #  show information about tile
  698.  
  699. procedure tile_info()
  700.    local line1, line2, pattern, bits, density
  701.  
  702.    pattern := rows2pat(grid_rows)
  703.    bits := tilebits(grid_rows)
  704.    density := left(bits / real(*grid_rows[1] * *grid_rows), 6)
  705.  
  706.    line1 := left(*grid_rows[1] || "x" || *grid_rows || " b=" || bits || " d=" ||
  707.       density, InfoLength)
  708.    line2 := if *pattern > InfoLength then pattern[1+:(InfoLength - 3)] ||
  709.       "..." else left(pattern, InfoLength)
  710.  
  711.    Notice(line1, line2)
  712.  
  713.    return
  714.  
  715. end
  716.  
  717. #  undo transformation
  718.  
  719. procedure undo_xform()
  720.  
  721.    grid_rows := pat2rows(old_pat)
  722.  
  723.    return setup()
  724.  
  725. end
  726.  
  727. #  write pattern
  728.  
  729. procedure write_tile()
  730.    local output
  731.  
  732.    repeat {
  733.       if SaveDialog("Write pattern") == "Cancel" then fail
  734.       output := open(dialog_value, "w") | {
  735.          Notice("Cannot open file for writing.")
  736.          next
  737.          }
  738.       write(output, rows2pat(grid_rows))
  739.       close(output)
  740.       return
  741.       }
  742.  
  743. end
  744.  
  745. #  write rows
  746.  
  747. procedure write_rows()
  748.    local output
  749.  
  750.    repeat {
  751.       if SaveDialog("Write rows") == "Cancel" then fail
  752.       output := open(dialog_value, "w") | {
  753.          Notice("Cannot open file for writing.")
  754.          next
  755.          }
  756.       every write(output, !grid_rows)
  757.       close(output)
  758.       return
  759.       }
  760.  
  761. end
  762.  
  763. #  handle transformation
  764.  
  765. procedure xform(col, row)
  766.    local result
  767.    static params
  768.  
  769.    tile_touched := 1
  770.  
  771.    return case col of {
  772.       0:   case row of {
  773.          1:   pshift(grid_rows, -1, "h")
  774.          4:   pflip(grid_rows, "r")
  775.          5:   pflip(grid_rows, "l")
  776.          7:   protate(grid_rows, 90)
  777.          8:   protate(grid_rows, -90)
  778.          10:  list(vbits, repl("0", hbits))
  779.          12:  ptrim(grid_rows)
  780.          14:  {
  781.            case Dialog("Crop:", ["left", "right", "top", "bottom"],
  782.               0, 3, ["Okay", "Cancel"]) of {
  783.                  "Cancel":   fail
  784.                   "Okay": {
  785.                      icheck(dialog_value) | fail
  786.                      result := copy(params := dialog_value)
  787.                      push(result, grid_rows)
  788.                      pcrop ! result
  789.                      }
  790.                  }
  791.             }
  792.          default:   fail
  793.          }
  794.       1: case row of {
  795.          0:   pshift(grid_rows, -1, "v")
  796.          2:   pshift(grid_rows, 1, "v")
  797.          4:   pflip(grid_rows, "v")
  798.          5:   pflip(grid_rows, "h")
  799.          7:   protate(grid_rows, 180)
  800.          10:  pinvert(grid_rows)
  801.          12:  {
  802.                case Dialog("Enlarge:", ["left", "right", "top", "bottom"],
  803.                   0, 3, ["Okay", "Cancel"]) of {
  804.                      "Cancel":  fail
  805.                      "Okay":  {
  806.                         icheck(dialog_value) | fail
  807.                         result := copy(params := dialog_value)
  808.                         push(result, grid_rows)
  809.                         pborder ! result
  810.                         }
  811.                     }
  812.                  }
  813.          default:   fail
  814.          }
  815.       2: case row of {
  816.          1:   pshift(grid_rows, 1, "h")
  817.          10:  pscramble(grid_rows, "b")
  818.          12:  {
  819.             case Dialog("Center:", ["width", "height"], [*grid_rows[1], *grid_rows], 
  820.                3, ["Okay", "Cancel"]) of {
  821.                "Cancel":  fail
  822.                "Okay": {
  823.                   icheck(dialog_value) | fail
  824.                   result := copy(params := dialog_value)
  825.                   push(result, grid_rows)
  826.                   pcenter ! result
  827.                     }
  828.                  }
  829.               }
  830.          default:   fail
  831.          }
  832.       default:   fail
  833.       }
  834.  
  835. end
  836.  
  837. #  transformation buttons
  838.  
  839. procedure xform_cb(vidget, e)
  840.    local col, row
  841.  
  842.    if e === (&lpress | &rpress | &mpress) then {
  843.       old_pat := rows2pat(grid_rows)
  844.       col := (&x - xform_xpos) / IconSize
  845.       row := (&y - xform_ypos) / IconSize
  846.       grid_rows := xform(col, row) | fail
  847.       return setup()
  848.       }
  849.  
  850. end
  851.  
  852. #===<<vib:begin>>===    modify using vib; do not remove this marker line
  853. procedure grid_ui_atts()
  854.    return ["size=635,568", "bg=pale gray", "label=Drawdown Editor"]
  855. end
  856.  
  857. procedure grid_ui(win, cbk)
  858. return vsetup(win, cbk,
  859.    ["grid_ui:Sizer:::0,0,635,568:Drawdown Editor",],
  860.    ["file:Menu:pull::0,0,36,21:File",grid_file_cb,
  861.       ["read  @R","open  @O","ims   @M","write @W","copy  @C",
  862.       "paste @P","quit  @Q ","save  @S"]],
  863.    ["line1:Line:::0,22,660,22:",],
  864.    ["symmetries:Label:::22,316,70,13:symmetries",],
  865.    ["symstate:Choice::2:26,384,64,42:",symstate_cb,
  866.       ["all  ","none "]],
  867.    ["tile:Menu:pull::38,0,64,21:Drawdown",tile_cb,
  868.       ["new  @N","info @I"]],
  869.    ["transformations:Label:::5,33,105,13:transformations",],
  870.    ["symregion:Rect:grooved::24,338,68,36:",symmet_cb],
  871.    ["info:Rect:invisible::123,32,251,19:",],
  872.    ["xform:Rect:grooved::32,58,52,244:",xform_cb],
  873.    ["grid:Rect:sunken::123,58,500,500:",grid_cb],
  874.    )
  875. end
  876. #===<<vib:end>>===    end of section maintained by vib
  877.