Microsoft Small Basic

Program Listing:
Embed this in your website
' Shapes Editor 0.8
' Copyright (c) 2012 Nonki Takahashi. All rights reserved.
'
' History :
' 0.8 2012/09/12 Supported re-sizing shapes. (XFZ657-8)
' 0.72 2012/09/11 Bug fixed (pen width). (XFZ657-7)
' 0.71 2012/09/11 Bug fixed (output). Minor change. (XFZ657-6)
' 0.7 2012/09/11 Supported color palette. (XFZ657-5)
' 0.6 2012/09/10 Supported cut menu. (XFZ657-4)
' 0.5 2012/09/09 Changed to add function of moving shapes. (XFZ657-3)
' 0.4 2012/09/09 Changed to add function of selecting shapes. (XFZ657-2)
' 0.3 2012/09/08 Changed to output shape array. (XFZ657-1)
' 0.2 2012/09/07 Bug fixed. Supported offset scale, and angle of shapes. (XFZ657-0)
' 0.1 2012/09/06 Created. (XFZ657)
'
title = "Shapes Editor 0.8"
GraphicsWindow.Title = title
debug = "False"
WQ = Text.GetCharacter(34)
CRLF = Text.GetCharacter(13) + Text.GetCharacter(10)
pw = "1=2;2=4;3=8;4=16;5=0;6=1;"  ' pen width
pen = 1                           ' pen width index
nPen = 6                          ' number of pen width
pwidth = GraphicsWindow.PenWidth
pcolor = GraphicsWindow.PenColor
bcolor = GraphicsWindow.BrushColor
CS_InitPalette()                  ' initialize palette for color slider
DrawMenu()
shape = ""
nShapes = 0
cont = "True"                               ' continue
param = "down=True;move=False;up=False;"    ' wait to click
Mouse_SetHandler()
While cont
  If clicked Then
    SearchClickedObject()
    DoObject()
  Else
    Program.Delay(100)
  EndIf
EndWhile
' end of program

Sub DoMenu
  While Text.StartsWith(obj, "menu")
    i = Text.GetSubTextToEnd(obj, 5)
    obj = ""
    func = menu[i]["func"]
    select = "True"
    ItemSelect()                  ' menu item select
    selecteditem = i
    If func = "cut" Then
      If selectedshape <> "" Then
        Shapes.Remove(shape[selectedshape]["obj"])
        shape["clipboard"] = shape[selectedshape]
        nShapes = nShapes - 1
        For _i = selectedshape To nShapes
          shape[_i] = shape[_i + 1]
        EndFor
      EndIf
    ElseIf func = "rect" Then     ' rectangle
      needClick = "True"          ' in DoShape()
      WaitToClick()               ' to get mxD, myD
      SearchClickedObject()       ' for clicked menu
      If Text.StartsWith(obj, "menu") = "False" Then
        WaitToRelease()           ' to get mxU, myU
        nShapes = nShapes + 1
        obj = "shape" + nShapes
        i = nShapes               ' to set shape[nShapes]
        resize = "False"
        SetShapeData()
        GraphicsWindow.BrushColor = bcolor
        GraphicsWindow.PenWidth = pwidth
        If pwidth > 0 Then
          GraphicsWindow.PenColor = pcolor
        EndIf
        shape[nShapes]["obj"] = Shapes.AddRectangle(w, h)
        Shapes.Move(shape[nShapes]["obj"], xmin, ymin)
      EndIf
    ElseIf func = "ell" Then      ' ellipse
      needClick = "True"          ' in DoShape()
      WaitToClick()               ' wait to click new point
      SearchClickedObject()       ' for menu clicked
      If Text.StartsWith(obj, "menu") = "False" Then
        WaitToRelease()           ' while sizing a rectangle
        nShapes = nShapes + 1
        obj = "shape" + nShapes
        i = nShapes               ' to set shape[nShapes]
        resize = "False"
        SetShapeData()
        GraphicsWindow.BrushColor = bcolor
        GraphicsWindow.PenWidth = pwidth
        If pwidth > 0 Then
          GraphicsWindow.PenColor = pcolor
        EndIf
        shape[nShapes]["obj"] = Shapes.AddEllipse(w, h)
        Shapes.Move(shape[nShapes]["obj"], xmin, ymin)
      EndIf
    ElseIf func = "tri" Then      ' triangle
      needClick = "True"          ' in DoShape()
      WaitToClick()               ' for new point
      SearchClickedObject()       ' for menu clicked
      If Text.StartsWith(obj, "menu") = "False" Then
        up = "True"
        WaitToRelease()           ' while sizing a triangle
        nShapes = nShapes + 1
        obj = "shape" + nShapes
        i = nShapes               ' to set shape[nShapes]
        resize = "False"
        SetShapeData()
        GraphicsWindow.BrushColor = bcolor
        GraphicsWindow.PenWidth = pwidth
        If pwidth > 0 Then
          GraphicsWindow.PenColor = pcolor
        EndIf
        shape[nShapes]["obj"] = Shapes.AddTriangle(x1, y1, x2, y2, x3, y3)
        Shapes.Move(shape[nShapes]["obj"], xmin, ymin)
      EndIf
    ElseIf func = "line" Then     ' line
      needClick = "True"          ' in DoShape()
      WaitToClick()               ' to get mxD, myD
      SearchClickedObject()       ' for menu clicked
      If Text.StartsWith(obj, "menu") = "False" Then
        WaitToRelease()           ' to get mxU, myU
        nShapes = nShapes + 1
        obj = "shape" + nShapes
        i = nShapes               ' to set shape[nShapes]
        resize = "False"
        SetShapeData()
        GraphicsWindow.BrushColor = bcolor
        GraphicsWindow.PenWidth = pwidth
        If pwidth > 0 Then
          GraphicsWindow.PenColor = pcolor
        EndIf
        shape[nShapes]["obj"] = Shapes.AddLine(mxD - xmin, myD - ymin, mxU - xmin, myU - ymin)
        Shapes.Move(shape[nShapes]["obj"], xmin, ymin)
      EndIf
    ElseIf func = "pc" Then   ' pen color
      color = pcolor
      CS_ShowPopup()
      pcolor = color
      DrawMenuItem()
    ElseIf func = "pw" Then   ' pen width
      If pen = nPen Then
        pen = 1
      Else
        pen = pen + 1
      EndIf
      pwidth = pw[pen]
      x = menu[i]["x0"]
      y = menu[i]["y0"]
      size = menu[i]["x1"] - x
      GraphicsWindow.BrushColor = "LightGray"
      GraphicsWindow.FillRectangle(x, y, size, size)
      DrawMenuItem()
    ElseIf func = "bc" Then   ' brush color
      color = bcolor
      CS_ShowPopup()
      bcolor = color
      DrawMenuItem()
    ElseIf func = "save" Then   ' save shapes
      param = "down=False;move=False;up=False;"   ' wait button pushed
      Mouse_SetHandler()
      DumpShapes()
    EndIf
    param = "down=True;move=False;up=False;"    ' wait next obj click
    Mouse_SetHandler()
    i = selecteditem
    select = "False"
    ItemSelect()  ' menu item unselect
  EndWhile
EndSub

Sub DoObject
  ' param obj
  While obj <> ""
    fromMenu = "False"
    DoMenu()
    If obj <> "" Then
      DoShape()
    EndIf
    If obj <> "" Then
      DoPinch()
    EndIf
  EndWhile
EndSub

Sub CalcOppositeVertex
  ' param obj - pinch name
  ' param selectedshape - parent shape index of pinch
  ' param shape[] - shape data
  ' return mxD, myD - fixed vertex
  iPinch = Text.GetSubTextToEnd(obj, 6)
  If shape[selectedshape]["func"] = "line" Then
    iOpposite = 3 - iPinch
    If iOpposite = 1 Then
      mxD = shape[selectedshape]["x"] + shape[selectedshape]["x1"]
      myD = shape[selectedshape]["y"] + shape[selectedshape]["y1"]
    ElseIf iOpposite = 2 Then
      mxD = shape[selectedshape]["x"] + shape[selectedshape]["x2"]
      myD = shape[selectedshape]["y"] + shape[selectedshape]["y2"]
    EndIf
  Else
    iOpposite = 5 - iPinch
    If iOpposite = 1 Then
      mxD = shape[selectedshape]["x"]
      myD = shape[selectedshape]["y"]
    ElseIf iOpposite = 2 Then
      mxD = shape[selectedshape]["x"] + shape[selectedshape]["width"]
      myD = shape[selectedshape]["y"]
    ElseIf iOpposite = 3 Then
      mxD = shape[selectedshape]["x"]
      myD = shape[selectedshape]["y"] + shape[selectedshape]["height"]
    ElseIf iOpposite = 4 Then
      mxD = shape[selectedshape]["x"] + shape[selectedshape]["width"]
      myD = shape[selectedshape]["y"] + shape[selectedshape]["height"]
    EndIf
  EndIf
EndSub

Sub DoPinch
  ' param obj -
  ' param selectedshape - parent shape index of the pinch
  If Text.StartsWith(obj, "pinch") Then
    CalcOppositeVertex()      ' to get mxD, myD
    i = Text.GetSubTextToEnd(obj, 6)
    If shape[selectedshape]["func"] = "tri" Then
      If shape[selectedshape]["y1"] = 0 And (i = 3 Or i = 4) Then
        up = "True"
      ElseIf shape[selectedshape]["y1"] <> 0 And (i = 1 Or i = 2) Then
        up = "True"
      Else
        up = "False"
      EndIf
    EndIf
    WaitToRelease()           ' to get mxU, myU
    i = selectedshape
    select = "False"
    ShapeSelect()             ' remove pinches
    ' selectedshape is broken in ShapeSelect() so use i instead
    resize = "True"
    If shape[i]["func"] = "tri" And up = "False" Then
      y = myD
      myD = myU
      myU = y
    EndIf
    SetShapeData()            ' re-size shape[i]
    iMin = selectedshape      ' to re-size Shapes
    iMax = nShapes            ' to keep z-order of Shapes
    Shapes_Remove()
    scale = 1
    shX = 0
    shY = 0
    Shapes_Add()
    param = "down=True;move=False;up=False;"    ' wait next obj click
    Mouse_SetHandler()
    obj = "shape" + i
    needClick = "True"
  EndIf
EndSub

