summaryrefslogtreecommitdiff
path: root/calcGTK/calc.hs
blob: ec47e0569d762758b9b06c32421bf962eb3409e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
-- Simple Stupid Calculator demonstrating basic gtk/glade and parsec parser usage -- 
-- Hacked togeter by Miguel on May 3, 2018

{-# LANGUAGE PackageImports #-}
import "gtk3" Graphics.UI.Gtk
import Control.Monad.IO.Class
import Data.ByteString.Char8 (pack,unpack)
import Numeric
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.Language
import Text.Parsec.Number (fractional2)
import Text.Parsec.Token

-- parse calculation -- 
calc s =  case parse expr "" s of Right x -> showFFloat Nothing x ""
                                  _       -> "?"

table = [ [binary "*" (*) AssocLeft, binary "/" (/) AssocLeft ]
        , [binary "+" (+) AssocLeft, binary "-" (-) AssocLeft ] ]

lexer =  makeTokenParser haskellDef
expr  =  buildExpressionParser table term <?> "expression"
term  =  parens lexer expr <|> fractional2 False <?> "simple expression"

binary  name fun assoc = Infix (do{ reservedOp lexer name; return fun }) assoc

-- gui for the calculator --
main = do   initGUI
            builder <- builderNew
            builderAddFromFile builder "calc.glade"
            window <- builderGetObject builder castToWindow "mainWindow"
            output <- builderGetObject builder castToTextView "output"
            outputBuff <- textViewGetBuffer output
            hist <- builderGetObject builder castToTextView "hist"
            histBuff <- textViewGetBuffer hist
            end<-textBufferGetEndIter histBuff
            histMark <- textBufferCreateMark histBuff Nothing end True

            let conn  = connBtn    builder outputBuff
                connA = connBtnAct builder outputBuff

            -- connecting buttons --
            sequence_ $ conn <$> map show [0..9] ++ ["+","-","/","*","(",")","."]

            connA "CLR" $ textBufferSetByteString outputBuff (pack "")
            connA "DEL" $ manipTextBuff outputBuff (\x -> case x of [] -> []; xs -> init xs)
            connA "="   $ do txt<-getTextBuff outputBuff
                             manipTextBuff outputBuff calc
                             res<-getTextBuff outputBuff
                             manipTextBuff histBuff (\x -> x++txt++" = "++res++"\n")
                             end<-textBufferGetEndIter histBuff
                             textBufferMoveMark histBuff histMark end
                             textViewScrollToMark hist histMark 0 $ Just (0,1)
                             return ()

            -- handler to run on window destruction
            window `on` deleteEvent $ do liftIO mainQuit
                                         return False
            widgetShowAll window
            mainGUI

getTextBuff outputBuff = do start<-textBufferGetStartIter outputBuff
                            end<-textBufferGetEndIter outputBuff
                            unpack <$> textBufferGetByteString outputBuff start end True

manipTextBuff outputBuff action = do txt<-getTextBuff outputBuff
                                     textBufferSetByteString outputBuff (pack $ action $ txt)

connBtn builder buff label  = connBtnAct builder buff label $
                              textBufferInsertByteStringAtCursor buff (pack label)

connBtnAct builder buff label act = do btn <- builderGetObject builder castToButton label
                                       btn `on` buttonActivated $ act