Labels may request an expanding height change
This commit is contained in:
		
							parent
							
								
									7754679710
								
							
						
					
					
						commit
						d9281b139f
					
				| @ -14,10 +14,11 @@ type characterLayout struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type wordLayout struct { | type wordLayout struct { | ||||||
| 	position   image.Point | 	position    image.Point | ||||||
| 	width      int | 	width       int | ||||||
| 	spaceAfter int | 	spaceAfter  int | ||||||
| 	text       []characterLayout | 	breaksAfter int | ||||||
|  | 	text        []characterLayout | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Align specifies a text alignment method. | // Align specifies a text alignment method. | ||||||
| @ -167,13 +168,16 @@ func (drawer *TextDrawer) LineHeight () (height fixed.Int26_6) { | |||||||
| func (drawer *TextDrawer) ReccomendedHeightFor (width int) (height int) { | func (drawer *TextDrawer) ReccomendedHeightFor (width int) (height int) { | ||||||
| 	if !drawer.layoutClean { drawer.recalculate() } | 	if !drawer.layoutClean { drawer.recalculate() } | ||||||
| 	metrics := drawer.face.Metrics() | 	metrics := drawer.face.Metrics() | ||||||
| 	dot := fixed.Point26_6 { 0, 0 } | 	dot := fixed.Point26_6 { 0, metrics.Height } | ||||||
| 	for _, word := range drawer.layout { | 	for _, word := range drawer.layout { | ||||||
| 		dot.X += fixed.Int26_6((word.width + word.spaceAfter) << 6) | 		if word.width + dot.X.Round() > width { | ||||||
| 		 |  | ||||||
| 		if word.width + word.position.X > width && word.position.X > 0 { |  | ||||||
| 			dot.Y += metrics.Height | 			dot.Y += metrics.Height | ||||||
| 			dot.X = fixed.Int26_6(word.width << 6) | 			dot.X = 0 | ||||||
|  | 		} | ||||||
|  | 		dot.X += fixed.I(word.width + word.spaceAfter) | ||||||
|  | 		if word.breaksAfter > 0 { | ||||||
|  | 			dot.Y += fixed.I(word.breaksAfter).Mul(metrics.Height) | ||||||
|  | 			dot.X = 0 | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -246,6 +250,7 @@ func (drawer *TextDrawer) recalculate () { | |||||||
| 			if character == '\n' { | 			if character == '\n' { | ||||||
| 				dot.Y += metrics.Height | 				dot.Y += metrics.Height | ||||||
| 				dot.X = 0 | 				dot.X = 0 | ||||||
|  | 				word.breaksAfter ++ | ||||||
| 				previousCharacter = character | 				previousCharacter = character | ||||||
| 				index ++ | 				index ++ | ||||||
| 			} else { | 			} else { | ||||||
| @ -290,7 +295,6 @@ func (drawer *TextDrawer) recalculate () { | |||||||
| 
 | 
 | ||||||
| 	if drawer.wrap { | 	if drawer.wrap { | ||||||
| 		drawer.layoutBounds.Max.X = drawer.width | 		drawer.layoutBounds.Max.X = drawer.width | ||||||
| 		println("aaa") |  | ||||||
| 	} else { | 	} else { | ||||||
| 		drawer.layoutBounds.Max.X = horizontalExtent | 		drawer.layoutBounds.Max.X = horizontalExtent | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -89,6 +89,7 @@ func (window *Window) Adopt (child tomo.Element) { | |||||||
| 		child.SetParentHooks (tomo.ParentHooks { | 		child.SetParentHooks (tomo.ParentHooks { | ||||||
| 			Draw: window.childDrawCallback, | 			Draw: window.childDrawCallback, | ||||||
| 			MinimumSizeChange: window.childMinimumSizeChangeCallback, | 			MinimumSizeChange: window.childMinimumSizeChangeCallback, | ||||||
|  | 			ExpandingHeightChange: window.resizeChildToFit, | ||||||
| 			SelectionRequest: window.childSelectionRequestCallback, | 			SelectionRequest: window.childSelectionRequestCallback, | ||||||
| 		}) | 		}) | ||||||
| 		 | 		 | ||||||
| @ -205,8 +206,25 @@ func (window *Window) resizeChildToFit () { | |||||||
| 	if child, ok := window.child.(tomo.Expanding); ok { | 	if child, ok := window.child.(tomo.Expanding); ok { | ||||||
| 		minimumHeight := child.MinimumHeightFor(window.metrics.width) | 		minimumHeight := child.MinimumHeightFor(window.metrics.width) | ||||||
| 		_, minimumWidth := child.MinimumSize() | 		_, minimumWidth := child.MinimumSize() | ||||||
| 		window.childMinimumSizeChangeCallback ( | 		 | ||||||
| 			minimumWidth, minimumHeight) | 			 | ||||||
|  | 		icccm.WmNormalHintsSet ( | ||||||
|  | 			window.backend.connection, | ||||||
|  | 			window.xWindow.Id, | ||||||
|  | 			&icccm.NormalHints { | ||||||
|  | 				Flags:     icccm.SizeHintPMinSize, | ||||||
|  | 				MinWidth:  uint(minimumWidth), | ||||||
|  | 				MinHeight: uint(minimumHeight), | ||||||
|  | 			}) | ||||||
|  | 				 | ||||||
|  | 		if window.metrics.height >= minimumHeight && | ||||||
|  | 			window.metrics.width >= minimumWidth { | ||||||
|  | 			 | ||||||
|  | 			window.child.Resize ( | ||||||
|  | 				window.metrics.width, | ||||||
|  | 				window.metrics.height) | ||||||
|  | 				window.redrawChildEntirely() | ||||||
|  | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		window.child.Resize ( | 		window.child.Resize ( | ||||||
| 			window.metrics.width, | 			window.metrics.width, | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								element.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								element.go
									
									
									
									
									
								
							| @ -16,6 +16,10 @@ type ParentHooks struct { | |||||||
| 	// event. | 	// event. | ||||||
| 	MinimumSizeChange func (width, height int) | 	MinimumSizeChange func (width, height int) | ||||||
| 
 | 
 | ||||||
|  | 	// ExpandingHeightChange is called when the parameters affecting the | ||||||
|  | 	// element's expanding height have changed. | ||||||
|  | 	ExpandingHeightChange func () | ||||||
|  | 	 | ||||||
| 	// SelectionRequest is called when the child element element wants | 	// SelectionRequest is called when the child element element wants | ||||||
| 	// itself to be selected. If the parent element chooses to grant the | 	// itself to be selected. If the parent element chooses to grant the | ||||||
| 	// request, it must send the child element a selection event and return | 	// request, it must send the child element a selection event and return | ||||||
| @ -42,6 +46,14 @@ func (hooks ParentHooks) RunMinimumSizeChange (width, height int) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // RunExpandingHeightChange runs the ExpandingHeightChange hook if it is not | ||||||
|  | // nil. If it is nil, it does nothing. | ||||||
|  | func (hooks ParentHooks) RunExpandingHeightChange () { | ||||||
|  | 	if hooks.ExpandingHeightChange != nil { | ||||||
|  | 		hooks.ExpandingHeightChange() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // RunSelectionRequest runs the SelectionRequest hook if it is not nil. If it is | // RunSelectionRequest runs the SelectionRequest hook if it is not nil. If it is | ||||||
| // nil, it does nothing. | // nil, it does nothing. | ||||||
| func (hooks ParentHooks) RunSelectionRequest () (granted bool) { | func (hooks ParentHooks) RunSelectionRequest () (granted bool) { | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ func NewLabel (text string, wrap bool) (element *Label) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Resize resizes the label and re-wraps the text if wrapping is enabled. | ||||||
| func (element *Label) Resize (width, height int) { | func (element *Label) Resize (width, height int) { | ||||||
| 	element.core.AllocateCanvas(width, height) | 	element.core.AllocateCanvas(width, height) | ||||||
| 	if element.wrap { | 	if element.wrap { | ||||||
| @ -37,6 +38,17 @@ func (element *Label) Resize (width, height int) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // MinimumHeightFor returns the reccomended height for this element based on the | ||||||
|  | // given width in order to allow the text to wrap properly. | ||||||
|  | func (element *Label) MinimumHeightFor (width int) (height int) { | ||||||
|  | 	if element.wrap { | ||||||
|  | 		return element.drawer.ReccomendedHeightFor(width) | ||||||
|  | 	} else { | ||||||
|  | 		_, height = element.MinimumSize() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // SetText sets the label's text. | // SetText sets the label's text. | ||||||
| func (element *Label) SetText (text string) { | func (element *Label) SetText (text string) { | ||||||
| 	if element.text == text { return } | 	if element.text == text { return } | ||||||
| @ -76,6 +88,7 @@ func (element *Label) updateMinimumSize () { | |||||||
| 		if em < 1 { em = theme.Padding() } | 		if em < 1 { em = theme.Padding() } | ||||||
| 		element.core.SetMinimumSize ( | 		element.core.SetMinimumSize ( | ||||||
| 			em, element.drawer.LineHeight().Round()) | 			em, element.drawer.LineHeight().Round()) | ||||||
|  | 		element.core.NotifyExpandingHeightChange() | ||||||
| 	} else { | 	} else { | ||||||
| 		bounds := element.drawer.LayoutBounds() | 		bounds := element.drawer.LayoutBounds() | ||||||
| 		element.core.SetMinimumSize(bounds.Dx(), bounds.Dy()) | 		element.core.SetMinimumSize(bounds.Dx(), bounds.Dy()) | ||||||
|  | |||||||
| @ -144,6 +144,12 @@ func (control CoreControl) SetMinimumSize (width, height int) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // NotifyExpandingHeightChange notifies the parent element that this element's | ||||||
|  | // expanding height has changed. | ||||||
|  | func (control CoreControl) NotifyExpandingHeightChange () { | ||||||
|  | 	control.core.hooks.RunExpandingHeightChange() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // ConstrainSize contstrains the specified width and height to the minimum width | // ConstrainSize contstrains the specified width and height to the minimum width | ||||||
| // and height, and returns wether or not anything ended up being constrained. | // and height, and returns wether or not anything ended up being constrained. | ||||||
| func (control CoreControl) ConstrainSize ( | func (control CoreControl) ConstrainSize ( | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ func run () { | |||||||
| 	world.Stages = map [string] func () { | 	world.Stages = map [string] func () { | ||||||
| 		"start": func () { | 		"start": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basic.NewLabel ( | ||||||
| 				"you are standing next to a river.", false) | 				"you are standing next to a river.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("go in the river") | 			button0 := basic.NewButton("go in the river") | ||||||
| 			button0.OnClick(world.SwitchFunc("wet")) | 			button0.OnClick(world.SwitchFunc("wet")) | ||||||
| @ -41,7 +41,7 @@ func run () { | |||||||
| 		"wet": func () { | 		"wet": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basic.NewLabel ( | ||||||
| 				"you get completely soaked.\n" + | 				"you get completely soaked.\n" + | ||||||
| 				"you die of hypothermia.", false) | 				"you die of hypothermia.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("try again") | 			button0 := basic.NewButton("try again") | ||||||
| 			button0.OnClick(world.SwitchFunc("start")) | 			button0.OnClick(world.SwitchFunc("start")) | ||||||
| @ -58,7 +58,7 @@ func run () { | |||||||
| 		"house": func () { | 		"house": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basic.NewLabel ( | ||||||
| 				"you are standing in front of a delapidated " + | 				"you are standing in front of a delapidated " + | ||||||
| 				"house.", false) | 				"house.", true) | ||||||
| 			 | 			 | ||||||
| 			button1 := basic.NewButton("go inside") | 			button1 := basic.NewButton("go inside") | ||||||
| 			button1.OnClick(world.SwitchFunc("inside")) | 			button1.OnClick(world.SwitchFunc("inside")) | ||||||
| @ -78,7 +78,7 @@ func run () { | |||||||
| 				"it is dark, but rays of light stream " + | 				"it is dark, but rays of light stream " + | ||||||
| 				"through the window.\n" + | 				"through the window.\n" + | ||||||
| 				"there is nothing particularly interesting " + | 				"there is nothing particularly interesting " + | ||||||
| 				"here.", false) | 				"here.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("go back outside") | 			button0 := basic.NewButton("go back outside") | ||||||
| 			button0.OnClick(world.SwitchFunc("house")) | 			button0.OnClick(world.SwitchFunc("house")) | ||||||
| @ -92,7 +92,7 @@ func run () { | |||||||
| 		"bear": func () { | 		"bear": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basic.NewLabel ( | ||||||
| 				"you come face to face with a bear.\n" + | 				"you come face to face with a bear.\n" + | ||||||
| 				"it eats you (it was hungry).", false) | 				"it eats you (it was hungry).", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("try again") | 			button0 := basic.NewButton("try again") | ||||||
| 			button0.OnClick(world.SwitchFunc("start")) | 			button0.OnClick(world.SwitchFunc("start")) | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ func main () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(480, 360) | 	window, _ := tomo.NewWindow(480, 2) | ||||||
| 	window.SetTitle("example label") | 	window.SetTitle("example label") | ||||||
| 	window.Adopt(basic.NewLabel(text, true)) | 	window.Adopt(basic.NewLabel(text, true)) | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user