From c9e702e66091e252543129a659ef001093cf4713 Mon Sep 17 00:00:00 2001 From: sheaf Date: Tue, 4 Aug 2020 08:15:06 +0200 Subject: [PATCH] WIP --- .gitignore | 5 + MetaBrush.cabal | 109 + app/Main.hs | 91 + assets/theme.css | 88 + cabal.project | 10 + img/MetaBrush_ui_mockup.svg | 5528 ++++++++++++++++++++++++ img/logo.png | Bin 0 -> 14311 bytes src/app/MetaBrush/Asset/Brush.hs | 60 + src/app/MetaBrush/Asset/Logo.hs | 81 + src/app/MetaBrush/Asset/Magnifier.hs | 60 + src/app/MetaBrush/Asset/Meta.hs | 42 + src/app/MetaBrush/Asset/TickBox.hs | 96 + src/app/MetaBrush/Asset/WindowIcons.hs | 31 + src/app/MetaBrush/Document.hs | 12 + src/app/MetaBrush/Render/Util.hs | 43 + src/app/MetaBrush/Stroke.hs | 11 + src/lib/Math/Bezier/Cubic.hs | 68 + src/lib/Math/Bezier/Quadratic.hs | 58 + src/lib/Math/Bezier/Stroke.hs | 3 + src/lib/Math/Bezier/Subdivision.hs | 3 + src/lib/Math/Module.hs | 41 + src/lib/Math/Vector2D.hs | 51 + 22 files changed, 6491 insertions(+) create mode 100644 .gitignore create mode 100644 MetaBrush.cabal create mode 100644 app/Main.hs create mode 100644 assets/theme.css create mode 100644 cabal.project create mode 100644 img/MetaBrush_ui_mockup.svg create mode 100644 img/logo.png create mode 100644 src/app/MetaBrush/Asset/Brush.hs create mode 100644 src/app/MetaBrush/Asset/Logo.hs create mode 100644 src/app/MetaBrush/Asset/Magnifier.hs create mode 100644 src/app/MetaBrush/Asset/Meta.hs create mode 100644 src/app/MetaBrush/Asset/TickBox.hs create mode 100644 src/app/MetaBrush/Asset/WindowIcons.hs create mode 100644 src/app/MetaBrush/Document.hs create mode 100644 src/app/MetaBrush/Render/Util.hs create mode 100644 src/app/MetaBrush/Stroke.hs create mode 100644 src/lib/Math/Bezier/Cubic.hs create mode 100644 src/lib/Math/Bezier/Quadratic.hs create mode 100644 src/lib/Math/Bezier/Stroke.hs create mode 100644 src/lib/Math/Bezier/Subdivision.hs create mode 100644 src/lib/Math/Module.hs create mode 100644 src/lib/Math/Vector2D.hs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf9a69b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +dist-newstyle/ +assets/*.svg +assets/*/ +*.txt +cabal.project.local diff --git a/MetaBrush.cabal b/MetaBrush.cabal new file mode 100644 index 0000000..bc58122 --- /dev/null +++ b/MetaBrush.cabal @@ -0,0 +1,109 @@ +cabal-version: 3.0 +name: MetaBrush +version: 0.1.0.0 +synopsis: GUI for brush calligraphy. +category: Calligraphy, Font, Geometry, Graphics, GUI +license: BSD-3-Clause +homepage: https://gitlab.com/sheaf/MetaBrush +build-type: Simple +data-files: + assets/theme.css +description: + + MetaBrush is a GUI for brush calligraphy based on Bézier curves. + + A brush stroke is defined by two components: + + * the path of the brush, specified using quadratic Bézier curves, + + * the shape of the brush, also specified with quadratic Bézier curves. + + The shape of the brush is allowed to vary along the path. + +common common + + build-depends: + base + >= 4.13 && < 4.16 + + default-language: + Haskell2010 + + ghc-options: + -O1 + -fexpose-all-unfoldings + -fspecialise-aggressively + -Wall + -Wcompat + -fwarn-missing-local-signatures + -fwarn-incomplete-patterns + -fwarn-incomplete-uni-patterns + -fwarn-missing-deriving-strategies + +library + + import: + common + + hs-source-dirs: + src/lib + + exposed-modules: + Math.Bezier.Cubic + , Math.Bezier.Quadratic + , Math.Bezier.Stroke + , Math.Bezier.Subdivision + , Math.Module + , Math.Vector2D + + build-depends: + acts + ^>= 0.3.1.0 + , generic-data + >= 0.8.0.0 && < 0.8.4.0 + , groups + ^>= 0.4.1.0 + , groups-generic + ^>= 0.1.0.0 + +executable MetaBrush + + hs-source-dirs: + src/app + , app + + main-is: + Main.hs + + other-modules: + MetaBrush.Asset.Brush + , MetaBrush.Asset.Logo + , MetaBrush.Asset.Magnifier + , MetaBrush.Asset.Meta + , MetaBrush.Asset.TickBox + , MetaBrush.Asset.WindowIcons + , MetaBrush.Document + , MetaBrush.Render.Util + , MetaBrush.Stroke + , Paths_MetaBrush + + autogen-modules: + Paths_MetaBrush + + ghc-options: + -threaded -rtsopts + + build-depends: + MetaBrush + , gi-gdk + >= 3.0.22 && < 3.1 + , gi-glib + >= 2.0.23 && < 2.1 + , gi-gtk + >= 3.0.35 && < 3.1 + , gi-cairo-render + ^>= 0.0.1 + , gi-cairo-connector + ^>= 0.0.1 + , text + ^>= 1.2.3.1 && < 1.2.5 diff --git a/app/Main.hs b/app/Main.hs new file mode 100644 index 0000000..8b575ae --- /dev/null +++ b/app/Main.hs @@ -0,0 +1,91 @@ +module Main + ( main ) + where + +-- gi-cairo-connector +import qualified GI.Cairo.Render.Connector as Cairo + ( renderWithContext ) + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- gi-gtk +import qualified GI.Gtk as GTK + +-- MetaBrush +import Paths_MetaBrush + ( getDataFileName ) + +-------------------------------------------------------------------------------- + +main :: IO () +main = do + + --------------------------------------------------------- + -- Initialise GTK + + _ <- GTK.init Nothing + Just screen <- GDK.screenGetDefault + + themePath <- getDataFileName "theme.css" + cssProvider <- GTK.cssProviderNew + GTK.cssProviderLoadFromPath cssProvider themePath + GTK.styleContextAddProviderForScreen screen cssProvider 1000 + + window <- GTK.windowNew GTK.WindowTypeToplevel + windowWidgetPath <- GTK.widgetGetPath window + widgetAddClass window "window" + GTK.setWindowResizable window True + GTK.setWindowDecorated window False + GTK.setWindowTitle window "MetaBrush" + GTK.windowSetDefaultSize window 800 600 + + let + baseMinWidth, baseMinHeight :: Int32 + baseMinWidth = 320 + baseMinHeight = 240 + + windowGeometry <- GDK.newZeroGeometry + GDK.setGeometryMinWidth windowGeometry baseMinWidth + GDK.setGeometryMinHeight windowGeometry baseMinHeight + GTK.windowSetGeometryHints window ( Nothing @GTK.Widget ) + ( Just windowGeometry ) + [ GDK.WindowHintsMinSize ] + + --------------------------------------------------------- + -- Create base UI elements + + baseOverlay <- GTK.overlayNew + GT.setContainerChild window baseOverlay + + uiGrid <- GTK.gridNew + GTK.overlaySetChild baseOverlay uiGrid + + logo <- GTK.boxNew GTK.OrientationVertical 0 + titleBar <- GTK.boxNew GTK.OrientationHorizontal 0 + toolBar <- GTK.boxNew GTK.OrientationVertical 0 + fileBar <- GTK.boxNew GTK.OrientationHorizontal 0 + mainView <- GTK.gridNew + panelGrid <- GTK.gridNew + infoBar <- GTK.boxNew GTK.OrientationHorizontal 0 + + GTK.gridAttach uiGrid logo 0 0 1 2 + GTK.gridAttach uiGrid titleBar 1 0 3 1 + GTK.gridAttach uiGrid toolBar 0 2 2 2 + GTK.gridAttach uiGrid fileBar 2 1 1 1 + GTK.gridAttach uiGrid mainView 2 2 1 1 + GTK.gridAttach uiGrid panelGrid 3 2 1 2 + GTK.gridAttach uiGrid infoBar 2 3 1 1 + + -------------------------------------- + -- Actions + + GTK.widgetAddEvents window [GDK.EventMaskKeyPressMask, GDK.EventMaskKeyReleaseMask] + _ <- GTK.onWidgetKeyPressEvent window ( handleKeyboardPressEvent ) + _ <- GTK.onWidgetKeyReleaseEvent window ( handleKeyboardReleaseEvent ) + + _ <- GTK.onWidgetDestroy window ( quitAll actionTVar ) + _ <- GTK.onButtonClicked quitIconButton ( quitAll actionTVar ) + + GTK.widgetShowAll window + GTK.main diff --git a/assets/theme.css b/assets/theme.css new file mode 100644 index 0000000..11a66f4 --- /dev/null +++ b/assets/theme.css @@ -0,0 +1,88 @@ +* { + all: unset; +} + +/* Window background colour */ +.bg { + color: #292828 +} + +/* Viewport background colour */ +.viewport_bg { + color: #ecdfd2 +} + +/* Basic text colour */ +.plain { + color: #d4be98 +} + +/* Basic text font */ +.text { + font-family: "Lato", "Roboto", "Helvetica", sans-serif +} + +/* Monospace font */ +.monospace { + font-family: "Fira Code", "Inconsolata", "Courier", "Courier New", monospace +} + +/* High-constrast text colour */ +.contrast { + color: #f7f4ef +} + +/* Active (highlighting) colour */ +.highlight { + color: #eadfcc +} + +/* Logo base colour */ +.logo_base { + color: #f7f4ef +} + +/* Logo highlight colour */ +.logo_highlight { + color: #f5881bff +} + +/* Viewport scrollbar colour */ +.viewport_scrollbar { + color: #28272793 +} + +/* Tab scrollbar colour */ +.tab_scrollbar { + color: #302d2693 +} + +/* Ruler colour */ +.ruler { + color: #ede29a +} + +/* Magnifying glass base colour */ +.magnifier { + color: #ecdfd2 +} + +/* Magnifying glass glass colour */ +.glass { + color: #9ce7ff72 +} + +/* Cursor colour */ +.cursor { + color: #f7f4ef +} + +/* Bézier path point colour */ +.point { + color: #8183f1 +} + +/* Bézier control point colour */ +.control { + color: #a1dde9 +} diff --git a/cabal.project b/cabal.project new file mode 100644 index 0000000..7c20422 --- /dev/null +++ b/cabal.project @@ -0,0 +1,10 @@ +constraints: + acts -finitary + , haskell-gi >= 0.24 + +-- fixes gi-cairo-render to work with haskell-gi >= 0.24 +source-repository-package + type: git + location: https://github.com/thestr4ng3r/gi-cairo-render + tag: 8727c43cdf91aeedffc9cb4c5575f56660a86399 + subdir: gi-cairo-render diff --git a/img/MetaBrush_ui_mockup.svg b/img/MetaBrush_ui_mockup.svg new file mode 100644 index 0000000..c36aca0 --- /dev/null +++ b/img/MetaBrush_ui_mockup.svg @@ -0,0 +1,5528 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + hover:select: + + + + + + + hover:select: + + + Strokes + + + + + + + + + + + + + + + + Strokes2 – MetaBrush + + + + + Strokes1 + Strokes2 + Strokes3 + Strokes4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Strokes + Stroke 1 + Stroke 2 + Stroke 3 + + + + + + + File + Edit + View + + Brushes + View + + + + Transform + Stroke 4 + + Stroke 5 + + Help + + + x: 212.12 pxy: 120.23 px + + + x: 10.05 pxy: 340.23 px + + + x: 410.12 pxy: 20.00 px + 300% + + Transform settings ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..64847406366b7d5f8a5d67aceb371d2e9a9b9ffb GIT binary patch literal 14311 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 literal 0 HcmV?d00001 diff --git a/src/app/MetaBrush/Asset/Brush.hs b/src/app/MetaBrush/Asset/Brush.hs new file mode 100644 index 0000000..a7e2aa9 --- /dev/null +++ b/src/app/MetaBrush/Asset/Brush.hs @@ -0,0 +1,60 @@ +module MetaBrush.Asset.Brush + ( drawBrush ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +import MetaBrush.Render.Util + ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | Calligraphy brush icon. Width = 29, height = 29. +drawBrush :: GDK.RGBA -> GDK.RGBA -> GDK.RGBA -> Cairo.Render () +drawBrush brushColour bodyColour loopColour = do + + -- Loop + Cairo.setLineWidth 0.2 + withRGBA loopColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 23.144531 6.199219 + Cairo.curveTo 22.40625 6.890625 21.382813 5.953125 20.375 7.300781 + Cairo.curveTo 21.109375 5.925781 19.828125 5.410156 20.398438 4.324219 + Cairo.curveTo 20.894531 3.375 21.757813 2.621094 23.046875 3.636719 + Cairo.curveTo 24.035156 4.414063 24.128906 5.273438 23.144531 6.199219 + Cairo.closePath + Cairo.strokePreserve + + -- Brush body + withRGBA bodyColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 20.605469 7.359375 + Cairo.curveTo 20.988281 7.566406 21.476563 8.136719 21.195313 8.464844 + Cairo.lineTo 15.539063 14.84375 + Cairo.lineTo 14.90625 18.964844 + Cairo.curveTo 14.074219 19.195313 11.992188 17.941406 11.246094 17.457031 + Cairo.curveTo 10.5 16.976563 9.460938 15.597656 9.816406 15.351563 + Cairo.lineTo 13.507813 13.835938 + Cairo.lineTo 18.980469 6.996094 + Cairo.curveTo 19.25 6.660156 19.671875 6.613281 20 6.894531 + Cairo.closePath + Cairo.fillPreserve + + -- Brush tip + withRGBA brushColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 10.339844 19.335938 + Cairo.curveTo 11.089844 19.847656 11.996094 20.34375 12.683594 20.507813 + Cairo.curveTo 12.683594 20.507813 7.59375 24.476563 7.59375 24.476563 + Cairo.curveTo 6.867188 25.160156 4.785156 26.105469 4.601563 25.941406 + Cairo.curveTo 4.4375 25.792969 5.042969 24.261719 5.652344 23.140625 + Cairo.curveTo 5.652344 23.140625 8.566406 17.773438 8.566406 17.773438 + Cairo.curveTo 8.804688 18.136719 9.585938 18.820313 10.339844 19.335938 + Cairo.curveTo 10.339844 19.335938 10.339844 19.335938 10.339844 19.335938 + Cairo.closePath + Cairo.fillPreserve diff --git a/src/app/MetaBrush/Asset/Logo.hs b/src/app/MetaBrush/Asset/Logo.hs new file mode 100644 index 0000000..e1ceee8 --- /dev/null +++ b/src/app/MetaBrush/Asset/Logo.hs @@ -0,0 +1,81 @@ +module MetaBrush.Asset.Logo + ( drawLogo ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +import MetaBrush.Render.Util + ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | MetaBrush logo. Width = 29, height = 29. +drawLogo :: GDK.RGBA -> GDK.RGBA -> GDK.RGBA -> Cairo.Render () +drawLogo brushColour bodyColour loopColour = do + + -- Loop + Cairo.setLineWidth 0.2 + withRGBA loopColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 17.480469 7.847656 + Cairo.curveTo 16.890625 8.402344 16.070313 7.648438 15.257813 8.730469 + Cairo.curveTo 15.847656 7.625 14.820313 7.210938 15.277344 6.339844 + Cairo.curveTo 15.675781 5.578125 16.371094 4.972656 17.40625 5.789063 + Cairo.curveTo 18.199219 6.414063 18.273438 7.101563 17.480469 7.847656 + Cairo.curveTo 17.480469 7.847656 17.480469 7.847656 17.480469 7.847656 + Cairo.closePath + Cairo.strokePreserve + + -- Body + withRGBA bodyColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 14.53125 8.257813 + Cairo.curveTo 14.386719 8.273438 14.246094 8.351563 14.140625 8.484375 + Cairo.curveTo 14.140625 8.484375 9.746094 13.976563 9.746094 13.976563 + Cairo.curveTo 9.746094 13.976563 6.78125 15.195313 6.78125 15.195313 + Cairo.curveTo 6.496094 15.390625 7.332031 16.5 7.929688 16.886719 + Cairo.curveTo 8.53125 17.273438 10.199219 18.28125 10.867188 18.097656 + Cairo.curveTo 10.867188 18.097656 11.375 14.789063 11.375 14.789063 + Cairo.curveTo 11.375 14.789063 13.117188 12.824219 13.117188 12.824219 + Cairo.curveTo 13.117188 12.824219 14.0625 11.660156 14.0625 11.660156 + Cairo.curveTo 14.53125 12.59375 16.511719 16.417969 16.605469 16.535156 + Cairo.curveTo 17.550781 16.058594 17.769531 15.773438 18.277344 15.167969 + Cairo.curveTo 18.863281 14.359375 18.9375 14.257813 19.722656 13.226563 + Cairo.curveTo 20.089844 13.980469 21.21875 15.222656 22.25 16.554688 + Cairo.curveTo 22.636719 17.058594 24.300781 18.761719 24.785156 18.570313 + Cairo.curveTo 25.046875 18.46875 25.972656 17.636719 26.136719 16.753906 + Cairo.curveTo 26.171875 16.554688 26.265625 15.800781 26.097656 15.648438 + Cairo.curveTo 25.976563 15.542969 24.988281 16.101563 24.679688 15.976563 + Cairo.curveTo 24.144531 15.195313 23.488281 13.832031 22.921875 12.886719 + Cairo.curveTo 22.023438 11.261719 21.320313 9.261719 20.597656 9.703125 + Cairo.curveTo 20.09375 10.011719 19.808594 10.394531 19.699219 10.554688 + Cairo.curveTo 19.195313 11.285156 18.960938 11.648438 18 12.988281 + Cairo.curveTo 17.140625 11.703125 16.738281 10.175781 15.789063 9.058594 + Cairo.curveTo 15.761719 9.03125 15.738281 9.011719 15.714844 8.992188 + Cairo.curveTo 15.6875 8.960938 15.660156 8.9375 15.632813 8.914063 + Cairo.curveTo 15.578125 8.871094 15.527344 8.832031 15.476563 8.800781 + Cairo.curveTo 15.464844 8.792969 15.457031 8.78125 15.445313 8.777344 + Cairo.curveTo 15.445313 8.777344 14.960938 8.40625 14.960938 8.40625 + Cairo.curveTo 14.828125 8.292969 14.675781 8.246094 14.53125 8.257813 + Cairo.curveTo 14.53125 8.257813 14.53125 8.257813 14.53125 8.257813 + Cairo.closePath + Cairo.fillPreserve + + -- Brush tip + withRGBA brushColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 7.199219 18.394531 + Cairo.curveTo 7.804688 18.804688 8.53125 19.203125 9.082031 19.335938 + Cairo.curveTo 9.082031 19.335938 4.996094 22.519531 4.996094 22.519531 + Cairo.curveTo 4.414063 23.074219 2.742188 23.832031 2.59375 23.699219 + Cairo.curveTo 2.460938 23.582031 2.949219 22.351563 3.4375 21.449219 + Cairo.curveTo 3.4375 21.449219 5.777344 17.140625 5.777344 17.140625 + Cairo.curveTo 5.96875 17.429688 6.597656 17.980469 7.199219 18.394531 + Cairo.curveTo 7.199219 18.394531 7.199219 18.394531 7.199219 18.394531 + Cairo.closePath + Cairo.fillPreserve diff --git a/src/app/MetaBrush/Asset/Magnifier.hs b/src/app/MetaBrush/Asset/Magnifier.hs new file mode 100644 index 0000000..c1ed128 --- /dev/null +++ b/src/app/MetaBrush/Asset/Magnifier.hs @@ -0,0 +1,60 @@ +module MetaBrush.Asset.Magnifier + ( drawMagnifier ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +import MetaBrush.Render.Util + ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | Magnifying glass icon. Width = 19, height = 25. +drawMagnifier :: GDK.RGBA -> GDK.RGBA -> Cairo.Render () +drawMagnifier magnifierColour glassColour = do + + -- Magnifying glass. + withRGBA glassColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 18.191406 6.144531 + Cairo.curveTo 19.238281 10.191406 16.804688 14.324219 12.753906 15.371094 + Cairo.curveTo 8.703125 16.417969 4.574219 13.984375 3.527344 9.933594 + Cairo.curveTo 2.480469 5.882813 4.914063 1.753906 8.964844 0.707031 + Cairo.curveTo 13.011719 -0.339844 17.144531 2.09375 18.191406 6.144531 + Cairo.closePath + Cairo.fillPreserve + + -- Magnifier. + withRGBA magnifierColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 11.144531 0.00390625 + Cairo.curveTo 8.296875 -0.09375 5.484375 1.332031 3.933594 3.960938 + Cairo.curveTo 1.871094 7.464844 2.980469 12.0625 6.089844 14.515625 + Cairo.curveTo 5.878906 14.90625 5.226563 16.132813 4.554688 15.75 + Cairo.curveTo 4.300781 15.609375 3.878906 15.882813 3.605469 16.363281 + Cairo.lineTo 0.128906 22.34375 + Cairo.curveTo -0.140625 22.828125 0.0273438 23.4375 0.503906 23.707031 + Cairo.lineTo 2.320313 24.738281 + Cairo.curveTo 2.800781 25.011719 3.410156 24.839844 3.683594 24.363281 + Cairo.lineTo 7.148438 18.210938 + Cairo.curveTo 7.421875 17.730469 7.34375 17.394531 7.09375 17.246094 + Cairo.curveTo 6.445313 16.855469 7.1875 15.789063 7.449219 15.332031 + Cairo.curveTo 11.136719 16.988281 15.683594 15.683594 17.78125 12.117188 + Cairo.curveTo 20.035156 8.292969 18.761719 3.367188 14.9375 1.113281 + Cairo.curveTo 13.742188 0.410156 12.441406 0.0507813 11.144531 0.00390625 + Cairo.closePath + Cairo.moveTo 10.855469 1.375 + Cairo.curveTo 13.894531 1.371094 16.550781 3.429688 17.3125 6.371094 + Cairo.curveTo 18.234375 9.9375 16.089844 13.570313 12.527344 14.492188 + Cairo.curveTo 8.960938 15.414063 5.328125 13.269531 4.40625 9.707031 + Cairo.curveTo 3.484375 6.144531 5.625 2.507813 9.191406 1.585938 + Cairo.curveTo 9.734375 1.445313 10.292969 1.375 10.855469 1.375 + Cairo.closePath + Cairo.setFillRule Cairo.FillRuleWinding + Cairo.fillPreserve + diff --git a/src/app/MetaBrush/Asset/Meta.hs b/src/app/MetaBrush/Asset/Meta.hs new file mode 100644 index 0000000..d44f537 --- /dev/null +++ b/src/app/MetaBrush/Asset/Meta.hs @@ -0,0 +1,42 @@ +module MetaBrush.Asset.Meta + ( drawMeta ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +import MetaBrush.Render.Util + ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | MetaParameter icon. Width = 29, height = 29. +drawMeta :: GDK.RGBA -> Cairo.Render () +drawMeta metaColour = do + withRGBA metaColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 16.140625 11.976563 + Cairo.curveTo 15.042969 10.355469 13.957031 7.050781 13.257813 7.195313 + Cairo.curveTo 12.878906 7.078125 5.332031 18.234375 4.664063 19.019531 + Cairo.curveTo 3.90625 18.234375 2.886719 19.078125 2.800781 20.273438 + Cairo.curveTo 2.800781 20.886719 4.28125 22.585938 5.566406 20.738281 + Cairo.curveTo 5.6875 20.566406 11.421875 12.542969 11.957031 11.753906 + Cairo.curveTo 12.421875 12.714844 14.351563 16.082031 14.46875 16.230469 + Cairo.curveTo 15.605469 15.660156 15.863281 15.316406 16.476563 14.589844 + Cairo.curveTo 17.171875 13.621094 17.265625 13.5 18.207031 12.261719 + Cairo.curveTo 18.644531 13.164063 20 14.65625 21.238281 16.253906 + Cairo.curveTo 21.703125 16.855469 23.695313 18.898438 24.28125 18.671875 + Cairo.curveTo 24.589844 18.550781 25.699219 17.550781 25.894531 16.492188 + Cairo.curveTo 25.941406 16.253906 26.050781 15.351563 25.847656 15.167969 + Cairo.curveTo 25.707031 15.039063 24.519531 15.707031 24.148438 15.5625 + Cairo.curveTo 23.507813 14.621094 22.722656 12.988281 22.042969 11.859375 + Cairo.curveTo 20.964844 9.90625 20.125 7.507813 19.257813 8.039063 + Cairo.curveTo 18.652344 8.410156 18.308594 8.867188 18.179688 9.058594 + Cairo.curveTo 17.574219 9.9375 17.289063 10.367188 16.140625 11.976563 + Cairo.curveTo 16.140625 11.976563 16.140625 11.976563 16.140625 11.976563 + Cairo.closePath + Cairo.fillPreserve diff --git a/src/app/MetaBrush/Asset/TickBox.hs b/src/app/MetaBrush/Asset/TickBox.hs new file mode 100644 index 0000000..8f49a7c --- /dev/null +++ b/src/app/MetaBrush/Asset/TickBox.hs @@ -0,0 +1,96 @@ +module MetaBrush.Asset.TickBox + ( drawBox, drawTickedBox ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +import MetaBrush.Render.Util + ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | Non-ticked box. Width = 14, height = 12. +drawBox :: GDK.RGBA -> Cairo.Render () +drawBox boxColour = do + withRGBA loopColour Cairo.setSourceRGBA + + Cairo.newPath + Cairo.moveTo 2.015625 0.769531 + Cairo.curveTo 0.910156 0.769531 0 1.6875 0 2.789063 + Cairo.lineTo 0 10 + Cairo.curveTo 0 11.101563 0.910156 12.015625 2.015625 12.015625 + Cairo.lineTo 9.226563 12.015625 + Cairo.curveTo 10.328125 12.015625 11.246094 11.101563 11.246094 10 + Cairo.lineTo 11.246094 2.789063 + Cairo.curveTo 11.246094 1.6875 10.328125 0.769531 9.226563 0.769531 + Cairo.closePath + Cairo.moveTo 2.015625 2.375 + Cairo.lineTo 9.226563 2.375 + Cairo.curveTo 9.46875 2.375 9.640625 2.546875 9.640625 2.789063 + Cairo.lineTo 9.640625 10 + Cairo.curveTo 9.640625 10.242188 9.46875 10.414063 9.226563 10.414063 + Cairo.lineTo 2.015625 10.414063 + Cairo.curveTo 1.769531 10.414063 1.597656 10.242188 1.597656 10 + Cairo.lineTo 1.597656 2.789063 + Cairo.curveTo 1.597656 2.546875 1.769531 2.375 2.015625 2.375 + Cairo.closePath + + Cairo.setFillRule Cairo.FillRuleWinding + Cairo.fillPreserve + +-- | Ticked box. Width = 14, height = 12. +drawTickedBox :: GDK.RGBA -> GDK.RGBA -> Cairo.Render () +drawTickedBox boxColour tickColour = do + + -- Box + withRGBA boxColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 2.015625 0.769531 + Cairo.curveTo 0.910156 0.769531 0 1.679688 0 2.785156 + Cairo.lineTo 0 9.996094 + Cairo.curveTo 0 11.097656 0.910156 12.015625 2.015625 12.015625 + Cairo.lineTo 9.226563 12.015625 + Cairo.curveTo 10.328125 12.015625 11.246094 11.097656 11.246094 9.996094 + Cairo.lineTo 11.246094 5.867188 + Cairo.lineTo 9.640625 7.476563 + Cairo.lineTo 9.640625 9.996094 + Cairo.curveTo 9.640625 10.238281 9.46875 10.410156 9.226563 10.410156 + Cairo.lineTo 2.015625 10.410156 + Cairo.curveTo 1.769531 10.410156 1.597656 10.238281 1.597656 9.996094 + Cairo.lineTo 1.597656 2.785156 + Cairo.curveTo 1.597656 2.539063 1.769531 2.371094 2.015625 2.371094 + Cairo.lineTo 9.226563 2.371094 + Cairo.curveTo 9.277344 2.371094 9.324219 2.378906 9.367188 2.394531 + Cairo.lineTo 10.511719 1.25 + Cairo.curveTo 10.160156 0.957031 9.710938 0.769531 9.226563 0.769531 + Cairo.closePath + Cairo.fillPreserve + + -- Tickmark + withRGBA tickColour Cairo.setSourceRGBA + Cairo.newPath + Cairo.moveTo 13.40625 0.0078125 + Cairo.curveTo 13.191406 0.0390625 12.96875 0.144531 12.785156 0.328125 + Cairo.lineTo 6.511719 6.605469 + Cairo.lineTo 4.597656 4.691406 + Cairo.curveTo 4.230469 4.328125 3.710938 4.257813 3.425781 4.542969 + Cairo.lineTo 3.144531 4.820313 + Cairo.curveTo 2.863281 5.105469 2.929688 5.628906 3.300781 5.992188 + Cairo.lineTo 5.8125 8.5 + Cairo.curveTo 5.925781 8.609375 6.046875 8.683594 6.175781 8.738281 + Cairo.curveTo 6.261719 8.78125 6.332031 8.804688 6.417969 8.816406 + Cairo.curveTo 6.425781 8.816406 6.429688 8.816406 6.445313 8.816406 + Cairo.curveTo 6.53125 8.824219 6.605469 8.820313 6.6875 8.796875 + Cairo.curveTo 6.71875 8.789063 6.746094 8.785156 6.773438 8.773438 + Cairo.curveTo 6.929688 8.722656 7.085938 8.644531 7.21875 8.511719 + Cairo.lineTo 14.097656 1.625 + Cairo.curveTo 14.464844 1.261719 14.53125 0.738281 14.253906 0.453125 + Cairo.lineTo 13.976563 0.179688 + Cairo.curveTo 13.835938 0.0351563 13.632813 -0.0195313 13.421875 0.0078125 + Cairo.closePath + Cairo.fillPreserve diff --git a/src/app/MetaBrush/Asset/WindowIcons.hs b/src/app/MetaBrush/Asset/WindowIcons.hs new file mode 100644 index 0000000..1531ca4 --- /dev/null +++ b/src/app/MetaBrush/Asset/WindowIcons.hs @@ -0,0 +1,31 @@ +module MetaBrush.Asset.WindowIcons + ( drawMinimise, drawRestoreDown, drawMaximise, drawClose ) + where + +-- gi-cairo-render +import qualified GI.Cairo.Render as Cairo + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- MetaBrush +--import MetaBrush.Render.Util +-- ( withRGBA ) + +-------------------------------------------------------------------------------- + +-- | Minimise window icon. +drawMinimise :: GDK.RGBA -> Cairo.Render () +drawMinimise iconColour = pure () + +-- | Restore down window icon. +drawRestoreDown :: GDK.RGBA -> Cairo.Render () +drawRestoreDown iconColour = pure () + +-- | Maximise window icon. +drawMaximise :: GDK.RGBA -> Cairo.Render () +drawMaximise iconColour = pure () + +-- | Close window icon. +drawClose :: GDK.RGBA -> Cairo.Render () +drawClose iconColour = pure () diff --git a/src/app/MetaBrush/Document.hs b/src/app/MetaBrush/Document.hs new file mode 100644 index 0000000..ef56466 --- /dev/null +++ b/src/app/MetaBrush/Document.hs @@ -0,0 +1,12 @@ +module MetaBrush.Document where + +-------------------------------------------------------------------------------- + +data Document + = Document + { displayName :: !Text + , filePath :: !(Maybe FilePath) + , unsavedChanges :: !Bool + , viewport :: !AABB + , strokes :: !(Set Stroke) + } diff --git a/src/app/MetaBrush/Render/Util.hs b/src/app/MetaBrush/Render/Util.hs new file mode 100644 index 0000000..b018dc3 --- /dev/null +++ b/src/app/MetaBrush/Render/Util.hs @@ -0,0 +1,43 @@ +module MetaBrush.Render.Util + ( withRGBA, showRGBA + , widgetAddClasses, widgetAddClass ) + where + +-- base +import GHC.Stack + ( HasCallStack ) + +-- gi-gdk +import qualified GI.Gdk as GDK + +-- text +import Data.Text + ( Text ) +import qualified Data.Text as Text + ( pack ) + +-- transformers +import Control.Monad.IO.Class + ( MonadIO(liftIO) ) + +-------------------------------------------------------------------------------- + +withRGBA :: MonadIO m => GDK.RGBA -> ( Double -> Double -> Double -> Double -> m b ) -> m b +withRGBA rgba f = do + r <- GDK.getRGBARed rgba + g <- GDK.getRGBAGreen rgba + b <- GDK.getRGBABlue rgba + a <- GDK.getRGBAAlpha rgba + f r g b a + +showRGBA :: MonadIO m => GDK.RGBA -> m String +showRGBA rgba = withRGBA rgba \ r g b a -> + pure $ "rgba(" ++ show r ++ "," ++ show g ++ "," ++ show b ++ "," ++ show a ++ ")" + +widgetAddClasses :: ( HasCallStack, GTK.IsWidget widget, MonadIO m ) => widget -> [Text] -> m () +widgetAddClasses widget classNames = do + styleContext <- GTK.widgetGetStyleContext widget + for_ classNames ( GTK.styleContextAddClass styleContext ) + +widgetAddClass :: ( HasCallStack, GTK.IsWidget widget, MonadIO m ) => widget -> Text -> m () +widgetAddClass widget className = GTK.widgetGetStyleContext widget >>= ( `GTK.styleContextAddClass` className ) diff --git a/src/app/MetaBrush/Stroke.hs b/src/app/MetaBrush/Stroke.hs new file mode 100644 index 0000000..743301d --- /dev/null +++ b/src/app/MetaBrush/Stroke.hs @@ -0,0 +1,11 @@ +module MetaBrush.Stroke where + +-------------------------------------------------------------------------------- + +data StrokePoint + = StrokePoint + { center :: Point2D Double + , + +newtype Stroke = + Stroke { strokePoints :: Seq ( \ No newline at end of file diff --git a/src/lib/Math/Bezier/Cubic.hs b/src/lib/Math/Bezier/Cubic.hs new file mode 100644 index 0000000..d4f742e --- /dev/null +++ b/src/lib/Math/Bezier/Cubic.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} + +module Math.Bezier.Cubic + ( Bezier(..) + , bezier, bezier' + ) + where + +-- base +import GHC.Generics + ( Generic ) + +-- acts +import Data.Act + ( Act + ( (•) ) + , Torsor + ( (-->) ) + ) + +-- MetaBrush +import Math.Module + ( Module (..) + , lerp + ) +import qualified Math.Bezier.Quadratic as Quadratic + ( Bezier(Bezier), bezier ) + +-------------------------------------------------------------------------------- + +-- | Points defining a cubic Bézier curve. +-- +-- @ p0 @ and @ p3 @ are endpoints, whereas @ p1 @ and @ p2 @ are control points. +data Bezier p + = Bezier + { p0 :: !p + , p1 :: !p + , p2 :: !p + , p3 :: !p + } + deriving stock ( Show, Generic, Functor, Foldable, Traversable ) + +instance Module r p => Module r ( Bezier p ) where + ( Bezier p0 p1 p2 p3 ) ^+^ ( Bezier q0 q1 q2 q3 ) = Bezier ( p0 ^+^ q0 ) ( p1 ^+^ q1 ) ( p2 ^+^ q2 ) ( p3 ^+^ q3 ) + r *^ bz = fmap ( r *^ ) bz + +-- | Cubic Bézier curve. +bezier :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> p +bezier ( Bezier { .. } ) t = + lerp @v t + ( Quadratic.bezier ( Quadratic.Bezier p0 p1 p2 ) t ) + ( Quadratic.bezier ( Quadratic.Bezier p1 p2 p3 ) t ) + +-- | Derivative of cubic Bézier curve. +bezier' :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> v +bezier' ( Bezier { .. } ) t + = ( 3 *^ ) + $ lerp @v t + ( lerp @v t ( p0 --> p1 ) ( p1 --> p2 ) ) + ( lerp @v t ( p1 --> p2 ) ( p2 --> p3 ) ) diff --git a/src/lib/Math/Bezier/Quadratic.hs b/src/lib/Math/Bezier/Quadratic.hs new file mode 100644 index 0000000..b315eb6 --- /dev/null +++ b/src/lib/Math/Bezier/Quadratic.hs @@ -0,0 +1,58 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} + +module Math.Bezier.Quadratic + ( Bezier(..) + , bezier, bezier' + ) + where + +-- base +import GHC.Generics + ( Generic ) + +-- acts +import Data.Act + ( Act + ( (•) ) + , Torsor + ( (-->) ) + ) + +-- MetaBrush +import Math.Module + ( Module (..) + , lerp + ) + +-------------------------------------------------------------------------------- + +-- | Points defining a quadratic Bézier curve. +-- +-- @ p0 @ and @ p2 @ are endpoints, whereas @ p1 @ is a control point. +data Bezier p + = Bezier + { p0 :: !p + , p1 :: !p + , p2 :: !p + } + deriving stock ( Show, Generic, Functor, Foldable, Traversable ) + +instance Module r p => Module r ( Bezier p ) where + ( Bezier p0 p1 p2 ) ^+^ ( Bezier q0 q1 q2 ) = Bezier ( p0 ^+^ q0 ) ( p1 ^+^ q1 ) ( p2 ^+^ q2 ) + r *^ bz = fmap ( r *^ ) bz + +-- | Quadratic Bézier curve. +bezier :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> p +bezier ( Bezier { .. } ) t = lerp @v t ( lerp @v t p0 p1 ) ( lerp @v t p1 p2 ) + +-- | Derivative of quadratic Bézier curve. +bezier' :: forall v r p. ( Torsor v p, Module r v ) => Bezier p -> r -> v +bezier' ( Bezier { .. } ) t = 2 *^ lerp @v t ( p0 --> p1 ) ( p1 --> p2 ) \ No newline at end of file diff --git a/src/lib/Math/Bezier/Stroke.hs b/src/lib/Math/Bezier/Stroke.hs new file mode 100644 index 0000000..4b746fe --- /dev/null +++ b/src/lib/Math/Bezier/Stroke.hs @@ -0,0 +1,3 @@ +module Math.Bezier.Stroke where + +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/lib/Math/Bezier/Subdivision.hs b/src/lib/Math/Bezier/Subdivision.hs new file mode 100644 index 0000000..58b09bb --- /dev/null +++ b/src/lib/Math/Bezier/Subdivision.hs @@ -0,0 +1,3 @@ +module Math.Bezier.Subdivision where + +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/lib/Math/Module.hs b/src/lib/Math/Module.hs new file mode 100644 index 0000000..c78613d --- /dev/null +++ b/src/lib/Math/Module.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Math.Module + ( Module(..) + , lerp + ) + where + +-- acts +import Data.Act + ( Torsor + ( (-->) ) + ) + +-------------------------------------------------------------------------------- + +infixl 6 ^+^, ^-^ +infix 8 ^*, *^ + +class Num r => Module r m where + + {-# MINIMAL (^+^), ( (^*) | (*^) ) #-} + + (^+^) :: m -> m -> m + (^-^) :: m -> m -> m + (*^) :: r -> m -> m + (^*) :: m -> r -> m + + (*^) = flip (^*) + (^*) = flip (*^) + m ^-^ n = m ^+^ (-1) *^ n + +instance Num a => Module a a where + (^+^) = (+) + (*^) = (*) + (^*) = (*) + +lerp :: forall v r p. ( Module r v , Torsor v p ) => r -> p -> p -> p +lerp t p0 p1 = ( t *^ ( p0 --> p1 ) ) • p0 \ No newline at end of file diff --git a/src/lib/Math/Vector2D.hs b/src/lib/Math/Vector2D.hs new file mode 100644 index 0000000..d74a448 --- /dev/null +++ b/src/lib/Math/Vector2D.hs @@ -0,0 +1,51 @@ +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE DerivingVia #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} + +module Math.Vector2D + ( Point2D(..), Vector2D(..) ) + where + +-- base +import GHC.Generics + ( Generic ) + +-- acts +import Data.Act + ( Act, Torsor ) + +-- generic-data +import Data.Generic + ( GenericProduct(..) ) + +-- groups +import Data.Group + ( Group ( invert ) ) + +-- MetaBrush +import Math.Module + ( Module (..) ) + +-------------------------------------------------------------------------------- + +data Point2D a = Point2D !a !a + deriving stock ( Show, Generic, Functor, Foldable, Traversable ) + deriving ( Act ( Vector2D a ), Torsor ( Vector2D a ) ) + via Vector2D a + +newtype Vector2D a = Vector2D { tip :: Point2D a } + deriving stock Show + deriving ( Semigroup, Monoid, Group ) + via GenericProduct ( Point2D ( Sum a ) ) + deriving newtype ( Functor, Foldable, Traversable ) + +instance Num a => Module a ( Vector2D a ) where + (^+^) = (<>) + p ^-^ q = p <> invert q + + c *^ p = fmap ( c * ) p + p ^* c = fmap ( * c ) p