Skip to content

Commit

Permalink
Merge pull request #1306 from cogentcore/stagesize
Browse files Browse the repository at this point in the history
 A set of stage / window sizing fixes
  • Loading branch information
kkoreilly authored Nov 15, 2024
2 parents c3b8172 + 56a2b0c commit 43c6bd6
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 29 deletions.
6 changes: 3 additions & 3 deletions core/enumgen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ func (fr *Frame) laySetContentFitOverflow(nsz math32.Vector2, pass LayoutPasses)
if nosz {
continue
}
if !(fr.Scene != nil && fr.Scene.hasFlag(scenePrefSizing)) && oflow.Dim(d) >= styles.OverflowAuto && fr.Parent != nil {
if !(fr.Scene != nil && fr.Scene.hasFlag(sceneContentSizing)) && oflow.Dim(d) >= styles.OverflowAuto && fr.Parent != nil {
if mx.Dim(d) > 0 {
asz.SetDim(d, styles.ClampMax(styles.ClampMin(asz.Dim(d), nsz.Dim(d)), mx.Dim(d)))
}
Expand Down Expand Up @@ -1519,7 +1519,7 @@ func (wb *WidgetBase) SizeFinal() {
// any factor > 1 produces a full fill along that dimension.
// Returns true if this resulted in a change in our Total size.
func (wb *WidgetBase) growToAlloc() bool {
if (wb.Scene != nil && wb.Scene.hasFlag(scenePrefSizing)) || wb.Styles.GrowWrap {
if (wb.Scene != nil && wb.Scene.hasFlag(sceneContentSizing)) || wb.Styles.GrowWrap {
return false
}
sz := &wb.Geom.Size
Expand Down
14 changes: 8 additions & 6 deletions core/mainstage.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ func (st *Stage) runWindow() *Stage {
if TheApp.Platform() == system.Offscreen ||
(!TheApp.Platform().IsMobile() &&
(st.NewWindow || !st.FullWindow || currentRenderWindow == nil)) {
sz = sc.prefSize(sz)
sz = sc.contentSize(sz)
// on offscreen, we don't want any extra space, as we want the smallest
// possible representation of the content
// also, on offscreen, if the new size is bigger than the current size,
Expand All @@ -236,7 +236,7 @@ func (st *Stage) runWindow() *Stage {
} else {
// on other platforms, we want extra space and a minimum window size
sz = sz.Add(image.Pt(20, 20))
if st.NewWindow {
if st.NewWindow && st.UseMinSize {
// we require windows to be at least 60% and no more than 80% of the
// screen size by default
scsz := system.TheApp.Screen(0).PixSize // TODO(kai): is there a better screen to get here?
Expand Down Expand Up @@ -317,11 +317,13 @@ func (st *Stage) runDialog() *Stage {

sz := ms.renderContext.geom.Size
if !st.FullWindow || st.NewWindow {
sz = sc.prefSize(sz)
sz = sc.contentSize(sz)
sz = sz.Add(image.Pt(50, 50))
// dialogs must be at least 400dp wide by default
minx := int(ctx.Scene.Styles.UnitContext.Dp(400))
sz.X = max(sz.X, minx)
if st.UseMinSize {
// dialogs must be at least 400dp wide by default
minx := int(ctx.Scene.Styles.UnitContext.Dp(400))
sz.X = max(sz.X, minx)
}
sc.Events.startFocusFirst = true // popup dialogs always need focus
}
if DebugSettings.WinRenderTrace {
Expand Down
13 changes: 10 additions & 3 deletions core/popupstage.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ func (st *Stage) runPopup() *Stage {

sc.SceneGeom.Size = maxGeom.Size
sc.SceneGeom.Pos = st.Pos
sz := sc.prefSize(maxGeom.Size)
sz := sc.contentSize(maxGeom.Size)
bigPopup := false
if usingWinGeom && 4*sz.X*sz.Y > 3*msc.SceneGeom.Size.X*msc.SceneGeom.Size.Y { // reasonable fraction
bigPopup = true
}
scrollWd := int(sc.Styles.ScrollbarWidth.Dots)
fontHt := 16
if sc.Styles.Font.Face != nil {
Expand Down Expand Up @@ -124,8 +128,9 @@ func (st *Stage) runPopup() *Stage {
}

sc.SceneGeom.Size = sz
sc.fitInWindow(maxGeom) // does resize
if usingWinGeom { // reposition to be as close to top-right of main scene as possible
if bigPopup { // we have a big popup -- make it not cover the original window;
sc.fitInWindow(maxGeom) // does resize
// reposition to be as close to top-right of main scene as possible
tpos := msc.SceneGeom.Pos
tpos.X += msc.SceneGeom.Size.X
if tpos.X+sc.SceneGeom.Size.X > maxGeom.Size.X { // favor left side instead
Expand All @@ -145,6 +150,8 @@ func (st *Stage) runPopup() *Stage {
tpos.Y = 0
}
sc.SceneGeom.Pos = tpos
} else {
sc.fitInWindow(msc.SceneGeom)
}
sc.showIter = 0

Expand Down
14 changes: 7 additions & 7 deletions core/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func (sc *Scene) doUpdate() bool {

if sc.showIter == sceneShowIters { // end of first pass
sc.showIter++
if !sc.hasFlag(scenePrefSizing) {
if !sc.hasFlag(sceneContentSizing) {
sc.Events.activateStartFocus()
}
}
Expand Down Expand Up @@ -255,20 +255,20 @@ func (sc *Scene) doRebuild() {
sc.layoutRenderScene()
}

// prefSize computes the preferred size of the scene based on current contents.
// initSz is the initial size -- e.g., size of screen.
// Used for auto-sizing windows.
func (sc *Scene) prefSize(initSz image.Point) image.Point {
// contentSize computes the size of the scene based on current content.
// initSz is the initial size, e.g., size of screen.
// Used for auto-sizing windows when created, and in [Scene.ResizeToContent].
func (sc *Scene) contentSize(initSz image.Point) image.Point {
sc.setFlag(true, sceneUpdating) // prevent rendering
defer func() { sc.setFlag(false, sceneUpdating) }()

sc.setFlag(true, scenePrefSizing)
sc.setFlag(true, sceneContentSizing)
sc.updateScene()
sc.applyStyleScene()
sc.layoutScene()
sz := &sc.Geom.Size
psz := sz.Actual.Total
sc.setFlag(false, scenePrefSizing)
sc.setFlag(false, sceneContentSizing)
sc.showIter = 0
return psz.ToPointFloor()
}
Expand Down
32 changes: 27 additions & 5 deletions core/scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,10 @@ const (
// copy the image up to the GPU or not.
sceneImageUpdated

// scenePrefSizing means that this scene is currently doing a
// PrefSize computation to compute the size of the scene
// (for sizing window for example); affects layout size computation
// only for Over
scenePrefSizing
// sceneContentSizing means that this scene is currently doing a
// contentSize computation to compute the size of the scene
// (for sizing window for example). Affects layout size computation.
sceneContentSizing
)

// hasFlag returns whether the given flag is set.
Expand Down Expand Up @@ -293,6 +292,29 @@ func (sc *Scene) resize(geom math32.Geom2DInt) {
sc.NeedsLayout()
}

// ResizeToContent resizes the scene so it fits the current content.
// Only applicable to Desktop systems where windows can be resized.
// Optional extra size is added to the amount computed to hold the contents,
// which is needed in cases with wrapped text elements, which don't
// always size accurately.
func (sc *Scene) ResizeToContent(extra ...image.Point) {
if TheApp.Platform().IsMobile() { // not resizable
return
}
win := sc.RenderWindow()
if win == nil {
return
}
go func() {
scsz := system.TheApp.Screen(0).PixSize
sz := sc.contentSize(scsz)
if len(extra) == 1 {
sz = sz.Add(extra[0])
}
win.SystemWindow.SetSize(sz)
}()
}

// Close closes the [Stage] associated with this [Scene].
// This only works for main stages (windows and dialogs).
// It returns whether the [Stage] was successfully closed.
Expand Down
2 changes: 1 addition & 1 deletion core/sizeclasses.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const (
// in terms of dp (density-independent pixels).
func (wb *WidgetBase) SceneSize() math32.Vector2 {
dots := math32.FromPoint(wb.Scene.SceneGeom.Size)
if wb.Scene.hasFlag(scenePrefSizing) {
if wb.Scene.hasFlag(sceneContentSizing) {
if currentRenderWindow != nil {
rg := currentRenderWindow.SystemWindow.RenderGeom()
dots = math32.FromPoint(rg.Size)
Expand Down
6 changes: 6 additions & 0 deletions core/stage.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ type Stage struct { //types:add -setters
// [WindowStage]s take up the entire window they are created in.
FullWindow bool

// UseMinSize uses a minimum size as a function of the total available size
// for sizing new windows and dialogs. Otherwise, only the content size is used.
// The saved window position and size takes precedence on multi-window platforms.
UseMinSize bool

// Timeout, if greater than 0, results in a popup stages disappearing
// after this timeout duration.
Timeout time.Duration
Expand Down Expand Up @@ -225,6 +230,7 @@ func (st *Stage) setPopups(mainSt *Stage) *Stage {
// setType sets the type and also sets default parameters based on that type
func (st *Stage) setType(typ StageTypes) *Stage {
st.Type = typ
st.UseMinSize = true
switch st.Type {
case WindowStage:
if !TheApp.Platform().IsMobile() {
Expand Down
Loading

0 comments on commit 43c6bd6

Please sign in to comment.