以下はうまくいくようです...しかし、それは不器用に思えます。
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 を設計する正しい方法は何ですか?