mirror of
https://github.com/Drezil/dear-imgui.hs.git
synced 2024-11-25 10:07:01 +00:00
Extended font & glyph support (#114)
* Separate font utils, add glyph support (#113) * Implement font glyph ranges builder * Implement raw font config binds * Implement font atlas module * Rewrite font altas rebuilder in Managed
This commit is contained in:
parent
13e68242a1
commit
bb94341ad5
@ -124,8 +124,12 @@ library
|
|||||||
src
|
src
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
DearImGui
|
DearImGui
|
||||||
|
DearImGui.FontAtlas
|
||||||
DearImGui.Raw
|
DearImGui.Raw
|
||||||
DearImGui.Raw.DrawList
|
DearImGui.Raw.DrawList
|
||||||
|
DearImGui.Raw.Font
|
||||||
|
DearImGui.Raw.Font.Config
|
||||||
|
DearImGui.Raw.Font.GlyphRanges
|
||||||
DearImGui.Raw.ListClipper
|
DearImGui.Raw.ListClipper
|
||||||
DearImGui.Raw.IO
|
DearImGui.Raw.IO
|
||||||
other-modules:
|
other-modules:
|
||||||
@ -295,6 +299,14 @@ executable readme
|
|||||||
if (!flag(examples) || !flag(sdl) || !flag(opengl2))
|
if (!flag(examples) || !flag(sdl) || !flag(opengl2))
|
||||||
buildable: False
|
buildable: False
|
||||||
|
|
||||||
|
executable fonts
|
||||||
|
import: common, build-flags
|
||||||
|
main-is: Main.hs
|
||||||
|
hs-source-dirs: examples/fonts
|
||||||
|
build-depends: sdl2, gl, dear-imgui, managed
|
||||||
|
if (!flag(examples) || !flag(sdl) || !flag(opengl2))
|
||||||
|
buildable: False
|
||||||
|
|
||||||
executable image
|
executable image
|
||||||
import: common, build-flags
|
import: common, build-flags
|
||||||
main-is: Image.hs
|
main-is: Image.hs
|
||||||
|
150
examples/fonts/Main.hs
Normal file
150
examples/fonts/Main.hs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
{-# language BlockArguments #-}
|
||||||
|
{-# language LambdaCase #-}
|
||||||
|
{-# language OverloadedStrings #-}
|
||||||
|
{-# language RecordWildCards #-}
|
||||||
|
{-# language NamedFieldPuns #-}
|
||||||
|
{-# language DeriveTraversable #-}
|
||||||
|
|
||||||
|
{- | Font usage example.
|
||||||
|
|
||||||
|
Loads two non-standard fonts
|
||||||
|
|
||||||
|
This example uses NotoSansJP-Regular.otf from Google Fonts
|
||||||
|
Licensed under the SIL Open Font License, Version 1.1
|
||||||
|
https://fonts.google.com/noto/specimen/Noto+Sans+JP
|
||||||
|
-}
|
||||||
|
|
||||||
|
module Main ( main ) where
|
||||||
|
|
||||||
|
import Control.Exception
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
import Control.Monad.Managed
|
||||||
|
import Data.IORef
|
||||||
|
import DearImGui
|
||||||
|
import qualified DearImGui.FontAtlas as FontAtlas
|
||||||
|
import DearImGui.OpenGL2
|
||||||
|
import DearImGui.SDL
|
||||||
|
import DearImGui.SDL.OpenGL
|
||||||
|
import Graphics.GL
|
||||||
|
import SDL
|
||||||
|
|
||||||
|
-- Rebuild syntax enables us to keep fonts in any
|
||||||
|
-- traversable type, so let's make our life a little easier.
|
||||||
|
-- But feel free to use lists or maps.
|
||||||
|
data FontSet a = FontSet
|
||||||
|
{ droidFont :: a
|
||||||
|
, defaultFont :: a
|
||||||
|
, notoFont :: a
|
||||||
|
}
|
||||||
|
deriving (Functor, Foldable, Traversable)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
-- Window initialization is similar to another examples.
|
||||||
|
initializeAll
|
||||||
|
runManaged do
|
||||||
|
window <- do
|
||||||
|
let title = "Hello, Dear ImGui!"
|
||||||
|
let config = defaultWindow { windowGraphicsContext = OpenGLContext defaultOpenGL }
|
||||||
|
managed $ bracket (createWindow title config) destroyWindow
|
||||||
|
glContext <- managed $ bracket (glCreateContext window) glDeleteContext
|
||||||
|
_ <- managed $ bracket createContext destroyContext
|
||||||
|
_ <- managed_ $ bracket_ (sdl2InitForOpenGL window glContext) sdl2Shutdown
|
||||||
|
_ <- managed_ $ bracket_ openGL2Init openGL2Shutdown
|
||||||
|
|
||||||
|
-- We use high-level syntax to build font atlas and
|
||||||
|
-- get handles to use in the main loop.
|
||||||
|
fontSet <- FontAtlas.rebuild FontSet
|
||||||
|
{ -- The first mentioned font is loaded first
|
||||||
|
-- and set as a global default.
|
||||||
|
droidFont =
|
||||||
|
FontAtlas.FromTTF
|
||||||
|
"./imgui/misc/fonts/DroidSans.ttf"
|
||||||
|
15
|
||||||
|
Nothing
|
||||||
|
FontAtlas.Cyrillic
|
||||||
|
|
||||||
|
-- You also may use a default hardcoded font for
|
||||||
|
-- some purposes (i.e. as fallback)
|
||||||
|
, defaultFont =
|
||||||
|
FontAtlas.DefaultFont
|
||||||
|
|
||||||
|
-- To optimize atlas size, use ranges builder and
|
||||||
|
-- provide source localization data.
|
||||||
|
, notoFont =
|
||||||
|
FontAtlas.FromTTF
|
||||||
|
"./examples/fonts/NotoSansJP-Regular.otf"
|
||||||
|
20
|
||||||
|
Nothing
|
||||||
|
( FontAtlas.RangesBuilder $ mconcat
|
||||||
|
[ FontAtlas.addRanges FontAtlas.Latin
|
||||||
|
, FontAtlas.addText "私をクリックしてください"
|
||||||
|
, FontAtlas.addText "こんにちは"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
liftIO $ do
|
||||||
|
fontFlag <- newIORef False
|
||||||
|
mainLoop window do
|
||||||
|
let FontSet{..} = fontSet
|
||||||
|
withWindowOpen "Hello, ImGui!" do
|
||||||
|
-- To use a font for widget text, you may either put it
|
||||||
|
-- into a 'withFont' block:
|
||||||
|
withFont defaultFont do
|
||||||
|
text "Hello, ImGui!"
|
||||||
|
|
||||||
|
text "Привет, ImGui!"
|
||||||
|
|
||||||
|
-- ...or you can explicitly push and pop a font.
|
||||||
|
-- Though it's not recommended.
|
||||||
|
toggled <- readIORef fontFlag
|
||||||
|
|
||||||
|
when toggled $
|
||||||
|
pushFont notoFont
|
||||||
|
|
||||||
|
-- Some of those are only present in Noto font range
|
||||||
|
-- and will render as `?`s.
|
||||||
|
text "こんにちは, ImGui!"
|
||||||
|
|
||||||
|
let buttonText = if toggled then "私をクリックしてください" else "Click Me!"
|
||||||
|
button buttonText >>= \clicked ->
|
||||||
|
when clicked $
|
||||||
|
modifyIORef' fontFlag not
|
||||||
|
|
||||||
|
when toggled
|
||||||
|
popFont
|
||||||
|
|
||||||
|
showDemoWindow
|
||||||
|
|
||||||
|
mainLoop :: Window -> IO () -> IO ()
|
||||||
|
mainLoop window frameAction = loop
|
||||||
|
where
|
||||||
|
loop = unlessQuit do
|
||||||
|
openGL2NewFrame
|
||||||
|
sdl2NewFrame
|
||||||
|
newFrame
|
||||||
|
|
||||||
|
frameAction
|
||||||
|
|
||||||
|
glClear GL_COLOR_BUFFER_BIT
|
||||||
|
render
|
||||||
|
openGL2RenderDrawData =<< getDrawData
|
||||||
|
glSwapWindow window
|
||||||
|
|
||||||
|
loop
|
||||||
|
|
||||||
|
unlessQuit action = do
|
||||||
|
shouldQuit <- checkEvents
|
||||||
|
if shouldQuit then pure () else action
|
||||||
|
|
||||||
|
checkEvents = do
|
||||||
|
pollEventWithImGui >>= \case
|
||||||
|
Nothing ->
|
||||||
|
return False
|
||||||
|
Just event ->
|
||||||
|
(isQuit event ||) <$> checkEvents
|
||||||
|
|
||||||
|
isQuit event =
|
||||||
|
SDL.eventPayload event == SDL.QuitEvent
|
BIN
examples/fonts/NotoSansJP-Regular.otf
Normal file
BIN
examples/fonts/NotoSansJP-Regular.otf
Normal file
Binary file not shown.
@ -134,12 +134,6 @@ app = do
|
|||||||
ImGui.createContext
|
ImGui.createContext
|
||||||
ImGui.destroyContext
|
ImGui.destroyContext
|
||||||
|
|
||||||
logDebug "Adding fonts"
|
|
||||||
ImGui.clearFontAtlas
|
|
||||||
_default <- ImGui.addFontDefault
|
|
||||||
_custom <- ImGui.addFontFromFileTTF "imgui/misc/fonts/ProggyTiny.ttf" 10
|
|
||||||
ImGui.buildFontAtlas
|
|
||||||
|
|
||||||
let
|
let
|
||||||
preferredFormat :: Vulkan.SurfaceFormatKHR
|
preferredFormat :: Vulkan.SurfaceFormatKHR
|
||||||
preferredFormat =
|
preferredFormat =
|
||||||
|
@ -86,6 +86,11 @@ module DearImGui
|
|||||||
, pushStyleVar
|
, pushStyleVar
|
||||||
, popStyleVar
|
, popStyleVar
|
||||||
|
|
||||||
|
, withFont
|
||||||
|
, Raw.Font.pushFont
|
||||||
|
, Raw.Font.popFont
|
||||||
|
, Raw.Font.Font
|
||||||
|
|
||||||
-- * Cursor/Layout
|
-- * Cursor/Layout
|
||||||
, Raw.separator
|
, Raw.separator
|
||||||
, Raw.sameLine
|
, Raw.sameLine
|
||||||
@ -247,13 +252,6 @@ module DearImGui
|
|||||||
, Raw.wantCaptureMouse
|
, Raw.wantCaptureMouse
|
||||||
, Raw.wantCaptureKeyboard
|
, Raw.wantCaptureKeyboard
|
||||||
|
|
||||||
-- * Fonts
|
|
||||||
, Raw.Font
|
|
||||||
, addFontFromFileTTF
|
|
||||||
, Raw.addFontDefault
|
|
||||||
, Raw.buildFontAtlas
|
|
||||||
, Raw.clearFontAtlas
|
|
||||||
|
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
|
|
||||||
-- ** ListClipper
|
-- ** ListClipper
|
||||||
@ -287,6 +285,9 @@ import System.IO
|
|||||||
-- dear-imgui
|
-- dear-imgui
|
||||||
import DearImGui.Enums
|
import DearImGui.Enums
|
||||||
import DearImGui.Structs
|
import DearImGui.Structs
|
||||||
|
import qualified DearImGui.Raw as Raw
|
||||||
|
import qualified DearImGui.Raw.Font as Raw.Font
|
||||||
|
import qualified DearImGui.Raw.ListClipper as Raw.ListClipper
|
||||||
|
|
||||||
-- managed
|
-- managed
|
||||||
import qualified Control.Monad.Managed as Managed
|
import qualified Control.Monad.Managed as Managed
|
||||||
@ -303,9 +304,6 @@ import Control.Monad.IO.Class
|
|||||||
import UnliftIO (MonadUnliftIO)
|
import UnliftIO (MonadUnliftIO)
|
||||||
import UnliftIO.Exception (bracket, bracket_)
|
import UnliftIO.Exception (bracket, bracket_)
|
||||||
|
|
||||||
import qualified DearImGui.Raw as Raw
|
|
||||||
import qualified DearImGui.Raw.ListClipper as Raw.ListClipper
|
|
||||||
|
|
||||||
-- vector
|
-- vector
|
||||||
import qualified Data.Vector as V
|
import qualified Data.Vector as V
|
||||||
import qualified Data.Vector.Storable as VS
|
import qualified Data.Vector.Storable as VS
|
||||||
@ -1691,24 +1689,9 @@ popStyleVar :: (MonadIO m) => Int -> m ()
|
|||||||
popStyleVar n = liftIO do
|
popStyleVar n = liftIO do
|
||||||
Raw.popStyleVar (fromIntegral n)
|
Raw.popStyleVar (fromIntegral n)
|
||||||
|
|
||||||
|
-- | Render widgets inside the block using provided font.
|
||||||
-- | Load a font from TTF file.
|
withFont :: MonadUnliftIO m => Raw.Font.Font -> m a -> m a
|
||||||
--
|
withFont font = bracket_ (Raw.Font.pushFont font) Raw.Font.popFont
|
||||||
-- Specify font path and atlas glyph size.
|
|
||||||
--
|
|
||||||
-- Use 'addFontDefault' if you want to retain built-in font too.
|
|
||||||
--
|
|
||||||
-- Call 'buildFontAtlas' after adding all the fonts.
|
|
||||||
--
|
|
||||||
-- Call backend-specific `CreateFontsTexture` before using 'newFrame'.
|
|
||||||
addFontFromFileTTF :: MonadIO m => FilePath -> Float -> m (Maybe Raw.Font)
|
|
||||||
addFontFromFileTTF font size = liftIO do
|
|
||||||
res@(Raw.Font ptr) <- withCString font \fontPtr ->
|
|
||||||
Raw.addFontFromFileTTF fontPtr (CFloat size)
|
|
||||||
pure $
|
|
||||||
if castPtr ptr == nullPtr
|
|
||||||
then Nothing
|
|
||||||
else Just res
|
|
||||||
|
|
||||||
-- | Clips a large list of items
|
-- | Clips a large list of items
|
||||||
--
|
--
|
||||||
|
@ -34,9 +34,12 @@ imguiContext = mempty
|
|||||||
, ( TypeName "ImVec3", [t| ImVec3 |] )
|
, ( TypeName "ImVec3", [t| ImVec3 |] )
|
||||||
, ( TypeName "ImVec4", [t| ImVec4 |] )
|
, ( TypeName "ImVec4", [t| ImVec4 |] )
|
||||||
, ( TypeName "ImU32", [t| ImU32 |] )
|
, ( TypeName "ImU32", [t| ImU32 |] )
|
||||||
|
, ( TypeName "ImWchar", [t| ImWchar |] )
|
||||||
, ( TypeName "ImDrawList", [t| ImDrawList |] )
|
, ( TypeName "ImDrawList", [t| ImDrawList |] )
|
||||||
, ( TypeName "ImGuiContext", [t| ImGuiContext |] )
|
, ( TypeName "ImGuiContext", [t| ImGuiContext |] )
|
||||||
, ( TypeName "ImFont", [t| ImFont |] )
|
, ( TypeName "ImFont", [t| ImFont |] )
|
||||||
|
, ( TypeName "ImFontConfig", [t| ImFontConfig |] )
|
||||||
|
, ( TypeName "ImFontGlyphRangesBuilder", [t| ImFontGlyphRangesBuilder |] )
|
||||||
, ( TypeName "ImGuiListClipper", [t| ImGuiListClipper |] )
|
, ( TypeName "ImGuiListClipper", [t| ImGuiListClipper |] )
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
501
src/DearImGui/FontAtlas.hs
Normal file
501
src/DearImGui/FontAtlas.hs
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
|
{-|
|
||||||
|
Module: DearImGui.FontAtlas
|
||||||
|
|
||||||
|
Font atlas builder, accompanied with lower-level functions.
|
||||||
|
|
||||||
|
@
|
||||||
|
import qualified DearImGui.FontAtlas as FontAtlas
|
||||||
|
|
||||||
|
prepareAtlas =
|
||||||
|
FontAtlas.rebuild
|
||||||
|
[ FontAtlas.FileTTF "comic-sans-mono.ttf" 13 csOptions csRanges
|
||||||
|
, FontAtlas.Default
|
||||||
|
]
|
||||||
|
where
|
||||||
|
csOptions = mconcat
|
||||||
|
[ FontAtlas.fontNo 1
|
||||||
|
, FontAtlas.glyphOffset (0, -1)
|
||||||
|
]
|
||||||
|
|
||||||
|
csRanges = RangeBuilder $ mconcat
|
||||||
|
[ FontAtlas.addText "Hello world"
|
||||||
|
, FontRanges.addChar 'Ꙑ'
|
||||||
|
, FontRanges.addRanges FontRanges.Korean
|
||||||
|
]
|
||||||
|
@
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
module DearImGui.FontAtlas
|
||||||
|
( -- * Main types
|
||||||
|
Raw.Font(..)
|
||||||
|
, FontSource(..)
|
||||||
|
-- * Building atlas
|
||||||
|
, rebuild
|
||||||
|
-- ** Configuring sources
|
||||||
|
, ConfigSetup(..)
|
||||||
|
, fontDataOwnedByAtlas
|
||||||
|
, fontNo
|
||||||
|
, sizePixels
|
||||||
|
, oversampleH
|
||||||
|
, oversampleV
|
||||||
|
, pixelSnapH
|
||||||
|
, glyphExtraSpacing
|
||||||
|
, glyphOffset
|
||||||
|
, glyphRanges
|
||||||
|
, glyphMinAdvanceX
|
||||||
|
, glyphMaxAdvanceX
|
||||||
|
, mergeMode
|
||||||
|
, fontBuilderFlags
|
||||||
|
, rasterizerMultiply
|
||||||
|
, ellipsisChar
|
||||||
|
|
||||||
|
-- ** Configuring ranges
|
||||||
|
, Ranges(..)
|
||||||
|
, RangesBuilderSetup(..)
|
||||||
|
, addChar
|
||||||
|
, addText
|
||||||
|
, addRanges
|
||||||
|
, addRangesRaw
|
||||||
|
|
||||||
|
, pattern Latin
|
||||||
|
, pattern Korean
|
||||||
|
, pattern Japanese
|
||||||
|
, pattern ChineseFull
|
||||||
|
, pattern ChineseSimplifiedCommon
|
||||||
|
, pattern Cyrillic
|
||||||
|
, pattern Thai
|
||||||
|
, pattern Vietnamese
|
||||||
|
|
||||||
|
-- * Lower level types and functions
|
||||||
|
-- , Raw.FontConfig(..)
|
||||||
|
-- , Raw.GlyphRanges(..)
|
||||||
|
, build
|
||||||
|
, clear
|
||||||
|
, setupFont
|
||||||
|
, setupRanges
|
||||||
|
, withRanges
|
||||||
|
, withConfig
|
||||||
|
, addFontFromFileTTF
|
||||||
|
, addFontFromFileTTF_
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
-- base
|
||||||
|
import Data.Bool (bool)
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
|
import Foreign
|
||||||
|
import Foreign.C
|
||||||
|
|
||||||
|
-- transformers
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
( MonadIO, liftIO )
|
||||||
|
|
||||||
|
-- managed
|
||||||
|
import Control.Monad.Managed
|
||||||
|
( MonadManaged, managed )
|
||||||
|
import qualified Control.Monad.Managed as Managed
|
||||||
|
|
||||||
|
-- unlift
|
||||||
|
import UnliftIO (MonadUnliftIO)
|
||||||
|
import UnliftIO.Exception (bracket)
|
||||||
|
|
||||||
|
-- dear-imgui
|
||||||
|
import DearImGui.Raw.Font (Font(..))
|
||||||
|
import qualified DearImGui.Raw.Font as Raw
|
||||||
|
import DearImGui.Raw.Font.Config (FontConfig(..))
|
||||||
|
import qualified DearImGui.Raw.Font.Config as FontConfig
|
||||||
|
import DearImGui.Raw.Font.GlyphRanges (GlyphRanges(..), GlyphRangesBuilder(..))
|
||||||
|
import qualified DearImGui.Raw.Font.GlyphRanges as GlyphRanges
|
||||||
|
|
||||||
|
import DearImGui.Structs (ImVec2(..), ImWchar)
|
||||||
|
|
||||||
|
-- | Font setup data
|
||||||
|
data FontSource
|
||||||
|
= DefaultFont
|
||||||
|
| FromTTF FilePath Float (Maybe ConfigSetup) Ranges
|
||||||
|
-- TODO: FromMemory
|
||||||
|
|
||||||
|
-- | Font config monoid interface to be used in 'FontSource'.
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- mergeMode True <> fontNo 1
|
||||||
|
-- @
|
||||||
|
newtype ConfigSetup = ConfigSetup
|
||||||
|
{ applyToConfig :: FontConfig -> IO ()
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Semigroup ConfigSetup where
|
||||||
|
ConfigSetup f <> ConfigSetup g =
|
||||||
|
ConfigSetup \fc -> f fc >> g fc
|
||||||
|
instance Monoid ConfigSetup where
|
||||||
|
mempty = ConfigSetup (const mempty)
|
||||||
|
|
||||||
|
-- | Glyph ranges settings, from presets to builder configuration.
|
||||||
|
data Ranges
|
||||||
|
= RangesRaw GlyphRanges
|
||||||
|
| RangesBuiltin GlyphRanges.Builtin
|
||||||
|
| RangesBuilder RangesBuilderSetup
|
||||||
|
|
||||||
|
-- | Basic Latin, Extended Latin
|
||||||
|
pattern Latin :: Ranges
|
||||||
|
pattern Latin = RangesBuiltin GlyphRanges.Latin
|
||||||
|
|
||||||
|
-- | Default + Korean characters
|
||||||
|
pattern Korean :: Ranges
|
||||||
|
pattern Korean = RangesBuiltin GlyphRanges.Korean
|
||||||
|
|
||||||
|
-- | Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs
|
||||||
|
pattern Japanese :: Ranges
|
||||||
|
pattern Japanese = RangesBuiltin GlyphRanges.Japanese
|
||||||
|
|
||||||
|
-- | Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs
|
||||||
|
pattern ChineseFull :: Ranges
|
||||||
|
pattern ChineseFull = RangesBuiltin GlyphRanges.ChineseFull
|
||||||
|
|
||||||
|
-- | Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese
|
||||||
|
pattern ChineseSimplifiedCommon :: Ranges
|
||||||
|
pattern ChineseSimplifiedCommon = RangesBuiltin GlyphRanges.ChineseSimplifiedCommon
|
||||||
|
|
||||||
|
-- | Default + about 400 Cyrillic characters
|
||||||
|
pattern Cyrillic :: Ranges
|
||||||
|
pattern Cyrillic = RangesBuiltin GlyphRanges.Cyrillic
|
||||||
|
|
||||||
|
-- | Default + Thai characters
|
||||||
|
pattern Thai :: Ranges
|
||||||
|
pattern Thai = RangesBuiltin GlyphRanges.Thai
|
||||||
|
|
||||||
|
-- | Default + Vietnamese characters
|
||||||
|
pattern Vietnamese :: Ranges
|
||||||
|
pattern Vietnamese = RangesBuiltin GlyphRanges.Vietnamese
|
||||||
|
|
||||||
|
|
||||||
|
-- | Ranges builder monoid interface to be executed through 'buildRanges'.
|
||||||
|
--
|
||||||
|
-- @
|
||||||
|
-- addRanges FontRanges.DefaultRanges <> addText "Привет"
|
||||||
|
-- @
|
||||||
|
newtype RangesBuilderSetup = RangesBuilderSetup
|
||||||
|
{ applyToBuilder :: GlyphRangesBuilder -> IO ()
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Semigroup RangesBuilderSetup where
|
||||||
|
RangesBuilderSetup f <> RangesBuilderSetup g =
|
||||||
|
RangesBuilderSetup \fc -> f fc >> g fc
|
||||||
|
|
||||||
|
instance Monoid RangesBuilderSetup where
|
||||||
|
mempty = RangesBuilderSetup (const mempty)
|
||||||
|
|
||||||
|
-- | Rebuild font atlas with provided configuration
|
||||||
|
-- and return corresponding structure of font handles
|
||||||
|
-- to be used with 'withFont'.
|
||||||
|
--
|
||||||
|
-- Accepts any 'Traversable' instance, so you are free to use
|
||||||
|
-- lists, maps or custom structures.
|
||||||
|
rebuild :: (MonadIO m, Traversable t) => t FontSource -> m (t Font)
|
||||||
|
rebuild sources = liftIO $ Managed.with action pure
|
||||||
|
where
|
||||||
|
action = do
|
||||||
|
clear
|
||||||
|
fonts <- traverse setupFont sources
|
||||||
|
build
|
||||||
|
return fonts
|
||||||
|
|
||||||
|
-- | Reset font atlas, clearing internal data
|
||||||
|
--
|
||||||
|
-- Alias for 'Raw.clearFontAtlas'
|
||||||
|
clear :: (MonadIO m) => m ()
|
||||||
|
clear = Raw.clearFontAtlas
|
||||||
|
|
||||||
|
-- | Build font atlas
|
||||||
|
--
|
||||||
|
-- Alias for 'Raw.buildFontAtlas'
|
||||||
|
build :: (MonadIO m) => m ()
|
||||||
|
build = Raw.buildFontAtlas
|
||||||
|
|
||||||
|
-- | Load a font from TTF file.
|
||||||
|
--
|
||||||
|
-- Specify font path and atlas glyph size.
|
||||||
|
--
|
||||||
|
-- Use 'Raw.addFontDefault' if you want to retain built-in font too.
|
||||||
|
--
|
||||||
|
-- Call 'build' after adding all the fonts,
|
||||||
|
-- particularly if you're loading them from memory or use custom glyphs.
|
||||||
|
-- Or stick to `rebuild` function.
|
||||||
|
--
|
||||||
|
-- Call backend-specific `CreateFontsTexture` before using 'newFrame'.
|
||||||
|
addFontFromFileTTF :: MonadIO m
|
||||||
|
=> FilePath -- ^ Font file path
|
||||||
|
-> Float -- ^ Font size in pixels
|
||||||
|
-> Maybe FontConfig -- ^ Configuration data
|
||||||
|
-> Maybe GlyphRanges -- ^ Glyph ranges to use
|
||||||
|
-> m (Maybe Font) -- ^ Returns font handle, if added successfully
|
||||||
|
addFontFromFileTTF font size config ranges = liftIO do
|
||||||
|
res@(Font ptr) <- withCString font \fontPtr ->
|
||||||
|
Raw.addFontFromFileTTF
|
||||||
|
fontPtr
|
||||||
|
(CFloat size)
|
||||||
|
(fromMaybe (FontConfig nullPtr) config)
|
||||||
|
(fromMaybe (GlyphRanges nullPtr) ranges)
|
||||||
|
pure $
|
||||||
|
if castPtr ptr == nullPtr
|
||||||
|
then Nothing
|
||||||
|
else Just res
|
||||||
|
-- FIXME: turn off asserts, so it would work
|
||||||
|
|
||||||
|
addFontFromFileTTF_ :: MonadIO m
|
||||||
|
=> FilePath -- ^ Font file path
|
||||||
|
-> Float -- ^ Font size in pixels
|
||||||
|
-> m (Maybe Raw.Font) -- ^ Returns font handle, if added successfully
|
||||||
|
addFontFromFileTTF_ font size =
|
||||||
|
addFontFromFileTTF font size Nothing Nothing
|
||||||
|
|
||||||
|
-- | Load a font with provided configuration, return its handle
|
||||||
|
-- and defer range builder and config destructors, if needed.
|
||||||
|
setupFont :: (MonadManaged m) => FontSource -> m Font
|
||||||
|
setupFont = \case
|
||||||
|
DefaultFont ->
|
||||||
|
Raw.addFontDefault
|
||||||
|
FromTTF path size configSetup ranges -> do
|
||||||
|
glyphRanges' <- setupRanges ranges
|
||||||
|
config <- managed (withConfig configSetup)
|
||||||
|
mFont <- addFontFromFileTTF path size config glyphRanges'
|
||||||
|
case mFont of
|
||||||
|
Nothing ->
|
||||||
|
liftIO . fail $ "Couldn't load font from " <> path
|
||||||
|
Just font ->
|
||||||
|
pure font
|
||||||
|
|
||||||
|
-- | Configure glyph ranges with provided configuration, return a handle
|
||||||
|
-- and defer builder destructors, if needed.
|
||||||
|
setupRanges :: (MonadManaged m) => Ranges -> m (Maybe GlyphRanges)
|
||||||
|
setupRanges = \case
|
||||||
|
RangesRaw ranges ->
|
||||||
|
pure $ Just ranges
|
||||||
|
RangesBuiltin builtin ->
|
||||||
|
pure $ GlyphRanges.builtinSetup builtin
|
||||||
|
RangesBuilder settings -> do
|
||||||
|
built <- managed $ withRanges settings
|
||||||
|
pure $ Just built
|
||||||
|
|
||||||
|
-- | Perform glyph ranges build based on provided configuration,
|
||||||
|
-- and execute a computation with built glyph ranges.
|
||||||
|
withRanges :: (MonadUnliftIO m) => RangesBuilderSetup -> (GlyphRanges -> m a) -> m a
|
||||||
|
withRanges (RangesBuilderSetup setup) fn =
|
||||||
|
bracket acquire release execute
|
||||||
|
where
|
||||||
|
acquire = do
|
||||||
|
builder <- GlyphRanges.new
|
||||||
|
liftIO $ setup builder
|
||||||
|
rangesVec <- GlyphRanges.buildRangesVector builder
|
||||||
|
return (rangesVec, builder)
|
||||||
|
|
||||||
|
release (rangesVec, builder) = do
|
||||||
|
GlyphRanges.destroyRangesVector rangesVec
|
||||||
|
GlyphRanges.destroy builder
|
||||||
|
|
||||||
|
execute (rangesVec, _) =
|
||||||
|
fn (GlyphRanges.fromRangesVector rangesVec)
|
||||||
|
|
||||||
|
-- | Configure font config with provided setup,
|
||||||
|
-- and execute a computation with built object.
|
||||||
|
-- return its handle and list of resource destructors.
|
||||||
|
withConfig :: (MonadUnliftIO m) => Maybe ConfigSetup -> (Maybe FontConfig -> m a) -> m a
|
||||||
|
withConfig mSetup action =
|
||||||
|
case mSetup of
|
||||||
|
Nothing ->
|
||||||
|
action Nothing
|
||||||
|
Just (ConfigSetup setup) ->
|
||||||
|
bracket acquire (FontConfig.destroy) (action . Just)
|
||||||
|
where
|
||||||
|
acquire = do
|
||||||
|
config <- FontConfig.new
|
||||||
|
liftIO $ setup config
|
||||||
|
return config
|
||||||
|
|
||||||
|
-- | Single Unicode character
|
||||||
|
addChar :: ImWchar -> RangesBuilderSetup
|
||||||
|
addChar char =
|
||||||
|
RangesBuilderSetup \builder ->
|
||||||
|
GlyphRanges.addChar builder char
|
||||||
|
|
||||||
|
-- | UTF-8 string
|
||||||
|
addText :: String -> RangesBuilderSetup
|
||||||
|
addText str =
|
||||||
|
RangesBuilderSetup \builder ->
|
||||||
|
withCString str (GlyphRanges.addText builder)
|
||||||
|
|
||||||
|
-- | Existing ranges (as is)
|
||||||
|
addRangesRaw :: GlyphRanges -> RangesBuilderSetup
|
||||||
|
addRangesRaw ranges =
|
||||||
|
RangesBuilderSetup \builder ->
|
||||||
|
GlyphRanges.addRanges builder ranges
|
||||||
|
|
||||||
|
-- | Existing ranges (through settings interface)
|
||||||
|
addRanges :: Ranges -> RangesBuilderSetup
|
||||||
|
addRanges = \case
|
||||||
|
RangesRaw ranges ->
|
||||||
|
addRangesRaw ranges
|
||||||
|
RangesBuilder settings ->
|
||||||
|
settings
|
||||||
|
RangesBuiltin builtin ->
|
||||||
|
addRangesRaw (GlyphRanges.getBuiltin builtin)
|
||||||
|
|
||||||
|
-- | TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
|
||||||
|
--
|
||||||
|
-- By default, it is @true@
|
||||||
|
fontDataOwnedByAtlas :: Bool -> ConfigSetup
|
||||||
|
fontDataOwnedByAtlas value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setFontDataOwnedByAtlas fc (bool 0 1 value)
|
||||||
|
|
||||||
|
-- | Index of font within TTF/OTF file.
|
||||||
|
--
|
||||||
|
-- By default, it is @0@
|
||||||
|
fontNo :: Int -> ConfigSetup
|
||||||
|
fontNo value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setFontNo fc (fromIntegral value)
|
||||||
|
|
||||||
|
-- | Size in pixels for rasterizer
|
||||||
|
--
|
||||||
|
-- More or less maps to the resulting font height.
|
||||||
|
--
|
||||||
|
-- Implicitly set by @addFont...@ functions.
|
||||||
|
sizePixels :: Float -> ConfigSetup
|
||||||
|
sizePixels value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setSizePixels fc (CFloat value)
|
||||||
|
|
||||||
|
-- | Rasterize at higher quality for sub-pixel positioning.
|
||||||
|
--
|
||||||
|
-- Note: the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory.
|
||||||
|
-- Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
|
||||||
|
--
|
||||||
|
-- By default, it is @3@
|
||||||
|
oversampleH :: Int -> ConfigSetup
|
||||||
|
oversampleH value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setOversampleH fc (fromIntegral value)
|
||||||
|
|
||||||
|
-- | Rasterize at higher quality for sub-pixel positioning.
|
||||||
|
--
|
||||||
|
-- This is not really useful as we don't use sub-pixel positions on the Y axis.
|
||||||
|
--
|
||||||
|
-- By default, it is @1@
|
||||||
|
oversampleV :: Int -> ConfigSetup
|
||||||
|
oversampleV value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setOversampleV fc (fromIntegral value)
|
||||||
|
|
||||||
|
-- | Align every glyph to pixel boundary.
|
||||||
|
--
|
||||||
|
-- Useful if you are merging a non-pixel aligned font with the default font.
|
||||||
|
-- If enabled, you can set OversampleH/V to 1.
|
||||||
|
--
|
||||||
|
-- By default, it is @false@
|
||||||
|
pixelSnapH :: Bool -> ConfigSetup
|
||||||
|
pixelSnapH value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setPixelSnapH fc (bool 0 1 value)
|
||||||
|
|
||||||
|
-- | Extra spacing (in pixels) between glyphs.
|
||||||
|
--
|
||||||
|
-- Only X axis is supported for now.
|
||||||
|
--
|
||||||
|
-- By default, it is @0, 0@
|
||||||
|
glyphExtraSpacing :: (Float, Float) -> ConfigSetup
|
||||||
|
glyphExtraSpacing (x, y) =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
Foreign.with (ImVec2 x y) (FontConfig.setGlyphExtraSpacing fc)
|
||||||
|
|
||||||
|
-- | Offset all glyphs from this font input.
|
||||||
|
--
|
||||||
|
-- By default, it is @0, 0@
|
||||||
|
glyphOffset :: (Float, Float) -> ConfigSetup
|
||||||
|
glyphOffset (x, y) =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
Foreign.with (ImVec2 x y) (FontConfig.setGlyphOffset fc)
|
||||||
|
|
||||||
|
-- | Pointer to a user-provided list of Unicode range.
|
||||||
|
--
|
||||||
|
-- 2 values per range, inclusive. Zero-terminated list.
|
||||||
|
--
|
||||||
|
-- THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE.
|
||||||
|
--
|
||||||
|
-- By default, it is @NULL@
|
||||||
|
glyphRanges :: GlyphRanges -> ConfigSetup
|
||||||
|
glyphRanges value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setGlyphRanges fc value
|
||||||
|
|
||||||
|
-- | Minimum AdvanceX for glyphs.
|
||||||
|
--
|
||||||
|
-- Set Min to align font icons, set both Min/Max to enforce mono-space font.
|
||||||
|
--
|
||||||
|
-- By default, it is @0@
|
||||||
|
glyphMinAdvanceX :: Float -> ConfigSetup
|
||||||
|
glyphMinAdvanceX value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setGlyphMinAdvanceX fc (CFloat value)
|
||||||
|
|
||||||
|
-- | Maximum AdvanceX for glyphs.
|
||||||
|
--
|
||||||
|
-- By default, it is @FLT_MAX@.
|
||||||
|
glyphMaxAdvanceX :: Float -> ConfigSetup
|
||||||
|
glyphMaxAdvanceX value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setGlyphMaxAdvanceX fc (CFloat value)
|
||||||
|
|
||||||
|
-- | Merge into previous ImFont, so you can combine multiple inputs font into one ImFont.
|
||||||
|
--
|
||||||
|
-- e.g. ASCII font + icons + Japanese glyphs.
|
||||||
|
-- You may want to use @GlyphOffset.y@ when merging font of different heights.
|
||||||
|
--
|
||||||
|
-- By default, it is @false@
|
||||||
|
mergeMode :: Bool -> ConfigSetup
|
||||||
|
mergeMode value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setMergeMode fc (bool 0 1 value)
|
||||||
|
|
||||||
|
-- | Settings for custom font GlyphRanges.
|
||||||
|
--
|
||||||
|
-- THIS IS BUILDER IMPLEMENTATION DEPENDENT.
|
||||||
|
--
|
||||||
|
-- By default, it is @0@. Leave it so if unsure.
|
||||||
|
fontBuilderFlags :: Int -> ConfigSetup
|
||||||
|
fontBuilderFlags value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setFontBuilderFlags fc (fromIntegral value)
|
||||||
|
|
||||||
|
-- | Brighten (>1.0f) or darken (<1.0f) font output.
|
||||||
|
--
|
||||||
|
-- Brightening small fonts may be a good workaround to make them more readable.
|
||||||
|
--
|
||||||
|
-- By default, it is @1.0f@.
|
||||||
|
rasterizerMultiply :: Float -> ConfigSetup
|
||||||
|
rasterizerMultiply value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setRasterizerMultiply fc (CFloat value)
|
||||||
|
|
||||||
|
-- | Explicitly specify unicode codepoint of ellipsis character.
|
||||||
|
--
|
||||||
|
-- When fonts are being merged first specified ellipsis will be used.
|
||||||
|
--
|
||||||
|
-- By default, it is @-1@
|
||||||
|
ellipsisChar :: ImWchar -> ConfigSetup
|
||||||
|
ellipsisChar value =
|
||||||
|
ConfigSetup \fc ->
|
||||||
|
FontConfig.setEllipsisChar fc value
|
@ -211,14 +211,6 @@ module DearImGui.Raw
|
|||||||
, wantCaptureMouse
|
, wantCaptureMouse
|
||||||
, wantCaptureKeyboard
|
, wantCaptureKeyboard
|
||||||
|
|
||||||
-- * Fonts in default font atlas
|
|
||||||
, Font(..)
|
|
||||||
, addFontDefault
|
|
||||||
, addFontFromFileTTF
|
|
||||||
, addFontFromMemoryTTF
|
|
||||||
, buildFontAtlas
|
|
||||||
, clearFontAtlas
|
|
||||||
|
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
|
|
||||||
-- ** Miscellaneous
|
-- ** Miscellaneous
|
||||||
@ -1563,58 +1555,6 @@ wantCaptureKeyboard :: MonadIO m => m Bool
|
|||||||
wantCaptureKeyboard = liftIO do
|
wantCaptureKeyboard = liftIO do
|
||||||
(0 /=) <$> [C.exp| bool { GetIO().WantCaptureKeyboard } |]
|
(0 /=) <$> [C.exp| bool { GetIO().WantCaptureKeyboard } |]
|
||||||
|
|
||||||
|
|
||||||
-- | Wraps @ImFont*@.
|
|
||||||
newtype Font = Font (Ptr ImFont)
|
|
||||||
|
|
||||||
addFontDefault :: MonadIO m => m Font
|
|
||||||
addFontDefault = liftIO do
|
|
||||||
Font <$> [C.block|
|
|
||||||
ImFont* {
|
|
||||||
return GetIO().Fonts->AddFontDefault();
|
|
||||||
}
|
|
||||||
|]
|
|
||||||
|
|
||||||
addFontFromFileTTF :: MonadIO m => CString -> CFloat -> m Font
|
|
||||||
addFontFromFileTTF filenamePtr sizePixels = liftIO do
|
|
||||||
Font <$> [C.block|
|
|
||||||
ImFont* {
|
|
||||||
return GetIO().Fonts->AddFontFromFileTTF(
|
|
||||||
$(char* filenamePtr),
|
|
||||||
$(float sizePixels));
|
|
||||||
}
|
|
||||||
|]
|
|
||||||
|
|
||||||
-- | Transfer a buffer with TTF data to font atlas builder.
|
|
||||||
addFontFromMemoryTTF :: MonadIO m => CStringLen -> CFloat -> m Font
|
|
||||||
addFontFromMemoryTTF (castPtr -> fontDataPtr, fromIntegral -> fontSize) sizePixels = liftIO do
|
|
||||||
Font <$> [C.block|
|
|
||||||
ImFont* {
|
|
||||||
return GetIO().Fonts->AddFontFromMemoryTTF(
|
|
||||||
$(void* fontDataPtr),
|
|
||||||
$(int fontSize),
|
|
||||||
$(float sizePixels)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|]
|
|
||||||
|
|
||||||
buildFontAtlas :: MonadIO m => m ()
|
|
||||||
buildFontAtlas = liftIO do
|
|
||||||
[C.block|
|
|
||||||
void {
|
|
||||||
GetIO().Fonts->Build();
|
|
||||||
}
|
|
||||||
|]
|
|
||||||
|
|
||||||
clearFontAtlas :: MonadIO m => m ()
|
|
||||||
clearFontAtlas = liftIO do
|
|
||||||
[C.block|
|
|
||||||
void {
|
|
||||||
GetIO().Fonts->Clear();
|
|
||||||
}
|
|
||||||
|]
|
|
||||||
|
|
||||||
|
|
||||||
-- | This draw list will be the first rendering one.
|
-- | This draw list will be the first rendering one.
|
||||||
--
|
--
|
||||||
-- Useful to quickly draw shapes/text behind dear imgui contents.
|
-- Useful to quickly draw shapes/text behind dear imgui contents.
|
||||||
|
141
src/DearImGui/Raw/Font.hs
Normal file
141
src/DearImGui/Raw/Font.hs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Fonts
|
||||||
|
|
||||||
|
It includes default atlas management, font configuration and glyph ranges.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
module DearImGui.Raw.Font
|
||||||
|
( -- * Types
|
||||||
|
Font(..)
|
||||||
|
, GlyphRanges(..)
|
||||||
|
-- * Adding fonts
|
||||||
|
, addFontDefault
|
||||||
|
, addFontFromFileTTF
|
||||||
|
, addFontFromMemoryTTF
|
||||||
|
-- * Using fonts
|
||||||
|
, pushFont
|
||||||
|
, popFont
|
||||||
|
|
||||||
|
-- * Atlas management
|
||||||
|
, clearFontAtlas
|
||||||
|
, buildFontAtlas
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
-- base
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
( MonadIO, liftIO )
|
||||||
|
import Foreign ( Ptr, castPtr )
|
||||||
|
import Foreign.C
|
||||||
|
|
||||||
|
-- dear-imgui
|
||||||
|
import DearImGui.Context
|
||||||
|
( imguiContext )
|
||||||
|
import DearImGui.Structs
|
||||||
|
import DearImGui.Raw.Font.Config
|
||||||
|
( FontConfig(..) )
|
||||||
|
import DearImGui.Raw.Font.GlyphRanges
|
||||||
|
( GlyphRanges(..) )
|
||||||
|
|
||||||
|
-- inline-c
|
||||||
|
import qualified Language.C.Inline as C
|
||||||
|
|
||||||
|
-- inline-c-cpp
|
||||||
|
import qualified Language.C.Inline.Cpp as Cpp
|
||||||
|
|
||||||
|
C.context (Cpp.cppCtx <> C.bsCtx <> imguiContext)
|
||||||
|
C.include "imgui.h"
|
||||||
|
Cpp.using "namespace ImGui"
|
||||||
|
|
||||||
|
|
||||||
|
-- | Font runtime data handle
|
||||||
|
--
|
||||||
|
-- Wraps @ImFont*@.
|
||||||
|
newtype Font = Font (Ptr ImFont)
|
||||||
|
|
||||||
|
-- | Add the default font (@ProggyClean.ttf@, 13 px) to the atlas.
|
||||||
|
addFontDefault :: MonadIO m
|
||||||
|
=> m Font -- ^ Returns font handle for future usage
|
||||||
|
addFontDefault = liftIO do
|
||||||
|
Font <$> [C.block|
|
||||||
|
ImFont* {
|
||||||
|
return GetIO().Fonts->AddFontDefault();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Add a custom OTF/TTF font from a file.
|
||||||
|
addFontFromFileTTF :: MonadIO m
|
||||||
|
=> CString -- ^ Font file path
|
||||||
|
-> CFloat -- ^ Font size in pixels
|
||||||
|
-> FontConfig -- ^ Configuration data
|
||||||
|
-> GlyphRanges -- ^ Glyph ranges to use
|
||||||
|
-> m Font -- ^ Returns font handle for future usage
|
||||||
|
addFontFromFileTTF filenamePtr sizePixels (FontConfig fontConfig) (GlyphRanges glyphRanges) = liftIO do
|
||||||
|
Font <$> [C.block|
|
||||||
|
ImFont* {
|
||||||
|
return GetIO().Fonts->AddFontFromFileTTF(
|
||||||
|
$(char* filenamePtr),
|
||||||
|
$(float sizePixels),
|
||||||
|
$(ImFontConfig* fontConfig),
|
||||||
|
$(ImWchar* glyphRanges));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Transfer a buffer with TTF data to font atlas builder.
|
||||||
|
addFontFromMemoryTTF :: MonadIO m => CStringLen -> CFloat -> FontConfig -> GlyphRanges -> m Font
|
||||||
|
addFontFromMemoryTTF (castPtr -> fontDataPtr, fromIntegral -> fontSize) sizePixels (FontConfig fontConfig) (GlyphRanges glyphRanges) = liftIO do
|
||||||
|
Font <$> [C.block|
|
||||||
|
ImFont* {
|
||||||
|
return GetIO().Fonts->AddFontFromMemoryTTF(
|
||||||
|
$(void* fontDataPtr),
|
||||||
|
$(int fontSize),
|
||||||
|
$(float sizePixels),
|
||||||
|
$(ImFontConfig* fontConfig),
|
||||||
|
$(ImWchar* glyphRanges)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
-- | Pushes a font into the parameters stack,
|
||||||
|
-- so ImGui would render following text using it.
|
||||||
|
pushFont :: MonadIO m => Font -> m ()
|
||||||
|
pushFont (Font font) = liftIO do
|
||||||
|
[C.exp| void { PushFont($(ImFont* font)); } |]
|
||||||
|
|
||||||
|
-- | Pops a font pushed into the parameters stack
|
||||||
|
--
|
||||||
|
-- Should be called only after a corresponding 'pushFont' call.
|
||||||
|
popFont :: MonadIO m => m ()
|
||||||
|
popFont = liftIO do
|
||||||
|
[C.exp| void { PopFont(); } |]
|
||||||
|
|
||||||
|
-- | Explicitly build pixels data for the atlas.
|
||||||
|
buildFontAtlas :: MonadIO m => m ()
|
||||||
|
buildFontAtlas = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
GetIO().Fonts->Build();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Clear all font atlas input and output data
|
||||||
|
clearFontAtlas :: MonadIO m => m ()
|
||||||
|
clearFontAtlas = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
GetIO().Fonts->Clear();
|
||||||
|
}
|
||||||
|
|]
|
256
src/DearImGui/Raw/Font/Config.hs
Normal file
256
src/DearImGui/Raw/Font/Config.hs
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Font configuration
|
||||||
|
|
||||||
|
IO functions to modify font config values.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
module DearImGui.Raw.Font.Config
|
||||||
|
( FontConfig(..)
|
||||||
|
, new
|
||||||
|
, destroy
|
||||||
|
-- * Changing settings
|
||||||
|
, setFontDataOwnedByAtlas
|
||||||
|
, setFontNo
|
||||||
|
, setSizePixels
|
||||||
|
, setOversampleH
|
||||||
|
, setOversampleV
|
||||||
|
, setPixelSnapH
|
||||||
|
, setGlyphExtraSpacing
|
||||||
|
, setGlyphOffset
|
||||||
|
, setGlyphRanges
|
||||||
|
, setGlyphMinAdvanceX
|
||||||
|
, setGlyphMaxAdvanceX
|
||||||
|
, setMergeMode
|
||||||
|
, setFontBuilderFlags
|
||||||
|
, setRasterizerMultiply
|
||||||
|
, setEllipsisChar
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
-- base
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
( MonadIO, liftIO )
|
||||||
|
import Foreign ( Ptr )
|
||||||
|
import Foreign.C
|
||||||
|
|
||||||
|
-- dear-imgui
|
||||||
|
import DearImGui.Context
|
||||||
|
( imguiContext )
|
||||||
|
import DearImGui.Structs
|
||||||
|
import DearImGui.Raw.Font.GlyphRanges
|
||||||
|
( GlyphRanges(..) )
|
||||||
|
|
||||||
|
-- inline-c
|
||||||
|
import qualified Language.C.Inline as C
|
||||||
|
|
||||||
|
-- inline-c-cpp
|
||||||
|
import qualified Language.C.Inline.Cpp as Cpp
|
||||||
|
|
||||||
|
C.context (Cpp.cppCtx <> C.bsCtx <> imguiContext)
|
||||||
|
C.include "imgui.h"
|
||||||
|
Cpp.using "namespace ImGui"
|
||||||
|
|
||||||
|
-- | Font configuration data handle
|
||||||
|
--
|
||||||
|
-- Wraps @ImFontConfig*@.
|
||||||
|
newtype FontConfig = FontConfig (Ptr ImFontConfig)
|
||||||
|
|
||||||
|
-- | Create an instance of config
|
||||||
|
new :: MonadIO m => m FontConfig
|
||||||
|
new = liftIO do
|
||||||
|
FontConfig <$> [C.block|
|
||||||
|
ImFontConfig* {
|
||||||
|
return IM_NEW(ImFontConfig);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Destroy an instance of config
|
||||||
|
--
|
||||||
|
-- Should be used __after__ font atlas building.
|
||||||
|
destroy :: MonadIO m => FontConfig -> m ()
|
||||||
|
destroy (FontConfig config) = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
IM_DELETE($(ImFontConfig* config));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
-- | TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
|
||||||
|
--
|
||||||
|
-- By default, it is @true@
|
||||||
|
setFontDataOwnedByAtlas :: MonadIO m => FontConfig -> CBool -> m ()
|
||||||
|
setFontDataOwnedByAtlas (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->FontDataOwnedByAtlas = $(bool value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Index of font within TTF/OTF file
|
||||||
|
--
|
||||||
|
-- By default, it is @0@
|
||||||
|
setFontNo :: MonadIO m => FontConfig -> CInt -> m ()
|
||||||
|
setFontNo (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->FontNo = $(int value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Size in pixels for rasterizer (more or less maps to the resulting font height).
|
||||||
|
--
|
||||||
|
-- Implicitly set by @addFont...@ functions.
|
||||||
|
setSizePixels :: MonadIO m => FontConfig -> CFloat -> m ()
|
||||||
|
setSizePixels (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->SizePixels = $(float value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
|
||||||
|
--
|
||||||
|
-- By default, it is @3@
|
||||||
|
setOversampleH :: MonadIO m => FontConfig -> CInt -> m ()
|
||||||
|
setOversampleH (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->OversampleH = $(int value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis.
|
||||||
|
--
|
||||||
|
-- By default, it is @1@
|
||||||
|
setOversampleV :: MonadIO m => FontConfig -> CInt -> m ()
|
||||||
|
setOversampleV (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->OversampleV = $(int value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
|
||||||
|
--
|
||||||
|
-- By default, it is @false@
|
||||||
|
setPixelSnapH :: MonadIO m => FontConfig -> CBool -> m ()
|
||||||
|
setPixelSnapH (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->PixelSnapH = $(bool value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
|
||||||
|
--
|
||||||
|
-- By default, it is @0, 0@
|
||||||
|
setGlyphExtraSpacing :: MonadIO m => FontConfig -> Ptr ImVec2 -> m ()
|
||||||
|
setGlyphExtraSpacing (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->GlyphExtraSpacing = *$(ImVec2* value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Offset all glyphs from this font input.
|
||||||
|
--
|
||||||
|
-- By default, it is @0, 0@
|
||||||
|
setGlyphOffset :: MonadIO m => FontConfig -> Ptr ImVec2 -> m ()
|
||||||
|
setGlyphOffset (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->GlyphOffset = *$(ImVec2* value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE.
|
||||||
|
--
|
||||||
|
-- By default, it is @NULL@
|
||||||
|
setGlyphRanges :: MonadIO m => FontConfig -> GlyphRanges -> m ()
|
||||||
|
setGlyphRanges (FontConfig fc) (GlyphRanges value) = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->GlyphRanges = $(ImWchar* value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
|
||||||
|
--
|
||||||
|
-- By default, it is @0@
|
||||||
|
setGlyphMinAdvanceX :: MonadIO m => FontConfig -> CFloat -> m ()
|
||||||
|
setGlyphMinAdvanceX (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->GlyphMinAdvanceX = $(float value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Maximum AdvanceX for glyphs
|
||||||
|
--
|
||||||
|
-- By default, it is @FLT_MAX@
|
||||||
|
setGlyphMaxAdvanceX :: MonadIO m => FontConfig -> CFloat -> m ()
|
||||||
|
setGlyphMaxAdvanceX (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->GlyphMaxAdvanceX = $(float value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
|
||||||
|
--
|
||||||
|
-- By default, it is @false@
|
||||||
|
setMergeMode :: MonadIO m => FontConfig -> CBool -> m ()
|
||||||
|
setMergeMode (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->MergeMode = $(bool value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Settings for custom font builder.
|
||||||
|
-- THIS IS BUILDER IMPLEMENTATION DEPENDENT.
|
||||||
|
--
|
||||||
|
-- By default, it is @0@. Leave it so if unsure.
|
||||||
|
setFontBuilderFlags :: MonadIO m => FontConfig -> CUInt -> m ()
|
||||||
|
setFontBuilderFlags (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->FontBuilderFlags = $(unsigned int value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Brighten (>1.0f) or darken (<1.0f) font output.
|
||||||
|
-- Brightening small fonts may be a good workaround to make them more readable.
|
||||||
|
--
|
||||||
|
-- By default, it is @1.0f@
|
||||||
|
setRasterizerMultiply :: MonadIO m => FontConfig -> CFloat -> m ()
|
||||||
|
setRasterizerMultiply (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->RasterizerMultiply = $(float value);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
|
||||||
|
--
|
||||||
|
-- By default, it is @-1@
|
||||||
|
setEllipsisChar :: MonadIO m => FontConfig -> ImWchar -> m ()
|
||||||
|
setEllipsisChar (FontConfig fc) value = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontConfig* fc)->EllipsisChar = $(ImWchar value);
|
||||||
|
}
|
||||||
|
|]
|
295
src/DearImGui/Raw/Font/GlyphRanges.hs
Normal file
295
src/DearImGui/Raw/Font/GlyphRanges.hs
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
|
{-| Font glyph ranges builder
|
||||||
|
|
||||||
|
Helper to build glyph ranges from text/string data.
|
||||||
|
Feed your application strings/characters to it then call 'buildRanges'.
|
||||||
|
|
||||||
|
Low-level example of usage:
|
||||||
|
|
||||||
|
@
|
||||||
|
-- import ImGui.Fonts
|
||||||
|
-- import ImGui.Raw.GlyphRangesBuilder as GRB
|
||||||
|
|
||||||
|
builder <- GRB.new
|
||||||
|
|
||||||
|
GRB.addRanges builder getGlyphRangesDefault
|
||||||
|
liftIO $ withCString "Привет" $ GRB.addText builder
|
||||||
|
rangesVec <- GRB.buildRanges builder
|
||||||
|
let ranges = GRB.fromRangesVector rangesVec
|
||||||
|
|
||||||
|
addFontFromFileTTF'
|
||||||
|
"./imgui/misc/fonts/DroidSans.ttf" 12
|
||||||
|
Nothing
|
||||||
|
(Just ranges)
|
||||||
|
|
||||||
|
-- it is strictly necessary to explicitly build the atlas
|
||||||
|
buildFontAtlas
|
||||||
|
|
||||||
|
-- resource destruction comes only after the building
|
||||||
|
GRB.destroyRangesVector rangesVec
|
||||||
|
GRB.destroy builder
|
||||||
|
@
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
module DearImGui.Raw.Font.GlyphRanges
|
||||||
|
( GlyphRanges(..)
|
||||||
|
|
||||||
|
-- * Built-in ranges
|
||||||
|
, Builtin(..)
|
||||||
|
, getBuiltin
|
||||||
|
, builtinSetup
|
||||||
|
|
||||||
|
-- * Preparing a builder
|
||||||
|
, GlyphRangesBuilder(..)
|
||||||
|
, new
|
||||||
|
, destroy
|
||||||
|
, addChar
|
||||||
|
, addText
|
||||||
|
, addRanges
|
||||||
|
|
||||||
|
-- * Extracting data
|
||||||
|
, GlyphRangesVector(..)
|
||||||
|
, buildRangesVector
|
||||||
|
, fromRangesVector
|
||||||
|
, destroyRangesVector
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
-- base
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
( MonadIO, liftIO )
|
||||||
|
import Foreign ( Ptr )
|
||||||
|
import Foreign.C
|
||||||
|
import System.IO.Unsafe (unsafePerformIO)
|
||||||
|
|
||||||
|
-- dear-imgui
|
||||||
|
import DearImGui.Context
|
||||||
|
( imguiContext )
|
||||||
|
import DearImGui.Structs
|
||||||
|
|
||||||
|
-- inline-c
|
||||||
|
import qualified Language.C.Inline as C
|
||||||
|
|
||||||
|
-- inline-c-cpp
|
||||||
|
import qualified Language.C.Inline.Cpp as Cpp
|
||||||
|
|
||||||
|
C.context (Cpp.cppCtx <> C.bsCtx <> imguiContext)
|
||||||
|
C.include "imgui.h"
|
||||||
|
Cpp.using "namespace ImGui"
|
||||||
|
|
||||||
|
-- | Glyph ranges handle
|
||||||
|
--
|
||||||
|
-- Wraps @ImWchar*@.
|
||||||
|
newtype GlyphRanges = GlyphRanges (Ptr ImWchar)
|
||||||
|
|
||||||
|
-- | Builtin glyph ranges tags.
|
||||||
|
data Builtin
|
||||||
|
= Latin
|
||||||
|
| Korean
|
||||||
|
| Japanese
|
||||||
|
| ChineseFull
|
||||||
|
| ChineseSimplifiedCommon
|
||||||
|
| Cyrillic
|
||||||
|
| Thai
|
||||||
|
| Vietnamese
|
||||||
|
deriving (Eq, Ord, Show, Enum, Bounded)
|
||||||
|
|
||||||
|
-- | Get builtin glyph ranges from a tag.
|
||||||
|
getBuiltin :: Builtin -> GlyphRanges
|
||||||
|
getBuiltin = \case
|
||||||
|
Latin -> getGlyphRangesDefault
|
||||||
|
Korean -> getGlyphRangesKorean
|
||||||
|
Japanese -> getGlyphRangesJapanese
|
||||||
|
ChineseFull -> getGlyphRangesChineseFull
|
||||||
|
ChineseSimplifiedCommon -> getGlyphRangesChineseSimplifiedCommon
|
||||||
|
Cyrillic -> getGlyphRangesCyrillic
|
||||||
|
Thai -> getGlyphRangesThai
|
||||||
|
Vietnamese -> getGlyphRangesVietnamese
|
||||||
|
|
||||||
|
-- | Special case of @getBuiltin@, but for font source setup.
|
||||||
|
builtinSetup :: Builtin -> Maybe GlyphRanges
|
||||||
|
builtinSetup = \case
|
||||||
|
Latin -> Nothing
|
||||||
|
others -> Just (getBuiltin others)
|
||||||
|
|
||||||
|
-- | Basic Latin, Extended Latin
|
||||||
|
getGlyphRangesDefault :: GlyphRanges
|
||||||
|
getGlyphRangesDefault = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesDefault();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Korean characters
|
||||||
|
getGlyphRangesKorean :: GlyphRanges
|
||||||
|
getGlyphRangesKorean = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesKorean();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs
|
||||||
|
getGlyphRangesJapanese :: GlyphRanges
|
||||||
|
getGlyphRangesJapanese = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesJapanese();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs
|
||||||
|
getGlyphRangesChineseFull :: GlyphRanges
|
||||||
|
getGlyphRangesChineseFull = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesChineseFull();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese
|
||||||
|
getGlyphRangesChineseSimplifiedCommon :: GlyphRanges
|
||||||
|
getGlyphRangesChineseSimplifiedCommon = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + about 400 Cyrillic characters
|
||||||
|
getGlyphRangesCyrillic :: GlyphRanges
|
||||||
|
getGlyphRangesCyrillic = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesCyrillic();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Thai characters
|
||||||
|
getGlyphRangesThai :: GlyphRanges
|
||||||
|
getGlyphRangesThai = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesThai();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Default + Vietnamese characters
|
||||||
|
getGlyphRangesVietnamese :: GlyphRanges
|
||||||
|
getGlyphRangesVietnamese = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
const ImWchar* {
|
||||||
|
return GetIO().Fonts->GetGlyphRangesVietnamese();
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Glyph ranges builder handle
|
||||||
|
--
|
||||||
|
-- Wraps @ImFontGlyphRangesBuilder*@.
|
||||||
|
newtype GlyphRangesBuilder = GlyphRangesBuilder (Ptr ImFontGlyphRangesBuilder)
|
||||||
|
|
||||||
|
-- | Glyph ranges vector handle to keep builder output
|
||||||
|
--
|
||||||
|
-- Wraps @ImVector<ImWchar>*@.
|
||||||
|
newtype GlyphRangesVector = GlyphRangesVector (Ptr ())
|
||||||
|
|
||||||
|
|
||||||
|
-- | Create an instance of builder
|
||||||
|
new :: MonadIO m => m GlyphRangesBuilder
|
||||||
|
new = liftIO do
|
||||||
|
GlyphRangesBuilder <$> [C.block|
|
||||||
|
ImFontGlyphRangesBuilder* {
|
||||||
|
return IM_NEW(ImFontGlyphRangesBuilder);
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Destroy an instance of builder
|
||||||
|
--
|
||||||
|
-- Should be used __after__ font atlas building.
|
||||||
|
destroy :: MonadIO m => GlyphRangesBuilder -> m ()
|
||||||
|
destroy (GlyphRangesBuilder builder) = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
IM_DELETE($(ImFontGlyphRangesBuilder* builder));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
-- | Add character
|
||||||
|
addChar :: MonadIO m => GlyphRangesBuilder -> ImWchar -> m ()
|
||||||
|
addChar (GlyphRangesBuilder builder) wChar = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontGlyphRangesBuilder* builder)->AddChar($(ImWchar wChar));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Add string (each character of the UTF-8 string are added)
|
||||||
|
addText :: MonadIO m => GlyphRangesBuilder -> CString -> m ()
|
||||||
|
addText (GlyphRangesBuilder builder) string = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontGlyphRangesBuilder* builder)->AddText($(char* string));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
-- FIXME: the function uses 'const char* text_end = NULL' parameter,
|
||||||
|
-- which is pointer for the line ending. It is low level, though it
|
||||||
|
-- could be utilized for string length parameter.
|
||||||
|
|
||||||
|
-- | Add ranges, e.g. 'addRanges builder getGlyphRangesDefault'
|
||||||
|
-- to force add all of ASCII/Latin+Ext
|
||||||
|
addRanges :: MonadIO m => GlyphRangesBuilder -> GlyphRanges -> m()
|
||||||
|
addRanges (GlyphRangesBuilder builder) (GlyphRanges ranges) = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
$(ImFontGlyphRangesBuilder* builder)->AddRanges($(ImWchar* ranges));
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
-- | Build new ranges and create ranges vector instance,
|
||||||
|
-- containing them
|
||||||
|
buildRangesVector :: MonadIO m => GlyphRangesBuilder -> m (GlyphRangesVector)
|
||||||
|
buildRangesVector (GlyphRangesBuilder builder) = liftIO do
|
||||||
|
GlyphRangesVector <$> [C.block|
|
||||||
|
void* {
|
||||||
|
ImVector<ImWchar>* ranges = IM_NEW(ImVector<ImWchar>);
|
||||||
|
$(ImFontGlyphRangesBuilder* builder)->BuildRanges(ranges);
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Extract glyph ranges from a vector
|
||||||
|
--
|
||||||
|
-- Should be used __before__ vector destruction.
|
||||||
|
fromRangesVector :: GlyphRangesVector -> GlyphRanges
|
||||||
|
fromRangesVector (GlyphRangesVector vecPtr) = unsafePerformIO do
|
||||||
|
GlyphRanges <$> [C.block|
|
||||||
|
ImWchar* {
|
||||||
|
return ((ImVector<ImWchar>*) $(void* vecPtr))->Data;
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
-- | Destroy a ranges vector instance
|
||||||
|
--
|
||||||
|
-- Should be used __after__ font atlas building.
|
||||||
|
destroyRangesVector :: MonadIO m => GlyphRangesVector -> m ()
|
||||||
|
destroyRangesVector (GlyphRangesVector vecPtr) = liftIO do
|
||||||
|
[C.block|
|
||||||
|
void {
|
||||||
|
IM_DELETE(((ImVector<ImWchar>*) $(void* vecPtr)));
|
||||||
|
}
|
||||||
|
|]
|
@ -5,7 +5,7 @@ module DearImGui.Structs where
|
|||||||
|
|
||||||
-- base
|
-- base
|
||||||
import Data.Word
|
import Data.Word
|
||||||
( Word32 )
|
( Word32, Word16 )
|
||||||
import Foreign
|
import Foreign
|
||||||
( Storable(..), castPtr, plusPtr )
|
( Storable(..), castPtr, plusPtr )
|
||||||
|
|
||||||
@ -80,6 +80,12 @@ data ImGuiContext
|
|||||||
-- | Individual font handle.
|
-- | Individual font handle.
|
||||||
data ImFont
|
data ImFont
|
||||||
|
|
||||||
|
-- | Font configuration handle.
|
||||||
|
data ImFontConfig
|
||||||
|
|
||||||
|
-- | Glyph ranges builder handle.
|
||||||
|
data ImFontGlyphRangesBuilder
|
||||||
|
|
||||||
-- | Opaque DrawList handle.
|
-- | Opaque DrawList handle.
|
||||||
data ImDrawList
|
data ImDrawList
|
||||||
|
|
||||||
@ -88,3 +94,7 @@ data ImGuiListClipper
|
|||||||
|
|
||||||
-- | 32-bit unsigned integer (often used to store packed colors).
|
-- | 32-bit unsigned integer (often used to store packed colors).
|
||||||
type ImU32 = Word32
|
type ImU32 = Word32
|
||||||
|
|
||||||
|
-- | Single wide character (used mostly in glyph management)
|
||||||
|
type ImWchar = Word16
|
||||||
|
-- FIXME: consider IMGUI_USE_WCHAR32
|
||||||
|
Loading…
Reference in New Issue
Block a user