This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
phi/lib/Phi/Widget.hs

154 lines
5.5 KiB
Haskell
Raw Normal View History

2011-07-14 01:47:10 +02:00
{-# LANGUAGE ExistentialQuantification, TypeFamilies, StandaloneDeriving, FlexibleContexts #-}
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-07-16 15:55:31 +02:00
, getScreens
, unionArea
2011-07-14 20:21:30 +02:00
, Widget(..)
2011-07-14 00:09:20 +02:00
, WidgetClass(..)
, WidgetState(..)
, separator
, createWidgetState
, layoutWidgets
, renderWidgets
2011-07-14 20:21:30 +02:00
, handleMessageWidgets
2011-07-14 00:09:20 +02:00
) where
import Control.Concurrent.MVar
2011-07-14 00:09:20 +02:00
import Control.Monad
2011-07-15 09:17:57 +02:00
import Control.Monad.IO.Class
2011-07-14 20:21:30 +02:00
2011-07-14 01:47:10 +02:00
import Data.Traversable
2011-07-14 00:09:20 +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-07-16 15:55:31 +02:00
data Display = Display (MVar Xlib.Display) Atoms [Xlib.Rectangle]
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
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-07-16 15:55:31 +02:00
getAtoms (Display _ atoms _) = atoms
getScreens :: Display -> [Xlib.Rectangle]
getScreens (Display _ _ screens) = screens
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-07-14 01:47:10 +02:00
class Show a => WidgetClass a where
2011-07-14 00:09:20 +02:00
type WidgetData a :: *
2011-07-14 20:21:30 +02:00
initWidget :: a -> Phi -> Display -> IO (WidgetData a)
2011-07-14 00:09:20 +02:00
2011-07-17 19:20:19 +02:00
minSize :: a -> WidgetData a -> Int -> Int
2011-07-14 00:09:20 +02:00
weight :: a -> Float
weight _ = 0
2011-07-14 01:47:10 +02:00
layout :: a -> WidgetData a -> Int -> Int -> WidgetData a
layout _ priv _ _ = priv
2011-07-14 00:09:20 +02:00
2011-07-16 15:55:31 +02:00
render :: a -> WidgetData a -> Int -> Int -> Xlib.Rectangle -> Render ()
2011-07-14 06:16:04 +02:00
handleMessage :: a -> WidgetData a -> Message -> WidgetData a
handleMessage _ priv _ = priv
2011-07-14 00:09:20 +02:00
2011-07-14 01:47:10 +02:00
data Widget = forall a. (WidgetClass a, Show (WidgetData a)) => Widget a
deriving instance Show Widget
2011-07-14 00:09:20 +02:00
2011-07-14 01:47:10 +02:00
data WidgetState = forall a. (WidgetClass a, Show (WidgetData a)) => WidgetState { stateWidget :: a
, stateX :: Int
, stateY :: Int
, stateWidth :: Int
, stateHeight :: Int
, statePrivateData :: WidgetData a
}
deriving instance Show WidgetState
2011-07-14 00:09:20 +02:00
2011-07-14 20:21:30 +02:00
createWidgetState :: Phi -> Display -> Widget -> IO WidgetState
createWidgetState phi disp (Widget w) = do
phi' <- dupPhi phi
priv <- initWidget w phi' disp
2011-07-14 20:21:30 +02:00
return WidgetState { stateWidget = w
, stateX = 0
, stateY = 0
, stateWidth = 0
, stateHeight = 0
, statePrivateData = priv
}
2011-07-14 00:09:20 +02:00
2011-07-14 01:47:10 +02:00
layoutWidgets :: [WidgetState] -> Int -> Int -> Int -> Int -> [WidgetState]
layoutWidgets widgets x y width height = snd $ mapAccumL layoutWidgetAndX x widgets
2011-07-14 00:09:20 +02:00
where
2011-07-17 19:20:19 +02:00
sizesum = sum $ map (\(WidgetState {stateWidget = w, statePrivateData = priv} ) -> nneg $ minSize w priv height) widgets
2011-07-14 01:47:10 +02:00
wsum = let wsum = sum $ map (\(WidgetState {stateWidget = w} ) -> nneg . weight $ w) widgets
in if wsum > 0 then wsum else 1
surplus = width - sizesum
layoutWidgetAndX wX state = let lw = layoutWidget wX state
in (wX + stateWidth lw, lw)
layoutWidget wX state = case state of
WidgetState {stateWidget = w, statePrivateData = priv} ->
2011-07-17 19:20:19 +02:00
let wWidth = floor $ (fromIntegral $ minSize w priv height) + (fromIntegral surplus)*(nneg $ weight w)/wsum
2011-07-14 01:47:10 +02:00
priv' = layout w priv wWidth height
2011-07-14 06:16:04 +02:00
in WidgetState w wX y wWidth height priv'
2011-07-14 01:47:10 +02:00
nneg :: (Num a, Ord a) => a -> a
nneg x = max 0 x
2011-07-14 00:09:20 +02:00
2011-07-16 15:55:31 +02:00
renderWidgets :: [WidgetState] -> Xlib.Rectangle -> Render ()
renderWidgets widgets screen = forM_ widgets $ \WidgetState { stateWidget = widget
, stateX = x
, stateY = y
, stateWidth = w
, stateHeight = h
, statePrivateData = priv } -> do
2011-07-14 01:47:10 +02:00
save
translate (fromIntegral x) (fromIntegral y)
2011-07-16 15:55:31 +02:00
render widget priv w h screen
2011-07-14 01:47:10 +02:00
restore
2011-07-14 00:09:20 +02:00
2011-07-14 06:16:04 +02:00
handleMessageWidgets :: Message -> [WidgetState] -> [WidgetState]
handleMessageWidgets message = map handleMessageWidget
where
handleMessageWidget (WidgetState w x y width height priv) = WidgetState w x y width height $ handleMessage w priv message
2011-07-14 00:09:20 +02:00
2011-07-14 01:47:10 +02:00
data Separator = Separator Int Float deriving Show
2011-07-14 00:09:20 +02:00
instance WidgetClass Separator where
type WidgetData Separator = ()
2011-07-14 20:21:30 +02:00
initWidget _ _ _ = return ()
2011-07-14 00:09:20 +02:00
2011-07-17 19:20:19 +02:00
minSize (Separator s _) _ _ = s
2011-07-14 00:09:20 +02:00
weight (Separator _ w) = w
2011-07-16 15:55:31 +02:00
render _ _ _ _ _ = return ()
2011-07-14 00:09:20 +02:00
separator :: Int -> Float -> Widget
separator s w = Widget $ Separator s w