implementation module relayout import StdBool, StdFunc, StdList, StdTuple import ospicture, osrgn, oswindow, ossystem import commondef, windowhandle :: RelayoutItem = { rliItemKind :: !ControlKind // The control kind , rliItemPtr :: !OSWindowPtr // The ptr to the item , rliItemPos :: !Vector2 // The exact position of the item , rliItemSize :: !Size // The exact size of the item , rliItemSelect :: !Bool // The item is Able (True) or Unable (False) , rliItemShow :: !Bool // The item is visible (True) or invisible (False) , rliItemInfo :: CompoundInfo // If the control kind is IsCompoundControl: its CompoundInfo; otherwise undefined , rliItemLook :: LookInfo // If the control kind is IsCustom(Button)Control: its LookInfo; otherwise undefined , rliItems :: ![RelayoutItem] // If the control kind is Is(Compound/Layout)Control: its elements; otherwise: [] } relayoutFatalError :: String String -> .x relayoutFatalError function error = fatalError function "relayout" error /* relayoutItems wMetrics guiPtr withinCompound (oldFrame,oldParent,oldCompound,oldItems) (newFrame,newParent,newCompound,newItems) resizes and moves changed items. guiPtr :: OSWindowPtr is the parent window/compound control. withinCompound :: Bool is True iff the elements are inside a CompoundControl. (old/new)Frame :: OSRect are the window frames in which the elements reside. (old/new)Parent :: Point2 are the positions of the parent window/compound/layout. (old/new)Compound :: Vector2 are the positions of the parent window/compound. (old/new)Items :: [RelayoutItem] contain the elements at their location and size. Assumptions: * (old/new)Items contain elements that are identical except for size and position. * (Radio/Check)Controls are flattened and have rliItemKind Is(Radio/Check)Control. * The ClipStates of CompoundControls are valid. This version uses the HDC of the parent window in order to suppress calls to initpicture. Regions are used to clip sibling controls. In addition, two regions (validRegion,invalidRegion) are maintained that administrate whether part of the window requires update after relayout. This is done as follows: * initially validRegion and invalidRegion are empty. * for each relayoutitem: if its oldFrame<>newFrame then it adds newFrame to validRegion, and oldFrame to invalidRegion * the area to be updated equals validRegion - invalidRegion (so if its empty, then no update is required) relayoutItems returns the background region that needs to be updated. */ relayoutItems :: !OSWindowMetrics !OSWindowPtr !Bool !(!OSRect,!Point2,!Vector2,![RelayoutItem]) !(!OSRect,!Point2,!Vector2,![RelayoutItem]) !*OSToolbox -> (!OSRgnHandle,!*OSToolbox) relayoutItems wMetrics wPtr withinCompound (oldFrame,oldParentPos,oldCompoundPos,oldHs) (newFrame,newParentPos,newCompoundPos,newHs) tb #! (clipRgn,tb) = osnewrectrgn newFrame tb #! (validRgn,tb) = osnewrectrgn zero tb #! (invalidRgn,tb) = osnewrectrgn zero tb #! (osPict,tb) = osGrabWindowPictContext wPtr tb #! picture = packPicture zero defaultPen True osPict tb #! ((clipRgn,validRgn,invalidRgn),picture) = accClipPicture (toRegion (rectToRectangle newFrame)) (relayoutItems` wPtr wMetrics withinCompound newArea (oldFrame,oldParentPos,oldCompoundPos,oldHs) (newFrame,newParentPos,newCompoundPos,newHs) (clipRgn,validRgn,invalidRgn) ) picture #! (_,_,_,osPict,tb)= unpackPicture picture #! tb = osReleaseWindowPictContext wPtr osPict tb #! (updRgn,tb) = osdiffrgn invalidRgn validRgn tb #! tb = stateMap2 osdisposergn [clipRgn,validRgn,invalidRgn] tb = (updRgn,tb) where newArea = subtractRects newFrame oldFrame relayoutItems` :: !OSWindowPtr !OSWindowMetrics !Bool ![OSRect] !(!OSRect,!Point2,!Vector2,![RelayoutItem]) !(!OSRect,!Point2,!Vector2,![RelayoutItem]) !(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle) !*Picture -> (!(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle),!*Picture) relayoutItems` wPtr wMetrics withinCompound newArea (oldFrame,oldParentPos,oldCompoundPos,[oldH:oldHs]) (newFrame,newParentPos,newCompoundPos,[newH:newHs]) rgnHs picture # (rgnHs,picture) = relayoutItem wPtr wMetrics withinCompound newArea (oldFrame,oldParentPos,oldCompoundPos,oldH) (newFrame,newParentPos,newCompoundPos,newH) rgnHs picture # (rgnHs,picture) = relayoutItems` wPtr wMetrics withinCompound newArea (oldFrame,oldParentPos,oldCompoundPos,oldHs) (newFrame,newParentPos,newCompoundPos,newHs) rgnHs picture = (rgnHs,picture) where relayoutItem :: !OSWindowPtr !OSWindowMetrics !Bool ![OSRect] !(!OSRect,!Point2,!Vector2,!RelayoutItem) !(!OSRect,!Point2,!Vector2,!RelayoutItem) !(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle) !*Picture -> (!(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle),!*Picture) relayoutItem wPtr wMetrics withinCompound newArea old=:(_,_,_,{rliItemShow,rliItemKind=k1}) new=:(_,_,_,{rliItemKind=k2}) rgnHs picture | k1<>k2 = relayoutFatalError "relayoutItem" "mismatching RelayoutItems" // | not rliItemShow = (rgnHs,picture) // the items are invisible, so nothing needs to be relayn out | otherwise = relayout wPtr wMetrics withinCompound newArea k1 old new rgnHs picture where /* relayout assumes that the two RelayoutItem arguments have the same ControlKind (fourth argument) and differ only in size or position or both. */ relayout :: !OSWindowPtr !OSWindowMetrics !Bool ![OSRect] !ControlKind !(!OSRect,!Point2,!Vector2,!RelayoutItem) !(!OSRect,!Point2,!Vector2,!RelayoutItem) !(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle) !*Picture -> (!(!OSRgnHandle,!OSRgnHandle,!OSRgnHandle),!*Picture) relayout wPtr wMetrics withinCompound newArea IsCompoundControl (oldFrame,oldParentPos,oldCompoundPos,old) (newFrame,newParentPos,newCompoundPos,new) (clipRgn,validRgn,invalidRgn) picture #! picture = apppicttoolbox (moveF o sizeF) picture #! picture = updF picture #! picture = apppicttoolbox updScrollbars picture // update scrollbars AFTER moving/sizing/updating #! ((clipRgn,validRgn,invalidRgn),picture) = relayoutItems` wPtr wMetrics True newArea1 (oldFrame1,oldAbsolutePos,oldCompoundPos1,old.rliItems) (newFrame1,newAbsolutePos,newCompoundPos1,new.rliItems) (clipRgn,validRgn,invalidRgn) picture | new.rliItemShow #! ((validRgn,invalidRgn),picture) = accpicttoolbox (checkUpdateRegions oldFrame1 newFrame1 (validRgn,invalidRgn)) picture #! (clipRgn,picture)= accpicttoolbox (subtractRectFromRgn (intersectRects newFrame newCompoundRect) clipRgn) picture = ((clipRgn,validRgn,invalidRgn),picture) | otherwise = ((clipRgn,validRgn,invalidRgn),picture) where sameSize = oldSize==newSize // samePos = osCompoundMovesControls && oldPos==newPos || oldAbsolutePos==newAbsolutePos samePos = if (withinCompound && osCompoundMovesControls) (oldPos==newPos) (oldAbsolutePos==newAbsolutePos) sizeF = if sameSize id (osSetCompoundSize wPtr newCompoundPos` itemPtr newPos` newSize` True) moveF = if (samePos && all isEmptyRect (map (intersectRects newFrame1) newArea)) id (osSetCompoundPos wPtr newCompoundPos` itemPtr newPos` newSize` True) updScrollbars = if (sameSize && samePos && all isEmptyRect (flatten (map (\area->[intersectRects hRect` area,intersectRects vRect` area]) newArea))) id ( (setCompoundScroll wPtr (snd hasScrolls) wMetrics itemPtr False newAble newVThumbSize oldOrigin.y newOrigin.y vRect`) o (setCompoundScroll wPtr (fst hasScrolls) wMetrics itemPtr True newAble newHThumbSize oldOrigin.x newOrigin.x hRect`) ) updF = if (sameSize && oldAbsolutePos==newAbsolutePos && oldFrame1==newFrame1 || isEmptyRect newFrame1 || not new.rliItemShow) id (updatecustomcontrol wPtr newParentPos clipRgn newFrame1 new) newParentPos` = toTuple newParentPos newCompoundPos` = toTuple newCompoundPos itemPtr = new.rliItemPtr newAble = new.rliItemSelect newSize` = toTuple newSize newPos` = toTuple newAbsolutePos newSize = new.rliItemSize; oldSize = old.rliItemSize newPos = new.rliItemPos; oldPos = old.rliItemPos newAbsolutePos = movePoint newPos newParentPos; oldAbsolutePos = movePoint oldPos oldParentPos newCompoundPos1 = newCompoundPos + newPos; oldCompoundPos1 = oldCompoundPos + oldPos newInfo = new.rliItemInfo; oldInfo = old.rliItemInfo newOrigin = newInfo.compoundOrigin; oldOrigin = oldInfo.compoundOrigin newDomainRect = newInfo.compoundDomain; oldDomainRect = oldInfo.compoundDomain newCompoundRect = posSizeToRect newAbsolutePos newSize; oldCompoundRect = posSizeToRect oldAbsolutePos oldSize newFrame1 = intersectRects newFrame newContentRect; oldFrame1 = intersectRects oldFrame oldContentRect newArea1 = subtractRects newFrame1 oldFrame1 hasScrolls = (isJust newInfo.compoundHScroll,isJust newInfo.compoundVScroll) (hScrollPtr,vScrollPtr) = (mscrollptr newInfo.compoundHScroll,mscrollptr newInfo.compoundVScroll) mscrollptr = mapMaybe (\{scrollItemPtr}->scrollItemPtr) newVisScrolls = osScrollbarsAreVisible wMetrics newDomainRect newSize` hasScrolls oldVisScrolls = osScrollbarsAreVisible wMetrics oldDomainRect (toTuple oldSize) hasScrolls newHThumbSize = if (snd newVisScrolls) (newSize.w-wMetrics.osmVSliderWidth + 1) (newSize.w+1) newVThumbSize = if (fst newVisScrolls) (newSize.h-wMetrics.osmHSliderHeight + 1) (newSize.h+1) oldContentRect = osGetCompoundContentRect wMetrics oldVisScrolls oldCompoundRect newContentRect = osGetCompoundContentRect wMetrics newVisScrolls newCompoundRect newContentSize = rectSize newContentRect hRect` = osGetCompoundHScrollRect wMetrics newVisScrolls (posSizeToRect newAbsolutePos newSize) vRect` = osGetCompoundVScrollRect wMetrics newVisScrolls (posSizeToRect newAbsolutePos newSize) setCompoundScroll :: !OSWindowPtr !Bool OSWindowMetrics OSWindowPtr Bool Bool Int Int Int !OSRect !*OSToolbox -> *OSToolbox setCompoundScroll wPtr hasScroll wMetrics compoundPtr isHorizontal able size old new rect=:{rright,rbottom} tb | not hasScroll = tb # tb = osSetCompoundSliderThumbSize wMetrics wPtr compoundPtr scrollPtr min max wid rect isHorizontal able (old==new) tb | old==new # tb = osUpdateCompoundScroll wPtr scrollPtr rect tb = tb | otherwise # tb = osSetCompoundSliderThumb wMetrics wPtr compoundPtr scrollPtr rect isHorizontal pos (rright,rbottom) True tb # tb = osUpdateCompoundScroll wPtr scrollPtr rect tb = tb where (min,pos,max,wid) = toOSscrollbarRange (scrollMin,new,scrollMax) scrollSize scrollPtr = if isHorizontal (fromJust hScrollPtr) (fromJust vScrollPtr) scrollMin = if isHorizontal newDomainRect.rleft newDomainRect.rtop scrollMax = if isHorizontal newDomainRect.rright newDomainRect.rbottom scrollSize = if isHorizontal newContentSize.w newContentSize.h relayout wPtr wMetrics withinCompound newArea IsLayoutControl (oldFrame,oldParentPos,oldCompoundPos,old) (newFrame,newParentPos,newCompoundPos,new) rgnHs picture = relayoutItems` wPtr wMetrics withinCompound newArea (oldFrame1,oldAbsolutePos,oldCompoundPos,old.rliItems) (newFrame1,newAbsolutePos,newCompoundPos,new.rliItems) rgnHs picture where newSize = new.rliItemSize; oldSize = old.rliItemSize newPos = new.rliItemPos; oldPos = old.rliItemPos newAbsolutePos = movePoint newPos newParentPos; oldAbsolutePos = movePoint oldPos oldParentPos newLayoutRect = posSizeToRect newAbsolutePos newSize; oldLayoutRect = posSizeToRect oldAbsolutePos oldSize newFrame1 = intersectRects newFrame newLayoutRect; oldFrame1 = intersectRects oldFrame oldLayoutRect relayout wPtr wMetrics withinCompound newArea controlKind (oldFrame,oldParentPos,oldCompoundPos,old) (newFrame,newParentPos,newCompoundPos,new) (clipRgn,validRgn,invalidRgn) picture #! picture = apppicttoolbox (moveF o sizeF) picture #! picture = updF picture | new.rliItemShow #! ((validRgn,invalidRgn),picture) = accpicttoolbox (checkUpdateRegions oldFrame1 newFrame1 (validRgn,invalidRgn)) picture #! (clipRgn,picture)= accpicttoolbox (subtractRectFromRgn newFrame1 clipRgn) picture = ((clipRgn,validRgn,invalidRgn),picture) | otherwise = ((clipRgn,validRgn,invalidRgn),picture) where sameSize = oldSize==newSize // samePos = osCompoundMovesControls && oldPos==newPos || oldAbsolutePos==newAbsolutePos samePos = if (withinCompound && osCompoundMovesControls) (oldPos==newPos) (oldAbsolutePos==newAbsolutePos) sizeF = if sameSize id (setSize wPtr newCompoundPos` itemPtr newPos` newSize` (not redraw)) moveF = if (samePos && all isEmptyRect (map (intersectRects newFrame1) newArea)) id (setPos wPtr newCompoundPos` itemPtr newPos` (toTuple oldSize) (not redraw)) updF = if (not redraw || sameSize && oldAbsolutePos==newAbsolutePos && newFrame1==oldFrame1 || isEmptyRect newFrame1 || not new.rliItemShow) id (updatecustomcontrol wPtr newParentPos clipRgn newFrame1 new) newParentPos` = toTuple newParentPos newCompoundPos` = toTuple newCompoundPos itemPtr = new.rliItemPtr newSize` = toTuple newSize newPos` = toTuple newAbsolutePos newPos = new.rliItemPos; oldPos = old.rliItemPos; newAbsolutePos = movePoint newPos newParentPos; oldAbsolutePos = movePoint oldPos oldParentPos newSize = new.rliItemSize; oldSize = old.rliItemSize; oldFrame1 = intersectRects oldFrame (posSizeToRect oldAbsolutePos oldSize) newFrame1 = intersectRects newFrame (posSizeToRect newAbsolutePos newSize) (setPos,setSize,redraw) = case controlKind of IsRadioControl -> (osSetRadioControlPos, \_ _ _ _ _ _ tb->tb, False) // DvA: moeten op mac elements gewijs verplaatst worden... IsCheckControl -> (osSetCheckControlPos, \_ _ _ _ _ _ tb->tb, False) // DvA: moeten op mac elements gewijs verplaatst worden... IsPopUpControl -> (osSetPopUpControlPos, osSetPopUpControlSize, False) IsSliderControl -> (osSetSliderControlPos, osSetSliderControlSize, False) IsTextControl -> (osSetTextControlPos, osSetTextControlSize, False) IsEditControl -> (osSetEditControlPos, osSetEditControlSize, False) IsButtonControl -> (osSetButtonControlPos, osSetButtonControlSize, False) IsCustomButtonControl -> (osSetCustomButtonControlPos,osSetCustomButtonControlSize,True) IsCustomControl -> (osSetCustomControlPos, osSetCustomControlSize, True) (IsOtherControl _) -> (\_ _ _ _ _ _ tb->tb, \_ _ _ _ _ _ tb->tb, False) _ -> relayoutFatalError "relayout" "unexpected ControlKind alternative" relayoutItems` _ _ _ _ (_,_,_,[]) (_,_,_,[]) rgnHs picture = (rgnHs,picture) relayoutItems` _ _ _ _ _ _ _ _ = relayoutFatalError "relayoutItems`" "mismatching RelayoutItems" checkUpdateRegions :: !OSRect !OSRect !(!OSRgnHandle,!OSRgnHandle) !*OSToolbox -> (!(!OSRgnHandle,!OSRgnHandle),!*OSToolbox) checkUpdateRegions oldFrame newFrame rgnHs=:(validRgn,invalidRgn) tb | oldFrame==newFrame = (rgnHs,tb) | otherwise # (newFrameRgn, tb)= osnewrectrgn newFrame tb # (oldFrameRgn, tb)= osnewrectrgn oldFrame tb # (okNewRgn, tb)= osdiffrgn newFrameRgn invalidRgn tb // PA+++ # (newValidRgn, tb)= osunionrgn okNewRgn validRgn tb // PA: okNewRgn <-- newFrameRgn # (newInvalidRgn,tb)= osunionrgn oldFrameRgn invalidRgn tb # tb = stateMap2 osdisposergn [validRgn,invalidRgn,newFrameRgn,oldFrameRgn,okNewRgn] tb // PA: okNewRgn added = ((newValidRgn,newInvalidRgn),tb) subtractRectFromRgn :: !OSRect !OSRgnHandle !*OSToolbox -> (!OSRgnHandle,!*OSToolbox) subtractRectFromRgn rect rgn tb | isEmptyRect rect = (rgn,tb) | otherwise # (rectRgn,tb) = osnewrectrgn rect tb # (diffRgn,tb) = osdiffrgn rgn rectRgn tb # tb = osdisposergn rectRgn tb # tb = osdisposergn rgn tb = (diffRgn,tb) // updatecustomcontrol assumes that the item is visible. updatecustomcontrol :: !OSWindowPtr !Point2 !OSRgnHandle !OSRect !RelayoutItem !*Picture -> *Picture updatecustomcontrol parentPtr parentPos clipRgn contentRect itemH=:{rliItemKind=IsCustomButtonControl} picture #! (curOrigin,picture) = getpictorigin picture #! (curPen, picture) = getpictpen picture #! picture = setpictorigin (zero-absolutePos) picture #! picture = setpictpen lookPen picture #! picture = clipospicture clipRgn contentRect (lookFun selectState updState) picture #! picture = setpictpen curPen picture # picture = setpictorigin curOrigin picture = picture where absolutePos = movePoint itemH.rliItemPos parentPos selectState = if itemH.rliItemSelect Able Unable {lookFun,lookPen} = itemH.rliItemLook cFrame = sizeToRectangle itemH.rliItemSize updState = {oldFrame=cFrame,newFrame=cFrame,updArea=[cFrame]} updatecustomcontrol parentPtr parentPos clipRgn contentRect itemH=:{rliItemKind=IsCustomControl} picture #! (curOrigin,picture) = getpictorigin picture #! (curPen, picture) = getpictpen picture #! picture = setpictorigin (zero-absolutePos) picture #! picture = setpictpen lookPen picture #! picture = clipospicture clipRgn contentRect (lookFun selectState updState) picture #! picture = setpictpen curPen picture # picture = setpictorigin curOrigin picture = picture where absolutePos = movePoint itemH.rliItemPos parentPos selectState = if itemH.rliItemSelect Able Unable {lookFun,lookPen} = itemH.rliItemLook cFrame = sizeToRectangle itemH.rliItemSize updState = {oldFrame=cFrame,newFrame=cFrame,updArea=[cFrame]} updatecustomcontrol parentPtr parentPos clipRgn contentRect itemH=:{rliItemKind=IsCompoundControl} picture #! (curOrigin,picture) = getpictorigin picture #! (curPen, picture) = getpictpen picture #! picture = setpictorigin (origin-absolutePos) picture #! picture = setpictpen lookPen picture #! (clip,picture) = accpicttoolbox (ossectrgn clipRgn clipInfo.clipRgn) picture #! picture = clipospicture clip clipRect (lookFun selectState updState) picture #! picture = apppicttoolbox (osdisposergn clip) picture #! picture = setpictpen curPen picture # picture = setpictorigin curOrigin picture = picture where absolutePos = movePoint itemH.rliItemPos parentPos selectState = if itemH.rliItemSelect Able Unable itemSize = itemH.rliItemSize info = itemH.rliItemInfo (origin,domainRect,hasScrolls) = (info.compoundOrigin,info.compoundDomain,(isJust info.compoundHScroll,isJust info.compoundVScroll)) visScrolls = osScrollbarsAreVisible wMetrics domainRect (toTuple itemSize) hasScrolls cFrameRect = osGetCompoundContentRect wMetrics visScrolls (posSizeToRect origin itemSize) cFrame = rectToRectangle cFrameRect compLookInfo = info.compoundLookInfo {lookFun,lookPen} = compLookInfo.compoundLook clipInfo = compLookInfo.compoundClip updState = {oldFrame=cFrame,newFrame=cFrame,updArea=[cFrame]} cRect = addVector (toVector (absolutePos-origin)) cFrameRect clipRect = intersectRects contentRect cRect clipospicture :: !OSRgnHandle !OSRect !(IdFun *Picture) !*Picture -> *Picture clipospicture newClipRgn rect drawf picture #! (rectRgn,picture) = accpicttoolbox (osnewrectrgn rect) picture #! (curClipRgn,picture) = pictgetcliprgn picture #! (emptyCur,picture) = accpicttoolbox (osisemptyrgn curClipRgn) picture #! (emptyNew,picture) = accpicttoolbox (osisemptyrgn newClipRgn) picture #! picture = (if emptyCur (pictsetcliprgn rectRgn) (pictandcliprgn rectRgn)) picture #! picture = (if emptyNew id (pictandcliprgn newClipRgn)) picture /* #! picture = (if (curClipRgn==0) (pictsetcliprgn rectRgn) (pictandcliprgn rectRgn)) picture #! picture = (if (newClipRgn==0) id (pictandcliprgn newClipRgn)) picture */ #! picture = drawf picture #! picture = pictsetcliprgn curClipRgn picture # picture = apppicttoolbox ( osdisposergn rectRgn o (if (curClipRgn==0) id (osdisposergn curClipRgn)) ) picture = picture