packages feed

tinytools-vty 0.1.0.4 → 0.1.0.7

raw patch · 26 files changed

+445/−458 lines, 26 filesdep ~aesondep ~aeson-prettydep ~ansi-terminalbinary-added

Dependency ranges changed: aeson, aeson-pretty, ansi-terminal, bimap, bytestring, clock, constraints-extras, containers, data-default, dependent-map, dependent-sum, directory, extra, file-embed, filepath, http-conduit, ilist, lens, mtl, optparse-applicative, primitive, ref-tf, reflex, reflex-potatoes, reflex-test-host, reflex-vty, relude, semialign, template-haskell, text, these, time, tinytools, vty

Files

ChangeLog.md view
@@ -1,5 +1,19 @@ # Changelog for tinytools-vty +## [unreleased]++## [0.1.0.7]+- fix several bugs+- update to use 0.1.0.7 of tinytools++## [0.1.0.5]+- add version string to welcome popup title+- add about button that brings up the welcome popup+- make the welcome popup contents scrollable+- clean up readme+- delete the old termwidth generation exe+- fix an issue where cursor doesn't show up at end of line in text input boxes+- update to use 0.1.0.5 of tinytools  ## [0.1.0.4] - update to use 0.1.0.4 of tinytools
README.md view
@@ -4,78 +4,101 @@  This repository contains the [reflex-vty](https://hackage.haskell.org/package/reflex-vty) based view/controller implementation built on top of the [tinytools](https://github.com/minimapletinytools/tinytools) model. +![](screenshot.png) -# running+tinytools is still in BETA and may be quite unstable. Save often!!! -To install tiny tools run `cabal install exe:tinytools` and then run `tinytools`+# installation  +### pre-requisites+[text-icu](https://github.com/haskell/text-icu) is required as a prerequisite. On mac++```+brew install icu4c+brew link icu4c --force+export PKG_CONFIG_PATH="$(brew --prefix)/opt/icu4c/lib/pkgconfig"+```++You will also need the haskell build tool cabal. The best way to do this is using [ghcup](https://www.haskell.org/ghcup/)++To install tiny tools run `cabal install tinytools-vty` and then you can run `tinytools`  Or if you are building locally then `cabal run tinytools` -NOTE that `tinytools` is also the name of the base model library for `tinytools-vty` which is why the `exe` is necessary. If you just `cabal install tinytools` you will install the library!+NOTE that `tinytools` is also the name of the base model library for `tinytools-vty`. If you just `cabal install tinytools` you will install the library and not the exe!!!  # usage -When you first run `tinytools` a tutorial file will open which contains information on how to use `tinytools-vty`. This same tutorial is copied at the bottom of this README file. `tinytools-vty` has a very intuitive interface and most operations should be clear.+When you first run `tinytools` a tutorial file will open which contains information on how to use `tinytools-vty`. +- To open an empty document do `tinytools --empty` (or `cabal run tinytools -- --empty`) +- In order to support unicode wide chars (optional), you must first generate the term width file for your terminal `tinytools --widthtable` -hotkeys are supported, unfortunately they seem to sometimes they get captured by the OS or the terminal and never get forwarded to the app :(.+`tinytools-vty` has a very intuitive interface and most operations should be clear. -# tutorial+## tools+```+[(v)select][(p)an][(b)ox]      +[(l)ine][pai(n)t]   +``` -(open in the app instead for a better view, browser code preview doesn't render certain unicode characters in monospace correctly)+### the [(v)select] tool +The select tool is your do all tool for interacting with existing elements in your document. Click on individual elements to select or modify it. Click and drag to select multiple elements.++### the [(p)an] tool++click + drag in the canvas area with the pan tool to pan the canvas.++### the [(b)ox] tool++Use the box tool to create boxes. After creating or selecting a box, click on the top border to add or modify a label. Click inside the box to add or modify text. You can change the styling of your lines in the left menu.++### the [(l)ine] tool++Use the line tool to create lines. Lines can attach to existing boxes on either end. After selecting a line, you can move either end point of line or change their attachment. You click and drag in the middle of a line to add midpoints to your line. You can double click on a line to add a line label. Line labels can be moved by clicking and dragging on highlighted handle in the middle. You can change the styling of your lines in the left menu.++### the [(t)ext] tool++Same as the box tool except you can immediately add text to the box without additional clicking!++### the [pai(n)t] tool++The paint tool lets you create areas that take free form text. After selecting a paint area, you can move the cursor anywhere inside and add text.++## layers++On the left hand side is a very sophisticated layering system. All elements will show up in the layer system. You can drag elements around to reorder them. You can add folders to create a hierarchical layer system. You can hide or lock elements in the layers menu. You can select elements in the layers menu.++## shortucts++- (ctrl-s) save+- (ctrl-p) print+- (ctrl-q) quit+- (ctrl-c) copy+- (ctrl-v) paste+- (ctrl-z) undo+- (ctrl-y) redo+- (ctrl-o) open+- (ctrl-n) new+++## menu ```+[new][open][save][save as]     +[write to "tt.txt"][quit] +``` -[new][open][save][save as]     *             ╔══════════════════════════════╗                                                                                            -[export to "potato.txt"][quit] *             ║                              ║ ╔IMPORTANT#########################╗                                                       --------------------------------*   ███████████████████                      ╚>#to explore the canvas, click the  #                                                       -[(v)select][(p)an][(b)ox]      *   █THIS IS TINYTOOLS█═╗                      #[(p)an] button or press p         #                                                       -[(l)ine][(t)extbox][pai(n)t]   *   ███████████████████ ║                      #                                  #                                                       --------------------------------*                       v                      #then click and drag in the canvas #                                                       -⇊ea 𐃛 starter                 #*   <═══╗   ╔══════════════════════╗           #area to move your view            #                                                       -  ea ⧈ info: more features    #*       ║   ║the menu on the left  ║           #                                  #                                                       -  ea ⤡ <line>                 #*       ╚═══║has a lot of important║═══╗       #                                  #                                                       -  ea ⤡ <line>                 #*           ║operations            ║   ║       ╚##################################╝                                                       -  ea ⤡ <line>                 #*           ╚══════════════════════╝   ║                        ^                                                                         -  ea ⧈ info: pan              #*                      ║               ║                        ║                                                                         -  ea ⤡ <line>                 #*                      v               ║                        ║                                                                         -  ea ⧈ info: box parameters   #*        ╔═══════════════════════════╗ ║                        ║                                                                         -  ea ⤡ <line>                 #*        ║to draw a box, click the   ║ ║                        ║                                                                         -  ea ⤡ <line>                 #*        ║[(b)ox] button or press b  ║ ║                        ╚════════════════════╗                                                    -  ea ⧈ info: canvas           #*        ║                           ║ ║                                             ║                                                    -  ea ⧈ info: box              #*        ║then click and drag in the ║ ║                                             ║                                                    -  ea ⧈ info: menu             #*        ║canvas area                ║ ║                        *------------------* ║                                                    -  ea ⤡ <line>                 #*        ╚═══════════════════════════╝ ║                        |this area (to the | ║                                                    -  ea ⤡ <line>                 #*                             ║        ╚═══════════════════════>|right) is called  |═╝                                                    -  ea ⧈ title                  #*                             ║                                 |the canvas        |                                                      -                              #*                             v                                 |                  |                                                      -                              #*            ╔═════════════════════════════════╗                |                  |                                                      -                              #*            ║after creating a box, it will be ║                |                  |                                                      -                              #*            ║selected, you can use the options║                *------------------*                                                      -                              #*            ║in the bottom right to change its║                                                                                          -                              #*      ╔═════║style. you can also convert your ║                                                                                          -                              #*  <═══╝     ║box into a text box or remove its║     ╔═══════════════════════════════╗                                                    -                              #*            ║border                           ║     ║of course there are many more  ║                                                    -                              #*            ║                                 ║     ║features, play around!         ║                                                    -                              #*            ║                                 ║     ║                               ║                                                    -                              #*            ╚═════════════════════════════════╝     ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -                              #*                                                    ║                               ║                                                    -[new folder]                   *                                                    ║                               ║                                                    --------------------------------*                                                    ╚═══════════════════════════════╝                                                    -canvas:                        *                                                                                                                                         - width: 500                    *                                                                                                                                         -height: 200                    *                                                                                                                                         -```                                                                                            +- [new]: creates a new empty doc, prompts to save if there are unsaved changes+- [open]: open a doc from disk, all docs must end .potato extension+- [save]: save the doc to the existing file context, same as save as if no file context+- [save as]: save the doc to a new file context+- [write to "tt.txt"]: writes the doc to "tt.txt"+- [quit]: quit the app, prompts to save if there are unsaved changes -# enabling unicode widechar support -## NOT WORKING, WILL CRASH RANDOMLY IF YOU USE UNICODE WIDE CHARS 😨 (this is due to bugs in TextZipper module that I still need to fix)+# unicode widechar and grapheme cluster support -Unicode character display width seems to vary by terminal so you will need to generate a unicode width table file in order to enable support for unicode wide characters.-You can run `tinytools-vty` with the `--widthtable` arg to generate the table to your local config directory for the current terminal. Generating the table samples each unicode character inside the terminal and takes a few seconds to run. Please see the `Graphics.Vty.UnicodeWidthTable` module of the [vty](https://hackage.haskell.org/package/vty) for more info.+Unicode character display width seems to vary by terminal. `tinytools-vty` uses the xterm-256 (mac default terminal) terminal width mappings by default. You can run `tinytools-vty` with the `--widthtable` arg to generate the table to your local config directory for the current terminal. Generating the table samples each unicode character inside the terminal and takes a few seconds to run. Please see the `Graphics.Vty.UnicodeWidthTable` module of the [vty](https://hackage.haskell.org/package/vty) for more info. Grapheme clusters are not really supported by terminals so they are currently disabled 😭.++Also note that many mono-space text displays do not display unicode widechars at a width consistent with its mono-spacing 😕. ++
app/Main.hs view
@@ -10,14 +10,18 @@ import           Potato.Flow.TestStates import           Potato.Flow.TutorialState import           Potato.Flow.Vty.Main+import qualified Paths_tinytools_vty (version)  + import           Control.Exception                    (try) import           GHC.IO.Handle import           Options.Applicative import           System.Directory import           System.FilePath import           System.IO                            hiding (putStrLn)+import Data.Version (showVersion)+import qualified Data.Text as T  import qualified Graphics.Vty                         as V import qualified Graphics.Vty.UnicodeWidthTable.IO    as V@@ -28,8 +32,9 @@  data PotatoCLIOptions = PotatoCLIOptions {   _potatoCLIOptions_args                        :: [String]-  , _potatoCLIOptions_empty                     :: Bool+  , _potatoCLIOptions_tutorial                     :: Bool   , _potatoCLIOptions_generateUnicodeWidthTable :: Bool+  , _potatoCLIOptions_version                   :: Bool }  @@ -37,12 +42,16 @@ sample = PotatoCLIOptions   <$> many (argument str (metavar "FILE"))   <*> switch-    ( long "empty"-    <> short 'e'-    <> help "open an empty document" )+    ( long "tutorial"+    <> short 't'+    <> help "open the tutorial doc" )   <*> switch     ( long "widthtable"     <> help "generate unicode width table for your terminal using vty" )+  <*> switch+    ( long "version"+    <> short 'v'+    <> help "show version" )   @@ -86,7 +95,7 @@     -- see if the argument file we passed in exists or not-  minitfile <- if _potatoCLIOptions_empty opts+  minitfile <- if not (_potatoCLIOptions_tutorial opts)     then       return Nothing     else case nonEmpty (_potatoCLIOptions_args opts) of@@ -95,42 +104,46 @@         exists <- doesFileExist x         return $ if exists then Just x else Nothing -  if _potatoCLIOptions_generateUnicodeWidthTable opts+  if _potatoCLIOptions_version opts     then do-      mTermName <- V.currentTerminalName-      case mTermName of-        Just termName -> do-          configdir <- tinytoolsConfigDir-          let-            fn = configdir </> (termName <> "_termwidthfile")-          rslt <- try $ do-            wt <- V.buildUnicodeWidthTable V.defaultUnicodeTableUpperBound-            createDirectoryIfMissing False configdir-            V.writeUnicodeWidthTable fn wt-          case rslt of-            Right _ -> do-              putStrLn "\n"-              putStrLn $ "successfully wrote " <> fn-              exitSuccess-            Left (SomeException e) -> do-              putStrLn "\n"-              die $ "failed to generate or write unicode width table " <> fn <> " with exception " <> show e-        Nothing -> do-          die "failed to generate unicode width table because could not obtain terminal name"--    else return ()+      putStrLn $ "tinytools-vty version " <> showVersion Paths_tinytools_vty.version+      exitSuccess+    else if _potatoCLIOptions_generateUnicodeWidthTable opts+      then do+        mTermName <- V.currentTerminalName+        case mTermName of+          Just termName -> do+            configdir <- tinytoolsConfigDir+            let+              fn = configdir </> (termName <> "_termwidthfile")+            rslt <- try $ do+              wt <- V.buildUnicodeWidthTable V.defaultUnicodeTableUpperBound+              createDirectoryIfMissing False configdir+              V.writeUnicodeWidthTable fn wt+            case rslt of+              Right _ -> do+                putStrLn "\n"+                putStrLn $ "successfully wrote " <> fn+                exitSuccess+              Left (SomeException e) -> do+                putStrLn "\n"+                die $ "failed to generate or write unicode width table " <> fn <> " with exception " <> show e+          Nothing -> do+            die "failed to generate unicode width table because could not obtain terminal name"+      else return ()    homeDir <- getHomeDirectory   let     config = MainPFWidgetConfig {       _mainPFWidgetConfig_initialFile = minitfile       , _mainPFWidgetConfig_homeDirectory = homeDir-      , _mainPFWidgetConfig_initialState = if _potatoCLIOptions_empty opts+      , _mainPFWidgetConfig_initialState = if not (_potatoCLIOptions_tutorial opts)         then (owlpfstate_newProject, emptyControllerMeta)         -- TODO load tutorial here owlpfstate_tutorial         --else owlpfstate_attachments1         else tutorialState       , _mainPFWidgetConfig_showWelcome = True+      , _mainPFWidgetConfig_version_tinytools_vty = T.pack $ showVersion Paths_tinytools_vty.version     }    -- set the title
− app/termwidth.hs
@@ -1,20 +0,0 @@-{-# OPTIONS_GHC -threaded #-}--import           Relude--import           Data.Maybe--import qualified Graphics.Vty                         as V-import qualified Graphics.Vty.UnicodeWidthTable.IO    as V-import qualified Graphics.Vty.UnicodeWidthTable.Query as V----main :: IO ()-main = do-  mTermName <- V.currentTerminalName-  let-    widthMapFile = fromJust mTermName <> "_termwidthfile"-  putStrLn $ "writing width for term: " <> show mTermName-  table <- V.buildUnicodeWidthTable '🥱'-  V.writeUnicodeWidthTable widthMapFile table
src/Potato/Flow/TutorialState.hs view
@@ -6,15 +6,12 @@ import           Relude  import           Potato.Flow-import qualified Potato.Flow.Serialization.Snake as Snake+import qualified Potato.Flow.Serialization.SnakeWrangler as Snake+import           Potato.Flow.TestStates -import           Data.ByteString import qualified Data.ByteString.Lazy as LBS import           Data.FileEmbed  (embedFile) -import qualified Data.Text as T-import qualified Data.Aeson as Aeson-import           Potato.Flow.TestStates   @@ -25,4 +22,4 @@   Right j -> Just j  tutorialjson :: ByteString-tutorialjson = $(embedFile "tutorial.potato")+tutorialjson = $(embedFile "tutorial.tt")
src/Potato/Flow/Vty/Attrs.hs view
@@ -50,6 +50,7 @@ renderHandlerColorToVtyColor :: RenderHandleColor -> Color renderHandlerColorToVtyColor = \case   RHC_Default -> brightMagenta+  RHC_Cursor -> brightBlue   RHC_Attachment -> brightBlue   RHC_AttachmentHighlight -> brightCyan 
src/Potato/Flow/Vty/Input.hs view
@@ -8,15 +8,12 @@ import           Relude  import           Potato.Flow-import           Potato.Flow.Controller  import qualified Graphics.Vty              as V-import qualified Graphics.Vty.Input.Events as V import           Reflex import           Reflex.Vty  import           Control.Monad.Fix-import qualified Data.Text.Encoding        as T  convertModifiers :: [V.Modifier] -> [KeyModifier] convertModifiers = fmap $ \case
src/Potato/Flow/Vty/Layer.hs view
@@ -11,32 +11,23 @@ import           Relude  import           Potato.Flow-import           Potato.Flow.Controller import           Potato.Flow.Vty.Attrs import           Potato.Flow.Vty.Input import           Potato.Reflex.Vty.Helpers-import           Potato.Reflex.Vty.Widget import Potato.Flow.Vty.PotatoReader import Potato.Flow.Vty.Common import Potato.Reflex.Vty.Widget.ScrollBar+import Potato.Reflex.Vty.Widget.TextInputHelpers   import qualified Potato.Data.Text.Zipper-import           Control.Monad.Fix-import           Data.Align-import           Data.Dependent.Sum          (DSum ((:=>)))-import qualified Data.IntMap.Strict          as IM import qualified Data.List                   as L import qualified Data.Sequence               as Seq import qualified Data.Text                   as T-import           Data.Text.Zipper import qualified Data.Text.Zipper            as TZ-import           Data.These  import qualified Graphics.Vty                as V import           Reflex-import           Reflex.Network-import           Reflex.Potato.Helpers import           Reflex.Vty  @@ -101,12 +92,14 @@     makeLayerImage width lhrentry = case lhrentry of       LayersHandlerRenderEntryDummy ident -> r where         r = V.text' lg_layer_selected . T.pack . L.take width-          $ replicate ident ' '+          $ +          replicate (max 0 (ident-1)) ' '+          <> (if ident > 0 then "└" else "")+          <> " "           <> replicate 10 '*'       LayersHandlerRenderEntryNormal selected mdots mrenaming lentry@LayerEntry{..} -> r where         ident = layerEntry_depth lentry         sowl = _layerEntry_superOwl-        rid = _superOwl_id sowl         label = hasOwlItem_name sowl          attr = case selected of@@ -128,6 +121,7 @@           OwlSubItemBox _ -> "⧈"           OwlSubItemLine _ -> "⤡"           OwlSubItemTextArea _ -> "𐂂"+          _ -> "?"          t1 = V.text' attr . T.pack $ @@ -138,7 +132,7 @@            -- render folder hide lock icons           -- <> [moveChar]-          <> if' (layerEntry_isFolder lentry) (if' _layerEntry_isCollapsed [expandChar] [closeChar]) [' ']+          <> if' (layerEntry_isFolder lentry) (if' _layerEntry_isCollapsed [expandChar] [closeChar]) ['●']           <> if' (lockHiddenStateToBool _layerEntry_hideState) [hiddenChar] [visibleChar]           <> if' (lockHiddenStateToBool _layerEntry_lockState) [lockedChar] [unlockedChar]           <> " " @@ -149,7 +143,7 @@           Nothing -> V.text' attr label           Just renaming -> img where             dls = TZ.displayLines 999999 attrrenamingbg attrrenamingcur (coerceZipper renaming)-            img = V.vertCat . images $ TZ._displayLines_spans dls+            img = V.vertCat . images . addCursorSpace $ TZ._displayLines_spans dls          r = t1 V.<|> t2 @@ -166,12 +160,6 @@   => LayerWidgetConfig t   -> m (LayerWidget t) holdLayerWidget lwc@LayerWidgetConfig {..} = do-----  potatostylebeh <- fmap _potatoConfig_style askPotato-  PotatoStyle {..} <- sample potatostylebeh    regionWidthDyn <- displayWidth   --regionHeightDyn <- displayHeight
src/Potato/Flow/Vty/Left.hs view
@@ -13,7 +13,6 @@   import           Potato.Flow-import           Potato.Flow.Vty.Info import           Potato.Flow.Vty.Layer import           Potato.Flow.Vty.Params import           Potato.Flow.Vty.PotatoReader@@ -36,6 +35,7 @@   , _menuButtonsWidget_saveAsEv :: Event t ()   , _menuButtonsWidget_exportEv :: Event t ()   , _menuButtonsWidget_quitEv :: Event t ()+  , _menuButtonsWidget_aboutEv :: Event t () }  data LeftWidgetConfig t = LeftWidgetConfig {@@ -78,8 +78,7 @@   -- this only works because you use splitHDrag to split the Left/Canvas panels (it toggles the focus)   focusDyn <- focus   let--    loseFocusEv = void $ ffilter (not . id) $ updated focusDyn+    leftLoseFocusEv = void $ ffilter (not . id) $ updated focusDyn    initLayout $ col $ mdo @@ -88,23 +87,24 @@     -- TODO height should be dynamic but not sure if there's away to do this dynamically because width (from which buttonsHeightDyn) is derived depends on `grout . fixed`. You need to pull width from outside of the `grout . fixed` call to make this work right...     (menuButtons, menuFocusEv, buttonsHeightDyn) <- (grout . fixed) buttonsHeightDyn $ row $ do -      (buttonsEv, heightDyn) <- buttonList (constDyn ["new", "open", "save", "save as", "export to \"potato.txt\"", "quit"]) (Just widthDyn)+      (buttonsEv, heightDyn) <- buttonList (constDyn ["about", "new", "open", "save", "save as", "write to \"tt.txt\"", "quit"]) (Just widthDyn)       let-        exportEv = ffilterButtonIndex 4 buttonsEv+        exportEv = ffilterButtonIndex 5 buttonsEv         menuButtons' = MenuButtonsWidget {-            _menuButtonsWidget_newEv = ffilterButtonIndex 0 buttonsEv-            , _menuButtonsWidget_openEv = ffilterButtonIndex 1 buttonsEv-            , _menuButtonsWidget_saveEv = ffilterButtonIndex 2 buttonsEv-            , _menuButtonsWidget_saveAsEv = ffilterButtonIndex 3 buttonsEv+            _menuButtonsWidget_aboutEv = ffilterButtonIndex 0 buttonsEv+            , _menuButtonsWidget_newEv = ffilterButtonIndex 1 buttonsEv+            , _menuButtonsWidget_openEv = ffilterButtonIndex 2 buttonsEv+            , _menuButtonsWidget_saveEv = ffilterButtonIndex 3 buttonsEv+            , _menuButtonsWidget_saveAsEv = ffilterButtonIndex 4 buttonsEv             , _menuButtonsWidget_exportEv = exportEv-            , _menuButtonsWidget_quitEv = ffilterButtonIndex 5 buttonsEv+            , _menuButtonsWidget_quitEv = ffilterButtonIndex 6 buttonsEv           }         clickPrintEv = tag (current $ _goatWidget_renderedCanvas _layersWidgetConfig_goatW) (void exportEv)       -- TODO don't do this here cmon...       performEvent_ $ ffor clickPrintEv $ \rc -> do          let t = renderedCanvasToText rc          -- TODO at least use filename...-         liftIO $ T.writeFile "potato.txt" t+         liftIO $ T.writeFile "tt.txt" t       menuFocusEv' <- mouseFocus       return (menuButtons', menuFocusEv', heightDyn) @@ -165,24 +165,30 @@           , _paramsWidgetConfig_canvasDyn = _goatWidget_canvas _layersWidgetConfig_goatW           , _paramsWidgetConfig_defaultParamsDyn = _goatWidget_potatoDefaultParameters _layersWidgetConfig_goatW           , _paramsWidgetConfig_toolDyn = _goatWidget_tool _layersWidgetConfig_goatW-          , _paramsWidgetConfig_loseFocusEv = loseFocusEv+          -- must manually remove focus from Params widget :|+          , _paramsWidgetConfig_loseFocusEv = leftmost [leftLoseFocusEv, void refineFocusNoParamsEv]         }       paramsFocusEv' <- mouseFocus       return (params', paramsFocusEv')      let -      refinedFocusEv = leftmost+      refineFocusNoParamsEv :: (Event t Text) = leftmost         [ fmap (const "menu") menuFocusEv         , fmap (const "tools") toolsFocusEv         , fmap (const "toolsOptions") toolsOptionsFocusEv         , fmap (const "layers") layersFocusEv         , fmap (const "info") infoFocusEv+        +        ]+      refinedFocusEv = leftmost+        [ refineFocusNoParamsEv         , fmap (const "params") paramsFocusEv          ]      refinedFocusDyn <- holdDyn "none" refinedFocusEv      let      +             setFocusDyn' = ffor2 focusDyn refinedFocusDyn $ \f1 f2 -> case (f1, f2) of         (True, "layers") -> Just GoatFocusedArea_Layers         (True, _)        -> Just GoatFocusedArea_Other
src/Potato/Flow/Vty/Main.hs view
@@ -13,7 +13,7 @@   import           Potato.Flow-import qualified Potato.Flow.Serialization.Snake as Snake+import qualified Potato.Flow.Serialization.SnakeWrangler as Snake import           Potato.Flow.TestStates import           Potato.Flow.Vty.Canvas import           Potato.Flow.Vty.Input@@ -47,7 +47,6 @@ import qualified Data.Text.Lazy                    as LT import qualified Data.Text.Lazy.Encoding           as LT import qualified Data.Text.IO as T-import           Data.Time.Clock import qualified Data.ByteString.Lazy as LBS import Data.These @@ -117,14 +116,18 @@   cfg'' <- V.standardIOConfig   configDir <- tinytoolsConfigDir   let+    -- using the xterm-256 one by default since it's better than nothing+    defaultWidthMapFile = "xterm-256color_termwidthfile"     mTermName = V.termName cfg''     widthMapFile = case mTermName of+      -- use the xterm one by default, should be fine lol       Nothing -> ""       Just termName -> configDir FP.</> (termName <> "_termwidthfile")   doesWidthMapFileExist <- FP.doesFileExist widthMapFile+  doesDefaultWidthMapFileExist <- FP.doesFileExist defaultWidthMapFile   if doesWidthMapFileExist     then putStrLn $ "attempting to load unicode width table file " <> widthMapFile-    else putStrLn $ "could not find unicode width table file " <> widthMapFile <> " please run --widthtable to generate unicode width table file"+    else putStrLn $ "could not find unicode width table file " <> widthMapFile <> " using the xterm-256 one by default instead. Please run --widthtable to generate unicode width table file"   let     cfg' = cfg'' { V.mouseMode = Just True }     cfg = if doesWidthMapFileExist@@ -132,7 +135,12 @@           V.allowCustomUnicodeWidthTables = Just True           , V.termWidthMaps = [(fromJust mTermName, widthMapFile)]         }-      else cfg'+      else if doesDefaultWidthMapFileExist+        then cfg' {+            V.allowCustomUnicodeWidthTables = Just True+            , V.termWidthMaps = [(fromJust mTermName, defaultWidthMapFile)]+          }+        else cfg'   vty <- V.mkVty cfg   potatoMainWidgetWithHandle vty child @@ -155,7 +163,7 @@  somedefaultpfcfg :: MainPFWidgetConfig somedefaultpfcfg = def {-    --_mainPFWidgetConfig_initialFile = Just "potato.flow"+    --_mainPFWidgetConfig_initialFile = Just ""     _mainPFWidgetConfig_initialState = (owlpfstate_newProject, emptyControllerMeta)   } @@ -185,14 +193,22 @@  -- NOTE, this will query welcome message each time you recreate this welcomeWidget :: forall t m. (MonadWidget t m)-  => m (Event t ())-welcomeWidget = do+  => Text+  -> m (Event t ())+welcomeWidget version = do   postBuildEv <- getPostBuild   welcomeMessageEv <- fetchMOTDAsync postBuildEv   welcomeMessageDyn <- holdDyn "loading..." welcomeMessageEv-  boxTitle (constant def) "😱 tinytools-vty (beta) 😱" $ do+  let+    scrollcfg = ScrollableConfig {+        _scrollableConfig_scrollBy = never+        , _scrollableConfig_scrollTo = never+        , _scrollableConfig_startingPosition = ScrollPos_Top+        , _scrollableConfig_scrollToBottom = constant Nothing+      }+  boxTitle (constant def) (constant $ "😱 tinytools-vty (beta v." <> version <> ") 😱") $ do     initLayout $ col $ do-      (grout . stretch) 1 $ text (current welcomeMessageDyn)+      _ <- (grout . stretch) 1 $ scrollableText scrollcfg welcomeMessageDyn       (grout . fixed) 3 $ textButton def (constant "bye")  @@ -238,6 +254,7 @@   -- should this include controller meta too?   , _mainPFWidgetConfig_initialState :: (OwlPFState, ControllerMeta) -- ^ will be overriden by initialFile if set   , _mainPFWidgetConfig_showWelcome :: Bool+  , _mainPFWidgetConfig_version_tinytools_vty :: Text }  instance Default MainPFWidgetConfig where@@ -247,6 +264,7 @@       , _mainPFWidgetConfig_homeDirectory = "/home/minimaple/kitchen/faucet/potato-flow-vty"       , _mainPFWidgetConfig_initialState = (emptyOwlPFState, emptyControllerMeta)       , _mainPFWidgetConfig_showWelcome = False+      , _mainPFWidgetConfig_version_tinytools_vty = "0.0.0.0"     }  mainPFWidget :: forall t m. (MonadWidget t m)@@ -330,7 +348,7 @@   AppKbCmd {..} <- captureInputEvents (That inputCapturedByPopupBeh) holdAppKbCmd    -- setup PotatoConfig-  currentOpenFileDyn <- holdDyn Nothing $ fmap Just $ leftmost [saveSuccessEv, fmap snd eLoadFileEv]+  currentOpenFileDyn <- holdDyn Nothing $ leftmost [fmap Just saveSuccessEv, fmap (Just . snd) eLoadFileEv, newEmptyFileEv $> Nothing]   let     potatoConfig = PotatoConfig {         _potatoConfig_style = constant def@@ -360,7 +378,7 @@         , _goatWidgetConfig_setFocusedArea = _leftWidget_setFocusEvent leftW          -- TODO-        --, _goatWidgetConfig_unicodeWidthFn =+        , _goatWidgetConfig_unicodeWidthFn = Nothing          -- debugging stuff         , _goatWidgetConfig_setDebugLabel = never@@ -379,7 +397,7 @@      rightPanel = do       dreg' <- askRegion-      let dreg = fmap (\region -> region { _region_left = 0, _region_top = 0}) dreg'+      let dreg = fmap (\reg -> reg { _region_left = 0, _region_top = 0}) dreg'       f <- focus       pane dreg f $ holdCanvasWidget $ CanvasWidgetConfig {           _canvasWidgetConfig_pan = _goatWidget_pan everythingW@@ -408,10 +426,10 @@     (clickSaveEv, nothingClickSaveEv)  = fanMaybe $ tag (_potatoConfig_appCurrentOpenFile potatoConfig) $ leftmost [_menuButtonsWidget_saveEv . _leftWidget_menuButtonsW $ leftW, _appKbCmd_save, _saveBeforeActionOutput_save]     clickSaveAsEv = leftmost $ [_menuButtonsWidget_saveAsEv . _leftWidget_menuButtonsW $ leftW, nothingClickSaveEv, _saveBeforeActionOutput_saveAs] -  -- 1 welcome popup+  -- 1 welcome/about popup   let-    showWelcomeEv = if _mainPFWidgetConfig_showWelcome then postBuildEv else never-  (_, popupStateDyn1) <- popupPaneSimple def (showWelcomeEv $> welcomeWidget)+    showWelcomeEv = leftmost $ [_menuButtonsWidget_aboutEv . _leftWidget_menuButtonsW $ leftW, if _mainPFWidgetConfig_showWelcome then postBuildEv else never]+  (_, popupStateDyn1) <- popupPaneSimple def (showWelcomeEv $> welcomeWidget _mainPFWidgetConfig_version_tinytools_vty)    -- 2 save as popup   (saveAsEv, popupStateDyn2) <- flip runPotatoReader potatoConfig $ popupSaveAsWindow $ SaveAsWindowConfig (tag (_potatoConfig_appCurrentDirectory potatoConfig) clickSaveAsEv)
src/Potato/Flow/Vty/Params.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecursiveDo     #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  module Potato.Flow.Vty.Params (   ParamsWidgetConfig(..)@@ -15,17 +16,12 @@ import           Relude  import           Potato.Flow-import Potato.Flow.OwlHelpers import           Potato.Flow.Vty.Common import           Potato.Reflex.Vty.Helpers import Potato.Flow.Vty.PotatoReader-import Potato.Flow.Vty.Attrs import Potato.Reflex.Vty.Widget.TextInputHelpers -import           Control.Monad.Fix-import           Control.Monad.NodeId import           Data.Align-import           Data.Char                         (isNumber) import           Data.Dependent.Sum                (DSum ((:=>))) import qualified Data.IntMap                       as IM import qualified Data.List.Extra                   as L@@ -35,7 +31,6 @@ import qualified Data.Text.Zipper                  as TZ import           Data.These import           Data.Tuple.Extra-import qualified Data.List as List  import qualified Graphics.Vty                      as V import           Reflex@@ -53,17 +48,22 @@ controllersWithId_to_llama = makePFCLlama . OwlPFCManipulate  -paramsNavigation :: (MonadWidget t m) => m (Event t Int)-paramsNavigation = do+paramsNavigation :: (MonadWidget t m) => Behavior t Bool -> m (Event t Int)+paramsNavigation allowReturnBeh = do   tabEv <- key (V.KChar '\t')+  -- TODO this will cause the return key to never get sent to Layers when in renaming mode so you can't confirm a rename with enter+  -- I guess you need to disablee return navigation if you're in the layers menu...   returnEv <- key V.KEnter-  let fwd  = fmap (const 1) $ leftmost [tabEv, returnEv]+  let fwd  = fmap (const 1) $ leftmost [tabEv, gate allowReturnBeh returnEv]   back <- fmap (const (-1)) <$> key V.KBackTab   return $ leftmost [fwd, back] -repeatNavigation :: (MonadWidget t m, HasFocus t m) => m ()+repeatNavigation :: (MonadWidget t m, HasFocus t m) =>  m () repeatNavigation = do-  navEv <- paramsNavigation+  -- only allow navigation if we have focus+  mfiddyn <- focusedId+  let allowReturnBeh = fmap isJust (current mfiddyn)+  navEv <- paramsNavigation allowReturnBeh   requestFocus $ Refocus_Shift <$> navEv  @@ -100,7 +100,7 @@   subSelection = SuperOwlParliament $ Seq.fromList $ fmap fst params   r = case values of     [] -> Nothing-    x:xs -> if L.allSame values+    x:_ -> if L.allSame values       then Just (subSelection, Just x)       else Just (subSelection, Nothing) @@ -116,9 +116,9 @@ makeLineStyleInputDyn tool selection pdp = r where    selectLineStyleFromSelection :: Selection -> Maybe (Selection, Maybe (Maybe LineStyle, Maybe LineStyle))-  selectLineStyleFromSelection (SuperOwlParliament selection) = r_d1 where+  selectLineStyleFromSelection (SuperOwlParliament sel) = r_d1 where     ps = (\x -> (getSEltLineStyle x, getSEltLineStyleEnd x)) . superOwl_toSElt_hack-    rawparams = ffilter (\(_,(x,y)) -> isJust x || isJust y) . fmap (\sowl -> (sowl, ps sowl)) $ selection+    rawparams = ffilter (\(_,(x,y)) -> isJust x || isJust y) . fmap (\sowl -> (sowl, ps sowl)) $ sel     startvalues = catMaybes . toList . fmap fst . fmap snd $ rawparams     endvalues = catMaybes . toList . fmap snd . fmap snd $ rawparams     subSelection = SuperOwlParliament $ fmap fst rawparams@@ -174,9 +174,11 @@ data SuperStyleCell = SSC_TL | SSC_TR | SSC_BL | SSC_BR | SSC_V | SSC_H | SSC_Fill deriving (Show)  updateFromSuperStyle :: SuperStyleCell -> (SuperStyle -> TZ.TextZipper)-updateFromSuperStyle ssc = TZ.top . TZ.fromText . T.singleton . gettfn ssc where-  gettfn ssc' = fromMaybe ' ' . gettfn' ssc'-  gettfn' = \case+updateFromSuperStyle ssc = r where+  r ss = case gettfn ssc ss of+    Nothing -> TZ.empty+    Just c -> TZ.top . TZ.fromText . T.singleton $ c+  gettfn = \case     SSC_TL -> _superStyle_tl     SSC_TR -> _superStyle_tr     SSC_BL -> _superStyle_bl@@ -188,23 +190,23 @@       _ -> Nothing) . _superStyle_fill  -makeSuperStyleTextEntry :: (MonadWidget t m, HasPotato t m) => SuperStyleCell -> Dynamic t (Maybe SuperStyle) -> m (Behavior t PChar)+makeSuperStyleTextEntry :: (MonadWidget t m, HasPotato t m) => SuperStyleCell -> Dynamic t (Maybe SuperStyle) -> m (Behavior t (Maybe PChar)) makeSuperStyleTextEntry ssc mssDyn = do   mss0 <- sample . current $ mssDyn   let modifyEv = (fmap (maybe id (\ss -> const (updateFromSuperStyle ssc ss))) (updated mssDyn))   ti <- singleCellTextInput modifyEv $ case mss0 of     Nothing  -> ""     Just ss0 -> updateFromSuperStyle ssc ss0-  return . current . fmap (\t -> maybe ' ' (\(c,_) -> c) (T.uncons t)) $ ti+  return . current . fmap (\t -> fmap (\(c,_) -> c) (T.uncons t)) $ ti  makeSuperStyleEvent :: (Reflex t)-  => Behavior t PChar-  -> Behavior t PChar-  -> Behavior t PChar-  -> Behavior t PChar-  -> Behavior t PChar-  -> Behavior t PChar-  -> Behavior t PChar+  => Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)+  -> Behavior t (Maybe PChar)   -> Event t ()   -> Event t SuperStyle makeSuperStyleEvent tl v bl h f tr br trig = pushAlways pushfn trig where@@ -218,14 +220,14 @@     br' <- sample br     return $ def {         -- TODO Nothing is text cell was blank...-        _superStyle_tl    = Just tl'-        , _superStyle_tr     = Just tr'-        , _superStyle_bl        = Just bl'-        , _superStyle_br         = Just br'-        , _superStyle_vertical   = Just v'-        , _superStyle_horizontal = Just h'+        _superStyle_tl    = tl'+        , _superStyle_tr     = tr'+        , _superStyle_bl        = bl'+        , _superStyle_br         = br'+        , _superStyle_vertical   = v'+        , _superStyle_horizontal = h'         --, _superStyle_point      :: PChar-        , _superStyle_fill       = FillStyle_Simple f'+        , _superStyle_fill       = maybe FillStyle_Blank FillStyle_Simple f'       }  -- TODO move to SELts.hs@@ -247,7 +249,7 @@             text (show i <> ". " <> constant (T.pack s))             fmap (fmap (\_ -> s)) (mouseDown V.BLeft)           return $ fmap superStyle_fromListFormat (leftmost presetClicks)-        return (5, never, setStyleEv')+        return (length presetSuperStyles + 2, never, setStyleEv')       0 -> do         -- TODO the awesome version of this has a toggle box so that you can choose to do horiz/vertical together (once you support separate horiz/vert left/right/top/down styles)         -- TODO also a toggle for setting corners to common sets@@ -283,13 +285,13 @@           setStyleEv' = makeSuperStyleEvent tl v bl h f tr br (void $ updated focusDynUnique)           captureEv' = leftmost [void setStyleEv', captureEv1]         return (5, captureEv', setStyleEv')+      _ -> error "radioList returned invalid index"      setStyleEv <- switchHold never (fmap thd3 setStyleEvEv)     captureEv <- switchHold never (fmap snd3 setStyleEvEv)     heightDyn <- holdDyn 0 (fmap fst3 setStyleEvEv)      let-      selectionDyn = fmap fst3 inputDyn       pushSuperStyleFn :: SuperStyle -> PushM t (Maybe (Either Llama SetPotatoDefaultParameters))       pushSuperStyleFn ss = do         (SuperOwlParliament selection, _, tool) <- sample . current $ inputDyn@@ -404,6 +406,7 @@             0 -> if start == end then start else Nothing             1 -> start             2 -> end+            _ -> error "radioList returned invalid index"          (focusDyn,wasChangeDyn,l,r,u,d) <- do           --(tile . fixed) 1 $ text (fmap (T.pack . superStyle_toListFormat . Data.Maybe.fromJust) $ current mssDyn)@@ -432,13 +435,13 @@           setStyleEv' = makeLineStyleEvent (current l) (current r) (current u) (current d) (void $ gate (current wasChangeDyn) (updated focusDynUnique))           captureEv' = leftmost [void setStyleEv', captureEv'']         return (7, captureEv', setStyleEv')+      _ -> error "radioList returned invalid index"    setStyleEv <- switchHold never (fmap thd3 setStyleEvEv)   captureEv <- switchHold never (fmap snd3 setStyleEvEv)   heightDyn <- holdDyn 0 (fmap fst3 setStyleEvEv)    let-    selectionDyn = fmap fst3 inputDyn     pushLineStyleFn :: Either () LineStyle -> PushM t (Maybe (Either Llama SetPotatoDefaultParameters))     pushLineStyleFn eflipss = do       pdp <- sample . current $ pdpDyn@@ -449,6 +452,7 @@           0 -> SetLineStyleEnd_Both           1 -> SetLineStyleEnd_Start           2 -> SetLineStyleEnd_End+          _ -> error "radioList returned invalid index"         (setstart, setend) = case whichEnd of           SetLineStyleEnd_Start -> (True, False)           SetLineStyleEnd_End -> (False, True)@@ -494,7 +498,6 @@ holdTextAlignmentWidget _ inputDyn = constDyn $ do   let     mtaDyn = fmap snd3 inputDyn-    selectionDyn = fmap fst3 inputDyn    let @@ -514,6 +517,7 @@         0 -> TextAlign_Left         1 -> TextAlign_Center         2 -> TextAlign_Right+        _ -> error "radioList returned invalid index"       ) $ setAlignmentEv'     pushAlignmentFn :: TextAlign -> PushM t (Maybe (Either Llama SetPotatoDefaultParameters))     pushAlignmentFn ta = do@@ -537,8 +541,6 @@ holdSBoxTypeWidget _ inputDyn = constDyn $ do   let     mBoxType = fmap snd3 inputDyn-    selectionDyn = fmap fst3 inputDyn-  mbt0 <- sample . current $ mBoxType    let     stateDyn = ffor mBoxType $ \case@@ -577,14 +579,14 @@             where               newbt = case bt of                 This border -> make_sBoxType border (sBoxType_isText oldbt)-                That text -> make_sBoxType (sBoxType_hasBorder oldbt) text-                These border text -> make_sBoxType border text+                That txt -> make_sBoxType (sBoxType_hasBorder oldbt) txt+                These border txt -> make_sBoxType border txt       return $  if toolOverrideSBoxType tool         -- UNTESTED, it's probably currect but the tool overrides this default so I never actually tested it         then Just . Right $ def { _setPotatoDefaultParameters_sBoxType = Just $ case bt of             This border -> make_sBoxType border (snd curState)-            That text -> make_sBoxType (fst curState) text-            These border text -> make_sBoxType border text+            That txt -> make_sBoxType (fst curState) txt+            These border txt -> make_sBoxType border txt           }         else case Data.Maybe.mapMaybe fmapfn . toList $ selection of           [] -> Nothing@@ -629,10 +631,6 @@     captureEv = leftmost [void outputEv, captureEv1]   return (3, captureEv, outputEv) -data SEltParams = SEltParams {-    --_sEltParams_sBox =-  }- data ParamsWidgetConfig t = ParamsWidgetConfig {    _paramsWidgetConfig_selectionDyn :: Dynamic t Selection   , _paramsWidgetConfig_canvasDyn :: Dynamic t SCanvas@@ -692,6 +690,9 @@      -- show canvas params when nothing is selected     mCanvasSizeInputDyn = ffor2 toolDyn selectionDyn (\t s -> if isParliament_null s then Just (isParliament_empty, Nothing, t) else Nothing)+++      -- TODO consider doing initManager_ within the widgets if you don't want to tab from one widget to the next   (paramsOutputEv, captureEv, canvasSizeOutputEv, heightDyn) <- initManager_ $ col $ do
src/Potato/Flow/Vty/PotatoReader.hs view
@@ -27,7 +27,7 @@  -- TODO move elsewhere kTinyToolsFileExtension :: (IsString a) => a-kTinyToolsFileExtension = ".potato"+kTinyToolsFileExtension = ".tt"  -- TODO move elsewhere addTinyToolsFileExtensionIfNecessary :: FP.FilePath -> FP.FilePath
src/Potato/Flow/Vty/Tools.hs view
@@ -41,7 +41,8 @@   Tool_Pan -> 1   Tool_Box -> 2   Tool_Line -> 3-  Tool_TextArea -> 4+  Tool_Text -> 4+  Tool_TextArea -> 5   _ -> 0  holdToolsWidget :: forall t m. (PostBuild t m, MonadWidget t m)@@ -49,13 +50,14 @@   -> m (ToolWidget t) holdToolsWidget ToolWidgetConfig {..} = mdo -  (radioEvs, heightDyn) <- radioList (constDyn ["(v)select","(p)an","(b)ox","(l)ine","pai(n)t"]) (fmap ((:[]) . toolWidgetToIndex) _toolWidgetConfig_tool) (Just _toolWidgetConfig_widthDyn)+  (radioEvs, heightDyn) <- radioList (constDyn ["(v)select","(p)an","(b)ox","(l)ine","(t)ext","pai(n)t"]) (fmap ((:[]) . toolWidgetToIndex) _toolWidgetConfig_tool) (Just _toolWidgetConfig_widthDyn)   let     selectB = void $ ffilter (==0) radioEvs     panB = void $ ffilter (==1) radioEvs     boxB = void $ ffilter (==2) radioEvs     lineB = void $ ffilter (==3) radioEvs-    textareaB = void $ ffilter (==4) radioEvs+    textb = void $ ffilter (==4) radioEvs+    textareaB = void $ ffilter (==5) radioEvs    let     setTool = leftmost@@ -63,6 +65,7 @@       , Tool_Pan <$ leftmost [panB]       , Tool_Box <$ leftmost [boxB]       , Tool_Line <$ leftmost [lineB]+      , Tool_Text <$ leftmost [textb]       , Tool_TextArea <$ leftmost [textareaB]] {-   vLayoutPad 4 $ debugStream [
src/Potato/Reflex/Vty/Helpers.hs view
@@ -31,7 +31,6 @@ import           Relude  import           Potato.Reflex.Vty.Widget-import Reflex.Potato.Helpers (simultaneous)  import           Control.Monad.Fix import           Control.Monad.NodeId@@ -84,7 +83,7 @@   t <- holdDyn "" $ mergeWith (\a b -> a <> "\n" <> b) evs   richText richTextConfig_simpleForeColorAttr (current t) -debugStreamBeh :: (MonadHold t m, HasDisplayRegion t m, HasImageWriter t m, HasTheme t m) => [Behavior t Text] -> m ()+debugStreamBeh :: (HasDisplayRegion t m, HasImageWriter t m, HasTheme t m) => [Behavior t Text] -> m () debugStreamBeh behs = text $ foldr (liftA2 (\t1 t2 -> t1 <> " " <> t2)) "" behs  countEv :: (Reflex t, MonadHold t m, MonadFix m) => Event t a -> m (Dynamic t Int)@@ -135,18 +134,20 @@ -}  +-- TODO DELETE UNUSED drag2AttachOnStart   :: forall t m a. (Reflex t, MonadFix m, MonadHold t m, HasInput t m)   => V.Button   -> Behavior t a   -> m (Event t (a, Drag2)) drag2AttachOnStart btn beh = do+  -- TODO pretty sure this should be btn?   dragEv <- drag2 V.BLeft   let     foldfn d ma = do       anew <- case ma of         Nothing                                   -> sample beh-        Just (a, _) | _drag2_state d == DragStart -> sample beh+        Just (_, _) | _drag2_state d == DragStart -> sample beh         Just (a, _)                               -> return a       return $ Just (anew, d)   dragBeh <- foldDynM foldfn Nothing dragEv
src/Potato/Reflex/Vty/Host.hs view
@@ -21,8 +21,7 @@  import Prelude -import System.IO-import Control.Concurrent (forkIO, killThread, MVar, newMVar, putMVar, readMVar, modifyMVar_)+import Control.Concurrent (forkIO, killThread, MVar, newMVar, readMVar, modifyMVar_) import Control.Concurrent.Chan (newChan, readChan, writeChan) import Control.Exception (onException) import Control.Monad (forM, forM_, forever)@@ -203,7 +202,7 @@       modifyMVar_ chanSizeVar (return . (+1))  -    numFramesVar :: MVar Int <- liftIO $ newMVar 0+    --numFramesVar :: MVar Int <- liftIO $ newMVar 0      -- The main application loop. We wait for new events, fire those that     -- have subscribers, and update the display. If we detect a shutdown
src/Potato/Reflex/Vty/Widget.hs view
@@ -42,7 +42,7 @@   -import           Control.Monad.NodeId+import Control.Monad.Fix import           Control.Monad.Reader import           System.Clock @@ -100,7 +100,7 @@     , _dobuleClickConfig_button      :: V.Button   } -doubleClick :: (Reflex t, MonadHold t m, MonadFix m, PerformEvent t m, MonadIO (Performable m), HasInput t m) => DoubleClickConfig -> m (Event t ())+doubleClick :: (MonadHold t m, MonadFix m, PerformEvent t m, MonadIO (Performable m), HasInput t m) => DoubleClickConfig -> m (Event t ()) doubleClick DoubleClickConfig {..} = do   singleClickEv <- singleClickNoDragOffSimple _dobuleClickConfig_button   singleClickTimeEv <- performEvent $ ffor singleClickEv $ \_ -> do@@ -112,7 +112,7 @@       then Just ()        else Nothing   -doubleClickSimple :: (Reflex t, MonadHold t m, MonadFix m, PerformEvent t m, MonadIO (Performable m), HasInput t m) => m (Event t ())+doubleClickSimple :: (MonadHold t m, MonadFix m, PerformEvent t m, MonadIO (Performable m), HasInput t m) => m (Event t ()) doubleClickSimple = doubleClick DoubleClickConfig {     --_doubleClickConfig_spaceTolerance = (0,0)     _doubleClickConfig_timeTolerance = 300@@ -126,7 +126,7 @@ -- | A split of the available space into two parts with a draggable separator. -- Starts with half the space allocated to each, and the first pane has focus. -- Clicking in a pane switches focus.-splitHDrag :: (Reflex t, MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)+splitHDrag :: (MonadFix m, MonadHold t m, HasDisplayRegion t m, HasInput t m, HasImageWriter t m, HasFocusReader t m)   => Int -- ^ initial width of left panel   -> m ()   -> m a
src/Potato/Reflex/Vty/Widget/Popup.hs view
@@ -9,7 +9,6 @@ import           Relude  import           Potato.Reflex.Vty.Helpers-import           Potato.Reflex.Vty.Widget  import qualified Graphics.Vty.Input.Events as V import           Reflex
src/Potato/Reflex/Vty/Widget/ScrollBar.hs view
@@ -13,14 +13,8 @@  import qualified Graphics.Vty as V import           Reflex-import           Reflex.Network-import           Reflex.Potato.Helpers import           Reflex.Vty --import           Data.Default-import qualified Data.Sequence as Seq-import Data.Fixed (div') import Data.These import Data.Align (align) @@ -44,9 +38,17 @@   _ -> Nothing  +-- TODO you can use reflex.vty.widget.scroll for this+--makeVScrollBarWidget :: forall t m a. (MonadWidget t m, MonadLayoutWidget t m')+--  => m a -- ^ contents+--  -> Dynamic t Int -- ^ content height+--  -> m' a ++ -- TODO write UTs -- TODO reduce constraints-vScrollBar :: forall t m a. (MonadWidget t m)+-- dynamically scaling vertical scroll bar+vScrollBar :: forall t m. (MonadWidget t m)   => Int -- ^ width   -> Dynamic t Int -- ^ content height   -> m (Dynamic t Int) -- ^ offset@@ -54,10 +56,7 @@   maxSizeDyn <- displayHeight   let     screen_over_content_dyn :: Dynamic t Float = liftA2 (\a b -> fromIntegral a / fromIntegral b ) maxSizeDyn contentSizeDyn-    maxSizeDiffDyn = liftA2 (-) maxSizeDyn boxHeightDyn-     maxContentSizeDiffDyn = fromIntegral . max 0 <$> liftA2 (-) contentSizeDyn maxSizeDyn-     boxHeightDyn = fmap ceiling $ liftA2 (*) screen_over_content_dyn (fromIntegral <$> maxSizeDyn)     boxRegionDyn = Region <$> 0 <*> offsetScreenUnitDyn <*> constDyn scrollBarWidth <*> boxHeightDyn @@ -84,13 +83,14 @@    -- TODO movement when you click on areas off the bar   -- TODO maybe do ^ v arrows at top and bottom to click scroll through 1 at a time-   -- TODO ugg you probably need an inputCaptured event here :\ (or you could just get rid of keyboard movement...)   -- keyboard/scroll movement   kup <- key V.KUp   kdown <- key V.KDown   kpgup <- key V.KPageUp   kpgdown <- key V.KPageDown++  -- TODO this is a mouse input so it only works if mouse is over the pane, which is not what we want. So instead you you probably need to capture moues input in the parent pane and pass it in instead....   mscroll <- mouseScroll   let     requestedScroll :: Event t Float
src/Potato/Reflex/Vty/Widget/TextInputHelpers.hs view
@@ -119,6 +119,7 @@   _                                   -> Nothing  +-- DELETE -- UNTESTED -- prob don't need this version filenameInputFireEventOnLoseFocus@@ -172,6 +173,19 @@ dropSpan _ [] = [] dropSpan n ((TZ.Span tag text):xs) = TZ.Span tag (T.drop n text) : dropSpan (max 0 (n - T.length text)) xs +addCursorSpace' :: [TZ.Span V.Attr] -> [TZ.Span V.Attr]+addCursorSpace' spans = case reverse spans of+  [] -> []+  (TZ.Span tag ""):xs -> reverse $ (TZ.Span tag " "):xs+  _ -> spans++--the EoL cursor is reported as a span with no text so convert it to a space+addCursorSpace :: [[TZ.Span V.Attr]] -> [[TZ.Span V.Attr]]+addCursorSpace spanss = case reverse spanss of+  [] -> []+  spans:xs -> reverse $ (addCursorSpace' spans):xs++ renderTextZipper :: (MonadWidget t m, HasPotato t m) => Dynamic t Int -> Dynamic t Int -> Dynamic t TZ.TextZipper -> m (Dynamic t (TZ.DisplayLines V.Attr)) renderTextZipper offsetDyn dw tz = do   f <- focus@@ -190,7 +204,7 @@         <$> dw         <*> tz         <*> attrsDyn-      img = ffor2 rows offsetDyn $ \rows' ox -> images . fmap (dropSpan ox) . TZ._displayLines_spans $ rows'+      img = ffor2 rows offsetDyn $ \rows' ox -> images . fmap (dropSpan ox) . addCursorSpace . TZ._displayLines_spans $ rows'   tellImages $ (\imgs -> (:[]) . V.vertCat $ imgs) <$> current img   return rows 
src/Reflex/Vty/Test/Monad/Host.hs view
@@ -23,10 +23,8 @@ import           Relude                   hiding (getFirst)  import           Control.Monad.Ref-import qualified Data.Map                 as Map  import qualified Graphics.Vty             as V-import           Potato.Reflex.Vty.Widget import           Reflex import           Reflex.Host.Class import           Reflex.Test.Monad.Host   (MonadReflexTest (..), ReflexTestT,@@ -36,14 +34,7 @@ import           Reflex.Vty  --- for debug layout/widget stuff-import           Control.Monad.Fix-import           Data.Bimap               (Bimap)-import qualified Data.Bimap               as Bimap-import           Data.Semigroup -- -- | reflex-vty variant of 'ReflexTestT' which packages an 'VtyEvent' into the input and 'Behavior t [V.Image]' into the output -- 'uintref' and 'uout' allow user to add their own inputs and outputs -- 'uintref' will often just be some singleton type (e.g. '()') as the app being tested still has access to the input 'Event t VtyEvent' through the 'VtyWidget' monad@@ -96,10 +87,10 @@ queueMouseEventInRegion dr mouse = do   let     absCoords (Region l t _ _) (x,y) = (x+l, y+t)-  region <- sample . current $ dr+  reg <- sample . current $ dr   case mouse of-    Left (MouseDown b c mods) -> queueVtyEvent $ uncurry V.EvMouseDown (absCoords region c) b mods-    Right (MouseUp b c) -> queueVtyEvent $ uncurry V.EvMouseUp (absCoords region c) b+    Left (MouseDown b c mods) -> queueVtyEvent $ uncurry V.EvMouseDown (absCoords reg c) b mods+    Right (MouseUp b c) -> queueVtyEvent $ uncurry V.EvMouseUp (absCoords reg c) b  -- | queue mouse event in a 'DynRegion' -- if (local) mouse coordinates are outside of the (absolute) region, returns False and does not queue any event@@ -108,18 +99,18 @@   -> Either MouseDown MouseUp -- ^ mouse coordinates are LOCAL to the input region   -> ReflexVtyTestT t uintref uout m Bool queueMouseEventInRegionGated dr mouse = do-  region <- sample . current $ dr+  reg <- sample . current $ dr   let     absCoords (Region l t _ _) (x,y) = (x+l, y+t)     coordinates = case mouse of       Left (MouseDown _ c _) -> c       Right (MouseUp _ c)    -> c     withinRegion (Region _ _ w h) (x,y) = not $ or [ x < 0, y < 0, x >= w, y >= h ]-  if withinRegion region coordinates+  if withinRegion reg coordinates     then do       case mouse of-        Left (MouseDown b c mods) -> queueVtyEvent $ uncurry V.EvMouseDown (absCoords region c) b mods-        Right (MouseUp b c) -> queueVtyEvent $ uncurry V.EvMouseUp (absCoords region c) b+        Left (MouseDown b c mods) -> queueVtyEvent $ uncurry V.EvMouseDown (absCoords reg c) b mods+        Right (MouseUp b c) -> queueVtyEvent $ uncurry V.EvMouseUp (absCoords reg c) b       return True     else return False 
test/Reflex/Vty/Test/Common.hs view
@@ -9,19 +9,10 @@  import           Relude -import           Test.Hspec-import           Test.Hspec.Contrib.HUnit   (fromHUnitTest) import           Test.HUnit -import           Control.Monad.IO.Class     (liftIO)-import           Data.Kind-import qualified Data.List as L--import qualified Graphics.Vty               as V import           Reflex import           Reflex.Host.Class-import           Reflex.Vty-import           Reflex.Vty.Test.Monad.Host   subscribeDynamic :: (MonadSubscribeEvent t m) => Dynamic t a -> m (EventHandle t a, Behavior t a)@@ -48,7 +39,7 @@   Nothing -> assertFailure "empty list"   Just x  -> Just a @=? head x -checkNothing :: (Show a) => [Maybe a] -> Assertion+checkNothing :: [Maybe a] -> Assertion checkNothing values = case nonEmpty values of   Nothing -> assertFailure "empty list"   -- TODO prob check that all elts in list are Nothing
tinytools-vty.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12  name:           tinytools-vty-version:        0.1.0.4+version:        0.1.0.7 description:    tinytools-vty is a terminal based monospace unicode diagram editing tool homepage:       https://github.com/minimapletinytools/tinytools-vty#readme bug-reports:    https://github.com/minimapletinytools/tinytools-vty/issues author:         minimaple maintainer:     minimapletinytools@gmail.com-category:       tinytools+category:       Graphics synopsis:       tinytools-vty is a terminal based monospace unicode diagram editing tool copyright:      2023 minimaple (Peter Lu) license:        BSD3@@ -15,10 +15,14 @@ build-type:     Simple extra-source-files:     README.md+    tutorial.md     ChangeLog.md-    tutorial.potato+    tutorial.tt+    xterm-256color_termwidthfile  +Tested-With: GHC ==9.2.5 || ==9.6.2+ source-repository head   type: git   location: https://github.com/minimapletinytools/tinytools-vty@@ -95,46 +99,47 @@       NoImplicitPrelude   ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints   build-depends:-      aeson-    , aeson-pretty-    , ansi-terminal-    , base >=4.7 && <5-    , bimap-    , bytestring-    , clock-    , constraints-extras-    , containers-    , data-default-    , dependent-map-    , dependent-sum-    , directory-    , extra-    , file-embed-    , filepath-    , http-conduit-    , ilist-    , lens-    , mtl-    , optparse-applicative-    , primitive-    , ref-tf-    , reflex-    , reflex-potatoes-    , reflex-test-host >=0.1.2.2-    , reflex-vty >= 0.5.1-    , relude-    , semialign-    -- TODO set latest version-    , template-haskell >=2.18-    , text-    , these-    , time-    , tinytools >= 0.1.0.3-    , vty+    base >=4.7 && <5+    , reflex >= 0.9.2 && < 1+    , reflex-test-host >=0.1.2.3 && < 0.2+    , reflex-potatoes >= 0.1.0 && < 0.2+    , reflex-vty >= 0.5.1 && < 0.6+    , tinytools == 0.1.0.7+    , aeson >= 2.1.2 && < 2.2+    , template-haskell >= 2.18 && < 2.21+    , containers >= 0.6.7 && < 0.7+    , bytestring >= 0.11.4 && < 0.12+    , mtl >= 2.3.1 && < 2.4+    , filepath >= 1.4.100 && < 1.5+    , text >= 2.0.2 && < 2.1+    , primitive >= 0.7.4 && < 0.8+    , time >= 1.12.2 && < 1.13+    , semialign >= 1.3 && < 1.4+    , these >= 1.2 && < 1.3+    , aeson-pretty >= 0.8.10 && < 0.9+    , directory >= 1.3.8 && < 1.4+    , ansi-terminal >= 1.0 && < 1.1+    , bimap >= 0.5.0 && < 0.6+    , clock >= 0.8.4 && < 0.9+    , constraints-extras >= 0.4.0 && < 0.5+    , data-default >= 0.7.1 && < 0.8+    , dependent-map >= 0.4.0 && < 0.5+    , dependent-sum >= 0.7.2 && < 0.8+    , extra >= 1.7.14 && < 1.8+    , file-embed >= 0.0.15 && < 0.1+    , http-conduit >= 2.3.8 && < 2.4+    , ilist >= 0.4.0 && < 0.5+    , lens >= 5.2.3 && < 5.3+    , ref-tf >= 0.5.0 && < 0.6+    , relude >= 1.2.1 && < 1.3+    , vty>=5.28 && <5.39+    , optparse-applicative >= 0.18.1 && < 0.19   default-language: Haskell2010  executable tinytools   main-is: Main.hs+  other-modules:+      Paths_tinytools_vty   hs-source-dirs:       app   default-extensions:@@ -175,123 +180,44 @@       NoImplicitPrelude   ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N +RTS -A128m -n2m -s -RTS   build-depends:-      aeson-    , aeson-pretty-    , ansi-terminal-    , base >=4.7 && <5-    , bimap-    , bytestring-    , clock-    , constraints-extras-    , containers-    , data-default-    , dependent-map-    , dependent-sum-    , directory-    , extra-    , file-embed-    , filepath-    , http-conduit-    , ilist-    , lens-    , mtl-    , optparse-applicative+    base >=4.7 && <5+    , reflex >= 0.9.2 && < 1+    , reflex-test-host >=0.1.2.3 && < 0.2+    , reflex-potatoes >= 0.1.0 && < 0.2+    , reflex-vty >= 0.5.1 && < 0.6+    , tinytools == 0.1.0.7+    , aeson >= 2.1.2 && < 2.2+    , template-haskell >= 2.18 && < 2.21+    , containers >= 0.6.7 && < 0.7+    , bytestring >= 0.11.4 && < 0.12+    , mtl >= 2.3.1 && < 2.4+    , filepath >= 1.4.100 && < 1.5+    , text >= 2.0.2 && < 2.1+    , primitive >= 0.7.4 && < 0.8+    , time >= 1.12.2 && < 1.13+    , semialign >= 1.3 && < 1.4+    , these >= 1.2 && < 1.3+    , aeson-pretty >= 0.8.10 && < 0.9+    , directory >= 1.3.8 && < 1.4+    , ansi-terminal >= 1.0 && < 1.1+    , bimap >= 0.5.0 && < 0.6+    , clock >= 0.8.4 && < 0.9+    , constraints-extras >= 0.4.0 && < 0.5+    , data-default >= 0.7.1 && < 0.8+    , dependent-map >= 0.4.0 && < 0.5+    , dependent-sum >= 0.7.2 && < 0.8+    , extra >= 1.7.14 && < 1.8+    , file-embed >= 0.0.15 && < 0.1+    , http-conduit >= 2.3.8 && < 2.4+    , ilist >= 0.4.0 && < 0.5+    , lens >= 5.2.3 && < 5.3+    , ref-tf >= 0.5.0 && < 0.6+    , relude >= 1.2.1 && < 1.3+    , vty>=5.28 && <5.39+    , optparse-applicative >= 0.18.1 && < 0.19     , tinytools-vty-    , primitive-    , ref-tf-    , reflex-vty >= 0.5.1-    , reflex >= 0.8 && <1-    , reflex-potatoes >=0.1-    , reflex-test-host >=0.1.2.2-    , tinytools >= 0.1.0.3-    , relude-    , semialign-    , template-haskell-    , text-    , these-    , time-    , vty   default-language: Haskell2010 -executable write-term-width-  main-is: termwidth.hs-  other-modules:-      Main-  hs-source-dirs:-      app-  default-extensions:-      ApplicativeDo-      BangPatterns-      DataKinds-      ConstraintKinds-      DeriveFoldable-      DeriveFunctor-      DeriveTraversable-      DeriveGeneric-      DeriveLift-      DeriveTraversable-      DerivingStrategies-      EmptyCase-      ExistentialQuantification-      FlexibleContexts-      FlexibleInstances-      FunctionalDependencies-      GADTs-      GeneralizedNewtypeDeriving-      InstanceSigs-      KindSignatures-      LambdaCase-      MultiParamTypeClasses-      MultiWayIf-      NamedFieldPuns-      OverloadedStrings-      PatternSynonyms-      RankNTypes-      ScopedTypeVariables-      StandaloneDeriving-      TupleSections-      TypeApplications-      TypeFamilies-      TypeFamilyDependencies-      TypeOperators-      NoImplicitPrelude-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N-  build-depends:-      aeson-    , aeson-pretty-    , ansi-terminal-    , base >=4.7 && <5-    , bimap-    , bytestring-    , clock-    , constraints-extras-    , containers-    , data-default-    , dependent-map-    , dependent-sum-    , directory-    , extra-    , file-embed-    , filepath-    , http-conduit-    , ilist-    , lens-    , mtl-    , optparse-applicative-    , primitive-    , ref-tf-    , reflex >= 0.8 && <1-    , reflex-potatoes >=0.1-    , reflex-test-host >=0.1.2.2-    , relude-    , semialign-    , template-haskell-    , text-    , these-    , time-    , vty-  default-language: Haskell2010- test-suite tinytools-vty-test   type: exitcode-stdio-1.0   main-is: Spec.hs@@ -343,43 +269,17 @@       NoImplicitPrelude   ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N   build-depends:-      HUnit-    , aeson-    , aeson-pretty-    , ansi-terminal-    , base >=4.7 && <5-    , bimap-    , bytestring-    , clock-    , constraints-extras-    , containers-    , data-default-    , dependent-map-    , dependent-sum-    , directory-    , extra-    , file-embed-    , filepath+    base >=4.7 && <5+    , HUnit     , hspec     , hspec-contrib-    , http-conduit-    , ilist-    , lens-    , mtl-    , optparse-applicative+    , reflex >= 0.9.2 && < 1+    , reflex-test-host >=0.1.2.3 && < 0.2+    , reflex-vty >= 0.5.1 && < 0.6+    , vty>=5.28 && <5.39+    , relude >= 1.2.1 && < 1.3+    , tinytools >= 0.1.0.7 && < 0.2     , tinytools-vty-    , primitive-    , ref-tf-    , reflex-    , reflex-potatoes-    , reflex-test-host >=0.1.2.2-    , reflex-vty >= 0.5.1-    , relude-    , semialign-    , template-haskell-    , text-    , these-    , time-    , tinytools >= 0.1.0.3-    , vty+    , ref-tf >= 0.5.0 && < 0.6+    , data-default >= 0.7.1 && < 0.8   default-language: Haskell2010
+ tutorial.md view
@@ -0,0 +1,51 @@+(open in the app instead for a better view, browser code preview doesn't render certain unicode characters in monospace correctly)++```++[new][open][save][save as]     *             ╔══════════════════════════════╗                                                                                            +[export to "potato.txt"][quit] *             ║                              ║ ╔IMPORTANT#########################╗                                                       +-------------------------------*   ███████████████████                      ╚>#to explore the canvas, click the  #                                                       +[(v)select][(p)an][(b)ox]      *   █THIS IS TINYTOOLS█═╗                      #[(p)an] button or press p         #                                                       +[(l)ine][(t)extbox][pai(n)t]   *   ███████████████████ ║                      #                                  #                                                       +-------------------------------*                       v                      #then click and drag in the canvas #                                                       +⇊ea 𐃛 starter                 #*   <═══╗   ╔══════════════════════╗           #area to move your view            #                                                       +  ea ⧈ info: more features    #*       ║   ║the menu on the left  ║           #                                  #                                                       +  ea ⤡ <line>                 #*       ╚═══║has a lot of important║═══╗       #                                  #                                                       +  ea ⤡ <line>                 #*           ║operations            ║   ║       ╚##################################╝                                                       +  ea ⤡ <line>                 #*           ╚══════════════════════╝   ║                        ^                                                                         +  ea ⧈ info: pan              #*                      ║               ║                        ║                                                                         +  ea ⤡ <line>                 #*                      v               ║                        ║                                                                         +  ea ⧈ info: box parameters   #*        ╔═══════════════════════════╗ ║                        ║                                                                         +  ea ⤡ <line>                 #*        ║to draw a box, click the   ║ ║                        ║                                                                         +  ea ⤡ <line>                 #*        ║[(b)ox] button or press b  ║ ║                        ╚════════════════════╗                                                    +  ea ⧈ info: canvas           #*        ║                           ║ ║                                             ║                                                    +  ea ⧈ info: box              #*        ║then click and drag in the ║ ║                                             ║                                                    +  ea ⧈ info: menu             #*        ║canvas area                ║ ║                        *------------------* ║                                                    +  ea ⤡ <line>                 #*        ╚═══════════════════════════╝ ║                        |this area (to the | ║                                                    +  ea ⤡ <line>                 #*                             ║        ╚═══════════════════════>|right) is called  |═╝                                                    +  ea ⧈ title                  #*                             ║                                 |the canvas        |                                                      +                              #*                             v                                 |                  |                                                      +                              #*            ╔═════════════════════════════════╗                |                  |                                                      +                              #*            ║after creating a box, it will be ║                |                  |                                                      +                              #*            ║selected, you can use the options║                *------------------*                                                      +                              #*            ║in the bottom right to change its║                                                                                          +                              #*      ╔═════║style. you can also convert your ║                                                                                          +                              #*  <═══╝     ║box into a text box or remove its║     ╔═══════════════════════════════╗                                                    +                              #*            ║border                           ║     ║of course there are many more  ║                                                    +                              #*            ║                                 ║     ║features, play around!         ║                                                    +                              #*            ║                                 ║     ║                               ║                                                    +                              #*            ╚═════════════════════════════════╝     ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +                              #*                                                    ║                               ║                                                    +[new folder]                   *                                                    ║                               ║                                                    +-------------------------------*                                                    ╚═══════════════════════════════╝                                                    +canvas:                        *                                                                                                                                         + width: 500                    *                                                                                                                                         +height: 200                    *                                                                                                                                         +```         
− tutorial.potato
@@ -1,5 +0,0 @@-{-    "_snake_data": "[\n    {\n        \"_sPotatoFlow_sCanvas\": {\n            \"_sCanvas_box\": {\n                \"_lBox_size\": [\n                    500,\n                    200\n                ],\n                \"_lBox_tl\": [\n                    0,\n                    0\n                ]\n            }\n        },\n        \"_sPotatoFlow_sEltTree\": [\n            [\n                66,\n                {\n                    \"_sEltLabel_name\": \"starter\",\n                    \"_sEltLabel_sElt\": {\n                        \"tag\": \"SEltFolderStart\"\n                    }\n                }\n            ],\n            [\n                65,\n                {\n                    \"_sEltLabel_name\": \"info: more features\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    33,\n                                    15\n                                ],\n                                \"_lBox_tl\": [\n                                    52,\n                                    28\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"of course there are many more features, play around!\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                64,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 21,\n                                    \"numerator\": 11\n                                },\n                                \"_attachment_target\": 1\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 11,\n                                    \"numerator\": 8\n                                },\n                                \"_attachment_target\": 37\n                            },\n                            \"_sAutoLine_end\": [\n                                13,\n                                1\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                40,\n                                3\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                55,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 1\n                            },\n                            \"_sAutoLine_end\": [\n                                23,\n                                5\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                22,\n                                2\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                46,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 37\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 10,\n                                    \"numerator\": 3\n                                },\n                                \"_attachment_target\": 5\n                            },\n                            \"_sAutoLine_end\": [\n                                71,\n                                13\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                82,\n                                20\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                37,\n                {\n                    \"_sEltLabel_name\": \"info: pan\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    36,\n                                    9\n                                ],\n                                \"_lBox_tl\": [\n                                    46,\n                                    1\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"#\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"#\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"to explore the canvas, click the [(p)an] button or press p\\n \\nthen click and drag in the canvas area to move your view\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": \"IMPORTANT\"\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                36,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 12\n                            },\n                            \"_sAutoLine_attachStart\": null,\n                            \"_sAutoLine_end\": [\n                                11,\n                                27\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                2,\n                                28\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                12,\n                {\n                    \"_sEltLabel_name\": \"info: box parameters\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    35,\n                                    10\n                                ],\n                                \"_lBox_tl\": [\n                                    12,\n                                    23\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"after creating a box, it will be selected, you can use the options in the bottom right to change its style. you can also convert your box into a text box or remove its border\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                24,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 31,\n                                    \"numerator\": 8\n                                },\n                                \"_attachment_target\": 4\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 12\n                            },\n                            \"_sAutoLine_end\": [\n                                30,\n                                19\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                29,\n                                22\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                11,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 4\n                            },\n                            \"_sAutoLine_end\": [\n                                22,\n                                11\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                23,\n                                16\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                5,\n                {\n                    \"_sEltLabel_name\": \"info: canvas\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    20,\n                                    8\n                                ],\n                                \"_lBox_tl\": [\n                                    63,\n                                    18\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"*\",\n                                \"_superStyle_br\": \"*\",\n                                \"_superStyle_fill\": {\n                                    \"tag\": \"FillStyle_Blank\"\n                                },\n                                \"_superStyle_horizontal\": \"-\",\n                                \"_superStyle_point\": \" \",\n                                \"_superStyle_tl\": \"*\",\n                                \"_superStyle_tr\": \"*\",\n                                \"_superStyle_vertical\": \"|\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"this area (to the right) is called the canvas\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                4,\n                {\n                    \"_sEltLabel_name\": \"info: box\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    29,\n                                    7\n                                ],\n                                \"_lBox_tl\": [\n                                    8,\n                                    13\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"to draw a box, click the [(b)ox] button or press b\\n\\n \\nthen click and drag in the canvas area\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                3,\n                {\n                    \"_sEltLabel_name\": \"info: menu\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    24,\n                                    5\n                                ],\n                                \"_lBox_tl\": [\n                                    11,\n                                    6\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"the menu on the left has a lot of important operations\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                8,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 5,\n                                    \"numerator\": 3\n                                },\n                                \"_attachment_target\": 5\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_end\": [\n                                63,\n                                21\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [\n                                [\n                                    38,\n                                    20\n                                ]\n                            ],\n                            \"_sAutoLine_start\": [\n                                35,\n                                8\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                2,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": null,\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_end\": [\n                                3,\n                                6\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                10,\n                                7\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                1,\n                {\n                    \"_sEltLabel_name\": \"title\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    19,\n                                    3\n                                ],\n                                \"_lBox_tl\": [\n                                    3,\n                                    2\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"█\",\n                                \"_superStyle_br\": \"█\",\n                                \"_superStyle_fill\": {\n                                    \"tag\": \"FillStyle_Blank\"\n                                },\n                                \"_superStyle_horizontal\": \"█\",\n                                \"_superStyle_point\": \" \",\n                                \"_superStyle_tl\": \"█\",\n                                \"_superStyle_tr\": \"█\",\n                                \"_superStyle_vertical\": \"█\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"THIS IS TINYTOOLS\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                67,\n                {\n                    \"_sEltLabel_name\": \"starter(end)\",\n                    \"_sEltLabel_sElt\": {\n                        \"tag\": \"SEltFolderEnd\"\n                    }\n                }\n            ]\n        ]\n    },\n    {\n        \"_controllerMeta_layers\": [\n            [\n                1,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                2,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                3,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                4,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                5,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                8,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                11,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                12,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                24,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                36,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                37,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                46,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                55,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                64,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                65,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                66,\n                {\n                    \"_layerMeta_isCollapsed\": false,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ]\n        ],\n        \"_controllerMeta_pan\": [\n            0,\n            0\n        ]\n    }\n]",-    "_snake_format": "json",-    "_snake_version": 1-}
+ tutorial.tt view
@@ -0,0 +1,5 @@+{+    "_snake_data": "[\n    {\n        \"_sPotatoFlow_sCanvas\": {\n            \"_sCanvas_box\": {\n                \"_lBox_size\": [\n                    500,\n                    200\n                ],\n                \"_lBox_tl\": [\n                    0,\n                    0\n                ]\n            }\n        },\n        \"_sPotatoFlow_sEltTree\": [\n            [\n                66,\n                {\n                    \"_sEltLabel_name\": \"starter\",\n                    \"_sEltLabel_sElt\": {\n                        \"tag\": \"SEltFolderStart\"\n                    }\n                }\n            ],\n            [\n                65,\n                {\n                    \"_sEltLabel_name\": \"info: more features\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    33,\n                                    15\n                                ],\n                                \"_lBox_tl\": [\n                                    52,\n                                    28\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"of course there are many more features, play around!\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                64,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 21,\n                                    \"numerator\": 11\n                                },\n                                \"_attachment_target\": 1\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 11,\n                                    \"numerator\": 8\n                                },\n                                \"_attachment_target\": 37\n                            },\n                            \"_sAutoLine_end\": [\n                                13,\n                                1\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                40,\n                                3\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                55,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 1\n                            },\n                            \"_sAutoLine_end\": [\n                                23,\n                                5\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                22,\n                                2\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                46,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 37\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 10,\n                                    \"numerator\": 3\n                                },\n                                \"_attachment_target\": 5\n                            },\n                            \"_sAutoLine_end\": [\n                                71,\n                                13\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                82,\n                                20\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                37,\n                {\n                    \"_sEltLabel_name\": \"info: pan\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    36,\n                                    9\n                                ],\n                                \"_lBox_tl\": [\n                                    46,\n                                    1\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"#\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"#\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"to explore the canvas, click the [(p)an] button or press p\\n \\nthen click and drag in the canvas area to move your view\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": \"IMPORTANT\"\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                36,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 12\n                            },\n                            \"_sAutoLine_attachStart\": null,\n                            \"_sAutoLine_end\": [\n                                11,\n                                27\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                2,\n                                28\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                12,\n                {\n                    \"_sEltLabel_name\": \"info: box parameters\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    35,\n                                    10\n                                ],\n                                \"_lBox_tl\": [\n                                    12,\n                                    23\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"after creating a box, it will be selected, you can use the options in the bottom right to change its style. you can also convert your box into a text box or remove its border\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                24,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 31,\n                                    \"numerator\": 8\n                                },\n                                \"_attachment_target\": 4\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 12\n                            },\n                            \"_sAutoLine_end\": [\n                                30,\n                                19\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                29,\n                                22\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                11,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Bot\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Top\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 4\n                            },\n                            \"_sAutoLine_end\": [\n                                22,\n                                11\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                23,\n                                16\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                5,\n                {\n                    \"_sEltLabel_name\": \"info: canvas\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    20,\n                                    8\n                                ],\n                                \"_lBox_tl\": [\n                                    63,\n                                    18\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"*\",\n                                \"_superStyle_br\": \"*\",\n                                \"_superStyle_fill\": {\n                                    \"tag\": \"FillStyle_Blank\"\n                                },\n                                \"_superStyle_horizontal\": \"-\",\n                                \"_superStyle_point\": \" \",\n                                \"_superStyle_tl\": \"*\",\n                                \"_superStyle_tr\": \"*\",\n                                \"_superStyle_vertical\": \"|\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"this area (to the right) is called the canvas\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                4,\n                {\n                    \"_sEltLabel_name\": \"info: box\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    29,\n                                    7\n                                ],\n                                \"_lBox_tl\": [\n                                    8,\n                                    13\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"to draw a box, click the [(b)ox] button or press b\\n\\n \\nthen click and drag in the canvas area\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                3,\n                {\n                    \"_sEltLabel_name\": \"info: menu\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    24,\n                                    5\n                                ],\n                                \"_lBox_tl\": [\n                                    11,\n                                    6\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"the menu on the left has a lot of important operations\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                8,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 5,\n                                    \"numerator\": 3\n                                },\n                                \"_attachment_target\": 5\n                            },\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Right\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_end\": [\n                                63,\n                                21\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [\n                                [\n                                    38,\n                                    20\n                                ]\n                            ],\n                            \"_sAutoLine_start\": [\n                                35,\n                                8\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                2,\n                {\n                    \"_sEltLabel_name\": \"<line>\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sAutoLine_attachEnd\": null,\n                            \"_sAutoLine_attachStart\": {\n                                \"_attachment_location\": \"AL_Left\",\n                                \"_attachment_offset_rel\": {\n                                    \"denominator\": 2,\n                                    \"numerator\": 1\n                                },\n                                \"_attachment_target\": 3\n                            },\n                            \"_sAutoLine_end\": [\n                                3,\n                                6\n                            ],\n                            \"_sAutoLine_labels\": [],\n                            \"_sAutoLine_lineStyle\": {\n                                \"_lineStyle_downArrows\": \"\",\n                                \"_lineStyle_leftArrows\": \"\",\n                                \"_lineStyle_rightArrows\": \"\",\n                                \"_lineStyle_upArrows\": \"\"\n                            },\n                            \"_sAutoLine_lineStyleEnd\": {\n                                \"_lineStyle_downArrows\": \"v\",\n                                \"_lineStyle_leftArrows\": \"<\",\n                                \"_lineStyle_rightArrows\": \">\",\n                                \"_lineStyle_upArrows\": \"^\"\n                            },\n                            \"_sAutoLine_midpoints\": [],\n                            \"_sAutoLine_start\": [\n                                10,\n                                7\n                            ],\n                            \"_sAutoLine_superStyle\": {\n                                \"_superStyle_bl\": \"╚\",\n                                \"_superStyle_br\": \"╝\",\n                                \"_superStyle_fill\": {\n                                    \"contents\": \" \",\n                                    \"tag\": \"FillStyle_Simple\"\n                                },\n                                \"_superStyle_horizontal\": \"═\",\n                                \"_superStyle_point\": \"█\",\n                                \"_superStyle_tl\": \"╔\",\n                                \"_superStyle_tr\": \"╗\",\n                                \"_superStyle_vertical\": \"║\"\n                            }\n                        },\n                        \"tag\": \"SEltLine\"\n                    }\n                }\n            ],\n            [\n                1,\n                {\n                    \"_sEltLabel_name\": \"title\",\n                    \"_sEltLabel_sElt\": {\n                        \"contents\": {\n                            \"_sBox_box\": {\n                                \"_lBox_size\": [\n                                    19,\n                                    3\n                                ],\n                                \"_lBox_tl\": [\n                                    3,\n                                    2\n                                ]\n                            },\n                            \"_sBox_boxType\": \"SBoxType_BoxText\",\n                            \"_sBox_superStyle\": {\n                                \"_superStyle_bl\": \"█\",\n                                \"_superStyle_br\": \"█\",\n                                \"_superStyle_fill\": {\n                                    \"tag\": \"FillStyle_Blank\"\n                                },\n                                \"_superStyle_horizontal\": \"█\",\n                                \"_superStyle_point\": \" \",\n                                \"_superStyle_tl\": \"█\",\n                                \"_superStyle_tr\": \"█\",\n                                \"_superStyle_vertical\": \"█\"\n                            },\n                            \"_sBox_text\": {\n                                \"_sBoxText_style\": {\n                                    \"_textStyle_alignment\": \"TextAlign_Left\"\n                                },\n                                \"_sBoxText_text\": \"THIS IS TINYTOOLS\"\n                            },\n                            \"_sBox_title\": {\n                                \"_sBoxTitle_align\": \"TextAlign_Left\",\n                                \"_sBoxTitle_title\": null\n                            }\n                        },\n                        \"tag\": \"SEltBox\"\n                    }\n                }\n            ],\n            [\n                67,\n                {\n                    \"_sEltLabel_name\": \"starter(end)\",\n                    \"_sEltLabel_sElt\": {\n                        \"tag\": \"SEltFolderEnd\"\n                    }\n                }\n            ]\n        ]\n    },\n    {\n        \"_controllerMeta_layers\": [\n            [\n                1,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                2,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                3,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                4,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                5,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                8,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                11,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                12,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                24,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                36,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                37,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                46,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                55,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                64,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                65,\n                {\n                    \"_layerMeta_isCollapsed\": true,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ],\n            [\n                66,\n                {\n                    \"_layerMeta_isCollapsed\": false,\n                    \"_layerMeta_isHidden\": false,\n                    \"_layerMeta_isLocked\": false\n                }\n            ]\n        ],\n        \"_controllerMeta_pan\": [\n            0,\n            0\n        ]\n    }\n]",+    "_snake_format": "json",+    "_snake_version": 1+}
+ xterm-256color_termwidthfile view

binary file changed (absent → 11493 bytes)