7

以下はうまくいくようです...しかし、それは不器用に思えます。

data Point = Point Int Int
data Box = Box Int Int
data Path = Path [Point]
data Text = Text

data Color = Color Int Int Int
    data WinPaintContext = WinPaintContext Graphics.Win32.HDC

class CanvasClass vc paint where
    drawLine :: vc -> paint -> Point -> Point -> IO ()
    drawRect :: vc -> paint -> Box -> IO ()
    drawPath :: vc -> paint -> Path -> IO ()

class (CanvasClass vc paint) => TextBasicClass vc paint where
    basicDrawText :: vc -> paint -> Point -> String -> IO ()

instance CanvasClass WinPaintContext WinPaint where
    drawLine = undefined
    drawRect = undefined
    drawPath = undefined

instance TextBasicClass WinPaintContext WinPaint where
    basicDrawText (WinPaintContext a) = winBasicDrawText a

op :: CanvasClass vc paint => vc -> Box -> IO ()
op canvas _ = do
    basicDrawText canvas WinPaint (Point 30 30) "Hi"

open :: IO ()
open = do
    makeWindow (Box 300 300) op

winBasicDrawText :: Graphics.Win32.HDC -> WinPaint -> Point -> String -> IO ()
winBasicDrawText hdc _ (Point x y) str = do
    Graphics.Win32.setBkMode hdc Graphics.Win32.tRANSPARENT
    Graphics.Win32.setTextColor hdc (Graphics.Win32.rgb 255 255 0)
    Graphics.Win32.textOut hdc 20 20 str
    return ()

windowsOnPaint :: (WinPaintContext -> Box -> IO ()) ->
                  Graphics.Win32.RECT ->
                  Graphics.Win32.HDC ->
                  IO ()
windowsOnPaint f rect hdc = f (WinPaintContext hdc) (Box 30 30)

makeWindow :: Box -> (WinPaintContext -> Box -> IO ()) -> IO ()
makeWindow (Box w h) onPaint =
  Graphics.Win32.allocaPAINTSTRUCT $ \ lpps -> do
  hwnd <- createWindow w h (wndProc lpps (windowsOnPaint onPaint))
  messagePump hwnd

さて、好ましい方法と思われるのは、単に持っていることです

data Canvas = Canvas {
    drawLine :: Point -> Point -> IO (),
    drawRect :: Box -> IO (),
    drawPath :: Path -> IO ()
}

hdc2Canvas :: Graphics.Win32.HDC -> Paint -> IO ( Canvas )
hdc2Canvas hdc paint = Canvas { drawLine = winDrawLine hdc paint ... }

でも...

絵の具は作成して破棄するのにコストがかかるため、描画プロセス全体でペイントを保持し、変更することを好みます。ペイントは単に [bgColor red, fgColor blue, font "Tahoma"] のようなリストである場合もあれば、ペイント システムが使用する内部構造へのポインタである場合もあります (これは Windows GDI の抽象化ですが、最終的にはDirect2d および coregraphics を介して)、何度も再作成してからバインドしたくない「ペイント」オブジェクトがあります。

私が考える実存主義の美しさは、何かを不透明にラップして抽象化し、どこかに保存したり、引き戻したりできることです。部分的に塗布すると、部分的に塗布したものが容器の中に「引っかかって」しまうという問題があると思います。例を次に示します。次のようなペイント オブジェクトがあるとします。

data Paint = Paint {
    setFg :: Color -> IO () ,
    setBg :: Color -> IO ()
}

ポインターはどこに配置できますか? Paint を Canvas のある関数に渡すと、彼はどのようにしてポインターを取得するのでしょうか? この API を設計する正しい方法は何ですか?

4

1 に答える 1