Sub DoShape
  currentobj = ""
  While Text.StartsWith(obj, "shape")
    If currentobj <> obj Then
      i = Text.GetSubTextToEnd(obj, 6)
      func = shape[i]["func"]
      select = "True"
      ShapeSelect()             ' shows pinches
      currentobj = obj
    EndIf
    If needClick Then           ' after a shape menu selected
      obj = ""
      WaitToClick()             ' wait to click a new positon
      SearchClickedObject()
      needClick = "False"
    EndIf
    If obj = currentobj Then
      WaitToRelease2()          ' for moving a shape
      needClick = "True"
    ElseIf Text.StartsWith(obj, "pinch") = "False" Then
      _shape = selectedshape
      select = "False"
      ShapeSelect()             ' remove pinches
      If obj = "menu2" Then     ' for cut
        selectedshape = _shape  ' keep selected shape index to remove
      EndIf
    EndIf
  EndWhile
EndSub

Sub DrawMenu
  cxMenu = 10
  cyMenu = 10
  sizeMenu = 40
  nMenu = 9
  xMenu = cxMenu
  For i = 1 To nMenu
    yMenu = cyMenu + (i - 1) * (sizeMenu + 2)
    GraphicsWindow.BrushColor = "LightGray"
    GraphicsWindow.FillRectangle(xMenu, yMenu, sizeMenu, sizeMenu)
    menu[i]["x0"] = xMenu
    menu[i]["y0"] = yMenu
    menu[i]["x1"] = xMenu + sizeMenu
    menu[i]["y1"] = yMenu + sizeMenu
    DrawMenuItem()
  EndFor
EndSub

Sub DrawMenuItem
  ' param i - item number
  ' param pwidth - pen width
  ' param pcolor - pen color
  ' param bcolor - brush color
  margin = 4
  x = menu[i]["x0"]
  y = menu[i]["y0"]
  size = menu[i]["x1"] - x
  GraphicsWindow.PenColor = "Black"
  GraphicsWindow.PenWidth = 2
  If i = 1 Then
    menu[i]["func"] = "save"
    GraphicsWindow.BrushColor = "SteelBlue"
    GraphicsWindow.FillRectangle(x + margin, y + margin, size - margin * 2, size - margin * 2)
    GraphicsWindow.BrushColor = "White"
    GraphicsWindow.FillRectangle(x + margin + 4, y + margin, size - (margin + 4) * 2, (size - margin * 2) / 3)
    GraphicsWindow.BrushColor = "Gray"
    GraphicsWindow.FillRectangle(x + margin + 6, y + size - 15, size - (margin + 8) * 2, 15 - margin)
  ElseIf i = 2 Then
    menu[i]["func"] = "cut"
    ' initialize shapes
    Scissors_Init()
    nShapes = Array.GetItemCount(shape)
    ' add shapes
    scale = 0.11
    iMin = 1
    iMax = nShapes
    Shapes_Add()
    x = x + 14
    Shapes_Move()
    x = x - 14
    nShapes = 3
    For t = 0 To 360 * 0.3
      angle = 30 - 30 * Math.Cos(t * Math.Pi / 180)
      Shapes_Rotate()
    EndFor
  ElseIf i = 3 Then
    menu[i]["func"] = "rect"
    GraphicsWindow.DrawRectangle(x + margin, y + margin, size - margin * 2, size - margin * 2)
  ElseIf i = 4 Then
    menu[i]["func"] = "ell"
    GraphicsWindow.DrawEllipse(x + margin, y + margin, size - margin * 2, size - margin * 2)
  ElseIf i = 5 Then
    menu[i]["func"] = "tri"
    x1 = x + size / 2
    y1 = y + margin
    x2 = x + margin
    y2 = y + size - margin
    x3 = x + size - margin
    y3 = y + size - margin
    GraphicsWindow.DrawTriangle(x1, y1, x2, y2, x3, y3)
  ElseIf i = 6 Then
    menu[i]["func"] = "line"
    x1 = x + margin
    y1 = y + margin
    x2 = x + size - margin
    y2 = y + size - margin
    GraphicsWindow.DrawLine(x1, y1, x2, y2)
  ElseIf i = 7 Then
    menu[i]["func"] = "pw"
    GraphicsWindow.PenWidth = pwidth
    x1 = x + margin
    y1 = y + size / 2
    x2 = x + size - margin
    y2 = y + size / 2
    GraphicsWindow.DrawLine(x1, y1, x2, y2)
  ElseIf i = 8 Then
    menu[i]["func"] = "pc"
    margin = 6
    GraphicsWindow.PenWidth = 4
    GraphicsWindow.PenColor = pcolor
    GraphicsWindow.DrawRectangle(x + margin, y + margin, size - margin * 2, size - margin * 2)
  ElseIf i = 9 Then
    menu[i]["func"] = "bc"
    GraphicsWindow.BrushColor = bcolor
    GraphicsWindow.FillRectangle(x + margin, y + margin, size - margin * 2, size - margin * 2)
    GraphicsWindow.PenColor = "Black"
    GraphicsWindow.PenWidth = 2
    GraphicsWindow.DrawRectangle(x + margin, y + margin, size - margin * 2, size - margin * 2)
  EndIf
EndSub

