tinytools-vty-0.1.0.0: src/Potato/Reflex/Vty/Widget/Windows.hs
-- TODO FINISH INCOMPLETE
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RecursiveDo #-}
module Potato.Reflex.Vty.Widget.Windows (
) where
import Relude
import Potato.Reflex.Vty.Helpers
import Potato.Reflex.Vty.Widget
import qualified Graphics.Vty.Input.Events as V
import Reflex
import Reflex.Network
import Reflex.Potato.Helpers
import Reflex.Vty
import qualified Data.Map as Map
import Data.Default
import Control.Monad.Fix
type WidgetId = Int
data WindowsAttrs t = WindowsAttrs {
}
data Window = Window {
_window_name :: Text
, _window_widgetId :: WidgetId
, _window_allowClose :: Bool
, _window_allowMove :: Bool
, _window_allowResize :: Bool
}
-- note, OneWindow can not have tabs added to it
data Tab = OneWindow Window | Tab [Window]
data DockDirection =
DockDirection_Left
| DockDirection_Right
| DockDirection_Top
| DockDirection_Bottom
deriving (Show)
data DockedTab = DockedTab {
_dockedTab_tabs :: [(Int, Tab)] -- left to right, or top to bottom
, _dockedTab_size :: Int
, _dockedTab_dir :: DockDirection
}
data FreeWindow = FreeWindow {
_freeWindow_window :: Window
, _freeWindow_position :: (Int, Int)
, _freeWindow_size :: (Int, Int)
}
type WindowWidgetMap t m a = Map WidgetId (m a)
data WindowManagerState t m a = WindowManagerState {
_windowManagerState_docked :: [DockedTab]
, _windowManagerState_free :: [FreeWindow]
, _windowManagerState_size :: Dimension
, _windowManagerState_widgetMap :: WindowWidgetMap t m a
}
emptyWindowManagerState :: WindowManagerState t m a
emptyWindowManagerState = WindowManagerState {
_windowManagerState_docked = []
, _windowManagerState_free = []
, _windowManagerState_size = (0,0)
, _windowManagerState_widgetMap = Map.empty
}
-- temp math stuff
type Position = (Int, Int)
type Dimension = (Int, Int)
type PosDim = (Position, Dimension)
makeDynRegion :: (Reflex t) => Dynamic t Position -> Dynamic t Dimension -> Dynamic t Region
makeDynRegion dp dd = ffor2 dp dd $ \(x,y) (w,h) -> Region x y w h
--(:+) :: (Int, Int) -> (Int, Int) -> (Int, Int)
--(a,b) :+ (x,y) = (a+x, b+y)
--infixl 6 :+
--(-+) :: (Int, Int) -> (Int, Int) -> (Int, Int)
--(a,b) :+ (x,y) = (a-x, b-y)
--infixl 6 -+
computeDockDimensions :: PosDim -> [DockedTab] -> [PosDim]
computeDockDimensions dim = snd . mapAccumL mapAccumFn dim where
mapAccumFn ((accx, accy), (accw, acch)) dt = (newAccDim, dtpd) where
(dtpd, newAccDim) = case _dockedTab_dir dt of
DockDirection_Left -> (
((accx, accy), (dw, acch))
, ((accx+dw, accy), (accw-dw, acch))
)
DockDirection_Right -> (
((accx + accw - dw, accy), (dw, acch))
, ((accx, accy), (accw-dw, acch))
)
DockDirection_Top -> (
((accx, accy), (accw, dh))
, ((accx, accy+dh), (accw, acch-dh))
)
DockDirection_Bottom -> (
((accx, accy + acch - dh), (accw, dh))
, ((accx, accy), (accw, acch-dh))
)
where
dw = min accw (_dockedTab_size dt)
dh = min acch (_dockedTab_size dt)
data WindowManagerConfig t m a = WindowManagerConfig {
_windowManagerConfig_initialWidgets :: Map WidgetId (m a)
-- TODO initial widget configuration
, _windowManagerConfig_style :: WindowsAttrs t
-- eventually
--, _windowManagerConfig_addWidget :: Event t
}
data WMCmd = WMCmd_None
{- TODO fix for new layout stuff
windowManager ::
forall t m a. (Reflex t, Adjustable t m, NotReady t m, PostBuild t m, MonadFix m, MonadHold t m, MonadNodeId m, Monad m)
=> WindowManagerConfig t m a
-> m (Event t (NonEmpty a))
windowManager WindowManagerConfig {..} = mdo
inpEv <- input
widthDyn <- displayWidth
heightDyn <- displayHeight
initialWidth <- sample . current $ widthDyn
initialHeight <- sample . current $ heightDyn
let
cmdev = never
foldfn :: WMCmd -> WindowManagerState t m a -> WindowManagerState t m a
foldfn cmd wms@WindowManagerState {..} = r where
r = wms
initialState = emptyWindowManagerState {
_windowManagerState_size = (initialWidth, initialHeight)
}
wmsDyn <- foldDyn foldfn initialState cmdev
-- TODO wrap everything in a VtyWidget so you can capture mouse input for dock manipulation
-- TODO first render docked widgets
-- next render floating widgets
let
freeWindowFn :: WindowWidgetMap t m a -> Dynamic t Bool -> Dynamic t FreeWindow -> m a
freeWindowFn wwm focussedDyn freeWindowDyn = do
-- TODO change return type to Dynamic t (m a) so that these params can change too
Window {..} <- sample . current $ fmap _freeWindow_window freeWindowDyn
let
child = case Map.lookup _window_widgetId wwm of
-- TODO pretty sure you should just change to m ()
Nothing -> return undefined
Just w -> w
dynRegion = makeDynRegion (_freeWindow_position <$> freeWindowDyn) (_freeWindow_size <$> freeWindowDyn)
pane dynRegion focussedDyn $ do
-- TODO add close button
-- TODO proper window widget, this is just temp render for testing
boxTitle (constant roundedBoxStyle) (constant _window_name) child
let
freeWindowsDyn = fmap _windowManagerState_free wmsDyn
-- TODO figure out how to pass in focussedDyn
fmapFnFreeWindow wms = simpleList freeWindowsDyn (freeWindowFn (_windowManagerState_widgetMap wms) (constDyn False))
outputEvs <- networkView $ fmap fmapFnFreeWindow wmsDyn
-- TODO fmap through wmsDyn window stack and render them
-- TODO fanMap out window events (close/moved)
return never
-}
-- TODO monad for making initial configuration
{-
dock = do
free $ widget1
free $ widget2
free $ widget3
dock DockDirection_Left $ do
addTab $ do
tab $ widget4
tab $ widget5
addTab $ do
tab $ widget6
tab $ widget7
dock DockDirection_Bottom $ do
addWindow $ widget8
-}