graphicstools-0.2.1: Graphics/Tools/DefaultGUI.hs
{-#LANGUAGE FlexibleInstances , FlexibleContexts, DoRec, NoMonomorphismRestriction, TypeFamilies #-}
module Graphics.Tools.DefaultGUI (
defaultGUI,
testFunction,
module Graphics.Tools.Tangible,
module Graphics.Tools.Tangible.Instances,
module Utils.Persist,
module Graphics.Tools.WX,
module GHC.Generics
) where
import Graphics.UI.WX hiding (image,value,parent,get)
import qualified Graphics.UI.WX as WX (value,parent,get)
import Graphics.Tools.WX
import Graphics.Tools.CV2WX()
import CV.Image as CV
import CV.Filters
import Data.IORef
import Control.Applicative
import Utils.Persist
import System.Directory (doesFileExist)
import qualified Data.Map as Map
import Graphics.Tools.Tangible
import Graphics.Tools.Tangible.Instances
import GHC.Generics
defaultGUI
:: (Tangible α,
Persist α,
Default α,
WxPaintable β,
WxImage (Image c d),
Loadable (Image c d)) =>
FilePath -- ^ File to store the filter parameters in
-> FilePath -- ^ Initial image file
-> (α -> Image c d -> β) -- ^ The processing function
-> IO ()
defaultGUI storeFile imageFile = start . buildGUI imageFile . mkGUIOp storeFile
testFunction :: Int -> Image GrayScale D32 -> Image GrayScale D32
testFunction i img = (!!i) . iterate (gaussian (3,3)) $ img
type GUIOp c d=
IORef (Image c d)
-> Frame () -> Panel () -> Frame ()
-> IO (IO ())
mkGUIOp :: (Persist α, Default α, Tangible α, WxPaintable β) =>
FilePath -- ^ File to persist parameters
-> (α -> Image c d -> β) -- ^ A function to transform a tangible value and image to something
-- that WX knows how to paint
-> GUIOp c d -- ^ Operation that can be given to `defaultMain`
mkGUIOp storeFile function imageRef frame surface controls =
let update lastValue value = do
image <- readIORef imageRef
let display = function value image
set frame [outerSize := paintSize display]
updateSurface surface display
store <- readIORef lastValue
let store' = Map.union (put "" value) store
writeIORef lastValue store'
writeFile storeFile (show store')
in do
e <- doesFileExist storeFile
store <- if e then read <$> readFile storeFile else return Map.empty
lastValue <- newIORef store
c <- present (get "" store) (update lastValue) controls
set controls [layout := widget c]
return (readIORef lastValue >>= update lastValue . get "")
buildGUI :: (WxImage (Image c d), Loadable (Image c d)) =>
FilePath -> GUIOp c d -> IO ()
buildGUI imagePath guiOp = do
-- Program state
image <- CV.readFromFile imagePath
imageRef <- newIORef image
-- Main window
f <- frame [ text := "Filter Tuner" ]
-- Create the menu
file <- menuPane [text := "&File"]
mopen <- menuItem file [text := "&Open Image\tCtrl+O"
, help := "Open image to be processed"]
msave <- menuItem file [text := "&Save Image\tCtrl+O"
, help := "Save current image"]
mclose <- menuQuit file []
set f [menuBar := [file]]
-- Create the image viewer
imgPanel <- panel f []
surface <- createSurface imgPanel image
-- Create the control panel
controls <- frameTool [] f
update <- guiOp imageRef f surface controls
-- Hook everything together
set f [on (menu mopen) := openFile f imageRef >> update
,on (menu mclose) := close f
,on (menu msave) := saveFile f imageRef
]
set f [layout := row 2 [widget imgPanel]]
-- Make sure the image is current
set f [on idle := update >> return False]
return ()
saveFile :: Window a -> IORef (Image c d) -> IO ()
saveFile f imageRef = do
file <- fileSaveDialog f True False "Save as" [("Image file",["*.png","*.jpg","*.tif","*.tiff"])] "" ""
case file of
Nothing -> return ()
Just filename -> readIORef imageRef >>= saveImage filename
openFile :: (CV.Sized a1, Loadable a1, CV.Size a1 ~ (Int, Int)) =>
Window a -> IORef a1 -> IO ()
openFile f imageRef = do
file <- fileOpenDialog f True True "Select Image"
[("Image file",["*.png","*.jpg","*.tif","*.tiff"])] "" ""
case file of
Nothing -> return ()
Just newFile -> do
img <- readFromFile newFile
writeIORef imageRef img
imageSize :: (Num b, CV.Sized a, CV.Size a ~ (b, b)) => a -> Size2D b
imageSize = uncurry Size . getSize
paintSurface' :: WxPaintable p => p -> DC a -> t -> IO ()
paintSurface' p dc _ = doPaint dc (point 0 0) p
createSurface :: WxPaintable p => Window a -> p -> IO (Panel ())
createSurface f p =
panel f [ on paint := paintSurface' p, outerSize := paintSize p ]
updateSurface :: (Paint w, Dimensions w, WxPaintable p) => w -> p -> IO ()
updateSurface s p = do
set s [ on paint := paintSurface p, outerSize := paintSize p ]
repaint s
paintSurface :: WxPaintable p => p -> DC a -> t -> IO ()
paintSurface p dc _ = doPaint dc (point 0 0) p