Sub DumpShapes
  Stack.PushValue("local", i)
  buf = "' " + Clock.Date + " " + Clock.Time + " Generated" + CRLF
  buf = buf + "' by " + title + CRLF
  buf = buf + "'" + CRLF
  buf = buf + "' initialize shapes" + CRLF
  buf = buf + "Shapes_Init()" + CRLF
  buf = buf + "' add shapes" + CRLF
  buf = buf + "scale = 1" + CRLF
  buf = buf + "Shapes_Add()" + CRLF
  buf = buf + "angle = 0" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_Init" + CRLF
  buf = buf + " ' return shX, shY - current position of shapes" + CRLF
  buf = buf + " ' return shape - array of shapes" + CRLF
  If nShapes > 0 Then
    xmin = shape[1]["x"]
    ymin = shape[1]["y"]
    xman = shape[1]["x"]
    yman = shape[1]["y"]
  EndIf
  For i = 2 To nShapes
    If shape[i]["x"] < xmin Then
      xmin = shape[i]["x"]
    EndIf
    If shape[i]["y"] < ymin Then
      ymin = shape[i]["y"]
    EndIf
    If xmax < shape[i]["x"] Then
      xmax = shape[i]["x"]
    EndIf
    If ymax < shape[i]["y"] Then
      ymax = shape[i]["y"]
    EndIf
  EndFor
  buf = buf + " shX = " + xmin + " ' x offset" + CRLF
  buf = buf + " shY = " + ymin + " ' y offset" + CRLF
  For i = 1 To nShapes
    If shape[i]["func"] = "rect" Then
      buf = buf + " shape[" + i + "] = " + WQ + "func=rect;"
      buf = buf + "x=" + (shape[i]["x"] - xmin) + ";"
      buf = buf + "y=" + (shape[i]["y"] - ymin) + ";"
      buf = buf + "width=" + shape[i]["width"] + ";"
      buf = buf + "height=" + shape[i]["height"] + ";"
      buf = buf + "bc=" + shape[i]["bc"] + ";"
    ElseIf shape[i]["func"] = "ell" Then
      buf = buf + " shape[" + i + "] = " + WQ + "func=ell;"
      buf = buf + "x=" + (shape[i]["x"] - xmin) + ";"
      buf = buf + "y=" + (shape[i]["y"] - ymin) + ";"
      buf = buf + "width=" + shape[i]["width"] + ";"
      buf = buf + "height=" + shape[i]["height"] + ";"
      buf = buf + "bc=" + shape[i]["bc"] + ";"
    ElseIf shape[i]["func"] = "tri" Then
      buf = buf + " shape[" + i + "] = " + WQ + "func=tri;"
      buf = buf + "x=" + (shape[i]["x"] - xmin) + ";"
      buf = buf + "y=" + (shape[i]["y"] - ymin) + ";"
      buf = buf + "x1=" + shape[i]["x1"] + ";"
      buf = buf + "y1=" + shape[i]["y1"] + ";"
      buf = buf + "x2=" + shape[i]["x2"] + ";"
      buf = buf + "y2=" + shape[i]["y2"] + ";"
      buf = buf + "x3=" + shape[i]["x3"] + ";"
      buf = buf + "y3=" + shape[i]["y3"] + ";"
      buf = buf + "bc=" + shape[i]["bc"] + ";"
    ElseIf shape[i]["func"] = "line" Then
      buf = buf + " shape[" + i + "] = " + WQ + "func=line;"
      buf = buf + "x=" + (shape[i]["x"] - xmin) + ";"
      buf = buf + "y=" + (shape[i]["y"] - ymin) + ";"
      buf = buf + "x1=" + shape[i]["x1"] + ";"
      buf = buf + "y1=" + shape[i]["y1"] + ";"
      buf = buf + "x2=" + shape[i]["x2"] + ";"
      buf = buf + "y2=" + shape[i]["y2"] + ";"
    EndIf
    If shape[i]["pw"] > 0 Then
      buf = buf + "pc=" + shape[i]["pc"] + ";"
    EndIf
    buf = buf + "pw=" + shape[i]["pw"] + ";" + WQ + CRLF
  EndFor
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_Add" + CRLF
  buf = buf + " ' param shape - array of shapes" + CRLF
  buf = buf + " ' param scale" + CRLF
  buf = buf + " ' return shWidth, shHeight - total size of shapes" + CRLF
  buf = buf + " ' return shAngle - current angle of shapes" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", i)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", x)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", y)" + CRLF
  buf = buf + " Shapes_CalcWidthAndHeight()" + CRLF
  buf = buf + " s = scale" + CRLF
  buf = buf + " For i = 1 To nShapes" + CRLF
  buf = buf + " GraphicsWindow.PenWidth = shape[i][" + WQ + "pw" + WQ + "] * s" + CRLF
  buf = buf + " If shape[i][" + WQ + "pw" + WQ + "] > 0 Then" + CRLF
  buf = buf + " GraphicsWindow.PenColor = shape[i][" + WQ + "pc" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If shape[i][" + WQ + "func" + WQ + "] = " + WQ + "rect" + WQ + " Then" + CRLF
  buf = buf + " GraphicsWindow.BrushColor = shape[i][" + WQ + "bc" + WQ + "]" + CRLF
  buf = buf + " x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " width = shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " height = shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " shape[i][" + WQ + "obj" + WQ + "] = Shapes.AddRectangle(width * s, height * s)" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + x * s, shY + y * s)" + CRLF
  buf = buf + " ElseIf shape[i][" + WQ + "func" + WQ + "] = " + WQ + "ell" + WQ + " Then" + CRLF
  buf = buf + " GraphicsWindow.BrushColor = shape[i][" + WQ + "bc" + WQ + "]" + CRLF
  buf = buf + " x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " width = shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " height = shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " shape[i][" + WQ + "obj" + WQ + "] = Shapes.AddEllipse(width * s, height * s)" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + x * s, shY + y * s)" + CRLF
  buf = buf + " ElseIf shape[i][" + WQ + "func" + WQ + "] = " + WQ + "tri" + WQ + " Then" + CRLF
  buf = buf + " GraphicsWindow.BrushColor = shape[i][" + WQ + "bc" + WQ + "]" + CRLF
  buf = buf + " x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " x1 = shape[i][" + WQ + "x1" + WQ + "]" + CRLF
  buf = buf + " y1 = shape[i][" + WQ + "y1" + WQ + "]" + CRLF
  buf = buf + " x2 = shape[i][" + WQ + "x2" + WQ + "]" + CRLF
  buf = buf + " y2 = shape[i][" + WQ + "y2" + WQ + "]" + CRLF
  buf = buf + " x3 = shape[i][" + WQ + "x3" + WQ + "]" + CRLF
  buf = buf + " y3 = shape[i][" + WQ + "y3" + WQ + "]" + CRLF
  buf = buf + " shape[i][" + WQ + "obj" + WQ + "] = Shapes.AddTriangle(x1 * s, y1 * s, x2 * s, y2 * s, x3 * s, y3 * s)" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + x * s, shY + y * s)" + CRLF
  buf = buf + " ElseIf shape[i][" + WQ + "func" + WQ + "] = " + WQ + "line" + WQ + " Then" + CRLF
  buf = buf + " x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " x1 = shape[i][" + WQ + "x1" + WQ + "]" + CRLF
  buf = buf + " y1 = shape[i][" + WQ + "y1" + WQ + "]" + CRLF
  buf = buf + " x2 = shape[i][" + WQ + "x2" + WQ + "]" + CRLF
  buf = buf + " y2 = shape[i][" + WQ + "y2" + WQ + "]" + CRLF
  buf = buf + " shape[i][" + WQ + "obj" + WQ + "] = Shapes.AddLine(x1 * s, y1 * s, x2 * s, y2 * s)" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + x * s, shY + y * s)" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " EndFor" + CRLF
  buf = buf + " shAngle = 0" + CRLF
  buf = buf + " y = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " x = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " i = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_CalcWidthAndHeight" + CRLF
  buf = buf + " ' return nShapes - number of shapes" + CRLF
  buf = buf + " ' return shWidth, shHeight - total size of shapes" + CRLF
  buf = buf + " nShapes = Array.GetItemCount(shape)" + CRLF
  buf = buf + " For i = 1 To nShapes" + CRLF
  buf = buf + " If shape[i][" + WQ + "func" + WQ + "] = " + WQ + "tri" + WQ + " Or shape[i][" + WQ + "func" + WQ + "] = " + WQ + "line" + WQ + " Then" + CRLF
  buf = buf + " xmin = shape[i][" + WQ + "x1" + WQ + "]" + CRLF
  buf = buf + " xmax = shape[i][" + WQ + "x1" + WQ + "]" + CRLF
  buf = buf + " ymin = shape[i][" + WQ + "y1" + WQ + "]" + CRLF
  buf = buf + " ymax = shape[i][" + WQ + "y1" + WQ + "]" + CRLF
  buf = buf + " If shape[i][" + WQ + "x2" + WQ + "] < xmin Then" + CRLF
  buf = buf + " xmin = shape[i][" + WQ + "x2" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If xmax < shape[i][" + WQ + "x2" + WQ + "] Then" + CRLF
  buf = buf + " xmax = shape[i][" + WQ + "x2" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If shape[i][" + WQ + "y2" + WQ + "] < ymin Then" + CRLF
  buf = buf + " ymin = shape[i][" + WQ + "y2" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If ymax < shape[i][" + WQ + "y2" + WQ + "] Then" + CRLF
  buf = buf + " ymax = shape[i][" + WQ + "y2" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If shape[i][" + WQ + "func" + WQ + "] = " + WQ + "tri" + WQ + " Then" + CRLF
  buf = buf + " If shape[i][" + WQ + "x3" + WQ + "] < xmin Then" + CRLF
  buf = buf + " xmin = shape[i][" + WQ + "x3" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If xmax < shape[i][" + WQ + "x3" + WQ + "] Then" + CRLF
  buf = buf + " xmax = shape[i][" + WQ + "x3" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If shape[i][" + WQ + "y3" + WQ + "] < ymin Then" + CRLF
  buf = buf + " ymin = shape[i][" + WQ + "y3" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If ymax < shape[i][" + WQ + "y3" + WQ + "] Then" + CRLF
  buf = buf + " ymax = shape[i][" + WQ + "y3" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " shape[i][" + WQ + "width" + WQ + "] = xmax - xmin" + CRLF
  buf = buf + " shape[i][" + WQ + "height" + WQ + "] = ymax - ymin" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If i = 1 Then" + CRLF
  buf = buf + " shWidth = shape[i][" + WQ + "x" + WQ + "] + shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " shHeight = shape[i][" + WQ + "y" + WQ + "] + shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " Else" + CRLF
  buf = buf + " If shWidth < shape[i][" + WQ + "x" + WQ + "] + shape[i][" + WQ + "width" + WQ + "] Then" + CRLF
  buf = buf + " shWidth = shape[i][" + WQ + "x" + WQ + "] + shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If shHeight < shape[i][" + WQ + "y" + WQ + "] + shape[i][" + WQ + "height" + WQ + "] Then" + CRLF
  buf = buf + " shHeight = shape[i][" + WQ + "y" + WQ + "] + shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " EndFor" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_CalcRotatePos" + CRLF
  buf = buf + " ' param x, y - position of a shape" + CRLF
  buf = buf + " ' param width, height - size of a shape" + CRLF
  buf = buf + " ' param cx, cy - center of shapes" + CRLF
  buf = buf + " ' param shAngle - rotate angle" + CRLF
  buf = buf + " ' return x, y - rotated position of a shape" + CRLF
  buf = buf + " _cx = x + width / 2" + CRLF
  buf = buf + " _cy = y + height / 2" + CRLF
  buf = buf + " x = _cx - cx" + CRLF
  buf = buf + " y = _cy - cy" + CRLF
  buf = buf + " Math_CartesianToPolar()" + CRLF
  buf = buf + " a = a + shAngle" + CRLF
  buf = buf + " x = r * Math.Cos(a * Math.Pi / 180)" + CRLF
  buf = buf + " y = r * Math.Sin(a * Math.Pi / 180)" + CRLF
  buf = buf + " _cx = x + cx" + CRLF
  buf = buf + " _cy = y + cy" + CRLF
  buf = buf + " x = _cx - width / 2" + CRLF
  buf = buf + " y = _cy - height / 2" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_Move" + CRLF
  buf = buf + " ' param shape - array of shapes" + CRLF
  buf = buf + " ' param scale" + CRLF
  buf = buf + " ' param x, y - position to move" + CRLF
  buf = buf + " ' return shX, shY - new position of shapes" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", i)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", x)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", y)" + CRLF
  buf = buf + " shX = x" + CRLF
  buf = buf + " shY = y" + CRLF
  buf = buf + " For i = 1 To nShapes" + CRLF
  buf = buf + " _x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " _y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " width = shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " height = shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " Shapes_CalcRotatePos()" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + _x * s, shY + _y * s)" + CRLF
  buf = buf + " EndFor" + CRLF
  buf = buf + " y = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " x = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " i = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_Remove" + CRLF
  buf = buf + " ' param shape - array of shapes" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", i)" + CRLF
  buf = buf + " For i = 1 To nShapes" + CRLF
  buf = buf + " Shapes.Remove(shape[i][" + WQ + "obj" + WQ + "])" + CRLF
  buf = buf + " EndFor" + CRLF
  buf = buf + " i = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Shapes_Rotate" + CRLF
  buf = buf + " ' param shape - array of shapes" + CRLF
  buf = buf + " ' param scale" + CRLF
  buf = buf + " ' param angle" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", i)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", x)" + CRLF
  buf = buf + " Stack.PushValue(" + WQ + "local" + WQ + ", y)" + CRLF
  buf = buf + " s = scale" + CRLF
  buf = buf + " shAngle = angle" + CRLF
  buf = buf + " cx = shWidth / 2" + CRLF
  buf = buf + " cy = shHeight / 2" + CRLF
  buf = buf + " For i = 1 To nShapes" + CRLF
  buf = buf + " x = shape[i][" + WQ + "x" + WQ + "]" + CRLF
  buf = buf + " y = shape[i][" + WQ + "y" + WQ + "]" + CRLF
  buf = buf + " width = shape[i][" + WQ + "width" + WQ + "]" + CRLF
  buf = buf + " height = shape[i][" + WQ + "height" + WQ + "]" + CRLF
  buf = buf + " Shapes_CalcRotatePos()" + CRLF
  buf = buf + " Shapes.Move(shape[i][" + WQ + "obj" + WQ + "], shX + x * s, shY + y * s)" + CRLF
  buf = buf + " Shapes.Rotate(shape[i][" + WQ + "obj" + WQ + "], shAngle)" + CRLF
  buf = buf + " EndFor" + CRLF
  buf = buf + " y = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " x = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + " i = Stack.PopValue(" + WQ + "local" + WQ + ")" + CRLF
  buf = buf + "EndSub" + CRLF
  buf = buf + CRLF
  buf = buf + "Sub Math_CartesianToPolar" + CRLF
  buf = buf + " ' param x, y - cartesian coordinate" + CRLF
  buf = buf + " ' return r, a - polar coordinate" + CRLF
  buf = buf + " r = Math.SquareRoot(x * x + y * y)" + CRLF
  buf = buf + " If x = 0 And y > 0 Then" + CRLF
  buf = buf + " a = 90 ' [degree]" + CRLF
  buf = buf + " ElseIf x = 0 And y < 0 Then" + CRLF
  buf = buf + " a = -90" + CRLF
  buf = buf + " Else" + CRLF
  buf = buf + " a = Math.ArcTan(y / x) * 180 / Math.Pi" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + " If x < 0 Then" + CRLF
  buf = buf + " a = a + 180" + CRLF
  buf = buf + " ElseIf x > 0 And y < 0 Then" + CRLF
  buf = buf + " a = a + 360" + CRLF
  buf = buf + " EndIf" + CRLF
  buf = buf + "EndSub" + CRLF
  File_Save()
  i = Stack.PopValue("local")
