From: Duncan C. <dun...@wo...> - 2005-12-07 16:39:15
|
On Wed, 2005-12-07 at 14:57 +0000, Axel Simon wrote: > On Wed, 2005-12-07 at 13:57 +0000, Duncan Coutts wrote: > > > > > where setBitSliceWord32 :: Word32 -> Int -> Int -> Word32 -> Word32 > > > > setBitSliceWord32 word off count value = > > > > let mask = (1 `shiftL` count - 1) `shiftL` off > > > > in (word .&. complement mask) .|. (value `shiftL` off) > > > > > > Ok, so you can do it :-) > > > > Yeah, ok that was overkill. :-) > > I could have just said "actually it's not too hard". > > Sorry that wasn't meant to be condescending. S'ok I didn't think you were :-). > I guess my point was that > it can be done, but it might be a bad trade-off since it is rather > tricky to get right and it's not clear if it has any advantages over an > array of arrays. I wonder what the API would look like if people where > to implement their own Model. The lowest level api looks like this: data CustomStoreImpl = CustomStoreImpl { customStoreGetFlags :: IO [TreeModelFlags], customStoreGetNColumns :: IO Int, customStoreGetColumnType :: Int -> IO GType, customStoreGetIter :: TreePath -> IO (Maybe Iter), -- convert a path to an iterator customStoreGetPath :: Iter -> IO TreePath, -- convert an iterator to a path customStoreGetValue :: Iter -> Int -> GValue -> IO (), -- get the value at an iter and column customStoreIterNext :: Iter -> IO (Maybe Iter), -- following row (if any) customStoreIterChildren :: Maybe Iter -> IO (Maybe Iter), -- first child row (if any) customStoreIterHasChild :: Iter -> IO Bool, -- row has any children at all customStoreIterNChildren :: Maybe Iter -> IO Int, -- number of children of a row customStoreIterNthChild :: Maybe Iter -> Int -> IO (Maybe Iter), -- nth child row of a given row customStoreIterParent :: Iter -> IO (Maybe Iter), -- parent row of a row customStoreRefNode :: Iter -> IO (), -- caching hint customStoreUnrefNode :: Iter -> IO () -- caching hint } data Iter = Iter !Word32 !Word32 !Word32 So there are ops to convert paths to Iters and vice versa and then most of the other ops are in terms of Iters. > Is your indexing scheme already part of a model (i.e. we pass three > integers from the TreeIter for people implementing their own model) or > is this built into the library (i.e. people implementing a model get a > TreePath). The Iter is just 3 words and the model implementation can use them however it likes. (Sadly Iters cannot be arbitrary Haskell types due to memory management restrictions) So the indexing system I've been using for the TreeStore implementation is separate and not built into the API. > > Sure. I'll start by committing the low level bits (C parts + low level > > Haskell wrapper) and post the high level bits to the list for review. > > I'm not so worried that your high level stuff doesn't work. Committing > is fine by me. I'm not sure where it should go yet. I'll post the high level stuff separately. > > Heh. Yeah that signal bocking/stopping stuff is less than pleasant. > > I added two functions called stopTextInsert and stopDeleteInsert. That > begs the question if we should have these functions for all handlers... So the ConnectId currently contains the object and the signal instance id. If it also contained the signal name/number then we could stop any signal via its ConnectId. So actually I think it's easy: type HandlerId = {# type gulong #} type SignalId = {# type guint #} data GObjectClass o => ConnectId o = ConnectId !HandlerId !SignalId !o connectGeneric signal after obj user = do sptr <- newStablePtr user gclosurePtr <- gtk2hs_closure_new sptr withCString signal $ \signalPtr -> withForeignPtr ((unGObject.toGObject) obj) $ \objPtr -> do handlerId <- {# call g_signal_connect_closure #} (castPtr objPtr) signalPtr (GClosure gclosurePtr) (fromBool after) signalId <- signalLookup objPtr signalPtr return $ ConnectId handlerId signalId obj which uses: signalLookup objPtr signalPtr = do gclass <- {# get GTypeInstance->g_class #} objPtr gtype <- {# get GTypeClass->g_type #} gclass {# call unsafe g_signal_lookup #} signalPtr gtype and then we can stop an emission using just the ConnectId. signalStopEmission (ConnectId handler signalId obj) = withForeignPtr ((unGObject.toGObject) obj) $ \objPtr -> {# call g_signal_stop_emission #} (castPtr objPtr) signalId 0 However I'm not really sure this is ideal either. It is possible to stop an emission with just the object and the signal name/id. But this api and the existing stopInsertText you've added requires a connected signal handler. If we were ever to change it, I think a better api for signals might be: clickedEvent = Event connect_NONE__NONE "clicked" and then: upon (Event connect, name) = connect name False after (Event connect, name) = connect name True So we'd say: upon clickedEvent myButton $ do ... rather than: onClicked myButton $ do ... It would also mean that we could do what wxHaskell does and allow signals to be set like properties: set myButton [ buttonLabel := "Blah", on clickedEvent := do ... ] but in particular it'd also allow us to say: signalStopEmission myButton clickedEvent without needing to have an already connected signal. Duncan |