core icon indicating copy to clipboard operation
core copied to clipboard

Split Content Spacing Issue

Open DapperMongoose opened this issue 7 months ago • 3 comments

Describe the bug

While creating a UI layout for large content in the center of a split I ran in to an issue where the scrollbars get doubled. It looks like the split's "handles" maybe aren't accounted for? The outer scrollbar is very small but very confusing, it can be fixed by setting the overflow of the center to be hidden, but I worry that I may be masking some other issue?

How to reproduce

  1. Run example code
  2. Scroll in center to see two scroll bars for outer and inner frames
  3. Un-comment line 31 to hide overflow in the "centerFrame"
  4. Re-run code, only one set of scroll bars, works nice

Example code

package main

import (
	"cogentcore.org/core/core"
	"cogentcore.org/core/styles"
	"cogentcore.org/core/styles/units"
)

func main() {
	b := core.NewBody("Split Scrollbar Bug?")

	splitFrame := core.NewSplits(b)
	splitFrame.Styler(func(s *styles.Style) {
		s.Grow.Set(1, 1)
		s.Direction = styles.Row
	})
	splitFrame.SetSplits(20, 60, 20)

	firstFrame := core.NewFrame(splitFrame)
	firstFrame.Styler(func(s *styles.Style) {
		s.Grow.Set(1, 1)
		s.Border.Width.Set(units.Dp(4))
		s.CenterAll()
	})
	core.NewText(firstFrame).SetText("20% Split Frame")

	// The center of the split, created so that we can put child widgets in it
	centerFrame := core.NewFrame(splitFrame)
	centerFrame.Styler(func(s *styles.Style) {
		s.Direction = styles.Column
		//s.Overflow.Set(styles.OverflowHidden)
	})

	// represents a top "menu" bar that has buttons in it
	centerMenu := core.NewFrame(centerFrame)
	centerMenu.Styler(func(s *styles.Style) {
		s.Min.Set(units.Pw(100), units.Ph(10))
		s.Max.Set(units.Pw(100), units.Ph(10))
		s.Border.Width.Set(units.Dp(4))
		s.CenterAll()
	})
	core.NewText(centerMenu).SetText("Menu Bar")

	// the frame that the child widget will use to wrap its content so that from the outside we only have a single frame
	centerContentArea := core.NewFrame(centerFrame)
	centerContentArea.Styler(func(s *styles.Style) {
		s.Grow.Set(1, 1)
		s.Border.Width.Set(units.Dp(4))
		s.Overflow.Set(styles.OverflowScroll)
	})

	// represents content that will be too large for this frame, user will need to scroll this on both
	// axes to interact with it correctly
	internalCenter := core.NewFrame(centerContentArea)
	internalCenter.Styler(func(s *styles.Style) {
		s.Min.Set(units.Pw(125), units.Ph(125))
		s.CenterAll()
	})
	core.NewText(internalCenter).SetText("Content in center frame")

	lastFrame := core.NewFrame(splitFrame)
	lastFrame.Styler(func(s *styles.Style) {
		s.Grow.Set(1, 1)
		s.CenterAll()
		s.Border.Width.Set(units.Dp(4))
	})
	core.NewText(lastFrame).SetText("20% Split Frame")

	b.RunMainWindow()
}

Relevant output


Platform

Linux

DapperMongoose avatar May 05 '25 20:05 DapperMongoose

@DapperMongoose Thanks for reporting this and providing a reproducible example.

Using Pw can sometimes cause problems, and in general it is better to use Grow when possible. For example, in this case, if you change the centerMenu styler to this:

	centerMenu.Styler(func(s *styles.Style) {
		s.Grow.Set(1, 0)
		s.Border.Width.Set(units.Dp(4))
		s.CenterAll()
	})

Then the issue goes away with no more Pw there. I will document that Grow is generally preferable to Pw.

The issue with Pw is that it can be somewhat recursive: Pw is based on the width of the parent, but the width of the widget can affect the width of the parent. Even when that could be avoided, the current logic is not super robust for Pw, and there are some other contexts in which Pw does not provide particularly stable values. I filed #1517 for the broader issue, but you can close this if my fix works.

kkoreilly avatar May 05 '25 21:05 kkoreilly

What would be the correct way to ensure the exact (relative) height still in this case?

Using Min and Max both seems super awkward, but I'm attempting to ensure exact relative sizes of some elements and it seems to be the most reliable way to get everything to lay out correctly.

DapperMongoose avatar May 05 '25 22:05 DapperMongoose

For height, just setting min should work in most cases, and Ph works pretty reliably, so s.Min.Y.Ph(10) should be fine. If it doesn't work, then you can always add s.Max.Y.Ph(10), but I think as long as your content fits and Grow is off for the Y direction, just Min should be sufficient.

Please let me know if you have any more questions or issues.

kkoreilly avatar May 05 '25 22:05 kkoreilly