EndSub

Sub ItemSelect
  ' i - menu index
  ' select - "True" if selected
  If select Then
    GraphicsWindow.PenColor = "Gray"
  Else
    GraphicsWindow.PenColor = "White"
  EndIf
  GraphicsWindow.PenWidth = 2
  x = menu[i]["x0"] - 1
  y = menu[i]["y0"] - 1
  width = menu[i]["x1"] - x + 1
  height = menu[i]["y1"] - y + 1
  GraphicsWindow.DrawRectangle(x, y, width, height)
EndSub

Sub SearchClickedObject
  ' return obj - name of object (menu, shape or pinch)
  Stack.PushValue("local", i)
  obj = ""
  For i = 1 To nPinch
    If pinch[i]["x0"] <= mxD And mxD <= pinch[i]["x1"] And pinch[i]["y0"] <= myD And myD <= pinch[i]["y1"] Then
      obj = "pinch" + i
      Goto sco_exit
    EndIf
  EndFor
  For i = 1 To nMenu
    If menu[i]["x0"] <= mxD And mxD <= menu[i]["x1"] And menu[i]["y0"] <= myD And myD <= menu[i]["y1"] Then
      obj = "menu" + i
      Goto sco_exit
    EndIf
  EndFor
  For i = nShapes To 1 Step -1
    _x0 = shape[i]["x"]
    _x1 = shape[i]["x"] + shape[i]["width"]
    _y0 = shape[i]["y"]
    _y1 = shape[i]["y"] + shape[i]["height"]
    If _x0 <= mxD And mxD <= _x1 And _y0 <= myD And myD <= _y1 Then
      If shape[i]["func"] = "rect" Then
        obj = "shape" + i
        Goto sco_exit
      ElseIf shape[i]["func"] = "ell" Then
        width = shape[i]["width"]
        height = shape[i]["height"]
        x = (mxD - (_x0 + width / 2)) / width * 2
        y = (myD - (_y0 + height / 2)) / height * 2
        r = Math.SquareRoot(x * x + y * y)
        If r <= 1 Then
          obj = "shape" + i
          Goto sco_exit
        EndIf
      ElseIf shape[i]["func"] = "tri" Then
        width = shape[i]["width"]
        height = shape[i]["height"]
        x = (mxD - (_x0 + width / 2)) / width * 2
        If shape[i]["y1"] = 0 Then
          y = (myD - _y1) / height
          r = Math.Abs(x) + Math.Abs(y)
          If r <= 1 And y <= 0 Then
            obj = "shape" + i
            Goto sco_exit
          EndIf
        Else
          y = (myD - _y0) / height
          r = Math.Abs(x) + Math.Abs(y)
          If r <= 1 And y >= 0 Then
            obj = "shape" + i
            Goto sco_exit
          EndIf
        EndIf
      ElseIf shape[i]["func"] = "line" Then
        _x1 = _x0 + shape[i]["x1"]
        _y1 = _y0 + shape[i]["y1"]
        _x2 = _x0 + shape[i]["x2"]
        _y2 = _y0 + shape[i]["y2"]
        r1 = Math.SquareRoot(Math.Power(_x1 - mxD, 2) + Math.Power(_y1 - myD, 2))
        r2 = Math.SquareRoot(Math.Power(_x2 - mxD, 2) + Math.Power(_y2 - myD, 2))
        r = Math.SquareRoot(Math.Power(_x2 - _x1, 2) + Math.Power(_y2 - _y1, 2))
        If r1 + r2 <= (r * 1.0001) Then
          obj = "shape" + i
          Goto sco_exit
        EndIf
      EndIf
    EndIf
  EndFor
  sco_exit:
  i = Stack.PopValue("local")
EndSub

Sub SetShapeData
  ' param i - index of shapes
  ' param resize - "True" then following 4 params ignored
  ' param func - "rect", "ell", "tri" or "line"
  ' param pwidth - pen width
  ' param pcolor - pen color
  ' param bcolor - brush color
  ' param mxD, myD - fixed vertex
  ' param mxU, myU - opposite vertex
  ' return shape[iShapes]
  If resize = "False" Then
    shape[i]["func"] = func
    shape[i]["pw"] = pwidth
    If pwidth > 0 Then
      shape[i]["pc"] = pcolor
    Else
      shape[i]["pc"] = ""
    EndIf
    If func <> "line" Then   ' rectangle, ellipse or triangle
      shape[i]["bc"] = bcolor
    EndIf
  Endif
  xmin = Math.Min(mxD, mxU)
  ymin = Math.Min(myD, myU)
  xmax = Math.Max(mxD, mxU)
  ymax = Math.Max(myD, myU)
  w = xmax - xmin
  h = ymax - ymin
  shape[i]["x"] = xmin
  shape[i]["y"] = ymin
  shape[i]["width"] = w
  shape[i]["height"] = h
  If func = "line" Then                   ' line
    shape[i]["x1"] = mxD - xmin
    shape[i]["y1"] = myD - ymin
    shape[i]["x2"] = mxU - xmin
    shape[i]["y2"] = myU - ymin
  ElseIf func = "tri" Then                ' triangle
    xt = Math.Floor((xmax - xmin) / 2)    ' x top
    If myU <= myD Then
      x1 = xt
      y1 = h
      x2 = 0
      y2 = 0
      x3 = w
      y3 = 0
    ElseIf myD < myU Then
      x1 = xt
      y1 = 0
      x2 = 0
      y2 = h
      x3 = w
      y3 = h
    EndIf
    shape[i]["x1"] = x1
    shape[i]["y1"] = y1
    shape[i]["x2"] = x2
    shape[i]["y2"] = y2
    shape[i]["x3"] = x3
    shape[i]["y3"] = y3
  EndIf
EndSub

Sub ShapeSelect
  ' i - shape index
  ' select - "True" if selected
  If select Then
    GraphicsWindow.PenColor = "Black"
    GraphicsWindow.PenWidth = 1
    sizePinch = 10
    selectedshape = i
    If shape[i]["func"] = "line" Then
      GraphicsWindow.BrushColor = "Lime"
      _x1 = shape[i]["x"] + shape[i]["x1"] - sizePinch / 2
      _y1 = shape[i]["y"] + shape[i]["y1"] - sizePinch / 2
      _x2 = shape[i]["x"] + shape[i]["x2"] - sizePinch / 2
      _y2 = shape[i]["y"] + shape[i]["y2"] - sizePinch / 2
      oEll1 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll1, _x1, _y1)
      oEll2 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll2, _x2, _y2)
      nPinch = 2
      pinch[1]["x0"] = _x1
      pinch[1]["y0"] = _y1
      pinch[1]["x1"] = _x1 + sizePinch
      pinch[1]["y1"] = _y1 + sizePinch
      pinch[2]["x0"] = _x2
      pinch[2]["y0"] = _y2
      pinch[2]["x1"] = _x2 + sizePinch
      pinch[2]["y1"] = _y2 + sizePinch
    Else
      GraphicsWindow.BrushColor = "#639AE7"
      _x1 = shape[i]["x"] - sizePinch / 2
      _y1 = shape[i]["y"] - sizePinch / 2
      _x2 = shape[i]["x"] + shape[i]["width"] - sizePinch / 2
      _y2 = shape[i]["y"] + shape[i]["height"] - sizePinch / 2
      oEll1 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll1, _x1, _y1)
      oEll2 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll2, _x2, _y1)
      oEll3 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll3, _x1, _y2)
      oEll4 = Shapes.AddEllipse(sizePinch, sizePinch)
      Shapes.Move(oEll4, _x2, _y2)
      nPinch = 4
      pinch[1]["x0"] = _x1
      pinch[1]["y0"] = _y1
      pinch[1]["x1"] = _x1 + sizePinch
      pinch[1]["y1"] = _y1 + sizePinch
      pinch[2]["x0"] = _x2
      pinch[2]["y0"] = _y1
      pinch[2]["x1"] = _x2 + sizePinch
      pinch[2]["y1"] = _y1 + sizePinch
      pinch[3]["x0"] = _x1
      pinch[3]["y0"] = _y2
      pinch[3]["x1"] = _x1 + sizePinch
      pinch[3]["y1"] = _y2 + sizePinch
      pinch[4]["x0"] = _x2
      pinch[4]["y0"] = _y2
      pinch[4]["x1"] = _x2 + sizePinch
      pinch[4]["y1"] = _y2 + sizePinch
    EndIf
  Else
    selectedshape = ""
    If shape[i]["func"] = "line" Then
      Shapes.Remove(oEll1)
      Shapes.Remove(oEll2)
      nPinch = 0
    Else
      Shapes.Remove(oEll1)
      Shapes.Remove(oEll2)
      Shapes.Remove(oEll3)
      Shapes.Remove(oEll4)
      nPinch = 0
    EndIf
  EndIf
EndSub

Sub WaitToClick
  ' return mxD, myD - clicked point
  param = "down=True;move=False;up=False;"    ' wait to click
  Mouse_SetHandler()
  While clicked = "False"
    Program.Delay(100)
  EndWhile
EndSub

