2011-08-29 15:10:55 +02:00
|
|
|
{-# LANGUAGE ExistentialQuantification, StandaloneDeriving, DeriveDataTypeable, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-07-14 22:50:03 +02:00
|
|
|
module Phi.Widget ( Display(..)
|
|
|
|
, withDisplay
|
2011-07-15 09:17:57 +02:00
|
|
|
, getAtoms
|
2011-08-29 15:10:55 +02:00
|
|
|
, XMessage(..)
|
2011-07-16 15:55:31 +02:00
|
|
|
, unionArea
|
2011-08-21 19:34:16 +02:00
|
|
|
, SurfaceSlice(..)
|
2011-07-14 20:21:30 +02:00
|
|
|
, Widget(..)
|
2011-08-21 08:40:08 +02:00
|
|
|
, CompoundWidget
|
|
|
|
, (<~>)
|
2011-08-21 21:39:26 +02:00
|
|
|
, IOCache
|
|
|
|
, RenderCache
|
|
|
|
, createIOCache
|
2011-08-22 06:17:22 +02:00
|
|
|
, runIOCache
|
2011-08-21 21:39:26 +02:00
|
|
|
, createRenderCache
|
|
|
|
, renderCached
|
2011-08-21 08:40:08 +02:00
|
|
|
, Separator
|
2011-07-14 00:09:20 +02:00
|
|
|
, separator
|
|
|
|
) where
|
|
|
|
|
2011-08-21 05:38:37 +02:00
|
|
|
import Control.Arrow
|
|
|
|
import Control.Arrow.Transformer
|
|
|
|
import Control.CacheArrow
|
2011-07-15 02:51:50 +02:00
|
|
|
import Control.Concurrent.MVar
|
2011-07-14 00:09:20 +02:00
|
|
|
import Control.Monad
|
2011-08-21 21:39:26 +02:00
|
|
|
import Control.Monad.State.Strict hiding (lift)
|
2011-07-15 09:17:57 +02:00
|
|
|
import Control.Monad.IO.Class
|
2011-07-14 20:21:30 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
import Data.Maybe
|
2011-08-29 15:10:55 +02:00
|
|
|
import Data.Typeable
|
2011-08-21 21:39:26 +02:00
|
|
|
|
2011-07-16 15:55:31 +02:00
|
|
|
import qualified Graphics.X11.Xlib as Xlib
|
2011-07-14 00:09:20 +02:00
|
|
|
import Graphics.Rendering.Cairo
|
|
|
|
|
2011-07-14 06:16:04 +02:00
|
|
|
import Phi.Phi
|
2011-07-15 09:17:57 +02:00
|
|
|
import Phi.X11.Atoms
|
2011-07-14 06:16:04 +02:00
|
|
|
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
data Display = Display !(MVar Xlib.Display) !Atoms
|
2011-07-14 22:50:03 +02:00
|
|
|
|
2011-07-16 15:55:31 +02:00
|
|
|
withDisplay :: MonadIO m => Display -> (Xlib.Display -> m a) -> m a
|
2011-08-29 15:10:55 +02:00
|
|
|
withDisplay (Display dispvar _) f = do
|
2011-07-15 09:17:57 +02:00
|
|
|
disp <- liftIO $ takeMVar dispvar
|
2011-07-14 22:50:03 +02:00
|
|
|
a <- f disp
|
2011-07-15 09:17:57 +02:00
|
|
|
liftIO $ putMVar dispvar disp
|
2011-07-14 22:50:03 +02:00
|
|
|
return a
|
2011-07-14 20:21:30 +02:00
|
|
|
|
2011-07-15 09:17:57 +02:00
|
|
|
getAtoms :: Display -> Atoms
|
2011-08-29 15:10:55 +02:00
|
|
|
getAtoms (Display _ atoms) = atoms
|
2011-07-16 15:55:31 +02:00
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
data XMessage = UpdateScreens [(Xlib.Rectangle, Xlib.Window)] deriving (Show, Typeable)
|
2011-07-19 11:16:50 +02:00
|
|
|
|
2011-07-16 15:55:31 +02:00
|
|
|
|
|
|
|
unionArea :: Xlib.Rectangle -> Xlib.Rectangle -> Int
|
|
|
|
unionArea a b = fromIntegral $ uw*uh
|
|
|
|
where
|
|
|
|
uw = max 0 $ (min ax2 bx2) - (max ax1 bx1)
|
|
|
|
uh = max 0 $ (min ay2 by2) - (max ay1 by1)
|
|
|
|
|
|
|
|
Xlib.Rectangle ax1 ay1 aw ah = a
|
|
|
|
Xlib.Rectangle bx1 by1 bw bh = b
|
|
|
|
|
|
|
|
ax2 = ax1 + fromIntegral aw
|
|
|
|
ay2 = ay1 + fromIntegral ah
|
|
|
|
|
|
|
|
bx2 = bx1 + fromIntegral bw
|
|
|
|
by2 = by1 + fromIntegral bh
|
2011-07-15 09:17:57 +02:00
|
|
|
|
2011-07-14 20:21:30 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
data SurfaceSlice = SurfaceSlice !Int !Surface
|
|
|
|
|
2011-08-22 06:17:22 +02:00
|
|
|
class Eq s => Widget w s c | w -> s, w -> c where
|
2011-08-29 15:10:55 +02:00
|
|
|
initWidget :: w -> Phi -> Display -> [(Xlib.Rectangle, Xlib.Window)] -> IO s
|
2011-08-21 21:39:26 +02:00
|
|
|
|
|
|
|
initCache :: w -> c
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
minSize :: w -> s -> Int -> Xlib.Rectangle -> Int
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
weight :: w -> Float
|
2011-07-14 00:09:20 +02:00
|
|
|
weight _ = 0
|
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
render :: w -> s -> Int -> Int -> Int -> Int -> Xlib.Rectangle -> StateT c IO [(Bool, SurfaceSlice)]
|
2011-07-14 06:16:04 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
handleMessage :: w -> s -> Message -> s
|
2011-07-14 06:16:04 +02:00
|
|
|
handleMessage _ priv _ = priv
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
type IOCache = CacheArrow (Kleisli IO)
|
2011-08-29 15:34:56 +02:00
|
|
|
type RenderCache s = IOCache (s, Int, Int, Int, Int, Xlib.Rectangle) Surface
|
2011-08-21 21:39:26 +02:00
|
|
|
|
|
|
|
createIOCache :: Eq a => (a -> IO b) -> IOCache a b
|
|
|
|
createIOCache = lift . Kleisli
|
|
|
|
|
2011-08-22 21:10:59 +02:00
|
|
|
runIOCache :: Eq a => a -> StateT (IOCache a b) IO b
|
2011-08-22 06:17:22 +02:00
|
|
|
runIOCache a = do
|
|
|
|
cache <- get
|
2011-08-22 21:10:59 +02:00
|
|
|
(b, cache') <- liftIO $ runKleisli (runCache cache) a
|
2011-08-22 06:17:22 +02:00
|
|
|
put cache'
|
2011-08-22 21:10:59 +02:00
|
|
|
return b
|
2011-08-22 06:17:22 +02:00
|
|
|
|
2011-08-29 15:34:56 +02:00
|
|
|
createRenderCache :: (s -> Int -> Int -> Int -> Int -> Xlib.Rectangle -> Render ())
|
|
|
|
-> CacheArrow (Kleisli IO) (s, Int, Int, Int, Int, Xlib.Rectangle) Surface
|
|
|
|
createRenderCache f = lift . Kleisli $ \(state, x, y, w, h, screen) -> do
|
2011-08-21 05:38:37 +02:00
|
|
|
surface <- createImageSurface FormatARGB32 w h
|
|
|
|
renderWith surface $ do
|
|
|
|
setOperator OperatorClear
|
|
|
|
paint
|
|
|
|
setOperator OperatorOver
|
2011-08-29 15:34:56 +02:00
|
|
|
f state x y w h screen
|
2011-08-21 21:39:26 +02:00
|
|
|
return surface
|
|
|
|
|
2011-08-29 15:34:56 +02:00
|
|
|
renderCached :: Eq s => s -> Int -> Int -> Int -> Int -> Xlib.Rectangle -> StateT (RenderCache s) IO [(Bool, SurfaceSlice)]
|
|
|
|
renderCached state x y w h screen = do
|
2011-08-21 21:39:26 +02:00
|
|
|
cache <- get
|
2011-08-29 15:34:56 +02:00
|
|
|
(surf, updated, cache') <- liftIO $ runKleisli (runCache' cache) (state, x, y, w, h, screen)
|
2011-08-21 21:39:26 +02:00
|
|
|
put cache'
|
|
|
|
return [(updated, SurfaceSlice 0 surf)]
|
2011-08-21 08:40:08 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
data CompoundWidget a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundWidget !a !b
|
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
data CompoundState a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundState !sa !sb
|
2011-08-21 19:34:16 +02:00
|
|
|
deriving instance Eq (CompoundState a sa ca b sb cb)
|
2011-08-21 08:40:08 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
data CompoundCache a sa ca b sb cb = (Widget a sa ca, Widget b sb cb) => CompoundCache !ca !cb
|
2011-08-21 08:40:08 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
|
|
|
|
instance Widget (CompoundWidget a sa ca b sb cb) (CompoundState a sa ca b sb cb) (CompoundCache a sa ca b sb cb) where
|
2011-08-29 15:10:55 +02:00
|
|
|
initWidget (CompoundWidget a b) phi disp screens = liftM2 CompoundState (initWidget a phi disp screens) (initWidget b phi disp screens)
|
2011-08-21 08:40:08 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
initCache (CompoundWidget a b) = CompoundCache (initCache a) (initCache b)
|
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
minSize (CompoundWidget a b) (CompoundState da db) height screen = minSize a da height screen + minSize b db height screen
|
2011-08-21 08:40:08 +02:00
|
|
|
|
|
|
|
weight (CompoundWidget a b) = weight' a + weight' b
|
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
render c@(CompoundWidget a b) s@(CompoundState sa sb) x y w h screen = do
|
|
|
|
let sizesum = minSize c s h screen
|
|
|
|
wsum = let wsum = weight c
|
|
|
|
in if wsum > 0 then wsum else 1
|
|
|
|
surplus = w - sizesum
|
|
|
|
xb = floor $ (fromIntegral $ minSize a sa h screen) + (fromIntegral surplus)*(weight' a)/wsum
|
2011-07-14 01:47:10 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
CompoundCache ca cb <- get
|
2011-08-29 15:10:55 +02:00
|
|
|
|
2011-08-21 21:39:26 +02:00
|
|
|
(surfacea, ca') <- liftIO $ flip runStateT ca $ render a sa x y xb h screen
|
|
|
|
(surfaceb, cb') <- liftIO $ flip runStateT cb $ render b sb (x+xb) y (w-xb) h screen
|
|
|
|
put $ CompoundCache ca' cb'
|
2011-08-21 19:34:16 +02:00
|
|
|
return $ surfacea ++ map (\(updated, SurfaceSlice x surface) -> (updated, SurfaceSlice (x+xb) surface)) surfaceb
|
2011-07-14 01:47:10 +02:00
|
|
|
|
2011-08-29 15:10:55 +02:00
|
|
|
handleMessage (CompoundWidget a b) (CompoundState sa sb) message = CompoundState (handleMessage a sa message) (handleMessage b sb message)
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
weight' :: (Widget a sa ca) => a -> Float
|
2011-08-21 08:40:08 +02:00
|
|
|
weight' = max 0 . weight
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 19:34:16 +02:00
|
|
|
(<~>) :: (Widget a sa ca, Widget b sb cb) => a -> b -> CompoundWidget a sa ca b sb cb
|
2011-08-21 08:40:08 +02:00
|
|
|
a <~> b = CompoundWidget a b
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 08:40:08 +02:00
|
|
|
data Separator = Separator !Int !Float deriving (Show, Eq)
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-29 15:34:56 +02:00
|
|
|
instance Widget Separator () (RenderCache ()) where
|
2011-08-29 15:10:55 +02:00
|
|
|
initWidget _ _ _ _ = return ()
|
2011-08-29 15:34:56 +02:00
|
|
|
initCache _ = createRenderCache $ \_ _ _ _ _ _ -> do
|
2011-08-21 21:39:26 +02:00
|
|
|
setOperator OperatorClear
|
|
|
|
paint
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-07-18 20:57:19 +02:00
|
|
|
minSize (Separator s _) _ _ _ = s
|
2011-07-14 00:09:20 +02:00
|
|
|
weight (Separator _ w) = w
|
2011-08-29 15:34:56 +02:00
|
|
|
render _ = renderCached
|
2011-08-21 19:34:16 +02:00
|
|
|
|
2011-07-14 00:09:20 +02:00
|
|
|
|
2011-08-21 08:40:08 +02:00
|
|
|
separator :: Int -> Float -> Separator
|
|
|
|
separator = Separator
|