mirror of
https://github.com/rgleichman/glance.git
synced 2024-11-22 23:28:34 +03:00
Add FPS counter.
This commit is contained in:
parent
373e913119
commit
00309dcc9c
@ -79,6 +79,7 @@ executable glance-gui
|
|||||||
, transformers
|
, transformers
|
||||||
, old-time
|
, old-time
|
||||||
, containers
|
, containers
|
||||||
|
, time
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
Other-modules:
|
Other-modules:
|
||||||
|
|
||||||
|
103
gui/Main.hs
103
gui/Main.hs
@ -7,19 +7,20 @@
|
|||||||
|
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import Control.Concurrent
|
import Data.Coerce
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad (when)
|
import Control.Monad.IO.Class (MonadIO)
|
||||||
import Control.Monad.Trans.Reader (runReaderT)
|
import Control.Monad.Trans.Reader (runReaderT)
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import qualified Data.IntMap.Strict as IntMap
|
import qualified Data.IntMap.Strict as IntMap
|
||||||
import Data.Maybe (fromJust, fromMaybe)
|
import Data.Maybe (fromJust, fromMaybe)
|
||||||
|
import Data.Time.Clock.System
|
||||||
|
|
||||||
import Data.GI.Base
|
import Data.GI.Base
|
||||||
import qualified GI.Cairo as GI.Cairo
|
import qualified GI.Cairo as GI.Cairo
|
||||||
import qualified GI.GLib as GLib
|
import qualified GI.GLib as GLib
|
||||||
import qualified GI.Gdk as Gdk
|
import qualified GI.Gdk as Gdk
|
||||||
import qualified GI.GdkPixbuf as GP
|
-- import qualified GI.GdkPixbuf as GP
|
||||||
import qualified GI.Gio as Gio
|
import qualified GI.Gio as Gio
|
||||||
import qualified GI.Gtk as Gtk
|
import qualified GI.Gtk as Gtk
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ import Graphics.Rendering.Cairo
|
|||||||
import Graphics.Rendering.Cairo.Internal (Render(runRender))
|
import Graphics.Rendering.Cairo.Internal (Render(runRender))
|
||||||
import Graphics.Rendering.Cairo.Types (Cairo(Cairo))
|
import Graphics.Rendering.Cairo.Types (Cairo(Cairo))
|
||||||
|
|
||||||
|
nodeSize :: (Double, Double)
|
||||||
nodeSize = (100, 40)
|
nodeSize = (100, 40)
|
||||||
|
|
||||||
-- | A graphical element that can be clicked
|
-- | A graphical element that can be clicked
|
||||||
@ -42,24 +44,32 @@ data AppState = AppState
|
|||||||
, _asEdges :: [(Element, Element)]
|
, _asEdges :: [(Element, Element)]
|
||||||
, _asMouseXandY :: !(Double, Double)
|
, _asMouseXandY :: !(Double, Double)
|
||||||
, _asElements :: IntMap.IntMap Element
|
, _asElements :: IntMap.IntMap Element
|
||||||
|
, _asTime :: SystemTime
|
||||||
|
, _asFPSr :: Double -- ^ FPS rouned down to nearest hundred if over 200 fps.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emptyAppState :: AppState
|
||||||
emptyAppState = AppState
|
emptyAppState = AppState
|
||||||
{ _asMovingNode = Nothing
|
{ _asMovingNode = Nothing
|
||||||
, _asEdges = []
|
, _asEdges = []
|
||||||
, _asMouseXandY = (0, 0)
|
, _asMouseXandY = (0, 0)
|
||||||
, _asElements = mempty
|
, _asElements = mempty
|
||||||
|
, _asTime = MkSystemTime 0 0
|
||||||
|
, _asFPSr = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderCairo :: Coercible a (ManagedPtr ()) => a -> Render c -> IO c
|
||||||
renderCairo c r = withManagedPtr c $ \pointer ->
|
renderCairo c r = withManagedPtr c $ \pointer ->
|
||||||
runReaderT (runRender r) (Cairo (castPtr pointer))
|
runReaderT (runRender r) (Cairo (castPtr pointer))
|
||||||
|
|
||||||
-- TODO Add type signature
|
getXandY
|
||||||
|
:: MonadIO f
|
||||||
|
=> Gdk.EventButton -> f (Double, Double)
|
||||||
getXandY event =
|
getXandY event =
|
||||||
(\x y -> (x, y)) <$> get event #x <*> get event #y
|
(\x y -> (x, y)) <$> Gdk.getEventButtonX event <*> Gdk.getEventButtonY event
|
||||||
|
|
||||||
-- updateCanvas :: WidgetClass widget => widget -> PangoLayout -> Render ()
|
_drawLine :: (Double, Double) -> (Double, Double) -> Render ()
|
||||||
drawLine (fromX, fromY) (toX, toY) = do
|
_drawLine (fromX, fromY) (toX, toY) = do
|
||||||
setSourceRGB 0 1 0
|
setSourceRGB 0 1 0
|
||||||
setLineWidth 5
|
setLineWidth 5
|
||||||
|
|
||||||
@ -67,7 +77,8 @@ drawLine (fromX, fromY) (toX, toY) = do
|
|||||||
lineTo toX toY
|
lineTo toX toY
|
||||||
stroke
|
stroke
|
||||||
|
|
||||||
drawCircle (x, y) = do
|
_drawCircle :: (Double, Double) -> Render ()
|
||||||
|
_drawCircle (x, y) = do
|
||||||
-- setSourceRGB 1 0 0
|
-- setSourceRGB 1 0 0
|
||||||
setLineWidth 1
|
setLineWidth 1
|
||||||
-- moveTo x y
|
-- moveTo x y
|
||||||
@ -76,6 +87,7 @@ drawCircle (x, y) = do
|
|||||||
arc x y radius 0 tau
|
arc x y radius 0 tau
|
||||||
stroke
|
stroke
|
||||||
|
|
||||||
|
drawNode :: Element -> Render ()
|
||||||
drawNode Element{..} = do
|
drawNode Element{..} = do
|
||||||
let
|
let
|
||||||
(x, y) = _elPosition
|
(x, y) = _elPosition
|
||||||
@ -86,15 +98,21 @@ drawNode Element{..} = do
|
|||||||
rectangle x y width height
|
rectangle x y width height
|
||||||
stroke
|
stroke
|
||||||
|
|
||||||
updateBackground canvas state = do
|
updateBackground :: p -> IORef AppState -> Render (IntMap.IntMap ())
|
||||||
width <- realToFrac <$> (liftIO $ Gtk.widgetGetAllocatedWidth canvas)
|
updateBackground _canvas state = do
|
||||||
height <- realToFrac <$> (liftIO $ Gtk.widgetGetAllocatedHeight canvas)
|
-- width <- (realToFrac <$> (liftIO $ Gtk.widgetGetAllocatedWidth canvas)
|
||||||
|
-- :: Render Double)
|
||||||
|
-- height <- (realToFrac <$> (liftIO $ Gtk.widgetGetAllocatedHeight canvas)
|
||||||
|
-- :: Render Double)
|
||||||
|
|
||||||
-- TODO This should be moved into the setup phase
|
-- TODO This should be moved into the setup phase
|
||||||
setSourceRGB 0 0 0
|
setSourceRGB 0 0 0
|
||||||
paint
|
paint
|
||||||
|
|
||||||
stateVal <- liftIO $ readIORef state
|
stateVal <- liftIO $ readIORef state
|
||||||
|
setSourceRGB 1 1 1
|
||||||
|
moveTo 10 10
|
||||||
|
showText ("fps=" <> show (_asFPSr stateVal))
|
||||||
setSourceRGB 1 0 0
|
setSourceRGB 1 0 0
|
||||||
traverse drawNode (_asElements stateVal)
|
traverse drawNode (_asElements stateVal)
|
||||||
|
|
||||||
@ -114,53 +132,64 @@ startApp app = do
|
|||||||
, Gdk.EventMaskButtonPressMask]
|
, Gdk.EventMaskButtonPressMask]
|
||||||
#add window backgroundArea
|
#add window backgroundArea
|
||||||
|
|
||||||
geometry <- new Gdk.Geometry [ #minWidth := 500, #minHeight := 500]
|
-- geometry <- new Gdk.Geometry [ #minWidth := 500, #minHeight := 500]
|
||||||
|
|
||||||
-- screen <- get window #screen
|
-- screen <- get window #screen
|
||||||
-- rgbaVisual <- #getRgbaVisual screen
|
-- rgbaVisual <- #getRgbaVisual screen
|
||||||
-- #setVisual window rgbaVisual
|
-- #setVisual window rgbaVisual
|
||||||
|
|
||||||
-- No noticable change with setting this to GLib.PRIORITY_DEFAULT
|
-- surfaceRef <- newIORef (Nothing)
|
||||||
-- GLib.timeoutAdd GLib.PRIORITY_LOW 1 (#queueDraw backgroundArea >> pure True)
|
|
||||||
|
|
||||||
surfaceRef <- newIORef (Nothing)
|
|
||||||
|
|
||||||
_ <- on backgroundArea #draw (\context -> do
|
_ <- on backgroundArea #draw (\context -> do
|
||||||
mSurface <- readIORef surfaceRef
|
-- mSurface <- readIORef surfaceRef
|
||||||
surface <- case mSurface of
|
-- surface <- case mSurface of
|
||||||
Nothing -> do
|
-- Nothing -> do
|
||||||
(width, height) <- #getSize window
|
-- (width, height) <- #getSize window
|
||||||
surf <- createImageSurface
|
-- surf <- createImageSurface
|
||||||
FormatARGB32
|
-- FormatARGB32
|
||||||
(fromIntegral width)
|
-- (fromIntegral width)
|
||||||
(fromIntegral height)
|
-- (fromIntegral height)
|
||||||
writeIORef surfaceRef $ Just $ surf
|
-- writeIORef surfaceRef $ Just $ surf
|
||||||
pure surf
|
-- pure surf
|
||||||
Just surface -> pure surface
|
-- Just surface -> pure surface
|
||||||
|
|
||||||
renderCairo context (updateBackground backgroundArea state)
|
_ <- renderCairo context (updateBackground backgroundArea state)
|
||||||
pure True)
|
pure True)
|
||||||
|
|
||||||
let
|
#showAll window
|
||||||
timeoutCallback :: IO Bool
|
|
||||||
timeoutCallback = do
|
|
||||||
gdkWindow <- fromJust <$> #getWindow window
|
gdkWindow <- fromJust <$> #getWindow window
|
||||||
display <- fmap fromJust Gdk.displayGetDefault -- TODO unsafe
|
display <- fmap fromJust Gdk.displayGetDefault -- TODO unsafe
|
||||||
deviceManager <- fromJust <$> Gdk.displayGetDeviceManager display -- TODO deprecated
|
deviceManager <- fromJust <$> Gdk.displayGetDeviceManager display -- TODO deprecated
|
||||||
device <- Gdk.deviceManagerGetClientPointer deviceManager
|
device <- Gdk.deviceManagerGetClientPointer deviceManager
|
||||||
|
let
|
||||||
|
timeoutCallback :: IO Bool
|
||||||
|
timeoutCallback = do
|
||||||
|
newTime@(MkSystemTime seconds nanoseconds) <- getSystemTime
|
||||||
|
oldState <- readIORef state
|
||||||
|
let
|
||||||
|
(MkSystemTime oldSeconds oldNanoseconds) = _asTime oldState
|
||||||
|
secondsDiff = seconds - oldSeconds
|
||||||
|
nanosecondDiff = nanoseconds - oldNanoseconds
|
||||||
|
fps = if secondsDiff == 0
|
||||||
|
then fromIntegral (div (10^(9 :: Int)) nanosecondDiff)
|
||||||
|
else 1 / (fromIntegral secondsDiff)
|
||||||
|
truncatedFps = if fps >= 200
|
||||||
|
then fromIntegral $ (div (truncate fps) 100) * (100 :: Int)
|
||||||
|
else fps
|
||||||
gdkDevicePosition <- Gdk.windowGetDevicePositionDouble gdkWindow device
|
gdkDevicePosition <- Gdk.windowGetDevicePositionDouble gdkWindow device
|
||||||
let (_, x, y, _) = gdkDevicePosition
|
let (_, x, y, _) = gdkDevicePosition
|
||||||
|
|
||||||
modifyIORef' state
|
modifyIORef' state
|
||||||
(\s@AppState{_asMouseXandY}
|
(\s@AppState{_asMouseXandY}
|
||||||
-> s{_asMouseXandY=(x, y)}
|
-> s{_asMouseXandY=(x, y)
|
||||||
|
, _asTime=newTime
|
||||||
|
, _asFPSr=truncatedFps}
|
||||||
)
|
)
|
||||||
-- print (x, y)
|
|
||||||
|
|
||||||
#queueDraw backgroundArea
|
#queueDraw backgroundArea
|
||||||
pure True
|
pure True
|
||||||
|
|
||||||
GLib.timeoutAdd GLib.PRIORITY_LOW 1 (timeoutCallback)
|
_ <- GLib.timeoutAdd GLib.PRIORITY_DEFAULT 1 (timeoutCallback)
|
||||||
|
|
||||||
let
|
let
|
||||||
backgroundPress eventButton = do
|
backgroundPress eventButton = do
|
||||||
@ -187,7 +216,7 @@ startApp app = do
|
|||||||
|
|
||||||
putStrLn "backgroundPressed"
|
putStrLn "backgroundPressed"
|
||||||
pure True
|
pure True
|
||||||
on backgroundArea #buttonPressEvent backgroundPress
|
_ <- on backgroundArea #buttonPressEvent backgroundPress
|
||||||
|
|
||||||
#showAll window
|
#showAll window
|
||||||
pure ()
|
pure ()
|
||||||
@ -196,6 +225,6 @@ main :: IO ()
|
|||||||
main = do
|
main = do
|
||||||
app <- new Gtk.Application []
|
app <- new Gtk.Application []
|
||||||
_ <- on app #activate (startApp app)
|
_ <- on app #activate (startApp app)
|
||||||
status <- Gio.applicationRun app Nothing
|
appStatus <- Gio.applicationRun app Nothing
|
||||||
putStrLn ("Application status is " <> show status)
|
putStrLn ("Application status is " <> show appStatus)
|
||||||
pure ()
|
pure ()
|
||||||
|
Loading…
Reference in New Issue
Block a user