Sub WaitToRelease  ' for sizing a shape
  ' param mxD, myD - fixed vertex of a shape
  ' param up - "True" if up side is top for triangle
  ' return mxU, myU - opposite vertex of a shape
  GraphicsWindow.PenWidth = 1
  GraphicsWindow.PenColor = "Black"
  GraphicsWindow.BrushColor = "White"
  param = "down=False;move=True;up=True;"   ' for sizing a shape / wait to release
  Mouse_SetHandler()
  While released = "False"
    If moved Then
      param = "move=False;"   ' while sizing a shape
      Mouse_SetHandler()
      If func = "rect" Then
        If oRect <> "" Then
          Shapes.Remove(oRect)
        EndIf
        xmin = Math.Min(mxD, mxM)
        ymin = Math.Min(myD, myM)
        xmax = Math.Max(mxD, mxM)
        ymax = Math.Max(myD, myM)
        oRect = Shapes.AddRectangle(xmax - xmin, ymax - ymin)
        Shapes.Move(oRect, xmin, ymin)
        Shapes.SetOpacity(oRect, 50)
      ElseIf func = "ell" Then
        If oEll <> "" Then
          Shapes.Remove(oEll)
        EndIf
        xmin = Math.Min(mxD, mxM)
        ymin = Math.Min(myD, myM)
        xmax = Math.Max(mxD, mxM)
        ymax = Math.Max(myD, myM)
        oEll = Shapes.AddEllipse(xmax - xmin, ymax - ymin)
        Shapes.Move(oEll, xmin, ymin)
        Shapes.SetOpacity(oEll, 50)
      ElseIf func = "tri" Then
        If oTri <> "" Then
          Shapes.Remove(oTri)
        EndIf
        If up Then
          oTri = Shapes.AddTriangle((mxM - mxD) / 2, 0, 0, myM - myD, mxM - mxD, myM - myD)
        Else
          oTri = Shapes.AddTriangle((mxM - mxD) / 2, myM - myD, 0, 0, mxM - mxD, 0)
        EndIf
        Shapes.Move(oTri, mxD, myD)
        Shapes.SetOpacity(oTri, 50)
      ElseIf func = "line" Then
        If oLine <> "" Then
          Shapes.Remove(oLine)
        EndIf
        oLine = Shapes.AddLine(mxD, myD, mxM, myM)
        Shapes.SetOpacity(oLine, 50)
      EndIf
      param = "move=True;"        ' for next sizing a shape
      Mouse_SetHandler()
    Else
      Program.Delay(100)
    EndIf
  EndWhile
  param = "move=False;up=False;"  ' mouse released
  Mouse_SetHandler()
  If oRect <> "" Then
    Shapes.Remove(oRect)
    oRect = ""
  EndIf
  If oEll <> "" Then
    Shapes.Remove(oEll)
    oEll = ""
  EndIf
  If oTri <> "" Then
    Shapes.Remove(oTri)
    oTri = ""
  EndIf
  If oLine <> "" Then
    Shapes.Remove(oLine)
    oLine = ""
  EndIf
EndSub

Sub WaitToRelease2 ' for moving a shape
  GraphicsWindow.PenWidth = 1
  GraphicsWindow.PenColor = "Black"
  GraphicsWindow.BrushColor = "White"
  param = "down=False;move=True;up=True;"   ' for moving a shape / wait to release
  Mouse_SetHandler()
  _x = shape[i]["x"]
  _y = shape[i]["y"]
  While released = "False"
    If moved Then
      param = "move=False;"   ' while moving a shape
      Mouse_SetHandler()
      _x = shape[i]["x"] + mxM - mxD
      _y = shape[i]["y"] + myM - myD
      If func = "rect" Then
        If oRect = "" Then
          oRect = Shapes.AddRectangle(shape[i]["width"], shape[i]["height"])
          Shapes.SetOpacity(oRect, 50)
        EndIf
        Shapes.Move(oRect, _x, _y)
      ElseIf func = "ell" Then
        If oEll = "" Then
          oEll = Shapes.AddEllipse(shape[i]["width"], shape[i]["height"])
          Shapes.SetOpacity(oEll, 50)
        EndIf
        Shapes.Move(oEll, _x, _y)
      ElseIf func = "tri" Then
        If oTri = "" Then
          _x1 = shape[i]["x1"]
          _y1 = shape[i]["y1"]
          _x2 = shape[i]["x2"]
          _y2 = shape[i]["y2"]
          _x3 = shape[i]["x3"]
          _y3 = shape[i]["y3"]
          oTri = Shapes.AddTriangle(_x1, _y1, _x2, _y2, _x3, _y3)
          Shapes.SetOpacity(oTri, 50)
        EndIf
        Shapes.Move(oTri, _x, _y)
      ElseIf func = "line" Then
        If oLine = "" Then
          _x1 = shape[i]["x1"]
          _y1 = shape[i]["y1"]
          _x2 = shape[i]["x2"]
          _y2 = shape[i]["y2"]
          oLine = Shapes.AddLine(_x1, _y1, _x2, _y2)
          Shapes.SetOpacity(oLine, 50)
        EndIf
        Shapes.Move(oLine, _x, _y)
      EndIf
      param = "move=True;"   ' for next moving a shape
      Mouse_SetHandler()
    Else
      Program.Delay(100)
    EndIf
  EndWhile
  param = "move=False;up=False;"   ' mouse released
  Mouse_SetHandler()
  shape[i]["x"] = _x
  shape[i]["y"] = _y
  Shapes.Move(shape[i]["obj"], _x, _y)
  If shape[i]["func"] = "line" Then
    _x1 = shape[i]["x"] + shape[i]["x1"] - sizePinch / 2
    _y1 = shape[i]["y"] + shape[i]["y1"] - sizePinch / 2
    _x2 = shape[i]["x"] + shape[i]["x2"] - sizePinch / 2
    _y2 = shape[i]["y"] + shape[i]["y2"] - sizePinch / 2
    Shapes.Move(oEll1, _x1, _y1)
    Shapes.Move(oEll2, _x2, _y2)
  Else
    _x1 = shape[i]["x"] - sizePinch / 2
    _y1 = shape[i]["y"] - sizePinch / 2
    _x2 = shape[i]["x"] + shape[i]["width"] - sizePinch / 2
    _y2 = shape[i]["y"] + shape[i]["height"] - sizePinch / 2
    Shapes.Move(oEll1, _x1, _y1)
    Shapes.Move(oEll2, _x2, _y1)
    Shapes.Move(oEll3, _x1, _y2)
    Shapes.Move(oEll4, _x2, _y2)
  EndIf
  If oRect <> "" Then
    Shapes.Remove(oRect)
    oRect = ""
  EndIf
  If oEll <> "" Then
    Shapes.Remove(oEll)
    oEll = ""
  EndIf
  If oTri <> "" Then
    Shapes.Remove(oTri)
    oTri = ""
  EndIf
  If oLine <> "" Then
    Shapes.Remove(oLine)
    oLine = ""
  EndIf
EndSub

Sub Color_ColorToRGB
  ' Color | Convert Color to RGB
  ' param sColor - "#rrggbb"
  ' return iR, iG, iB - [0, 255]
  sR = Text.GetSubText(sColor, 2, 2)
  sG = Text.GetSubText(sColor, 4, 2)
  sB = Text.GetSubText(sColor, 6, 2)
  sHex = sR
  Math_Hex2Dec()
  iR = iDec
  sHex = sG
  Math_Hex2Dec()
  iG = iDec
  sHex = sB
  Math_Hex2Dec()
  iB = iDec
EndSub

Sub Color_HSLtoRGB
  ' Color | Convert HSL to RGB
  ' param rHue - [0, 360) or UNDEFINED
  ' param rLightness - [0, 1]
  ' param rSaturation - [0, 1]
  ' return iR, iG, iB - RGB color
  ' return sColor - "#rrggbb"
  If rLightness <= 0.5 Then
    rN2 = rLightness * (1 + rSaturation)
  Else
    rN2 = rLightness + rSaturation - rLightness * rSaturation
  EndIf
  rN1 = 2 * rLightness - rN2
  If rSaturation = 0 Then
    iR = Math.Round(rLightness * 255)
    iG = Math.Round(rLightness * 255)
    iB = Math.Round(rLightness * 255)
  Else
    rH = rHue + 120
    Color_Value()
    iR = iValue
    rH = rHue
    Color_Value()
    iG = iValue
    rH = rHue - 120
    Color_Value()
    iB = iValue
  EndIf
  sColor = GraphicsWindow.GetColorFromRGB(iR, iG, iB)
EndSub

Sub Color_RGBtoHSL
  ' Color | Convert RGB to HSL
  ' param sColor - "#rrggbb"
  ' return rHue - [0, 360) or UNDEFINED
  ' return rLightness - (0, 1)
  ' return rSaturation - (0, 1)
  Color_ColorToRGB()
  ' rR = iR / 255 ' occurs Math.Max() bug
  rR = Math.Round(iR / 255 * 10000) / 10000
  ' rG = iG / 255 ' occurs Math.Max() bug
  rG = Math.Round(iG / 255 * 10000) / 10000
  ' rB = iB / 255 ' occurs Math.Max() bug
  rB = Math.Round(iB / 255 * 10000) / 10000
  rMax = Math.Max(rR, rG)
  rMax = Math.Max(rMax, rB)
  rMin = Math.Min(rR, rG)
  rMin = Math.Min(rMin, rB)
  rLightness = (rMax + rMin) / 2
  If rMax = rMin Then ' rR = rG = rB
    rSaturation = 0
    rHue = UNDEFINED
  Else
    If rLightness <= 0.5 Then
      rSaturation = (rMax - rMin) / (rMax + rMin)
    Else
      rSaturation = (rMax - rMin) / (2 - rMax - rMin)
    EndIf
    rRC = (rMax - rR) / (rMax - rMin)
    rGC = (rMax - rG) / (rMax - rMin)
    rBC = (rMax - rB) / (rMax - rMin)
    If rR = rMax Then     ' between Yellow and Magenta
      rHue = rBC - rGC
    ElseIf rG = rMax Then ' between Cyan and Yellow
      rHue = 2 + rRC - rBC
    ElseIf rB = rMax Then ' between Magenta and Cyan
      rHue = 4 + rGC - rRC
    Else
      TextWindow.WriteLine("Error:")
      TextWindow.WriteLine("rMax=" + rMax)
      TextWindow.WriteLine("rR=" + rR + ",sR=" + sR)
      TextWindow.WriteLine("rG=" + rG + ",sG=" + sG)
      TextWindow.WriteLine("rB=" + rB + ",sB=" + sB)
    EndIf
    rHue = rHue * 60
    If rHue < 0 Then
      rHue = rHue + 360
    EndIf
  EndIf
EndSub

Sub Color_Value
  ' Color | Function value
  ' param rN1, rN2
  ' param rH - [-120, 480)
  ' return iValue - 0..255
  If rH >= 360 Then
    rH = rH - 360
  EndIF
  If rH < 0 Then
    rH = rH + 360
  EndIF
  If rH < 60 Then
    rV = rN1 + (rN2 - rN1) * rH / 60
  ElseIf rH < 180 Then
    rV = rN2
  ElseIf rH < 240 Then
    rV = rN1 + (rN2 - rN1) * (240 - rH) / 60
  Else
    rV = rN1
  EndIf
  iValue = Math.Round(rV * 255)
EndSub

Sub CS_AddColorToPalette
  ' Color Selector | Add color to palette
  ' param color - color to set
  ' param maxPalette
  ' param nPalette
  ' param palette
  ' param tPalette - target palette
  Stack.PushValue("local", i)
  For i = 1 To nPalette
    If color = palette[i]["color"] Then
      Goto csactp_not_new_color
    EndIf
  EndFor
  palette[tPalette]["color"] = color
  If nPalette < maxPalette Then
    nPalette = nPalette + 1
  EndIf
  tPalette = tPalette + 1
  If maxPalette < tPalette Then
    tPalette = 1
  EndIf
  csactp_not_new_color:
  i = Stack.PopValue("local")
