Skip to content

Commit

Permalink
Avoid infinite resize loop in multiline label (#233)
Browse files Browse the repository at this point in the history
* Avoid infinite resize loop in multiline label

* Avoid weird macOS 'command encoder is already encoding to this command buffer' error when resizing window

* Render resized window unconditionally when running on Linux
  • Loading branch information
fjvallarino committed Dec 6, 2022
1 parent df6ae02 commit 344edc6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 18 deletions.
11 changes: 6 additions & 5 deletions src/Monomer/Main/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import Control.Monad.Extra
import Control.Monad.State
import Control.Monad.STM (atomically)
import Data.Default
import Data.Maybe
import Data.Either (isLeft)
import Data.Maybe (fromMaybe)
import Data.Map (Map)
import Data.List (foldl')
import Data.Text (Text)
Expand Down Expand Up @@ -348,14 +349,14 @@ mainLoop window fontManager config loopArgs = do

-- Rendering
renderCurrentReq <- checkRenderCurrent startTs _mlLatestRenderTs
renderMethod <- use L.renderMethod

let actionEvt = any isActionEvent eventsPayload
let windowRenderEvt = windowResized || any isWindowRenderEvent eventsPayload
let renderResize = windowResized && (isLinux wenv || isLeft renderMethod)
let windowRenderEvt = renderResize || any isWindowRenderEvent eventsPayload
let renderNeeded = windowRenderEvt || actionEvt || renderCurrentReq

when (prevRenderNeeded || renderNeeded) $ do
renderMethod <- use L.renderMethod

when (prevRenderNeeded || renderNeeded) $
case renderMethod of
Right renderChan -> do
liftIO . atomically $ writeTChan renderChan (MsgRender newWenv newRoot)
Expand Down
31 changes: 18 additions & 13 deletions src/Monomer/Widgets/Singles/Label.hs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ data LabelState = LabelState {
_lstStyle :: StyleState,
_lstTextRect :: Rect,
_lstTextLines :: Seq TextLine,
_lstPrevResize :: (Millisecond, Bool)
_lstResizeStep :: (Millisecond, Bool)
} deriving (Eq, Show, Generic)

-- | Creates a label using the provided 'Text'.
Expand Down Expand Up @@ -201,7 +201,7 @@ makeLabel config state = widget where
| otherwise = SingleLine
maxLines = _lscTextMaxLines config
labelCurrentStyle = fromMaybe currentStyle (_lscCurrentStyle config)
LabelState caption textStyle textRect textLines prevResize = state
LabelState caption textStyle textRect textLines resizeStep = state

getBaseStyle wenv node
| ignoreTheme = Nothing
Expand All @@ -216,11 +216,12 @@ makeLabel config state = widget where
& L.widget .~ makeLabel config newState

merge wenv newNode oldNode oldState = result where
LabelState prevCaption prevStyle prevRect prevLines prevResize = oldState
(tsResized, alreadyResized) = prevResize

widgetId = newNode ^. L.info . L.widgetId
style = labelCurrentStyle wenv newNode
prevStyle = _lstStyle oldState

captionChanged = _lstCaption oldState /= caption
captionChanged = prevCaption /= caption
styleChanged = prevStyle ^. L.text /= style ^. L.text
|| prevStyle ^. L.padding /= style ^. L.padding
|| prevStyle ^. L.border /= style ^. L.border
Expand All @@ -231,11 +232,13 @@ makeLabel config state = widget where
-- This is used in resize to know if glyphs have to be recalculated
newRect
| changeReq = def
| otherwise = _lstTextRect oldState
newState = oldState {
| otherwise = prevRect
newState = LabelState {
_lstCaption = caption,
_lstStyle = style,
_lstTextRect = newRect
_lstTextRect = newRect,
_lstTextLines = prevLines,
_lstResizeStep = (tsResized, alreadyResized && not captionChanged)
}

reqs = [ ResizeWidgets widgetId | changeReq ]
Expand All @@ -246,7 +249,7 @@ makeLabel config state = widget where
getSizeReq wenv node = (sizeW, sizeH) where
ts = wenv ^. L.timestamp
caption = _lstCaption state
prevResize = _lstPrevResize state
prevResize = _lstResizeStep state
style = labelCurrentStyle wenv node

cw = getContentArea node style ^. L.w
Expand Down Expand Up @@ -286,18 +289,20 @@ makeLabel config state = widget where
= fitTextToSize fontMgr style overflow mode trim maxLines size caption
newTextLines = alignTextLines style alignRect fittedLines

(prevTs, prevStep) = prevResize
needsSndResize = mode == MultiLine && (prevTs /= ts || not prevStep)
rectEq = textRect == crect
(tsResized, alreadyResized) = resizeStep
resizeAgain = mode == MultiLine && (tsResized /= ts || not alreadyResized)
isResized = (alreadyResized && rectEq) || (resizeAgain && tsResized == ts)

newState = state {
_lstStyle = style,
_lstTextRect = crect,
_lstTextLines = newTextLines,
_lstPrevResize = (ts, needsSndResize && prevTs == ts)
_lstResizeStep = (ts, isResized)
}
newNode = node
& L.widget .~ makeLabel config newState
result = resultReqs newNode [ResizeWidgets widgetId | needsSndResize]
result = resultReqs newNode [ResizeWidgets widgetId | resizeAgain]

render wenv node renderer = do
drawInScissor renderer True scissorVp $
Expand Down

0 comments on commit 344edc6

Please sign in to comment.