typed-spreadsheet 1.1.0 → 1.1.1
raw patch · 5 files changed
+314/−146 lines, 5 filesdep ~asyncdep ~basedep ~diagrams-caironew-component:exe:typed-spreadsheet-example-cellnew-component:exe:typed-spreadsheet-example-text
Dependency ranges changed: async, base, diagrams-cairo, diagrams-gtk, diagrams-lib, foldl, gtk, microlens, transformers
Files
- exec/Cell.hs +16/−0
- exec/Graphics.hs +7/−11
- exec/Text.hs +7/−9
- src/Typed/Spreadsheet.hs +252/−111
- typed-spreadsheet.cabal +32/−15
+ exec/Cell.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE ApplicativeDo #-}+{-# LANGUAGE OverloadedStrings #-}++import Typed.Spreadsheet++main :: IO ()+main = cellUI "Example program" $ do+ a <- checkBox "a"+ b <- spinButton "b" 1+ c <- spinButton "c" 0.1+ d <- entry "d"+ return+ [ ("a" , display a )+ , ("b + c", display (b + c))+ , ("d" , display d )+ ]
exec/Graphics.hs view
@@ -1,6 +1,6 @@+{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE OverloadedStrings #-} -import Diagrams.Backend.Cairo (Cairo) import Diagrams.Prelude import Typed.Spreadsheet @@ -16,13 +16,9 @@ toColor Purple = purple main :: IO ()-main = graphicalUI "Example program" logic- where- logic = combine <$> radioButton "Color" Red [Orange .. Purple]- <*> spinButtonAt 100 "Radius" 1- <*> spinButton "X Coordinate" 1- <*> spinButton "Y Coordinate" 1-- combine :: AColor -> Double -> Double -> Double -> Diagram Cairo- combine color r x y =- circle r # fc (toColor color) # translate (r2 (x, y))+main = graphicalUI "Example program" $ do+ color <- radioButton "Color" Red [Orange .. Purple]+ r <- spinButtonAt 100 "Radius" 1+ x <- hscaleWithRange (-200) 200 0 "X Coordinate" 10+ y <- vscaleWithRange (-200) 200 0 "Y Coordinate" 10+ return (circle r # fc (toColor color) # translate (r2 (x, y)))
exec/Text.hs view
@@ -1,14 +1,12 @@+{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE OverloadedStrings #-} -import Control.Applicative import Typed.Spreadsheet main :: IO ()-main = textUI "Example program" logic- where- logic = combine <$> checkBox "a"- <*> spinButton "b" 1- <*> spinButton "c" 0.1- <*> entry "d"-- combine a b c d = display (a, b + c, d)+main = textUI "Example program" $ do+ a <- checkBox "a"+ b <- spinButton "b" 1+ c <- spinButton "c" 0.1+ d <- entry "d"+ return (display (a, b + c, d))
src/Typed/Spreadsheet.hs view
@@ -1,22 +1,21 @@ {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ApplicativeDo #-} -- | The following program: --+-- > {-# LANGUAGE ApplicativeDo #-} -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Control.Applicative -- > import Typed.Spreadsheet -- > -- > main :: IO ()--- > main = textUI "Example program" logic--- > where--- > logic = combine <$> checkBox "a"--- > <*> spinButton "b" 1--- > <*> spinButton "c" 0.1--- > <*> entry "d"--- > --- > combine a b c d = display (a, b + c, d)+-- > main = textUI "Example program" $ do+-- > a <- checkBox "a"+-- > b <- spinButton "b" 1+-- > c <- spinButton "c" 0.1+-- > d <- entry "d"+-- > return (display (a, b + c, d)) -- -- ... creates a user interface that looks like this: --@@ -27,27 +26,11 @@ -- -- <<http://i.imgur.com/TTxgSwN.png User interface after user input>> ----- Once @ghc-8.0@ is out then you can simplify the above program even further--- using the `ApplicativeDo` extension:------ > {-# LANGUAGE ApplicativeDo #-}--- > {-# LANGUAGE OverloadedStrings #-}--- > --- > import Typed.Spreadsheet--- > --- > main :: IO ()--- > main = textUI "Example program" (do--- > a <- checkBox "a"--- > b <- spinButton "b" 1--- > c <- spinButton "c" 0.1--- > d <- entry "d"--- > return (display (a, b + c, d)) )--- -- This library also supports graphical output, like in the following program: --+-- > {-# LANGUAGE ApplicativeDo #-} -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Diagrams.Backend.Cairo (Cairo) -- > import Diagrams.Prelude -- > import Typed.Spreadsheet -- > @@ -63,16 +46,12 @@ -- > toColor Purple = purple -- > -- > main :: IO ()--- > main = graphicalUI "Example program" logic--- > where--- > logic = combine <$> radioButton "Color" Red [Orange .. Purple]--- > <*> spinButtonAt 100 "Radius" 1--- > <*> spinButton "X Coordinate" 1--- > <*> spinButton "Y Coordinate" 1--- > --- > combine :: AColor -> Double -> Double -> Double -> Diagram Cairo--- > combine color r x y =--- > circle r # fc (toColor color) # translate (r2 (x, y))+-- > main = graphicalUI "Example program" $ do+-- > color <- radioButton "Color" Red [Orange .. Purple]+-- > r <- spinButtonAt 100 "Radius" 1+-- > x <- spinButton "X Coordinate" 1+-- > y <- spinButton "Y Coordinate" 1+-- > return (circle r # fc (toColor color) # translate (r2 (x, y))) -- -- This produces a canvas that colors, resizes, and moves a circle in response -- to user input:@@ -84,9 +63,8 @@ -- * You build primitive `Updatable` values using `checkBox`, `spinButton`, -- `entry`, or `radioButton`, each of which corresponds to a control on the -- left panel of the user interface--- * You transform or combine `Updatable` values using `Functor` and--- `Applicative` operations. Composite values update whenever one of their--- substituent values update+-- * Combine `Updatable` values using @ApplicativeDo@ notation. Composite values+-- update whenever one of their substituent values update -- * You consume an @(`Updatable` `Text`)@ value using `textUI`, which displays -- the continuously updating value in the right panel of the user interface --@@ -96,9 +74,13 @@ -- > $ stack build --install-ghc # Builds the executable -- > $ stack exec typed-spreadsheet-example # Runs the executable ----- That project includes the code for the above example in @exec/Main.hs@. Just--- modify that file and rebuild to play with the example.+-- ... or if you are using OS X, then build the project using: --+-- > $ stack --stack-yaml=osx.yaml build --install-ghc+--+-- That project includes the code for the above examples in the @exec/@+-- subdirectory. Just modify that file and rebuild to play with the example.+-- -- NOTE: You must compile your program with the @-threaded@ flag. The example -- project takes care of this. --@@ -108,6 +90,7 @@ -- * Types Updatable , textUI+ , cellUI , graphicalUI -- * Controls@@ -119,6 +102,12 @@ -- * Controls with Defaults , checkBoxAt , spinButtonAt+ , hscale+ , hscaleAt+ , hscaleWithRange+ , vscale+ , vscaleAt+ , vscaleWithRange , entryAt -- * Utilities@@ -129,23 +118,22 @@ ) where import Control.Applicative-import Control.Concurrent (threadDelay) import Control.Concurrent.STM (STM) import Control.Foldl (Fold(..)) import Control.Monad.IO.Class (liftIO)-import Data.Monoid import Data.String (IsString(..)) import Data.Text (Text) import Diagrams.Backend.Cairo (Cairo)-import Diagrams.Backend.Gtk (renderToGtk) import Diagrams.Prelude (Diagram, r2, reflectY, translate, (#)) import Lens.Micro (_Left, _Right) import Graphics.UI.Gtk (AttrOp((:=))) +import qualified Control.Concurrent import qualified Control.Concurrent.STM as STM-import qualified Control.Concurrent.Async as Async-import qualified Control.Foldl as Fold-import qualified Data.Text as Text+import qualified Control.Concurrent.Async+import qualified Control.Foldl+import qualified Data.Text+import qualified Diagrams.Backend.Gtk import qualified Graphics.UI.Gtk as Gtk data Cell a = forall e . Cell (IO (STM e, Fold e a))@@ -162,7 +150,10 @@ where input = fmap Left inputF <|> fmap Right inputX - fold = Fold.handles _Left foldF <*> Fold.handles _Right foldX+ fold = do+ f <- Control.Foldl.handles _Left foldF+ x <- Control.Foldl.handles _Right foldX+ return (f x) -- | An updatable input value data Updatable a = Updatable (Control -> Cell a)@@ -225,10 +216,12 @@ -- | Use a `Control` to obtain updatable input `Updatable`s data Control = Control- { _checkBoxAt :: Bool -> Text -> Cell Bool- , _spinButtonAt :: Double -> Text -> Double -> Cell Double- , _entryAt :: Text -> Text -> Cell Text- , _radioButton :: forall a . Show a => Text -> a -> [a] -> Cell a+ { _checkBoxAt :: Bool -> Text -> Cell Bool+ , _spinButtonAt :: Double -> Text -> Double -> Cell Double+ , _hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double+ , _vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double+ , _entryAt :: Text -> Text -> Cell Text+ , _radioButton :: forall a . Show a => Text -> a -> [a] -> Cell a } -- | Build a `Text`-based user interface@@ -253,8 +246,10 @@ vAdjust <- Gtk.textViewGetVadjustment textView scrolledWindow <- Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust) Gtk.set scrolledWindow- [ Gtk.containerChild := textView- , Gtk.scrolledWindowShadowType := Gtk.ShadowIn+ [ Gtk.containerChild := textView+ , Gtk.scrolledWindowShadowType := Gtk.ShadowIn+ , Gtk.scrolledWindowHscrollbarPolicy := Gtk.PolicyAutomatic+ , Gtk.scrolledWindowVscrollbarPolicy := Gtk.PolicyAutomatic ] Gtk.boxPackStart hBox scrolledWindow Gtk.PackGrow 0 return textBuffer@@ -263,6 +258,57 @@ processTextEvent textBuffer txt = Gtk.set textBuffer [ Gtk.textBufferText := txt ] +-- | Build a cell-based user interface+cellUI+ :: Text+ -- ^ Window title+ -> Updatable [(Text, Text)]+ -- ^ Program logic+ -> IO ()+cellUI = ui cellSetup processCellEvent+ where+ cellSetup :: Gtk.HBox -> IO Gtk.VBox+ cellSetup hBox = do+ vbox <- Gtk.vBoxNew False 5+ Gtk.boxPackStart hBox vbox Gtk.PackGrow 0+ return vbox++ processCellEvent :: Gtk.VBox -> [(Text, Text)] -> IO ()+ processCellEvent vbox keyVals = do+ cells <- Gtk.containerGetChildren vbox+ mapM_ (Gtk.containerRemove vbox) cells++ let createCell (key, val) = do+ textView <- Gtk.textViewNew+ textBuffer <- Gtk.get textView Gtk.textViewBuffer+ Gtk.set textView+ [ Gtk.textViewEditable := False+ , Gtk.textViewCursorVisible := False+ ]+ Gtk.set textBuffer [ Gtk.textBufferText := val ]+ hAdjust <- Gtk.textViewGetHadjustment textView+ vAdjust <- Gtk.textViewGetVadjustment textView+ scrolledWindow <- do+ Gtk.scrolledWindowNew (Just hAdjust) (Just vAdjust)+ Gtk.set scrolledWindow+ [ Gtk.containerChild :=+ textView+ , Gtk.scrolledWindowShadowType :=+ Gtk.ShadowIn+ , Gtk.scrolledWindowHscrollbarPolicy :=+ Gtk.PolicyAutomatic+ , Gtk.scrolledWindowVscrollbarPolicy :=+ Gtk.PolicyAutomatic+ ]+ frame <- Gtk.frameNew+ Gtk.set frame+ [ Gtk.containerChild := scrolledWindow+ , Gtk.frameLabel := key+ ]+ Gtk.boxPackStart vbox frame Gtk.PackNatural 0+ mapM_ createCell keyVals+ Gtk.widgetShowAll vbox+ -- | Build a `Diagram`-based user interface graphicalUI :: Text@@ -284,7 +330,8 @@ (w, h) <- Gtk.widgetGetSize drawingArea let w' = fromIntegral w / 2 let h' = fromIntegral h / 2- renderToGtk drawWindow (diagram # reflectY # translate (r2 (w', h')))+ let diagram' = diagram # reflectY # translate (r2 (w', h'))+ Diagrams.Backend.Gtk.renderToGtk drawWindow diagram' -- | Shared logic for `textUI` and `graphicalUI` ui :: (Gtk.HBox -> IO a)@@ -334,8 +381,46 @@ Gtk.boxPackStart vBox frame Gtk.PackNatural 0 Gtk.widgetShowAll vBox- return (STM.takeTMVar tmvar, Fold.lastDef s0) )+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) ) + let __hscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double+ __hscaleWithRange minY maxY s0 label stepY = Cell (do+ tmvar <- STM.newEmptyTMVarIO+ slider <- Gtk.hScaleNewWithRange minY maxY stepY+ Gtk.set slider+ [ Gtk.rangeValue := s0+ ]+ _ <- Gtk.onRangeValueChanged slider (do+ n <- Gtk.get slider Gtk.rangeValue+ STM.atomically (STM.putTMVar tmvar n) )+ frame <- Gtk.frameNew+ Gtk.set frame+ [ Gtk.containerChild := slider+ , Gtk.frameLabel := label+ ]+ Gtk.boxPackStart vBox frame Gtk.PackNatural 0+ Gtk.widgetShowAll vBox+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )++ let __vscaleWithRange :: Double -> Double -> Double -> Text -> Double -> Cell Double+ __vscaleWithRange minY maxY s0 label stepY = Cell (do+ tmvar <- STM.newEmptyTMVarIO+ slider <- Gtk.vScaleNewWithRange minY maxY stepY+ Gtk.set slider+ [ Gtk.rangeValue := (-s0)+ ]+ _ <- Gtk.onRangeValueChanged slider (do+ n <- Gtk.get slider Gtk.rangeValue+ STM.atomically (STM.putTMVar tmvar (-n)) )+ frame <- Gtk.frameNew+ Gtk.set frame+ [ Gtk.containerChild := slider+ , Gtk.frameLabel := label+ ]+ Gtk.boxPackStart hBox frame Gtk.PackNatural 0+ Gtk.widgetShowAll hBox+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) )+ let __checkBoxAt :: Bool -> Text -> Cell Bool __checkBoxAt s0 label = Cell (do checkButton <- Gtk.checkButtonNewWithLabel label@@ -348,7 +433,7 @@ Gtk.boxPackStart vBox checkButton Gtk.PackNatural 0 Gtk.widgetShowAll vBox- return (STM.takeTMVar tmvar, Fold.lastDef s0) )+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) ) let __entryAt :: Text -> Text -> Cell Text __entryAt s0 label = Cell (do@@ -368,7 +453,7 @@ Gtk.boxPackStart vBox frame Gtk.PackNatural 0 Gtk.widgetShowAll frame- return (STM.takeTMVar tmvar, Fold.lastDef s0) )+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef s0) ) let __radioButton :: Show a => Text -> a -> [a] -> Cell a __radioButton label x xs = Cell (do@@ -376,13 +461,13 @@ vBoxRadio <- Gtk.vBoxNew False 5 - let makeButton f a = do- button <- f (show a)+ let makeButton f y = do+ button <- f (show y) Gtk.boxPackStart vBoxRadio button Gtk.PackNatural 0 _ <- Gtk.on button Gtk.toggled (do active <- Gtk.get button Gtk.toggleButtonActive if active- then STM.atomically (STM.putTMVar tmvar a)+ then STM.atomically (STM.putTMVar tmvar y) else return () ) return button @@ -396,13 +481,15 @@ ] Gtk.boxPackStart vBox frame Gtk.PackNatural 0 Gtk.widgetShowAll frame- return (STM.takeTMVar tmvar, Fold.lastDef x) )+ return (STM.takeTMVar tmvar, Control.Foldl.lastDef x) ) let control = Control- { _checkBoxAt = __checkBoxAt- , _spinButtonAt = __spinButtonAt- , _entryAt = __entryAt- , _radioButton = __radioButton+ { _checkBoxAt = __checkBoxAt+ , _spinButtonAt = __spinButtonAt+ , _hscaleWithRange = __hscaleWithRange+ , _vscaleWithRange = __vscaleWithRange+ , _entryAt = __entryAt+ , _radioButton = __radioButton } doneTMVar <- STM.newEmptyTMVarIO@@ -410,7 +497,7 @@ let run (Cell m) = do (stm, Fold step begin done) <- Gtk.postGUISync m -- I don't know why this delay is necessary for diagrams output- threadDelay 200000+ Control.Concurrent.threadDelay 200000 let loop x = do let b = done x Gtk.postGUISync (process a b)@@ -428,9 +515,9 @@ Gtk.mainQuit return False )) Gtk.widgetShowAll window- Async.withAsync (run (k control)) (\a -> do+ Control.Concurrent.Async.withAsync (run (k control)) (\s -> do Gtk.mainGUI- Async.wait a )+ Control.Concurrent.Async.wait s ) -- | A check box that returns `True` if selected and `False` if unselected checkBox@@ -448,12 +535,30 @@ -> Updatable Double spinButton = spinButtonAt 0 +-- | A `Double` horizontal slider+hscale+ :: Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+hscale = hscaleAt 0++-- | A `Double` vertical slider+vscale+ :: Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+vscale = vscaleAt 0+ -- | A `Text` entry entry :: Text -- ^ Label -> Updatable Text-entry = entryAt Text.empty+entry = entryAt Data.Text.empty -- | A control that selects from one or more mutually exclusive choices radioButton@@ -490,6 +595,60 @@ spinButtonAt s0 label x = Updatable (\control -> _spinButtonAt control s0 label x) +-- | Same as `hscaleButton` except that you can specify the initial state+hscaleAt+ :: Double+ -- ^ Initial state+ -> Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+hscaleAt = hscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))++-- | Same as `hscaleButton` except that you can specify the range and initial state+hscaleWithRange+ :: Double+ -- ^ Minimum value+ -> Double+ -- ^ Maximum value+ -> Double+ -- ^ Initial state+ -> Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+hscaleWithRange b0 b1 s0 label x =+ Updatable (\control -> _hscaleWithRange control b0 b1 s0 label x)++-- | Same as `vscaleButton` except that you can specify the initial state+vscaleAt+ :: Double+ -- ^ Initial state+ -> Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+vscaleAt = vscaleWithRange (fromIntegral (minBound :: Int)) (fromIntegral (maxBound :: Int))++-- | Same as `vscaleButton` except that you can specify the range and initial state+vscaleWithRange+ :: Double+ -- ^ Minimum value+ -> Double+ -- ^ Maximum value+ -> Double+ -- ^ Initial state+ -> Text+ -- ^ Label+ -> Double+ -- ^ Step size+ -> Updatable Double+vscaleWithRange b0 b1 s0 label x =+ Updatable (\control -> _vscaleWithRange control b0 b1 s0 label x)+ -- | Same as `entry` except that you can specify the initial state entryAt :: Text@@ -501,34 +660,25 @@ -- | Convert a `Show`able value to `Text` display :: Show a => a -> Text-display = Text.pack . show+display = Data.Text.pack . show -- $examples -- -- Mortgage calculator: --+-- > {-# LANGUAGE ApplicativeDo #-} -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Control.Applicative--- > import Data.Monoid--- > import Data.Text (Text) -- > import Typed.Spreadsheet -- > --- > payment :: Double -> Double -> Double -> Text--- > payment mortgageAmount numberOfYears yearlyInterestRate--- > = "Monthly payment: $"--- > <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1))--- > where--- > n = truncate (numberOfYears * 12)--- > i = yearlyInterestRate / 12 / 100--- > --- > logic :: Updatable Text--- > logic = payment <$> spinButton "Mortgage Amount" 1000--- > <*> spinButton "Number of years" 1--- > <*> spinButton "Yearly interest rate (%)" 0.01--- > -- > main :: IO ()--- > main = textUI "Mortgage payment" logic+-- > main = textUI "Mortgage payment" $ do+-- > mortgageAmount <- spinButton "Mortgage Amount" 1000+-- > numberOfYears <- spinButton "Number of years" 1+-- > yearlyInterestRate <- spinButton "Yearly interest rate (%)" 0.01+-- > let n = truncate (numberOfYears * 12)+-- > let i = yearlyInterestRate / 12 / 100+-- > return ("Monthly payment: $" <> display (mortgageAmount * (i * (1 + i) ^ n) / ((1 + i) ^ n - 1))) -- -- Example input and output: --@@ -538,7 +688,6 @@ -- -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Data.Monoid -- > import Typed.Spreadsheet -- > -- > noun = entry "Noun"@@ -564,28 +713,25 @@ -- -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Diagrams.Backend.Cairo (Cairo) -- > import Diagrams.Prelude -- > import Typed.Spreadsheet -- > -- > main :: IO ()--- > main = graphicalUI "Example program" logic--- > where--- > logic = combine <$> spinButtonAt 50 "Amplitude (Pixels)" 0.1--- > <*> spinButtonAt 0.1 "Frequency (Pixels⁻¹)" 0.001--- > <*> spinButtonAt 90 "Phase (Degrees)" 1+-- > main = graphicalUI "Example program" $ do+-- > amplitude <- spinButtonAt 50 "Amplitude (Pixels)" 0.1+-- > frequency <- spinButtonAt 0.1 "Frequency (Pixels⁻¹)" 0.001+-- > phase <- spinButtonAt 90 "Phase (Degrees)" 1 -- > --- > combine :: Double -> Double -> Double -> Diagram Cairo--- > combine amplitude frequency phase = strokeP (fromVertices points) <> axes--- > where--- > axes = arrowBetween (p2 (0, 0)) (p2 ( 100, 0))+-- > let axes = arrowBetween (p2 (0, 0)) (p2 ( 100, 0)) -- > <> arrowBetween (p2 (0, 0)) (p2 (-100, 0)) -- > <> arrowBetween (p2 (0, 0)) (p2 ( 0, 100)) -- > <> arrowBetween (p2 (0, 0)) (p2 ( 0, -100)) -- > --- > f x = amplitude * cos (frequency * x + phase * pi / 180)+-- > let f x = amplitude * cos (frequency * x + phase * pi / 180) -- > --- > points = map (\x -> p2 (x, f x)) [-100, -99 .. 100]+-- > let points = map (\x -> p2 (x, f x)) [-100, -99 .. 100]+-- > +-- > return (strokeP (fromVertices points) <> axes) -- -- Example input and output: --@@ -595,21 +741,16 @@ -- -- > {-# LANGUAGE OverloadedStrings #-} -- > --- > import Diagrams.Backend.Cairo (Cairo) -- > import Diagrams.Prelude -- > import Diagrams.TwoD.Factorization (factorDiagram') -- > import Typed.Spreadsheet -- > -- > main :: IO ()--- > main = graphicalUI "Factor diagram" logic--- > where--- > logic = combine <$> spinButtonAt 3 "Factor #1" 1--- > <*> spinButtonAt 3 "Factor #2" 1--- > <*> spinButtonAt 3 "Factor #3" 1--- > --- > combine :: Double -> Double -> Double -> Diagram Cairo--- > combine x y z =--- > factorDiagram' [truncate x, truncate y, truncate z] # scale 10+-- > main = graphicalUI "Factor diagram" $ do+-- > x <- spinButtonAt 3 "Factor #1" 1+-- > y <- spinButtonAt 3 "Factor #2" 1+-- > z <- spinButtonAt 3 "Factor #3" 1+-- > return (factorDiagram' [truncate x, truncate y, truncate z] # scale 10) -- -- Example input and output: --
typed-spreadsheet.cabal view
@@ -1,5 +1,5 @@ Name: typed-spreadsheet-Version: 1.1.0+Version: 1.1.1 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -9,6 +9,7 @@ Maintainer: Gabriel439@gmail.com Bug-Reports: https://github.com/Gabriel439/Haskell-Typed-Spreadsheet-Library/issues Synopsis: Typed and composable spreadsheets+Tested-With: GHC == 8.0.2, GHC == 8.2.2 Description: This library provides a typed and composable API for building spreadsheets. This differs from traditional spreadsheets in a few important ways:@@ -31,35 +32,51 @@ Library Hs-Source-Dirs: src Build-Depends:- base >= 4 && < 5 ,- async >= 2.0 && < 2.1 ,- diagrams-cairo >= 1.3 && < 1.4 ,- diagrams-gtk >= 1.3 && < 1.4 ,- diagrams-lib >= 1.3 && < 1.4 ,- foldl >= 1.1 && < 1.2 ,- gtk >= 0.13 && < 0.14,- microlens < 0.4 ,+ base >= 4.9 && < 5 ,+ async >= 2.0 && < 2.2 ,+ diagrams-cairo >= 1.3 && < 1.5 ,+ diagrams-gtk >= 1.3 && < 1.5 ,+ diagrams-lib >= 1.3 && < 1.5 ,+ foldl >= 1.1 && < 1.3 ,+ gtk >= 0.13 && < 0.15,+ microlens < 0.5 , stm < 2.5 , text < 1.3 ,- transformers >= 0.2.0.0 && < 0.5+ transformers >= 0.2.0.0 && < 0.6+ if os(darwin)+ frameworks: Cocoa Exposed-Modules: Typed.Spreadsheet GHC-Options: -O2 -Wall -Executable typed-spreadsheet-example+Executable typed-spreadsheet-example-text Hs-Source-Dirs: exec Main-Is: Text.hs Build-Depends:- base >= 4 && < 5 ,- text < 1.3,+ base >= 4.9 && < 5 ,+ text < 1.3, typed-spreadsheet+ if os(darwin)+ frameworks: Cocoa GHC-Options: -O2 -Wall -threaded +Executable typed-spreadsheet-example-cell+ Hs-Source-Dirs: exec+ Main-Is: Cell.hs+ Build-Depends:+ base >= 4.9 && < 5 ,+ text < 1.3,+ typed-spreadsheet+ if os(darwin)+ frameworks: Cocoa+ GHC-Options: -Wall -threaded+ Executable typed-spreadsheet-example-graphics Hs-Source-Dirs: exec Main-Is: Graphics.hs Build-Depends: base >= 4 && < 5 ,- diagrams-cairo >= 1.3 && < 1.4,- diagrams-lib >= 1.3 && < 1.4,+ diagrams-lib >= 1.3 && < 1.5, typed-spreadsheet+ if os(darwin)+ frameworks: Cocoa GHC-Options: -O2 -Wall -threaded