EndSub

Sub CS_AdjustSlider
  ' Color Selector | Adjust slider
  ' param iSlider - moved slider
  Stack.PushValue("local", iSlider)
  If iSlider = iHue Or iSlider = iLightness Or iSlider = iSaturation Then
    If iSlider = iHue Then
      Slider_GetLevel()
      rHue = level
    ElseIf iSlider = iLightness Then
      Slider_GetLevel()
      rLightness = level / 100
    Else
      Slider_GetLevel()
      rSaturation = level / 100
    EndIf
    Color_HSLtoRGB()
    iSlider = iRed
    level = iR
    Slider_SetLevel()
    iSlider = iGreen
    level = iG
    Slider_SetLevel()
    iSlider = iBlue
    level = iB
    Slider_SetLevel()
  Else
    CS_GetColorFromSlider()
    sColor = GraphicsWindow.GetColorFromRGB(red, green, blue)
    Color_RGBtoHSL()
    If rHue = UNDEFINED Then
      rHue = 0
    EndIf
    level = Math.Floor(rHue)
    iSlider = iHue
    Slider_SetLevel()
    level = Math.Floor(rSaturation * 100)
    iSlider = iSaturation
    Slider_SetLevel()
    level = Math.Floor(rLightness * 100)
    iSlider = iLightness
    Slider_SetLevel()
  EndIf
  iSlider = Stack.PopValue("local")
EndSub

Sub CS_DoObject
  ' Color Selector | Do object
  ' param - obj
  While obj <> ""
    CS_DoSlider()
    If obj <> "" Then
      CS_DoPalette()
    EndIf
  EndWhile
EndSub

Sub CS_DoPalette
  ' Color Selector | Do palette
  ' param obj - clicked object
  If Text.StartsWith(obj, "palette") Then
    iPalette = Text.GetSubTextToEnd(obj, 8)
    color = palette[iPalette]["color"]
    CS_SetColorToSlider()   ' set color to slider
    CS_ShowNewColor()       ' show new color name
    CS_DrawColorRect()      ' draw new color rectangle
    obj = ""
    param = "down=True;move=False;up=False;"  ' wait to click
    Mouse_SetHandler()
  EndIf
EndSub

Sub CS_DoSlider
  ' Color Selector | Do slider
  ' param obj - clicked object
  ' param iSlider - index of slider
  If Text.StartsWith(obj, "slider") Then
    Slider_WaitToRelease()
    obj = ""
    param = "down=True;move=False;up=False;"  ' wait to click
    Mouse_SetHandler()
  EndIf
EndSub

Sub CS_DrawColorRect
  ' Color Selector | Draw color rectangle
  ' param color - color of rectangle
  ' param x, y - position of rectangle
  ' param width, height - size of rectangle
  ' return oRect - rectangle object
  GraphicsWindow.BrushColor = color
  GraphicsWindow.PenColor = BORDERCOLOR
  If oRect <> "" Then
    Shapes.Remove(oRect)
  EndIf
  oRect = Shapes.AddRectangle(width, height)
  Shapes.Move(oRect, x, y)
EndSub

Sub CS_DrawPalette
  ' Color Selector | Draw palette
  ' param palette[] - color palette
  ' param nPalette - number of color in palette
  ' param x, y - position of rectangle
  ' param width, height - size of rectangle
  ' return oPalette[] - palette object array
  Stack.PushValue("local", i)
  GraphicsWindow.PenColor = BORDERCOLOR
  For i = 1 To nPalette
    GraphicsWindow.BrushColor = palette[i]["color"]
    palette[i]["oCell"] = Shapes.AddRectangle(width, height)
    dx = Math.Remainder((i - 1), 8) * (width + 4)
    dy = Math.Floor((i - 1) / 8) * (height + 4)
    Shapes.Move(palette[i]["oCell"], x + dx, y + dy)
    palette[i]["x"] = x + dx
    palette[i]["y"] = y + dy
    palette[i]["width"] = width
    palette[i]["height"] = height
  EndFor
  i = Stack.PopValue("local")
EndSub

Sub CS_GetColorFromSlider
  ' Color Selector | get color from slider
  ' return color
  Stack.PushValue("local", iSlider)
  iSlider = iRed    ' slider index
  Slider_GetLevel()
  red = level
  iSlider = iGreen  ' slider index
  Slider_GetLevel()
  green = level
  iSlider = iBlue   ' slider index
  Slider_GetLevel()
  blue = level
  color = GraphicsWindow.GetColorFromRGB(red, green, blue)
  iSlider = Stack.PopValue("local")
EndSub

Sub CS_Init
  ' Color Selector | Initialize sliders
  width = 256
  min = 0
  max = 255
  left = 190
  ' add red slider
  top = TOPY
  caption = "R"
  Slider_Add()
  iRed = iSlider        ' index of slider
  ' add green slider
  top = top + DELTAY
  caption = "G"
  Slider_Add()
  iGreen = iSlider      ' index of slider
  ' add blue slider
  top = top + DELTAY
  caption = "B"
  Slider_Add()
  iBlue = iSlider       ' index of slider
  ' add hue slider
  width = 360
  top = top + DELTAY
  max = 360
  caption = "H"
  Slider_Add()
  iHue = iSlider        ' index of slider
  ' add saturation slider
  width = 100
  top = top + DELTAY
  max = 100
  caption = "S"
  Slider_Add()
  iSaturation = iSlider ' index of slider
  ' add lightness slider
  width = 100
  top = top + DELTAY
  max = 100
  caption = "L"
  Slider_Add()
  iLightness = iSlider  ' index of slider
  ' draw color rectangle
  CS_GetColorFromSlider()
  CS_ShowNewColor()
  x = LEFTX
  y = TOPY + DELTAY * 4
  width = 100
  height = 100
  CS_DrawColorRect()
  ' add text box
  GraphicsWindow.BrushColor = CAPTIONCOLOR
  top = y + height + 4
  oNewColor = Shapes.AddText("")
  Shapes.Move(oNewColor, LEFTX, top)
EndSub

Sub CS_DumpSlider
  ' Color Selector | Dump slider for debug
  For i = 1 To numSlider
    TextWindow.WriteLine("slider" + i)
    TextWindow.WriteLine(slider[i])
  EndFor
EndSub

Sub CS_InitPalette
  ' Color Selector | Initialize palette
  ' This subroutine should be called before CS_ShowPopup().
  maxPalette = 16 ' max cell number of palette
  nPalette = 2    ' number of palette in use
  tPalette = 3    ' index of update target cell
  palette[1]["color"] = pcolor
  palette[2]["color"] = bcolor
EndSub

Sub CS_RemovePalette
  ' Color Selector | Remove palette
  ' param nPalette - number of color in palette
  ' return oPalette[] - palette object array
  Stack.PushValue("local", i)
  For i = 1 To nPalette
    oPalette = "Palette" + i
    Shapes.Remove(palette[i]["oCell"])
  EndFor
  i = Stack.PopValue("local")
EndSub

Sub CS_RemoveSliders
  ' Color Selector | Remove sliders
  For iSlider = 1 To numSlider
    Slider_Remove()
  EndFor
  numSlider = 0
EndSub

Sub CS_SearchClickedObject
  ' Color Selector | Check slider clicked
  ' param mxD, myD - clicked point
  ' return obj - clicked slider or palette
  ' return iSlider - index if obj is slider
  ' return iPalette - index if obj is palette
  Stack.PushValue("local", i)
  For iSlider = 1 To numSlider
    obj = "slider" + iSlider
    x2 = slider[iSlider]["x2"]
    y2 = slider[iSlider]["y2"]
    x3 = slider[iSlider]["x3"]
    y3 = slider[iSlider]["y3"]
    If x2 <= mxD And mxD <= x3 And y2 <= myD And myD <= y3 Then
      Goto scco_obj_found
    EndIf
  EndFor
  For iPalette = 1 To nPalette
    obj = "palette" + iPalette
    x2 = palette[iPalette]["x"]
    y2 = palette[iPalette]["y"]
    x3 = palette[iPalette]["x"] + palette[iPalette]["width"]
    y3 = palette[iPalette]["y"] + palette[iPalette]["height"]
    If x2 <= mxD And mxD <= x3 And y2 <= myD And myD <= y3 Then
      Goto scco_obj_found
    EndIf
  EndFor
  obj = ""
scco_obj_found:
  i = Stack.PopValue("local")
EndSub

Sub CS_SetColorToSlider
  ' Color Selector | Set color to slider
  ' param color
  Stack.PushValue("local", iSlider)
  sColor = color
  Color_ColorToRGB()
  iSlider = iRed
  level = iR
  Slider_SetLevel()
  iSlider = iGreen
  level = iG
  Slider_SetLevel()
  iSlider = iBlue
  level = iB
  Slider_SetLevel()
  CS_AdjustSlider()
  iSlider = Stack.PopValue("local")
EndSub

Sub CS_ShowNewColor
  ' Color Selector | Show new color
  ' param oColor
  ' param color
  Shapes.SetText(oNewColor, color)
EndSub

