From: Jules B. <ju...@je...> - 2008-03-29 11:05:03
|
So, I have successfully added some of the missing bindings that I needed. The code is so short that I embed it in this email. I'd be interested to hear any comments on the way I did this, and what you would want to change before committing it to wxhaskell. 1) Loading images from in-memory blocks Stub C++ file to bind to the appropriate wxImage constructor: #include "wx/wx.h" #include "wx/image.h" #include "wx/mstream.h" extern "C" { void * wxImage_CreateFromFileInMemory(void* data,int length,int type) { wxMemoryInputStream in(data,length); return (void*) new wxImage(in,type); } } You can compile this with "g++ -c `wx-config --cppflags` cstub.cpp" Then a haskell stub file to wrap a Ptr version of this and two bytestring versions: {-# OPTIONS -fglasgow-exts #-} module ImageExtras where import qualified Data.ByteString.Lazy as LB import qualified Data.ByteString as B import Foreign import Foreign.C import Graphics.UI.WXCore.WxcTypes import Graphics.UI.WXCore.WxcClassTypes imageCreateFromPtrFile :: Ptr b -> Int -> Int -> IO (Image ()) imageCreateFromPtrFile ptr len typ = withManagedObjectResult $ wxImage_CreateFromFileInMemory ptr (fromIntegral len) (fromIntegral typ) foreign import ccall "wxImage_CreateFromFileInMemory" wxImage_CreateFromFileInMemory :: Ptr b -> CInt -> CInt -> IO (Ptr (TImage ())) imageCreateFromLBytestringFile :: LB.ByteString -> Int -> IO (Image ()) imageCreateFromLBytestringFile bs typ = withArray (LB.unpack bs) $ \ptr -> imageCreateFromPtrFile ptr (fromIntegral $ LB.length bs) typ imageCreateFromBytestringFile :: B.ByteString -> Int -> IO (Image ()) imageCreateFromBytestringFile bs typ = withArray (B.unpack bs) $ \ptr -> imageCreateFromPtrFile ptr (B.length bs) typ I'm not sure if you can make these a bit more efficient by attacking the underlying bytestring rep, but I didn't try. It works, anyhow. I am able to load images from bytestreams (as it happens, the cover art from an M4A file). The magic invocation to get ghc to link it correctly seems to be: ghc --make main.hs cstub.o -lstdc++ `wx-config --libs` -optl -fexceptions 2) GetOption / SetOption for Images Slightly more fiddly. The C++ stub looks like this: #include "wx/wx.h" #include "wx/image.h" extern "C" { void wxImage_SetOption(void *_obj, void* key,void *value) { ((wxImage*)_obj)->SetOption((wxChar*)key,(wxChar*)value); } wxString* wxImage_GetOption(void *_obj, void* key) { return new wxString(((wxImage*)_obj)->GetOption((wxChar*)key)); } } (it took me quite a while to understand why casting to wxChar* works when the underlying type is WxString&; there is an implicit conversion because of a constructor) The haskell stub is this: {-# OPTIONS -fglasgow-exts #-} module ImageOptions where import Graphics.UI.WXCore.WxcTypes import Graphics.UI.WXCore.WxcClassTypes imageSetOption :: Image a -> String -> String -> IO () imageSetOption _obj key value = withObjectRef "imageSetOption" _obj $ \cobj -> withCWString key $ \cstr_key -> withCWString value $ \cstr_value -> wxImage_SetOption cobj cstr_key cstr_value foreign import ccall "wxImage_SetOption" wxImage_SetOption :: Ptr (TImage a) -> CWString -> CWString -> IO () imageGetOption :: Image a -> String -> IO String imageGetOption _obj key = withManagedStringResult $ withObjectRef "imageGetOption" _obj $ \cobj -> withCWString key $ \cstr_key -> wxImage_GetOption cobj cstr_key foreign import ccall "wxImage_GetOption" wxImage_GetOption :: Ptr (TImage a) -> CWString -> IO (Ptr (TWxString ())) 3) Points of confusion: For return types of type String, looking at the examples in elj*.cpp, why does it sometimes use copyStrToBuf to unpack the WxString on the C++ side in combination with withWStringResult on the haskell side, and other times just pass back the a freshly allocated WxString* from C++ in combination with withManagedStringResult? For arguments of object types, why do some bindings use withObjectPtr and some use withObjectRef? What's the EXWXEXPORT() macro for? It didn't seem very useful to me... Thanks, Jules |