2020-08-05 20:23:16 +00:00
|
|
|
|
{-# LANGUAGE BlockArguments #-}
|
2020-08-06 03:06:18 +00:00
|
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
|
|
|
|
{-# LANGUAGE GADTs #-}
|
|
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2020-08-10 14:38:27 +00:00
|
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2020-08-08 03:33:35 +00:00
|
|
|
|
{-# LANGUAGE NegativeLiterals #-}
|
2020-08-05 20:23:16 +00:00
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2020-08-10 14:38:27 +00:00
|
|
|
|
{-# LANGUAGE PatternSynonyms #-}
|
2020-08-05 20:23:16 +00:00
|
|
|
|
{-# LANGUAGE RecordWildCards #-}
|
|
|
|
|
{-# LANGUAGE TypeApplications #-}
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
module Main
|
|
|
|
|
( main )
|
|
|
|
|
where
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
-- base
|
2020-08-06 03:06:18 +00:00
|
|
|
|
import Control.Monad
|
2020-08-10 14:38:27 +00:00
|
|
|
|
( void, unless )
|
2020-08-06 00:45:20 +00:00
|
|
|
|
import Data.Foldable
|
|
|
|
|
( for_ )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import Data.Int
|
|
|
|
|
( Int32 )
|
2020-08-10 14:38:27 +00:00
|
|
|
|
import Data.Word
|
|
|
|
|
( Word32 )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import System.Exit
|
|
|
|
|
( exitSuccess )
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
-- acts
|
|
|
|
|
import Data.Act
|
|
|
|
|
( Act
|
|
|
|
|
( (•) )
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
-- containers
|
|
|
|
|
import Data.IntMap.Strict
|
|
|
|
|
( IntMap )
|
|
|
|
|
import qualified Data.IntMap.Strict as IntMap
|
|
|
|
|
( fromList, lookup, insert, traverseWithKey )
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
-- directory
|
|
|
|
|
import qualified System.Directory as Directory
|
|
|
|
|
( canonicalizePath )
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
-- gi-cairo-connector
|
|
|
|
|
import qualified GI.Cairo.Render.Connector as Cairo
|
|
|
|
|
( renderWithContext )
|
|
|
|
|
|
2020-08-08 03:33:35 +00:00
|
|
|
|
-- gi-cairo-render
|
|
|
|
|
import qualified GI.Cairo.Render as Cairo
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
-- gi-gdk
|
|
|
|
|
import qualified GI.Gdk as GDK
|
|
|
|
|
|
|
|
|
|
-- gi-gtk
|
|
|
|
|
import qualified GI.Gtk as GTK
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
-- stm
|
|
|
|
|
import qualified Control.Concurrent.STM as STM
|
|
|
|
|
( atomically )
|
|
|
|
|
import qualified Control.Concurrent.STM.TVar as STM
|
|
|
|
|
( newTVarIO, writeTVar, readTVarIO )
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
-- text
|
|
|
|
|
import qualified Data.Text as Text
|
|
|
|
|
( pack )
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
-- MetaBrush
|
2020-08-10 14:38:27 +00:00
|
|
|
|
import Math.Module
|
|
|
|
|
( (*^) )
|
|
|
|
|
import Math.Vector2D
|
|
|
|
|
( Point2D(..), Vector2D(..) )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import MetaBrush.Asset.Colours
|
2020-08-08 03:33:35 +00:00
|
|
|
|
( getColours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
import MetaBrush.Asset.Cursor
|
|
|
|
|
( drawCursorIcon )
|
2020-08-08 03:33:35 +00:00
|
|
|
|
import MetaBrush.Asset.InfoBar
|
|
|
|
|
( drawMagnifier, drawTopLeftCornerRect )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import MetaBrush.Asset.Logo
|
|
|
|
|
( drawLogo )
|
2020-08-07 22:41:08 +00:00
|
|
|
|
import MetaBrush.Asset.Tools
|
|
|
|
|
( drawBrush, drawMeta, drawPath, drawPen )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
import MetaBrush.Asset.WindowIcons
|
|
|
|
|
( drawMinimise, drawRestoreDown, drawMaximise, drawClose )
|
2020-08-10 14:38:27 +00:00
|
|
|
|
import MetaBrush.Document
|
|
|
|
|
( Document(..)
|
|
|
|
|
, AABB(..)
|
|
|
|
|
, Stroke(..)
|
|
|
|
|
)
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import MetaBrush.Event
|
2020-08-10 14:38:27 +00:00
|
|
|
|
( handleKeyboardPressEvent, handleKeyboardReleaseEvent
|
|
|
|
|
, pattern Control_L, pattern Control_R
|
|
|
|
|
, pattern Shift_L, pattern Shift_R
|
|
|
|
|
)
|
|
|
|
|
import MetaBrush.Render.Document
|
|
|
|
|
( renderDocument )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
import MetaBrush.Render.Util
|
|
|
|
|
( widgetAddClass, widgetAddClasses )
|
|
|
|
|
import MetaBrush.UI.Menu
|
|
|
|
|
( newMenuBar )
|
|
|
|
|
import qualified Paths_MetaBrush as Cabal
|
2020-08-04 06:15:06 +00:00
|
|
|
|
( getDataFileName )
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
testDocuments :: IntMap Document
|
|
|
|
|
testDocuments = IntMap.fromList
|
|
|
|
|
$ zip [0..]
|
|
|
|
|
[ Document
|
|
|
|
|
{ displayName = "Document 1"
|
|
|
|
|
, filePath = Nothing
|
|
|
|
|
, unsavedChanges = False
|
|
|
|
|
, strokes = [ Stroke [ Point2D 10 10, Point2D 30 30, Point2D 40 70 ] ]
|
|
|
|
|
, bounds = AABB ( Point2D 0 0 ) ( Point2D 100 100 )
|
|
|
|
|
, viewportCenter = Point2D 50 50
|
|
|
|
|
, zoomFactor = 1
|
|
|
|
|
}
|
|
|
|
|
, Document
|
|
|
|
|
{ displayName = "Document 2"
|
|
|
|
|
, filePath = Nothing
|
|
|
|
|
, unsavedChanges = True
|
|
|
|
|
, strokes = [ Stroke [ Point2D 0 0, Point2D 10 10, Point2D 20 20 ] ]
|
|
|
|
|
, bounds = AABB ( Point2D 0 0 ) ( Point2D 50 50 )
|
|
|
|
|
, viewportCenter = Point2D 10 10
|
|
|
|
|
, zoomFactor = 0.25
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
main :: IO ()
|
|
|
|
|
main = do
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Initialise state
|
|
|
|
|
|
|
|
|
|
activeDocumentTVar <- STM.newTVarIO @( Maybe Int ) Nothing
|
|
|
|
|
openDocumentsTVar <- STM.newTVarIO @( IntMap Document ) testDocuments
|
|
|
|
|
pressedKeysTVar <- STM.newTVarIO @[ Word32 ] []
|
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Initialise GTK
|
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
void $ GTK.init Nothing
|
2020-08-04 06:15:06 +00:00
|
|
|
|
Just screen <- GDK.screenGetDefault
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
themePath <- Text.pack <$> ( Directory.canonicalizePath =<< Cabal.getDataFileName "theme.css" )
|
2020-08-04 06:15:06 +00:00
|
|
|
|
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
|
2020-08-10 14:38:27 +00:00
|
|
|
|
GTK.setWindowDecorated window False
|
2020-08-04 06:15:06 +00:00
|
|
|
|
GTK.setWindowTitle window "MetaBrush"
|
|
|
|
|
GTK.windowSetDefaultSize window 800 600
|
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
baseMinWidth, baseMinHeight :: Int32
|
2020-08-05 20:23:16 +00:00
|
|
|
|
baseMinWidth = 480
|
2020-08-04 06:15:06 +00:00
|
|
|
|
baseMinHeight = 240
|
|
|
|
|
|
|
|
|
|
windowGeometry <- GDK.newZeroGeometry
|
|
|
|
|
GDK.setGeometryMinWidth windowGeometry baseMinWidth
|
|
|
|
|
GDK.setGeometryMinHeight windowGeometry baseMinHeight
|
|
|
|
|
GTK.windowSetGeometryHints window ( Nothing @GTK.Widget )
|
|
|
|
|
( Just windowGeometry )
|
|
|
|
|
[ GDK.WindowHintsMinSize ]
|
|
|
|
|
|
2020-08-07 19:39:24 +00:00
|
|
|
|
iconPath <- Directory.canonicalizePath =<< Cabal.getDataFileName "icon.png"
|
|
|
|
|
GTK.windowSetIconFromFile window iconPath
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
colours <- getColours windowWidgetPath
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-04 06:15:06 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Create base UI elements
|
|
|
|
|
|
|
|
|
|
baseOverlay <- GTK.overlayNew
|
2020-08-05 20:23:16 +00:00
|
|
|
|
GTK.setContainerChild window baseOverlay
|
2020-08-04 06:15:06 +00:00
|
|
|
|
|
|
|
|
|
uiGrid <- GTK.gridNew
|
2020-08-05 20:23:16 +00:00
|
|
|
|
GTK.setContainerChild baseOverlay uiGrid
|
2020-08-04 06:15:06 +00:00
|
|
|
|
|
2020-08-08 13:53:06 +00:00
|
|
|
|
logo <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
titleBar <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
toolBar <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
mainPane <- GTK.panedNew GTK.OrientationHorizontal
|
|
|
|
|
panelBox <- GTK.boxNew GTK.OrientationVertical 0
|
2020-08-04 06:15:06 +00:00
|
|
|
|
|
|
|
|
|
GTK.gridAttach uiGrid logo 0 0 1 2
|
2020-08-07 19:39:24 +00:00
|
|
|
|
GTK.gridAttach uiGrid titleBar 1 0 2 1
|
|
|
|
|
GTK.gridAttach uiGrid toolBar 0 2 2 1
|
|
|
|
|
GTK.gridAttach uiGrid mainPane 2 2 1 1
|
2020-08-05 21:30:36 +00:00
|
|
|
|
|
|
|
|
|
mainView <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
|
2020-08-08 13:53:06 +00:00
|
|
|
|
GTK.panedPack1 mainPane mainView True False
|
|
|
|
|
GTK.panedPack2 mainPane panelBox False False
|
2020-08-05 21:30:36 +00:00
|
|
|
|
|
2020-08-06 00:45:20 +00:00
|
|
|
|
fileBar <- GTK.scrolledWindowNew ( Nothing @GTK.Adjustment ) ( Nothing @GTK.Adjustment )
|
|
|
|
|
viewportGrid <- GTK.gridNew
|
|
|
|
|
infoBar <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart mainView fileBar False False 0
|
2020-08-05 21:30:36 +00:00
|
|
|
|
GTK.boxPackStart mainView viewportGrid True True 0
|
|
|
|
|
GTK.boxPackStart mainView infoBar False False 0
|
2020-08-04 06:15:06 +00:00
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Background
|
|
|
|
|
|
|
|
|
|
widgetAddClass uiGrid "bg"
|
|
|
|
|
|
|
|
|
|
---------------------------------------------------------
|
2020-08-08 03:33:35 +00:00
|
|
|
|
-- Title bar
|
|
|
|
|
|
|
|
|
|
widgetAddClass titleBar "titleBar"
|
|
|
|
|
|
|
|
|
|
--------
|
2020-08-05 20:23:16 +00:00
|
|
|
|
-- Logo
|
|
|
|
|
|
|
|
|
|
widgetAddClass logo "logo"
|
|
|
|
|
|
|
|
|
|
logoArea <- GTK.drawingAreaNew
|
|
|
|
|
GTK.boxPackStart logo logoArea True True 0
|
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
void $ GTK.onWidgetDraw logoArea
|
2020-08-07 22:41:08 +00:00
|
|
|
|
$ Cairo.renderWithContext ( drawLogo colours )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-08 03:33:35 +00:00
|
|
|
|
------------
|
|
|
|
|
-- Menu bar
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
|
|
|
|
( menuBar, _menu ) <- newMenuBar
|
2020-08-06 00:45:20 +00:00
|
|
|
|
widgetAddClasses menuBar [ "menuBar", "text", "plain" ]
|
2020-08-05 20:23:16 +00:00
|
|
|
|
GTK.boxPackStart titleBar menuBar False False 0
|
|
|
|
|
|
2020-08-07 19:39:24 +00:00
|
|
|
|
-- TODO: this is a bit of a workaround to add hover highlight to top-level menu items.
|
|
|
|
|
-- Activating a menu somehow sets the "hover" setting,
|
|
|
|
|
-- so instead we use the "selected" setting for actual hover highlighting.
|
|
|
|
|
topLevelMenuItems <- GTK.containerGetChildren menuBar
|
|
|
|
|
for_ topLevelMenuItems \ topLevelMenuItem -> do
|
|
|
|
|
void $ GTK.onWidgetEnterNotifyEvent topLevelMenuItem \ _ -> do
|
|
|
|
|
flags <- GTK.widgetGetStateFlags topLevelMenuItem
|
|
|
|
|
GTK.widgetSetStateFlags topLevelMenuItem ( GTK.StateFlagsSelected : flags ) True
|
|
|
|
|
pure False
|
|
|
|
|
void $ GTK.onWidgetLeaveNotifyEvent topLevelMenuItem \ _ -> do
|
|
|
|
|
flags <- GTK.widgetGetStateFlags topLevelMenuItem
|
|
|
|
|
GTK.widgetSetStateFlags topLevelMenuItem ( filter ( /= GTK.StateFlagsSelected ) flags ) True
|
|
|
|
|
pure False
|
|
|
|
|
|
2020-08-05 21:30:36 +00:00
|
|
|
|
windowIcons <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
widgetAddClasses windowIcons [ "windowIcon" ]
|
|
|
|
|
GTK.boxPackEnd titleBar windowIcons False False 0
|
|
|
|
|
|
2020-08-06 00:45:20 +00:00
|
|
|
|
title <- GTK.labelNew ( Just "● New Document (1) – MetaBrush" )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
widgetAddClasses title [ "text", "title", "plain" ]
|
2020-08-05 21:30:36 +00:00
|
|
|
|
GTK.boxSetCenterWidget titleBar ( Just title )
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-07 19:39:24 +00:00
|
|
|
|
minimiseButton <- GTK.buttonNew
|
|
|
|
|
fullscreenButton <- GTK.buttonNew
|
|
|
|
|
closeButton <- GTK.buttonNew
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart windowIcons minimiseButton True True 0
|
|
|
|
|
GTK.boxPackStart windowIcons fullscreenButton True True 0
|
|
|
|
|
GTK.boxPackStart windowIcons closeButton True True 0
|
|
|
|
|
|
|
|
|
|
minimiseArea <- GTK.drawingAreaNew
|
|
|
|
|
fullscreenArea <- GTK.drawingAreaNew
|
|
|
|
|
closeArea <- GTK.drawingAreaNew
|
|
|
|
|
|
|
|
|
|
GTK.containerAdd minimiseButton minimiseArea
|
|
|
|
|
GTK.containerAdd fullscreenButton fullscreenArea
|
|
|
|
|
GTK.containerAdd closeButton closeArea
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw minimiseArea
|
|
|
|
|
$ Cairo.renderWithContext
|
2020-08-07 22:41:08 +00:00
|
|
|
|
( drawMinimise colours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw fullscreenArea \ cairoContext -> do
|
|
|
|
|
Just gdkWindow <- GTK.widgetGetWindow window
|
|
|
|
|
windowState <- GDK.windowGetState gdkWindow
|
|
|
|
|
if any ( \case { GDK.WindowStateFullscreen -> True; GDK.WindowStateMaximized -> True; _ -> False } ) windowState
|
2020-08-07 22:41:08 +00:00
|
|
|
|
then Cairo.renderWithContext ( drawRestoreDown colours ) cairoContext
|
|
|
|
|
else Cairo.renderWithContext ( drawMaximise colours ) cairoContext
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw closeArea
|
|
|
|
|
$ Cairo.renderWithContext
|
2020-08-07 22:41:08 +00:00
|
|
|
|
( drawClose colours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
for_ [ minimiseButton, fullscreenButton, closeButton ] \ button -> do
|
|
|
|
|
widgetAddClass button "windowIcon"
|
|
|
|
|
|
|
|
|
|
widgetAddClass closeButton "closeWindowIcon"
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Tool bar
|
|
|
|
|
|
|
|
|
|
widgetAddClass toolBar "toolBar"
|
|
|
|
|
|
2020-08-07 19:39:24 +00:00
|
|
|
|
GTK.widgetSetValign toolBar GTK.AlignStart
|
|
|
|
|
GTK.widgetSetVexpand toolBar True
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
selectionTool <- GTK.radioButtonNew ( [] @GTK.RadioButton )
|
|
|
|
|
penTool <- GTK.radioButtonNewFromWidget ( Just selectionTool )
|
|
|
|
|
|
|
|
|
|
pathTool <- GTK.radioButtonNew ( [] @GTK.RadioButton )
|
|
|
|
|
brushTool <- GTK.radioButtonNewFromWidget ( Just pathTool )
|
|
|
|
|
metaTool <- GTK.radioButtonNewFromWidget ( Just pathTool )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
toolSep1 <- GTK.boxNew GTK.OrientationVertical 0
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
GTK.boxPackStart toolBar selectionTool True True 0
|
2020-08-07 22:41:08 +00:00
|
|
|
|
GTK.boxPackStart toolBar penTool True True 0
|
|
|
|
|
GTK.boxPackStart toolBar toolSep1 True True 0
|
|
|
|
|
GTK.boxPackStart toolBar pathTool True True 0
|
2020-08-07 19:39:24 +00:00
|
|
|
|
GTK.boxPackStart toolBar brushTool True True 0
|
|
|
|
|
GTK.boxPackStart toolBar metaTool True True 0
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
for_ [ selectionTool, penTool, pathTool, brushTool, metaTool ] \ tool -> do
|
2020-08-07 19:39:24 +00:00
|
|
|
|
GTK.toggleButtonSetMode tool False -- don't display radio indicator
|
|
|
|
|
widgetAddClass tool "toolItem"
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
widgetAddClass toolSep1 "toolBarSeparator"
|
|
|
|
|
|
|
|
|
|
GTK.widgetSetTooltipText selectionTool ( Just "Select" )
|
|
|
|
|
GTK.widgetSetTooltipText penTool ( Just "Draw" )
|
|
|
|
|
GTK.widgetSetTooltipText pathTool ( Just "Brush path" )
|
|
|
|
|
GTK.widgetSetTooltipText brushTool ( Just "Brushes" )
|
|
|
|
|
GTK.widgetSetTooltipText metaTool ( Just "Meta-parameters" )
|
|
|
|
|
|
2020-08-07 19:39:24 +00:00
|
|
|
|
selectionToolArea <- GTK.drawingAreaNew
|
2020-08-07 22:41:08 +00:00
|
|
|
|
penToolArea <- GTK.drawingAreaNew
|
|
|
|
|
pathToolArea <- GTK.drawingAreaNew
|
2020-08-07 19:39:24 +00:00
|
|
|
|
brushToolArea <- GTK.drawingAreaNew
|
|
|
|
|
metaToolArea <- GTK.drawingAreaNew
|
|
|
|
|
|
|
|
|
|
GTK.containerAdd selectionTool selectionToolArea
|
2020-08-07 22:41:08 +00:00
|
|
|
|
GTK.containerAdd penTool penToolArea
|
|
|
|
|
GTK.containerAdd pathTool pathToolArea
|
2020-08-07 19:39:24 +00:00
|
|
|
|
GTK.containerAdd brushTool brushToolArea
|
|
|
|
|
GTK.containerAdd metaTool metaToolArea
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw selectionToolArea
|
|
|
|
|
$ Cairo.renderWithContext
|
2020-08-07 22:41:08 +00:00
|
|
|
|
( drawCursorIcon colours )
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw penToolArea
|
|
|
|
|
$ Cairo.renderWithContext
|
|
|
|
|
( drawPen colours )
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw pathToolArea
|
|
|
|
|
$ Cairo.renderWithContext
|
|
|
|
|
( drawPath colours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw brushToolArea
|
|
|
|
|
$ Cairo.renderWithContext
|
2020-08-07 22:41:08 +00:00
|
|
|
|
( drawBrush colours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw metaToolArea
|
|
|
|
|
$ Cairo.renderWithContext
|
2020-08-07 22:41:08 +00:00
|
|
|
|
( drawMeta colours )
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
---------------------------------------------------------
|
2020-08-06 03:06:18 +00:00
|
|
|
|
-- Main viewport
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
widgetAddClass viewportGrid "viewport"
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
rvRulerCorner <- GTK.revealerNew
|
|
|
|
|
rvLeftRuler <- GTK.revealerNew
|
|
|
|
|
rvTopRuler <- GTK.revealerNew
|
|
|
|
|
viewportOverlay <- GTK.overlayNew
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
GTK.gridAttach viewportGrid rvRulerCorner 0 0 1 1
|
|
|
|
|
GTK.gridAttach viewportGrid rvLeftRuler 0 1 1 1
|
|
|
|
|
GTK.gridAttach viewportGrid rvTopRuler 1 0 1 1
|
|
|
|
|
GTK.gridAttach viewportGrid viewportOverlay 1 1 1 1
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
----------
|
|
|
|
|
-- Rulers
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
rulerCorner <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
leftRuler <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
topRuler <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
|
|
|
|
|
GTK.containerAdd rvRulerCorner rulerCorner
|
|
|
|
|
GTK.containerAdd rvLeftRuler leftRuler
|
|
|
|
|
GTK.containerAdd rvTopRuler topRuler
|
|
|
|
|
|
|
|
|
|
widgetAddClass rulerCorner "ruler"
|
|
|
|
|
widgetAddClass leftRuler "ruler"
|
|
|
|
|
widgetAddClass topRuler "ruler"
|
|
|
|
|
|
|
|
|
|
GTK.revealerSetRevealChild rvRulerCorner True
|
|
|
|
|
GTK.revealerSetRevealChild rvLeftRuler True
|
|
|
|
|
GTK.revealerSetRevealChild rvTopRuler True
|
|
|
|
|
|
|
|
|
|
GTK.revealerSetTransitionType rvRulerCorner GTK.RevealerTransitionTypeSlideLeft
|
|
|
|
|
GTK.revealerSetTransitionType rvLeftRuler GTK.RevealerTransitionTypeSlideLeft
|
|
|
|
|
GTK.revealerSetTransitionType rvTopRuler GTK.RevealerTransitionTypeSlideUp
|
|
|
|
|
|
|
|
|
|
rulerCornerArea <- GTK.drawingAreaNew
|
|
|
|
|
GTK.boxPackStart rulerCorner rulerCornerArea True True 0
|
|
|
|
|
|
|
|
|
|
leftRulerArea <- GTK.drawingAreaNew
|
|
|
|
|
GTK.boxPackStart leftRuler leftRulerArea True True 0
|
|
|
|
|
|
|
|
|
|
topRulerArea <- GTK.drawingAreaNew
|
|
|
|
|
GTK.boxPackStart topRuler topRulerArea True True 0
|
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
GTK.widgetSetHexpand rulerCorner False
|
|
|
|
|
GTK.widgetSetVexpand rulerCorner False
|
|
|
|
|
GTK.widgetSetHexpand leftRuler False
|
|
|
|
|
GTK.widgetSetVexpand leftRuler True
|
|
|
|
|
GTK.widgetSetHexpand topRuler True
|
|
|
|
|
GTK.widgetSetVexpand topRuler False
|
|
|
|
|
GTK.widgetSetHexpand viewportOverlay True
|
|
|
|
|
GTK.widgetSetVexpand viewportOverlay True
|
|
|
|
|
|
2020-08-07 22:41:08 +00:00
|
|
|
|
viewportArea <- GTK.drawingAreaNew
|
|
|
|
|
GTK.setContainerChild viewportOverlay viewportArea
|
2020-08-06 03:06:18 +00:00
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
-----------------
|
|
|
|
|
-- Viewport scrolling
|
|
|
|
|
|
2020-08-06 03:06:18 +00:00
|
|
|
|
viewportScrollbarGrid <- GTK.gridNew
|
|
|
|
|
GTK.overlayAddOverlay viewportOverlay viewportScrollbarGrid
|
2020-08-10 14:38:27 +00:00
|
|
|
|
GTK.overlaySetOverlayPassThrough viewportOverlay viewportScrollbarGrid True
|
2020-08-06 03:06:18 +00:00
|
|
|
|
|
|
|
|
|
viewportHScrollbar <- GTK.scrollbarNew GTK.OrientationHorizontal ( Nothing @GTK.Adjustment )
|
|
|
|
|
viewportVScrollbar <- GTK.scrollbarNew GTK.OrientationVertical ( Nothing @GTK.Adjustment )
|
|
|
|
|
GTK.widgetSetValign viewportHScrollbar GTK.AlignEnd
|
|
|
|
|
GTK.widgetSetHalign viewportVScrollbar GTK.AlignEnd
|
|
|
|
|
GTK.widgetSetVexpand viewportVScrollbar True
|
|
|
|
|
GTK.widgetSetHexpand viewportHScrollbar True
|
|
|
|
|
GTK.gridAttach viewportScrollbarGrid viewportHScrollbar 0 1 1 1
|
|
|
|
|
GTK.gridAttach viewportScrollbarGrid viewportVScrollbar 1 0 1 1
|
|
|
|
|
widgetAddClass viewportHScrollbar "viewportScrollbar"
|
|
|
|
|
widgetAddClass viewportVScrollbar "viewportScrollbar"
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
void $ GTK.onWidgetScrollEvent viewportArea \ scrollEvent -> do
|
|
|
|
|
|
|
|
|
|
dx <- GDK.getEventScrollDeltaX scrollEvent
|
|
|
|
|
dy <- GDK.getEventScrollDeltaY scrollEvent
|
|
|
|
|
--GDK.getEventScrollDirection scrollEvent
|
|
|
|
|
--GDK.getEventScrollType scrollEvent
|
|
|
|
|
--GDK.getEventScrollX scrollEvent
|
|
|
|
|
--GDK.getEventScrollY scrollEvent
|
|
|
|
|
|
|
|
|
|
unless ( dx == 0 && dy == 0 ) do
|
|
|
|
|
mbActiveDoc <- STM.readTVarIO activeDocumentTVar
|
|
|
|
|
for_ mbActiveDoc \ i -> do
|
|
|
|
|
docs <- STM.readTVarIO openDocumentsTVar
|
|
|
|
|
for_ ( IntMap.lookup i docs ) \ ( doc@(Document { viewportCenter, zoomFactor } ) ) -> do
|
|
|
|
|
pressedKeys <- STM.readTVarIO pressedKeysTVar
|
|
|
|
|
let
|
|
|
|
|
newDoc :: Document
|
|
|
|
|
newDoc
|
|
|
|
|
-- Zooming using 'Control'.
|
|
|
|
|
| any ( \ key -> key == Control_L || key == Control_R ) pressedKeys
|
|
|
|
|
= let
|
|
|
|
|
newZoomFactor :: Double
|
|
|
|
|
newZoomFactor
|
|
|
|
|
| dy > 0
|
|
|
|
|
= max 0.0078125 ( zoomFactor / 2 )
|
|
|
|
|
| otherwise
|
|
|
|
|
= zoomFactor * 2
|
|
|
|
|
in doc { zoomFactor = newZoomFactor }
|
|
|
|
|
-- Vertical scrolling turned into horizontal scrolling using 'Shift'.
|
|
|
|
|
| dx == 0 && any ( \ key -> key == Shift_L || key == Shift_R ) pressedKeys
|
|
|
|
|
= let
|
|
|
|
|
newCenter :: Point2D Double
|
|
|
|
|
newCenter = ( ( 25 / zoomFactor ) *^ Vector2D ( Point2D dy 0 ) ) • viewportCenter
|
|
|
|
|
in doc { viewportCenter = newCenter }
|
|
|
|
|
-- Vertical scrolling.
|
|
|
|
|
| otherwise
|
|
|
|
|
= let
|
|
|
|
|
newCenter :: Point2D Double
|
|
|
|
|
newCenter = ( ( 25 / zoomFactor ) *^ Vector2D ( Point2D dx dy ) ) • viewportCenter
|
|
|
|
|
in doc { viewportCenter = newCenter }
|
|
|
|
|
docs' :: IntMap Document
|
|
|
|
|
docs' = IntMap.insert i newDoc docs
|
|
|
|
|
STM.atomically ( STM.writeTVar openDocumentsTVar docs' )
|
|
|
|
|
GTK.widgetQueueDraw viewportArea
|
|
|
|
|
pure True
|
|
|
|
|
|
|
|
|
|
-----------------
|
|
|
|
|
-- Rendering
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw viewportArea \ctx -> do
|
|
|
|
|
-- Get the relevant document information
|
|
|
|
|
mbActiveDoc <- STM.readTVarIO activeDocumentTVar
|
|
|
|
|
for_ mbActiveDoc \ i -> do
|
|
|
|
|
docs <- STM.readTVarIO openDocumentsTVar
|
|
|
|
|
for_ ( IntMap.lookup i docs ) \ doc -> do
|
|
|
|
|
( `Cairo.renderWithContext` ctx ) $ do
|
|
|
|
|
viewportWidth <- GTK.widgetGetAllocatedWidth viewportArea
|
|
|
|
|
viewportHeight <- GTK.widgetGetAllocatedHeight viewportArea
|
|
|
|
|
renderDocument colours ( viewportWidth, viewportHeight ) doc
|
|
|
|
|
pure True
|
|
|
|
|
|
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- File bar
|
|
|
|
|
|
|
|
|
|
widgetAddClass fileBar "fileBar"
|
|
|
|
|
|
|
|
|
|
fileTabs <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
GTK.containerAdd fileBar fileTabs
|
|
|
|
|
widgetAddClasses fileTabs [ "fileBar", "plain", "text" ]
|
|
|
|
|
|
|
|
|
|
fileBarPhantomRadioButton <- GTK.radioButtonNew ( [] @GTK.RadioButton )
|
|
|
|
|
|
|
|
|
|
-- TODO: currently using static list of documents.
|
|
|
|
|
-- Need to dynamically update this widget as the user opens/closes documents.
|
|
|
|
|
fileButtons <- ( `IntMap.traverseWithKey` testDocuments ) \ i ( Document { displayName, unsavedChanges } ) -> do
|
|
|
|
|
-- File tab elements.
|
|
|
|
|
pgButton <- GTK.radioButtonNewWithLabelFromWidget ( Just fileBarPhantomRadioButton ) displayName
|
|
|
|
|
GTK.toggleButtonSetMode pgButton False -- don't display radio indicator
|
|
|
|
|
closeFileButton <- GTK.buttonNewWithLabel "x"
|
|
|
|
|
|
|
|
|
|
-- Create box for file tab elements.
|
|
|
|
|
tab <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
widgetAddClasses tab [ "fileBarTab" ]
|
|
|
|
|
GTK.boxPackStart fileTabs tab False False 0
|
|
|
|
|
GTK.boxPackStart tab pgButton True True 0
|
|
|
|
|
GTK.boxPackStart tab closeFileButton False False 0
|
|
|
|
|
|
|
|
|
|
widgetAddClasses pgButton [ "fileBarTabButton" ]
|
|
|
|
|
widgetAddClasses closeFileButton [ "fileBarCloseButton" ]
|
|
|
|
|
|
|
|
|
|
-- Make both file tab elements activate styling on the whole tab
|
|
|
|
|
-- (e.g. hovering over the close file button should highlight the whole tab).
|
|
|
|
|
void $ GTK.onButtonClicked pgButton do
|
|
|
|
|
isActive <- GTK.toggleButtonGetActive pgButton
|
|
|
|
|
flags <- GTK.widgetGetStateFlags tab
|
|
|
|
|
if isActive
|
|
|
|
|
then do
|
|
|
|
|
GTK.widgetSetStateFlags tab ( GTK.StateFlagsActive : flags ) True
|
|
|
|
|
STM.atomically ( STM.writeTVar activeDocumentTVar ( Just i ) )
|
|
|
|
|
GTK.widgetQueueDraw viewportArea
|
|
|
|
|
else
|
|
|
|
|
GTK.widgetSetStateFlags tab ( filter ( /= GTK.StateFlagsActive ) flags ) True
|
|
|
|
|
|
|
|
|
|
{-
|
|
|
|
|
void $ GTK.onButtonClicked closeFileButton do
|
|
|
|
|
closeFileDialog ...
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
for_ @_ @_ @_ @() [ Exists @GTK.IsWidget pgButton, Exists @GTK.IsWidget closeFileButton ] \ ( Exists button ) -> do
|
|
|
|
|
void $ GTK.onWidgetEnterNotifyEvent button \ _ -> do
|
|
|
|
|
flags <- GTK.widgetGetStateFlags tab
|
|
|
|
|
GTK.widgetSetStateFlags tab ( GTK.StateFlagsPrelight : flags ) True
|
|
|
|
|
pure False
|
|
|
|
|
void $ GTK.onWidgetLeaveNotifyEvent button \ _ -> do
|
|
|
|
|
flags <- GTK.widgetGetStateFlags tab
|
|
|
|
|
GTK.widgetSetStateFlags tab ( filter ( /= GTK.StateFlagsPrelight ) flags ) True
|
|
|
|
|
pure False
|
|
|
|
|
|
|
|
|
|
pure pgButton
|
|
|
|
|
|
|
|
|
|
GTK.scrolledWindowSetPolicy fileBar GTK.PolicyTypeAutomatic GTK.PolicyTypeNever
|
|
|
|
|
GTK.scrolledWindowSetOverlayScrolling fileBar True
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Panels
|
|
|
|
|
|
2020-08-08 13:53:06 +00:00
|
|
|
|
widgetAddClass panelBox "panels"
|
|
|
|
|
|
|
|
|
|
pane1 <- GTK.panedNew GTK.OrientationVertical
|
|
|
|
|
GTK.boxPackStart panelBox pane1 True True 0
|
|
|
|
|
|
|
|
|
|
panels1 <- GTK.notebookNew
|
|
|
|
|
panels2 <- GTK.notebookNew
|
|
|
|
|
|
|
|
|
|
GTK.notebookSetGroupName panels1 ( Just "Panel" )
|
|
|
|
|
GTK.notebookSetGroupName panels2 ( Just "Panel" )
|
|
|
|
|
|
|
|
|
|
GTK.panedPack1 pane1 panels1 True True
|
|
|
|
|
GTK.panedPack2 pane1 panels2 True True
|
|
|
|
|
|
|
|
|
|
strokesPanel <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
brushesPanel <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
transformPanel <- GTK.boxNew GTK.OrientationVertical 0
|
|
|
|
|
|
|
|
|
|
strokesTab <- GTK.labelNew ( Just "Strokes" )
|
|
|
|
|
brushesTab <- GTK.labelNew ( Just "Brushes" )
|
|
|
|
|
transformTab <- GTK.labelNew ( Just "Transform" )
|
|
|
|
|
|
|
|
|
|
for_ [ strokesTab, brushesTab, transformTab ] \ tab -> do
|
|
|
|
|
widgetAddClasses tab [ "plain", "text", "panelTab" ]
|
|
|
|
|
|
|
|
|
|
for_ [ strokesPanel, brushesPanel, transformPanel ] \ panel -> do
|
|
|
|
|
widgetAddClass panel "panel"
|
|
|
|
|
|
|
|
|
|
void $ GTK.notebookAppendPage panels1 strokesPanel ( Just strokesTab )
|
|
|
|
|
void $ GTK.notebookAppendPage panels1 brushesPanel ( Just brushesTab )
|
|
|
|
|
|
|
|
|
|
void $ GTK.notebookAppendPage panels2 transformPanel ( Just transformTab )
|
|
|
|
|
|
|
|
|
|
GTK.notebookSetTabReorderable panels1 strokesPanel True
|
|
|
|
|
GTK.notebookSetTabDetachable panels1 strokesPanel True
|
|
|
|
|
GTK.notebookSetTabReorderable panels1 brushesPanel True
|
|
|
|
|
GTK.notebookSetTabDetachable panels1 brushesPanel True
|
|
|
|
|
|
|
|
|
|
GTK.notebookSetTabReorderable panels2 transformPanel True
|
|
|
|
|
GTK.notebookSetTabDetachable panels2 transformPanel True
|
|
|
|
|
|
|
|
|
|
strokesContent <- GTK.labelNew ( Just "Strokes tab content..." )
|
|
|
|
|
brushesContent <- GTK.labelNew ( Just "Brushes tab content..." )
|
|
|
|
|
transformContent <- GTK.labelNew ( Just "Transform tab content..." )
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart strokesPanel strokesContent True True 0
|
|
|
|
|
GTK.boxPackStart brushesPanel brushesContent True True 0
|
|
|
|
|
GTK.boxPackStart transformPanel transformContent True True 0
|
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Info bar
|
|
|
|
|
|
2020-08-08 03:33:35 +00:00
|
|
|
|
widgetAddClasses infoBar [ "infoBar", "monospace", "contrast" ]
|
|
|
|
|
|
|
|
|
|
zoomBox <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
cursorPosBox <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
topLeftPosBox <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
botRightPosBox <- GTK.boxNew GTK.OrientationHorizontal 0
|
|
|
|
|
|
|
|
|
|
for_ [ botRightPosBox, topLeftPosBox, cursorPosBox, zoomBox ] \ box -> do
|
|
|
|
|
GTK.boxPackEnd infoBar box False False 0
|
|
|
|
|
widgetAddClass box "infoBarBox"
|
|
|
|
|
|
|
|
|
|
-------------
|
|
|
|
|
-- Magnifier
|
|
|
|
|
|
|
|
|
|
magnifierArea <- GTK.drawingAreaNew
|
|
|
|
|
zoomText <- GTK.labelNew ( Just "300%" )
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart zoomBox magnifierArea True True 0
|
|
|
|
|
GTK.boxPackStart zoomBox zoomText True True 0
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw magnifierArea \ctx ->
|
|
|
|
|
( `Cairo.renderWithContext` ctx ) $ do
|
|
|
|
|
Cairo.scale 0.9 0.9
|
|
|
|
|
Cairo.translate 14 10
|
|
|
|
|
drawMagnifier colours
|
|
|
|
|
|
|
|
|
|
-------------------
|
|
|
|
|
-- Cursor position
|
|
|
|
|
|
|
|
|
|
cursorPosArea <- GTK.drawingAreaNew
|
|
|
|
|
cursorPosText <- GTK.labelNew ( Just "x: 212.12 px\ny: 120.23 px" )
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart cursorPosBox cursorPosArea False False 0
|
|
|
|
|
GTK.boxPackStart cursorPosBox cursorPosText False False 0
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw cursorPosArea \ctx ->
|
|
|
|
|
( `Cairo.renderWithContext` ctx ) $ do
|
|
|
|
|
Cairo.scale 0.75 0.75
|
|
|
|
|
Cairo.translate 10 7
|
|
|
|
|
drawCursorIcon colours
|
|
|
|
|
|
|
|
|
|
---------------------
|
|
|
|
|
-- Top left position
|
|
|
|
|
|
|
|
|
|
topLeftPosArea <- GTK.drawingAreaNew
|
|
|
|
|
topLeftPosText <- GTK.labelNew ( Just "x: 212.12 px\ny: 120.23 px" )
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart topLeftPosBox topLeftPosArea False False 0
|
|
|
|
|
GTK.boxPackStart topLeftPosBox topLeftPosText False False 0
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw topLeftPosArea
|
|
|
|
|
$ Cairo.renderWithContext
|
|
|
|
|
( drawTopLeftCornerRect colours )
|
|
|
|
|
|
|
|
|
|
-------------------------
|
|
|
|
|
-- Bottom right position
|
|
|
|
|
|
|
|
|
|
botRightPosArea <- GTK.drawingAreaNew
|
|
|
|
|
botRightPosText <- GTK.labelNew ( Just "x: 212.12 px\ny: 120.23 px" )
|
|
|
|
|
|
|
|
|
|
GTK.boxPackStart botRightPosBox botRightPosArea False False 0
|
|
|
|
|
GTK.boxPackStart botRightPosBox botRightPosText False False 0
|
|
|
|
|
|
|
|
|
|
void $ GTK.onWidgetDraw botRightPosArea \ctx ->
|
|
|
|
|
( `Cairo.renderWithContext` ctx ) $ do
|
|
|
|
|
Cairo.scale -1 -1
|
|
|
|
|
Cairo.translate -40 -40
|
|
|
|
|
drawTopLeftCornerRect colours
|
|
|
|
|
|
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
|
for_ [ magnifierArea, cursorPosArea, topLeftPosArea, botRightPosArea ] \ area -> do
|
|
|
|
|
widgetAddClass area "infoBarIcon"
|
|
|
|
|
GTK.widgetSetSizeRequest area 40 40 -- not sure why this is needed...?
|
|
|
|
|
|
|
|
|
|
for_ [ zoomText, cursorPosText, topLeftPosText, botRightPosText ] \ info -> do
|
|
|
|
|
widgetAddClass info "infoBarInfo"
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
|
|
|
|
---------------------------------------------------------
|
2020-08-04 06:15:06 +00:00
|
|
|
|
-- Actions
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
GTK.widgetAddEvents window
|
|
|
|
|
[ GDK.EventMaskKeyPressMask, GDK.EventMaskKeyReleaseMask ]
|
|
|
|
|
GTK.widgetAddEvents viewportArea
|
|
|
|
|
[ GDK.EventMaskScrollMask, GDK.EventMaskSmoothScrollMask ]
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
|
|
|
|
_ <- GTK.onButtonClicked closeButton GTK.mainQuit
|
|
|
|
|
_ <- GTK.onButtonClicked minimiseButton ( GTK.windowIconify window )
|
|
|
|
|
_ <- GTK.onButtonClicked fullscreenButton do
|
|
|
|
|
Just gdkWindow <- GTK.widgetGetWindow window
|
|
|
|
|
windowState <- GDK.windowGetState gdkWindow
|
|
|
|
|
if GDK.WindowStateFullscreen `elem` windowState
|
|
|
|
|
then GTK.windowUnfullscreen window
|
|
|
|
|
else
|
|
|
|
|
if GDK.WindowStateMaximized `elem` windowState
|
|
|
|
|
then GTK.windowUnmaximize window
|
|
|
|
|
else GTK.windowMaximize window
|
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
_ <- GTK.onWidgetKeyPressEvent window ( handleKeyboardPressEvent pressedKeysTVar )
|
|
|
|
|
_ <- GTK.onWidgetKeyReleaseEvent window ( handleKeyboardReleaseEvent pressedKeysTVar )
|
|
|
|
|
_ <- GTK.onWidgetDestroy window GTK.mainQuit
|
2020-08-07 19:39:24 +00:00
|
|
|
|
|
2020-08-05 20:23:16 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- GTK main loop
|
2020-08-04 06:15:06 +00:00
|
|
|
|
|
|
|
|
|
GTK.widgetShowAll window
|
|
|
|
|
GTK.main
|
2020-08-05 20:23:16 +00:00
|
|
|
|
|
|
|
|
|
exitSuccess
|
2020-08-06 03:06:18 +00:00
|
|
|
|
|
2020-08-10 14:38:27 +00:00
|
|
|
|
---------------------------------------------------------
|
|
|
|
|
-- Utils.
|
2020-08-06 03:06:18 +00:00
|
|
|
|
|
|
|
|
|
data Exists c where
|
2020-08-10 14:38:27 +00:00
|
|
|
|
Exists :: c a => a -> Exists c
|