Sub CS_ShowPopup
  ' Color Selector | Show popup
  ' param color - current color
  ' return color - new color
  ' define constant
  Stack.PushValue("local", cont)
  colorInit = color           ' initial color
  TOPY = 80   ' top y
  LEFTX = 36  ' left x
  BORDERCOLOR = "#666666"
  BOXCOLOR = "LightGray"
  CAPTIONCOLOR = "White"
  DELTAY = 36 ' delta y
  SLITCOLOR = "#555555"
  TEXTCOLOR = "Black"
  UNDEFINED = "N/A"
  POPUPCOLOR = "Black"
  GraphicsWindow.PenWidth = 2
  GraphicsWindow.PenColor = POPUPCOLOR
  GraphicsWindow.BrushColor = POPUPCOLOR
  oPopup = Shapes.AddRectangle(570, 310)
  Shapes.SetOpacity(oPopup, 64)
  Shapes.Move(oPopup, LEFTX - 10, TOPY - 10)
  oOK = Controls.AddButton("OK", LEFTX + 440, TOPY + 260)
  oCancel = Controls.AddButton("Cancel", LEFTX + 480, TOPY + 260)
  Controls.ButtonClicked = CS_OnButtonClicked
  CS_Init()
  Stack.PushValue("local", y)
  y = TOPY
  color = colorInit
  CS_DrawColorRect()    ' original color
  oRectCurrent = oRect
  oRect = ""            ' keep current color
  GraphicsWindow.SetPixel(0, 0, colorInit)
  color = GraphicsWindow.GetPixel(0, 0)
  GraphicsWindow.SetPixel(0, 0, "LightGray")
  GraphicsWindow.BrushColor = CAPTIONCOLOR
  oColor = Shapes.AddText(colorInit)
  Shapes.Move(oColor, x, y + height + 2)
  If color <> colorInit Then
    oColor2 = Shapes.AddText(color)
    Shapes.Move(oColor2, x, y + height + 14)
  EndIf
  y = Stack.PopValue("local")
  CS_SetColorToSlider()
  CS_DrawColorRect()      ' draw new color rectangle
  CS_ShowNewColor()       ' show new color name
  Stack.PushValue("local", x)
  Stack.PushValue("local", y)
  Stack.PushValue("local", width)
  Stack.PushValue("local", height)
  x = x + width + 30
  y = TOPY + height * 2 + 24
  width = 30
  height = 30
  CS_DrawPalette()
  height = Stack.PopValue("local")
  width = Stack.PopValue("local")
  y = Stack.PopValue("local")
  x = Stack.PopValue("local")
  cont = "True"         ' continue
  param = "down=True;move=False;up=False;"   ' wait click
  Mouse_SetHandler()
  While cont
    If clicked Then
      CS_SearchClickedObject()
      CS_DoObject()
    Else
      Program.Delay(100)
    EndIf
  EndWhile
  If cancel Then
    color = colorInit
  Else
    CS_AddColorToPalette()
  EndIf
  CS_RemovePalette()
  CS_RemoveSliders()
  Shapes.Remove(oColor)
  Shapes.Remove(oColor2)
  Shapes.Remove(oNewColor)
  Shapes.Remove(oRectCurrent)
  Shapes.Remove(oRect)
  Controls.Remove(oOK)
  Controls.Remove(oCancel)
  Shapes.Remove(oPopup)
  cont = Stack.PopValue("local")
EndSub

Sub CS_OnButtonClicked
  ' Color Selector | Event handler on button clicked
  cont = "False"
  If Controls.LastClickedButton = oCancel Then
    cancel = "True"
  Else
    cancel = "False"
  EndIf
EndSub

Sub File_Save
  ' File | Show output program to save
  ' param buf - program buffer
  ' define constant
  Stack.PushValue("local", cont)
  colorInit = color           ' initial color
  TOPY = 80   ' top y
  LEFTX = 36  ' left x
  DELTAY = 40 ' delta y
  CAPTIONCOLOR = "White"
  POPUPCOLOR = "Black"
  TEXTCOLOR = "Black"
  GraphicsWindow.PenWidth = 0
  GraphicsWindow.BrushColor = POPUPCOLOR
  oPopup = Shapes.AddRectangle(570, 310)
  Shapes.SetOpacity(oPopup, 64)
  Shapes.Move(oPopup, LEFTX - 10, TOPY - 10)
  oText = Controls.AddTextBox(LEFTX, TOPY)
  Controls.SetSize(oText, 550, 240)
  Controls.SetTextBoxText(oText, buf)
  oOK = Controls.AddButton("OK", LEFTX + 500, TOPY + 260)
  cont = "True"         ' continue
  Controls.ButtonClicked = File_OnButtonClicked
  While cont
    Program.Delay(200)
  EndWhile
  Controls.Remove(oText)
  Controls.Remove(oOK)
  Controls.Remove(oPopup)
  cont = Stack.PopValue("local")
EndSub

Sub File_OnButtonClicked
  ' File | Button event handler
  cont = "False"
EndSub

Sub Math_CartesianToPolar
  ' Math | convert cartesian coodinate to polar coordinate
  ' param x, y - cartesian coordinate
  ' return r, a - polar coordinate
  r = Math.SquareRoot(x * x + y * y)
  If x = 0 And y > 0 Then
    a = 90 ' [degree]
  ElseIf x = 0 And y < 0 Then
    a = -90
  Else
    a = Math.ArcTan(y / x) * 180 / Math.Pi
  EndIf
  If x < 0 Then
    a = a + 180
  ElseIf x > 0 And y < 0 Then
    a = a + 360
  EndIf
EndSub

Sub Math_Hex2Dec
  ' Math | Convert hexadecimal to decimal
  ' param sHex
  ' return iDec
  iDec = 0
  iLen = Text.GetLength(sHex)
  For iPtr = 1 To iLen
    iDec = iDec * 16 + Text.GetIndexOf("0123456789ABCDEF", Text.GetSubText(sHex, iPtr, 1)) - 1
  EndFor
EndSub

Sub Scissors_Init
  ' Scissors | Initialize shapes data
  ' return shX, shY - current position of shapes
  ' return shape - array of shapes
  shX = 237 ' x offset
  shY = 30 ' y offset
  shape[1] = "func=tri;x=45;y=0;x1=22;y1=0;x2=0;y2=213;x3=44;y3=213;bc=#6E6E6E;pw=0;"
  shape[2] = "func=rect;x=45;y=212;width=15;height=47;bc=#6E6E6E;pw=0;"
  shape[3] = "func=ell;x=0;y=235;width=66;height=104;bc=LightGray;pc=#0C95BB;pw=16;"
  shape[4] = "func=tri;x=45;y=0;x1=22;y1=0;x2=0;y2=213;x3=44;y3=213;bc=#939393;pw=0;"
  shape[5] = "func=rect;x=75;y=212;width=14;height=49;bc=#919191;pw=0;"
  shape[6] = "func=ell;x=61;y=163;width=13;height=15;bc=#6E6E6E;pw=0;"
  shape[7] = "func=ell;x=70;y=236;width=64;height=104;bc=LightGray;pc=#0C95BB;pw=16;"
EndSub

Sub Shapes_Add
  ' Shapes | add shapes data as shapes
  ' param shape - array of shapes
  ' param iMin, iMax - shape indices to add
  ' param scale - 1 if same scale
  ' return shWidth, shHeight - total size of shapes
  ' return shAngle - current angle of shapes
  Stack.PushValue("local", i)
  Stack.PushValue("local", x)
  Stack.PushValue("local", y)
  Shapes_CalcWidthAndHeight()
  s = scale
  For i = iMin To iMax
    GraphicsWindow.PenWidth = shape[i]["pw"] * s
    If shape[i]["pw"] > 0 Then
      GraphicsWindow.PenColor = shape[i]["pc"]
    EndIf
    If shape[i]["func"] = "rect" Then
      GraphicsWindow.BrushColor = shape[i]["bc"]
      x = shape[i]["x"]
      y = shape[i]["y"]
      width = shape[i]["width"]
      height = shape[i]["height"]
      shape[i]["obj"] = Shapes.AddRectangle(width * s, height * s)
      Shapes.Move(shape[i]["obj"], shX + x * s, shY + y * s)
    ElseIf shape[i]["func"] = "ell" Then
      GraphicsWindow.BrushColor = shape[i]["bc"]
      x = shape[i]["x"]
      y = shape[i]["y"]
      width = shape[i]["width"]
      height = shape[i]["height"]
      shape[i]["obj"] = Shapes.AddEllipse(width * s, height * s)
      Shapes.Move(shape[i]["obj"], shX + x * s, shY + y * s)
    ElseIf shape[i]["func"] = "tri" Then
      GraphicsWindow.BrushColor = shape[i]["bc"]
      x = shape[i]["x"]
      y = shape[i]["y"]
      x1 = shape[i]["x1"]
      y1 = shape[i]["y1"]
      x2 = shape[i]["x2"]
      y2 = shape[i]["y2"]
      x3 = shape[i]["x3"]
      y3 = shape[i]["y3"]
      shape[i]["obj"] = Shapes.AddTriangle(x1 * s, y1 * s, x2 * s, y2 * s, x3 * s, y3 * s)
      Shapes.Move(shape[i]["obj"], shX + x * s, shY + y * s)
    ElseIf shape[i]["func"] = "line" Then
      x = shape[i]["x"]
      y = shape[i]["y"]
      x1 = shape[i]["x1"]
      y1 = shape[i]["y1"]
      x2 = shape[i]["x2"]
      y2 = shape[i]["y2"]
      shape[i]["obj"] = Shapes.AddLine(x1 * s, y1 * s, x2 * s, y2 * s)
      Shapes.Move(shape[i]["obj"], shX + x * s, shY + y * s)
    EndIf
  EndFor
  shAngle = 0
  y = Stack.PopValue("local")
  x = Stack.PopValue("local")
  i = Stack.PopValue("local")
EndSub

Sub Shapes_CalcWidthAndHeight
  ' Shapes | Calculate total width and height of shapes
  ' param iMin, iMax - shape indices to add
  ' return nShapes - number of shapes
  ' return shWidth, shHeight - total size of shapes
  For i = iMin To iMax
    If shape[i]["func"] = "tri" Or shape[i]["func"] = "line" Then
      xmin = shape[i]["x1"]
      xmax = shape[i]["x1"]
      ymin = shape[i]["y1"]
      ymax = shape[i]["y1"]
      If shape[i]["x2"] < xmin Then
        xmin = shape[i]["x2"]
      EndIf
      If xmax < shape[i]["x2"] Then
        xmax = shape[i]["x2"]
      EndIf
      If shape[i]["y2"] < ymin Then
        ymin = shape[i]["y2"]
      EndIf
      If ymax < shape[i]["y2"] Then
        ymax = shape[i]["y2"]
      EndIf
      If shape[i]["func"] = "tri" Then
        If shape[i]["x3"] < xmin Then
          xmin = shape[i]["x3"]
        EndIf
        If xmax < shape[i]["x3"] Then
          xmax = shape[i]["x3"]
        EndIf
        If shape[i]["y3"] < ymin Then
          ymin = shape[i]["y3"]
        EndIf
        If ymax < shape[i]["y3"] Then
          ymax = shape[i]["y3"]
        EndIf
      EndIf
      shape[i]["width"] = xmax - xmin
      shape[i]["height"] = ymax - ymin
    EndIf
    If i = 1 Then
      shWidth = shape[i]["x"] + shape[i]["width"]
      shHeight = shape[i]["y"] + shape[i]["height"]
    Else
      If shWidth < shape[i]["x"] + shape[i]["width"] Then
        shWidth = shape[i]["x"] + shape[i]["width"]
      EndIf
      If shHeight < shape[i]["y"] + shape[i]["height"] Then
        shHeight = shape[i]["y"] + shape[i]["height"]
      EndIf
    EndIf
  EndFor
