{-# LANGUAGE ImplicitParams, ScopedTypeVariables, OverloadedStrings, AllowAmbiguousTypes, GADTs, CPP, ExistentialQuantification, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts, ScopedTypeVariables, UndecidableInstances #-}
module Graphics.UI.FLTK.Theme.Light.Dial
(
dialNew,
fillDialNew,
lineDialNew,
drawDial
)
where
import Control.Exception
import Control.Monad
import Data.List
import Graphics.UI.FLTK.LowLevel.Dispatch
import Graphics.UI.FLTK.LowLevel.Fl_Enumerations
import Graphics.UI.FLTK.LowLevel.Fl_Types
import Graphics.UI.FLTK.Theme.Light.Common
import Text.Printf
import qualified Data.ByteString.Char8 as BC
import qualified Data.Text as T
import qualified Graphics.UI.FLTK.LowLevel.FL as FL
import qualified Graphics.UI.FLTK.LowLevel.FLTKHS as LowLevel
import Graphics.UI.FLTK.Theme.Light.Assets
dialOutline w h rW rH a1X a1Y rWWithStroke rHWithStroke bigCircle a2X a2Y sw colorString =
""
meter w h rW rH meterCenter meterX meterY mw =
""
fillEllipse w h rW rH startX startY rWWithStroke rHWithStroke bigCircle endX endY colorString =
""
arrow =
[
""
]
makeDialOutline :: Size -> PreciseAngle -> PreciseAngle -> String -> String
makeDialOutline (Size (Width w) (Height h)) a1 a2 colorString =
let ((rW,rH) :: (Double,Double)) = center w h
PrecisePosition (PreciseX a1X) (PreciseY a1Y) = angleToCoordinate (fromFltkAngle a1)
PrecisePosition (PreciseX a2X) (PreciseY a2Y) = angleToCoordinate (fromFltkAngle a2)
sw = strokeWidth (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
in
dialOutline w h rW rH (a1X * (rW-(sw/2))) ((-a1Y) * (rH-(sw/2))) (rW-(sw/2)) (rH-(sw/2)) (if (a1 < a2) then (1 :: Int) else (0 :: Int)) (a2X * (rW-(sw/2))) ((-a2Y) * (rH-(sw/2))) sw colorString
center :: Int -> Int -> (Double,Double)
center w h = (fromIntegral w / 2, fromIntegral h / 2)
strokeWidth = percentOfSmallerEllipseRadius 10
meterCenterRadius = percentOfSmallerEllipseRadius 8
meterWidth = percentOfSmallerEllipseRadius 5
knobPadding = percentOfSmallerEllipseRadius 3
arrowBase = percentOfSmallerEllipseRadius 25
arrowHeight = percentOfSmallerEllipseRadius 20
arrowPadding = percentOfSmallerEllipseRadius 15
makeMeter :: PreciseAngle -> Size -> String
makeMeter angle (Size (Width w) (Height h)) =
let (rW,rH) = center w h
meterLength = if (rW < rH) then rW else rH
PrecisePosition (PreciseX x) (PreciseY y) = angleToCoordinate (fromFltkAngle angle)
sw :: Double
sw = strokeWidth (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
meterCenter = meterCenterRadius (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
mw = meterWidth (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
in
meter w h rW rH meterCenter (x * (meterLength - sw - (mw / 2))) ((-y) * (meterLength - sw - (mw / 2))) mw
makeFill :: Size -> PreciseAngle -> PreciseAngle -> String -> String
makeFill (Size (Width w) (Height h)) a1@(PreciseAngle a1') a2@(PreciseAngle a2') colorString =
let ((rW,rH) :: (Double,Double)) = center w h
PrecisePosition (PreciseX a1X) (PreciseY a1Y) = angleToCoordinate (fromFltkAngle a1)
PrecisePosition (PreciseX a2X) (PreciseY a2Y) = angleToCoordinate (fromFltkAngle a2)
sw = strokeWidth (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
in
fillEllipse w h rW rH (a1X * (rW-sw)) ((-a1Y) * (rH-sw)) (rW-sw) (rH-sw) (if (abs (a2'-a1') < 180) then (0 :: Int) else (1 :: Int)) (a2X * (rW-sw)) ((-a2Y) * (rH-sw)) colorString
makeArrow :: Size -> PreciseAngle -> String
makeArrow (Size (Width w) (Height h)) a =
let ((rW,rH) :: (Double,Double)) = center w h
sw = strokeWidth (PreciseSize (PreciseWidth rW) (PreciseHeight rH))
circleR = if (rW"] ++ svgs ++ [""]))
-- | Custom dial drawing function
drawDial :: Ref LowLevel.Dial -> IO ()
drawDial d = do
bounds@(Rectangle dialPos@(Position (X dialX) (Y dialY)) dialSize@(Size (Width dialW) (Height dialH))) <- LowLevel.getRectangle d
p <- LowLevel.getParent d
color <- maybe (return lightBackground) LowLevel.getColor p
drawBorderBox d
(BorderBoxSpec
{
borderBoxBounds = bounds
, borderBoxFocusedColor = color
, borderBoxHoveringColor = color
, borderBoxColor = color
, borderBoxFillColor = color
})
True
color <- fmap (\c -> colorAverage c blackColor 0.80) (LowLevel.getColor d)
(colorR,colorG,colorB) <- FL.getColorRgb color
(Angle a1) <- LowLevel.getAngle1 d
(Angle a2) <- LowLevel.getAngle2 d
let dialOutlineSvg = makeDialOutline dialSize (PreciseAngle (fromIntegral a1)) (PreciseAngle (fromIntegral a2)) ("rgb(" ++ show colorR ++ "," ++ show colorG ++ "," ++ show colorB ++ ")")
dialMin <- LowLevel.getMinimum d
dialMax <- LowLevel.getMaximum d
when (dialMin>dialMax) (throwIO (userError ("Dial minimum cannot be less than maximum:(" ++ (show dialMin) ++ "," ++ (show dialMax) ++ ")")))
dialV <- LowLevel.getValue d >>= LowLevel.clamp d
dialType <- LowLevel.getType_ d
let dialLocation = (dialV-dialMin) / (dialMax-dialMin)
let meterAngle = PreciseAngle (((fromIntegral (a2-a1)) * dialLocation) + (fromIntegral a1))
(selectionColorR, selectionColorG, selectionColorB) <- LowLevel.getSelectionColor d >>= FL.getColorRgb
let svg =
case dialType of
LowLevel.FillDialType ->
wrapSvgs
[
dialOutlineSvg
, if (a1
wrapSvgs
[
dialOutlineSvg
, makeMeter meterAngle dialSize
]
LowLevel.NormalDialType ->
wrapSvgs
[
dialOutlineSvg
, makeArrow dialSize meterAngle
]
iE <- LowLevel.svgImageNew (BC.pack svg)
case iE of
Left _ -> throwIO (userError ("drawDial: the generated SVG is invalid: \n" ++ svg))
Right i -> do
LowLevel.draw i dialPos
LowLevel.destroy i
LowLevel.drawLabel d Nothing
dialNew :: (?assets :: Assets) => Rectangle -> Maybe T.Text -> IO (Ref LowLevel.Dial)
dialNew rectangle label = do
d <- LowLevel.dialCustom
rectangle
label
(Just drawDial)
Nothing
color <- commonColor
LowLevel.setColor d color
color <- commonFillColor
LowLevel.setSelectionColor d color
LowLevel.setLabelfont d commonFont
LowLevel.setLabelsize d commonFontSize
return d
fillDialNew :: (?assets :: Assets) => Rectangle -> Maybe T.Text -> IO (Ref LowLevel.FillDial)
fillDialNew rect l = do
d <- dialNew rect l
LowLevel.setType d LowLevel.FillDialType
return (castTo d)
lineDialNew :: (?assets :: Assets) => Rectangle -> Maybe T.Text -> IO (Ref LowLevel.LineDial)
lineDialNew rect l = do
d <- dialNew rect l
LowLevel.setType d LowLevel.LineDialType
return (castTo d)