Skip to content

Commit

Permalink
D.TwoD.Arrow: Lenses for setting head, tail, and shaft style directly.
Browse files Browse the repository at this point in the history
This is the sort of convenient thing that we can do now that we use
lens for everything: we can provide headColor, tailColor, and
shaftColor directly as "virtual fields" so the user doesn't have to
think about style modification functions in the common case where they
just want to set the color (and we also protect them from the easy
mistake of setting the line color on the head, or fill color on the
shaft).

This is something of a proof-of-concept.  Ideally we could even
refactor these as e.g. headColor = headStyle . styleFillColor where
styleFillColor :: (Color c, Color c') => Setter (Style v) (Style v) c c'.
  • Loading branch information
Brent Yorgey committed Nov 14, 2013
1 parent a9339c6 commit 4937215
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/Diagrams/TwoD.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,11 @@ module Diagrams.TwoD
, tailSize
, headGap
, tailGap
, headColor
, headStyle
, tailColor
, tailStyle
, shaftColor
, shaftStyle

-- * Text
Expand Down
43 changes: 41 additions & 2 deletions src/Diagrams/TwoD/Arrow.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,11 @@ module Diagrams.TwoD.Arrow
, tailSize
, headGap
, tailGap
, headColor
, headStyle
, tailColor
, tailStyle
, shaftColor
, shaftStyle

-- | See "Diagrams.TwoD.Arrowheads" for a list of standard
Expand All @@ -86,9 +89,10 @@ module Diagrams.TwoD.Arrow
) where

import Control.Arrow (first)
import Control.Lens (Lens', generateSignatures,
import Control.Lens (Lens', Setter,
generateSignatures,
lensRules, makeLensesWith,
(%~), (&), (.~), (^.))
sets, (%~), (&), (.~), (^.))
import Data.AffineSpace
import Data.Default.Class
import Data.Functor ((<$>))
Expand All @@ -102,6 +106,7 @@ import Data.VectorSpace
import Data.Colour hiding (atop)
import Diagrams.Attributes
import Diagrams.Core
import Diagrams.Core.Style (setAttr)
import Diagrams.Core.Types (QDiaLeaf (..), mkQD')

import Diagrams.Parametric
Expand Down Expand Up @@ -188,6 +193,40 @@ tailStyle :: Lens' ArrowOpts (Style R2)
-- | Style to apply to the shaft. See `headStyle`.
shaftStyle :: Lens' ArrowOpts (Style R2)

-- | A lens for setting or modifying the color of an arrowhead. For
-- example, one may write @... (with & headColor .~ blue)@ to get an
-- arrow with a blue head, or @... (with & headColor %~
-- (\`withOpacity\` 0.5))@ to make an arrow's head 50\% transparent.
-- For more general control over the style of arrowheads, see
-- 'headStyle'.
headColor :: (Color c, Color c') => Setter ArrowOpts ArrowOpts c c'
headColor = sets modifyHeadColor
where
modifyHeadColor f opts@(ArrowOpts { _headStyle = sty }) =
let c = fromMaybe (fromAlphaColour (opaque black))
(fromAlphaColour . someToAlpha . getFillColor <$> getAttr sty)
in opts & headStyle %~ setAttr (mkFillColor (f c))

-- | A lens for setting or modifying the color of an arrow
-- tail. See 'headColor'.
tailColor :: (Color c, Color c') => Setter ArrowOpts ArrowOpts c c'
tailColor = sets modifyTailColor
where
modifyTailColor f opts@(ArrowOpts { _tailStyle = sty }) =
let c = fromMaybe (fromAlphaColour (opaque black))
(fromAlphaColour . someToAlpha . getFillColor <$> getAttr sty)
in opts & tailStyle %~ setAttr (mkFillColor (f c))

-- | A lens for setting or modifying the color of an arrow
-- shaft. See 'headColor'.
shaftColor :: (Color c, Color c') => Setter ArrowOpts ArrowOpts c c'
shaftColor = sets modifyShaftColor
where
modifyShaftColor f opts@(ArrowOpts { _shaftStyle = sty }) =
let c = fromMaybe (fromAlphaColour (opaque black))
(fromAlphaColour . someToAlpha . getLineColor <$> getAttr sty)
in opts & shaftStyle %~ setAttr (mkLineColor (f c))

-- Set the default shaft style of an `ArrowOpts` record by applying the
-- default style after all other styles have been applied.
-- The semigroup stucture of the lw attribute will insure that the default
Expand Down

3 comments on commit 4937215

@bergey
Copy link
Member

@bergey bergey commented on 4937215 Nov 14, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool, and looks very convenient. Does Diagrams now have better support for arrows than Inkscape? :)

I look forward to styleFillColor in the future, too. I would have expected something more general than a Setter,though. If not a Lens, at least a Prism. Is that not possible? Or shall I take a stab at it and find out?

ETA: Should have read the next commit.

@bergey
Copy link
Member

@bergey bergey commented on 4937215 Nov 15, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, ignore me. Prisms are apparently more like Isos and less like Lenses than I (mis)remembered.

@byorgey
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, a Setter lets you set or modify but not get. We could make a Lens' Style (Maybe c) which might also be useful (this would let you delete an existing, say, fill color by setting it to Nothing).

Prisms are precisely Isos which are allowed to be partial in one direction, i.e. they express when one type is a "subset" of another type.

Please sign in to comment.