EndSub

Sub Shapes_CalcRotatePos
  ' Shapes | Calculate position for rotated shape
  ' param x, y - position of a shape
  ' param width, height - size of a shape
  ' param cx, cy - center of shapes
  ' param shAngle - rotate angle
  ' return x, y - rotated position of a shape
  _cx = x + width / 2
  _cy = y + height / 2
  x = _cx - cx
  y = _cy - cy
  Math_CartesianToPolar()
  a = a + shAngle
  x = r * Math.Cos(a * Math.Pi / 180)
  y = r * Math.Sin(a * Math.Pi / 180)
  _cx = x + cx
  _cy = y + cy
  x = _cx - width / 2
  y = _cy - height / 2
EndSub

Sub Shapes_Move
  ' Shapes | Move shapes
  ' param shape - array of shapes
  ' param scale
  ' param x, y - position to move
  ' return shX, shY - new position of shapes
  Stack.PushValue("local", i)
  Stack.PushValue("local", x)
  Stack.PushValue("local", y)
  shX = x
  shY = y
  For i = 1 To nShapes
    _x = shape[i]["x"]
    _y = shape[i]["y"]
    width = shape[i]["width"]
    height = shape[i]["height"]
    Shapes_CalcRotatePos()
    Shapes.Move(shape[i]["obj"], shX + _x * s, shY + _y * s)
  EndFor
  y = Stack.PopValue("local")
  x = Stack.PopValue("local")
  i = Stack.PopValue("local")
EndSub

Sub Shapes_Remove
  ' Shapes | Remove shapes
  ' param iMin, iMax - shapes indices to remove
  ' param shape - array of shapes
  Stack.PushValue("local", i)
  For i = iMin To iMax
    Shapes.Remove(shape[i]["obj"])
  EndFor
  i = Stack.PopValue("local")
EndSub

Sub Shapes_Rotate
  ' Shapes | Rotate shapes
  ' param shape - array of shapes
  ' param scale
  ' param angle
  Stack.PushValue("local", i)
  Stack.PushValue("local", x)
  Stack.PushValue("local", y)
  s = scale
  shAngle = angle
  cx = shWidth / 2
  cy = shHeight / 2
  For i = 1 To nShapes
    x = shape[i]["x"]
    y = shape[i]["y"]
    width = shape[i]["width"]
    height = shape[i]["height"]
    Shapes_CalcRotatePos()
    Shapes.Move(shape[i]["obj"], shX + x * s, shY + y * s)
    Shapes.Rotate(shape[i]["obj"], shAngle)
  EndFor
  y = Stack.PopValue("local")
  x = Stack.PopValue("local")
  i = Stack.PopValue("local")
EndSub

Sub Slider_Add
  ' Slider | Add slider as shapes and property
  ' param width
  ' param caption
  ' param min, max
  ' param left, top
  ' return slider[] - property of slider
  ' return iSlider - added slider index
  numSlider = numSlider + 1
  iSlider = numSlider
  ' add shapes for slider
  GraphicsWindow.BrushColor = CAPTIONCOLOR
  len = Text.GetLength(caption)
  slider[iSlider]["oCaption"] = Shapes.AddText(caption)
  Shapes.Move(slider[iSlider]["oCaption"], left - (len * 5 + 10), top + 1)
  level = Math.Floor((min + max) / 2)
  slider[iSlider]["level"] = level  ' property
  slider[iSlider]["min"] = min
  slider[iSlider]["max"] = max
  GraphicsWindow.PenColor = BORDERCOLOR
  mag = (level - min) / (max - min)
  GraphicsWindow.BrushColor = SLITCOLOR
  slider[iSlider]["oSlit"] = Shapes.AddRectangle(width, 10)
  GraphicsWindow.PenColor = BORDERCOLOR
  GraphicsWindow.BrushColor = BOXCOLOR
  slider[iSlider]["oBox"] = Shapes.AddRectangle(10, 18)
  GraphicsWindow.BrushColor = CAPTIONCOLOR
  slider[iSlider]["oLevel"] = Shapes.AddText(level)
  slider[iSlider]["x0"] = left
  slider[iSlider]["x1"] = left + width
  slider[iSlider]["y0"] = top
  Shapes.Move(slider[iSlider]["oLevel"], left + width + 5, top)
  ' move and zoom shapes for slider
  Shapes.Move(slider[iSlider]["oSlit"], left, top + 4)
  Slider_SetLevel()
EndSub

Sub Slider_CallBack
  ' Slider | Call back
  ' param iSlider - changed slider
  CS_AdjustSlider()
  CS_GetColorFromSlider()
  CS_ShowNewColor()       ' show new color name
  CS_DrawColorRect()      ' draw new color rectangle
EndSub

Sub Slider_GetLevel
  ' Slider | Get latest level of slider
  ' param iSlider
  ' return level
  level = slider[iSlider]["level"]
EndSub

Sub Slider_GetMouseLevel
  ' Slider | Get mouse level of slider
  ' param iSlider
  ' return level
  x0 = slider[iSlider]["x0"]
  x1 = slider[iSlider]["x1"]
  max = slider[iSlider]["max"]
  min = slider[iSlider]["min"]
  level = min + Math.Floor((max - min) * (mxM - x0) / (x1 - x0))
EndSub

Sub Slider_WaitToRelease
  ' Slider | Get released point for slider moving
  ' param iSlider
  param = "down=False;move=True;up=True;"  ' for slider moving / wait to release
  Mouse_SetHandler()
  While released = "False"
    If moved Then
      param = "move=False;"  ' while slider moving
      Mouse_SetHandler()
      x0_ = slider[iSlider]["x0"]
      x1_ = slider[iSlider]["x1"]
      If mxM < x0_ Then
        mxM = x0_
      EndIf
      If x1_ < mxM Then
        mxM = x1_
      EndIf
      Slider_GetMouseLevel()  ' get mouse level of slider
      Slider_SetLevel()       ' set slider level and move slider box
      Slider_CallBack()
      param = "move=True;"    ' for next slider moving
      Mouse_SetHandler()
    Else
      Program.Delay(100)
    EndIf
  EndWhile
  param = "move=False;up=False;"  ' mouse released
  Mouse_SetHandler()
EndSub

Sub Slider_Remove
  ' Slider | Remove a slider
  ' param iSlider
  Shapes.Remove(slider[iSlider]["oCaption"])
  Shapes.Remove(slider[iSlider]["oSlit"])
  Shapes.Remove(slider[iSlider]["oBox"])
  Shapes.Remove(slider[iSlider]["oLevel"])
EndSub

Sub Slider_SetLevel
  ' Slider | Set slider level and move slider box
  ' param iSlider
  ' param level
  Stack.PushValue("local", width)
  x0 = slider[iSlider]["x0"]
  x1 = slider[iSlider]["x1"]
  y0 = slider[iSlider]["y0"]
  width = x1 - x0
  slider[iSlider]["level"] = level
  Shapes.SetText(slider[iSlider]["oLevel"], level)
  ' move bar
  min = slider[iSlider]["min"]
  max = slider[iSlider]["max"]
  mag = (level - min) / (max - min)
  ' move box
  Shapes.Move(slider[iSlider]["oBox"], x0 + Math.Floor(width * mag) - 5, y0)
  slider[iSlider]["x2"] = x0 + Math.Floor(width * mag) - 5
  slider[iSlider]["x3"] = x0 + Math.Floor(width * mag) - 5 + 10
  slider[iSlider]["y2"] = y0
  slider[iSlider]["y3"] = y0 + 18
  width = Stack.PopValue("local")
EndSub

Sub Mouse_SetHandler
  ' Mouse | Common event handler setting
  ' param["down"] - "True" if set, "False" if reset mouse event handler
  ' param["move"] - "True" if set, "False" if reset mouse event handler
  ' param["up"] - - "True" if set, "False" if reset mouse event handler
  ' return clicked - "False" if set MouseDown
  ' return moved - "False" if set MouseMove
  ' return released - "False" if set MouseUp
  ' return dmu - which handlers are set for debug
  If param["down"] Then
    clicked = "False"
    GraphicsWindow.MouseDown = Mouse_OnDown
    handler["down"] = "D"
  ElseIf param["down"] = "False" Then
    GraphicsWindow.MouseDown = Mouse_DoNothing
    handler["down"] = ""
  EndIf
  If param["move"] Then
    moved = "False"
    GraphicsWindow.MouseMove = Mouse_OnMove
    handler["move"] = "M"
  ElseIf param["move"] = "False" Then
    GraphicsWindow.MouseMove = Mouse_DoNothing
    handler["move"] = ""
  EndIf
  If param["up"] Then
    released = "False"
    GraphicsWindow.MouseUp = Mouse_OnUp
    handler["up"] = "U"
  ElseIf param["up"] = "False" Then
    GraphicsWindow.MouseUp = Mouse_DoNothing
    handler["up"] = ""
  EndIf
  dmu = handler["down"] + handler["move"] + handler["up"]
  If debug Then
    GraphicsWindow.Title = title + " set " + dmu
  EndIf
EndSub

Sub Mouse_OnDown
  ' Mouse | Common event handler on mouse down
  ' return mxD, myD - position on mouse down
  mxD = GraphicsWindow.MouseX
  myD = GraphicsWindow.MouseY
  clicked = "True"
  If debug Then
    GraphicsWindow.Title = title + " clicked " + mxD + "," + myD + " " + dmu
  EndIf
EndSub

Sub Mouse_DoNothing
  ' Mouse | Common event handler to do nothing
EndSub

Sub Mouse_OnMove
  ' Mouse | Common event handler on mouse move
  ' return mxM, myM - position on mouse move
  mxM = GraphicsWindow.MouseX
  myM = GraphicsWindow.MouseY
  moved = "True"
  If debug Then
    GraphicsWindow.Title = title + " moved " + mxM + "," + myM + " " + dmu
  EndIf
EndSub

Sub Mouse_OnUp
  ' Mouse | Common event handler on mouse up
  ' return mxU, myU - position on mouse up
  mxU = GraphicsWindow.MouseX
  myU = GraphicsWindow.MouseY
  released = "True"
  If debug Then
    GraphicsWindow.Title = title + " released " + mxU + "," + myU + " " + dmu
  EndIf
EndSub
Copyright (c) Microsoft Corporation. All rights reserved.