atomize-modules #7
| @ -3,11 +3,11 @@ package artist | |||||||
| import "math" | import "math" | ||||||
| import "image" | import "image" | ||||||
| import "image/color" | import "image/color" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| // FillEllipse draws a filled ellipse with the specified pattern. | // FillEllipse draws a filled ellipse with the specified pattern. | ||||||
| func FillEllipse ( | func FillEllipse ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	bounds image.Rectangle, | 	bounds image.Rectangle, | ||||||
| ) ( | ) ( | ||||||
| @ -36,7 +36,7 @@ func FillEllipse ( | |||||||
| // StrokeEllipse draws the outline of an ellipse with the specified line weight | // StrokeEllipse draws the outline of an ellipse with the specified line weight | ||||||
| // and pattern. | // and pattern. | ||||||
| func StrokeEllipse ( | func StrokeEllipse ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	weight int, | 	weight int, | ||||||
| 	bounds image.Rectangle, | 	bounds image.Rectangle, | ||||||
|  | |||||||
| @ -2,14 +2,14 @@ package artist | |||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "image/color" | import "image/color" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| // TODO: draw thick lines more efficiently | // TODO: draw thick lines more efficiently | ||||||
| 
 | 
 | ||||||
| // Line draws a line from one point to another with the specified weight and | // Line draws a line from one point to another with the specified weight and | ||||||
| // pattern. | // pattern. | ||||||
| func Line ( | func Line ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	weight int, | 	weight int, | ||||||
| 	min image.Point, | 	min image.Point, | ||||||
| @ -46,7 +46,7 @@ func Line ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func lineLow ( | func lineLow ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	weight int, | 	weight int, | ||||||
| 	min image.Point, | 	min image.Point, | ||||||
| @ -82,7 +82,7 @@ func lineLow ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func lineHigh ( | func lineHigh ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	weight int, | 	weight int, | ||||||
| 	min image.Point, | 	min image.Point, | ||||||
|  | |||||||
| @ -1,12 +1,12 @@ | |||||||
| package artist | package artist | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| // Paste transfers one canvas onto another, offset by the specified point. | // Paste transfers one canvas onto another, offset by the specified point. | ||||||
| func Paste ( | func Paste ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source tomo.Canvas, | 	source canvas.Canvas, | ||||||
| 	offset image.Point, | 	offset image.Point, | ||||||
| ) ( | ) ( | ||||||
| 	updatedRegion image.Rectangle, | 	updatedRegion image.Rectangle, | ||||||
| @ -31,7 +31,7 @@ func Paste ( | |||||||
| 
 | 
 | ||||||
| // FillRectangle draws a filled rectangle with the specified pattern. | // FillRectangle draws a filled rectangle with the specified pattern. | ||||||
| func FillRectangle ( | func FillRectangle ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	bounds image.Rectangle, | 	bounds image.Rectangle, | ||||||
| ) ( | ) ( | ||||||
| @ -61,7 +61,7 @@ func FillRectangle ( | |||||||
| // StrokeRectangle draws the outline of a rectangle with the specified line | // StrokeRectangle draws the outline of a rectangle with the specified line | ||||||
| // weight and pattern. | // weight and pattern. | ||||||
| func StrokeRectangle ( | func StrokeRectangle ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source Pattern, | 	source Pattern, | ||||||
| 	weight int, | 	weight int, | ||||||
| 	bounds image.Rectangle, | 	bounds image.Rectangle, | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ import "unicode" | |||||||
| import "image/draw" | import "image/draw" | ||||||
| import "golang.org/x/image/font" | import "golang.org/x/image/font" | ||||||
| import "golang.org/x/image/math/fixed" | import "golang.org/x/image/math/fixed" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| type characterLayout struct { | type characterLayout struct { | ||||||
| 	x         int | 	x         int | ||||||
| @ -95,7 +95,7 @@ func (drawer *TextDrawer) SetAlignment (align Align) { | |||||||
| 
 | 
 | ||||||
| // Draw draws the drawer's text onto the specified canvas at the given offset. | // Draw draws the drawer's text onto the specified canvas at the given offset. | ||||||
| func (drawer *TextDrawer) Draw ( | func (drawer *TextDrawer) Draw ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	source      Pattern, | 	source      Pattern, | ||||||
| 	offset      image.Point, | 	offset      image.Point, | ||||||
| ) ( | ) ( | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| package tomo | package tomo | ||||||
| 
 | 
 | ||||||
| import "errors" | import "errors" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/data" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| // Backend represents a connection to a display server, or something similar. | // Backend represents a connection to a display server, or something similar. | ||||||
| // It is capable of managing an event loop, and creating windows. | // It is capable of managing an event loop, and creating windows. | ||||||
| @ -19,13 +21,13 @@ type Backend interface { | |||||||
| 	// NewWindow creates a new window with the specified width and height, | 	// NewWindow creates a new window with the specified width and height, | ||||||
| 	// and returns a struct representing it that fulfills the Window | 	// and returns a struct representing it that fulfills the Window | ||||||
| 	// interface. | 	// interface. | ||||||
| 	NewWindow (width, height int) (window Window, err error) | 	NewWindow (width, height int) (window elements.Window, err error) | ||||||
| 
 | 
 | ||||||
| 	// Copy puts data into the clipboard. | 	// Copy puts data into the clipboard. | ||||||
| 	Copy (Data) | 	Copy (data.Data) | ||||||
| 
 | 
 | ||||||
| 	// Paste returns the data currently in the clipboard. | 	// Paste returns the data currently in the clipboard. | ||||||
| 	Paste (accept []Mime) (Data) | 	Paste (accept []data.Mime) (data.Data) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // BackendFactory represents a function capable of constructing a backend | // BackendFactory represents a function capable of constructing a backend | ||||||
|  | |||||||
| @ -3,64 +3,64 @@ package x | |||||||
| import "unicode" | import "unicode" | ||||||
| import "github.com/jezek/xgb/xproto" | import "github.com/jezek/xgb/xproto" | ||||||
| import "github.com/jezek/xgbutil/keybind" | import "github.com/jezek/xgbutil/keybind" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| 
 | 
 | ||||||
| // when making changes to this file, look at keysymdef.h and | // when making changes to this file, look at keysymdef.h and | ||||||
| // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html | // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html | ||||||
| 
 | 
 | ||||||
| var buttonCodeTable = map[xproto.Keysym] tomo.Key { | var buttonCodeTable = map[xproto.Keysym] input.Key { | ||||||
| 	0xFFFFFF: tomo.KeyNone, | 	0xFFFFFF: input.KeyNone, | ||||||
| 
 | 
 | ||||||
| 	0xFF63: tomo.KeyInsert, | 	0xFF63: input.KeyInsert, | ||||||
| 	0xFF67: tomo.KeyMenu, | 	0xFF67: input.KeyMenu, | ||||||
| 	0xFF61: tomo.KeyPrintScreen, | 	0xFF61: input.KeyPrintScreen, | ||||||
| 	0xFF6B: tomo.KeyPause, | 	0xFF6B: input.KeyPause, | ||||||
| 	0xFFE5: tomo.KeyCapsLock, | 	0xFFE5: input.KeyCapsLock, | ||||||
| 	0xFF14: tomo.KeyScrollLock, | 	0xFF14: input.KeyScrollLock, | ||||||
| 	0xFF7F: tomo.KeyNumLock, | 	0xFF7F: input.KeyNumLock, | ||||||
| 	0xFF08: tomo.KeyBackspace, | 	0xFF08: input.KeyBackspace, | ||||||
| 	0xFF09: tomo.KeyTab, | 	0xFF09: input.KeyTab, | ||||||
| 	0xFE20: tomo.KeyTab, | 	0xFE20: input.KeyTab, | ||||||
| 	0xFF0D: tomo.KeyEnter, | 	0xFF0D: input.KeyEnter, | ||||||
| 	0xFF1B: tomo.KeyEscape, | 	0xFF1B: input.KeyEscape, | ||||||
| 	 | 	 | ||||||
| 	0xFF52: tomo.KeyUp, | 	0xFF52: input.KeyUp, | ||||||
| 	0xFF54: tomo.KeyDown, | 	0xFF54: input.KeyDown, | ||||||
| 	0xFF51: tomo.KeyLeft, | 	0xFF51: input.KeyLeft, | ||||||
| 	0xFF53: tomo.KeyRight, | 	0xFF53: input.KeyRight, | ||||||
| 	0xFF55: tomo.KeyPageUp, | 	0xFF55: input.KeyPageUp, | ||||||
| 	0xFF56: tomo.KeyPageDown, | 	0xFF56: input.KeyPageDown, | ||||||
| 	0xFF50: tomo.KeyHome, | 	0xFF50: input.KeyHome, | ||||||
| 	0xFF57: tomo.KeyEnd, | 	0xFF57: input.KeyEnd, | ||||||
| 	 | 	 | ||||||
| 	0xFFE1: tomo.KeyLeftShift, | 	0xFFE1: input.KeyLeftShift, | ||||||
| 	0xFFE2: tomo.KeyRightShift, | 	0xFFE2: input.KeyRightShift, | ||||||
| 	0xFFE3: tomo.KeyLeftControl, | 	0xFFE3: input.KeyLeftControl, | ||||||
| 	0xFFE4: tomo.KeyRightControl, | 	0xFFE4: input.KeyRightControl, | ||||||
| 
 | 
 | ||||||
| 	0xFFE7: tomo.KeyLeftMeta, | 	0xFFE7: input.KeyLeftMeta, | ||||||
| 	0xFFE8: tomo.KeyRightMeta, | 	0xFFE8: input.KeyRightMeta, | ||||||
| 	0xFFE9: tomo.KeyLeftAlt, | 	0xFFE9: input.KeyLeftAlt, | ||||||
| 	0xFFEA: tomo.KeyRightAlt, | 	0xFFEA: input.KeyRightAlt, | ||||||
| 	0xFFEB: tomo.KeyLeftSuper, | 	0xFFEB: input.KeyLeftSuper, | ||||||
| 	0xFFEC: tomo.KeyRightSuper, | 	0xFFEC: input.KeyRightSuper, | ||||||
| 	0xFFED: tomo.KeyLeftHyper, | 	0xFFED: input.KeyLeftHyper, | ||||||
| 	0xFFEE: tomo.KeyRightHyper, | 	0xFFEE: input.KeyRightHyper, | ||||||
| 	 | 	 | ||||||
| 	0xFFFF: tomo.KeyDelete, | 	0xFFFF: input.KeyDelete, | ||||||
| 	 | 	 | ||||||
| 	0xFFBE: tomo.KeyF1, | 	0xFFBE: input.KeyF1, | ||||||
| 	0xFFBF: tomo.KeyF2, | 	0xFFBF: input.KeyF2, | ||||||
| 	0xFFC0: tomo.KeyF3, | 	0xFFC0: input.KeyF3, | ||||||
| 	0xFFC1: tomo.KeyF4, | 	0xFFC1: input.KeyF4, | ||||||
| 	0xFFC2: tomo.KeyF5, | 	0xFFC2: input.KeyF5, | ||||||
| 	0xFFC3: tomo.KeyF6, | 	0xFFC3: input.KeyF6, | ||||||
| 	0xFFC4: tomo.KeyF7, | 	0xFFC4: input.KeyF7, | ||||||
| 	0xFFC5: tomo.KeyF8, | 	0xFFC5: input.KeyF8, | ||||||
| 	0xFFC6: tomo.KeyF9, | 	0xFFC6: input.KeyF9, | ||||||
| 	0xFFC7: tomo.KeyF10, | 	0xFFC7: input.KeyF10, | ||||||
| 	0xFFC8: tomo.KeyF11, | 	0xFFC8: input.KeyF11, | ||||||
| 	0xFFC9: tomo.KeyF12, | 	0xFFC9: input.KeyF12, | ||||||
| 
 | 
 | ||||||
| 	// TODO: send this whenever a compose key, dead key, etc is pressed, | 	// TODO: send this whenever a compose key, dead key, etc is pressed, | ||||||
| 	// and then send the resulting character while witholding the key | 	// and then send the resulting character while witholding the key | ||||||
| @ -68,46 +68,46 @@ var buttonCodeTable = map[xproto.Keysym] tomo.Key { | |||||||
| 	// concerned, a magical key with the final character was pressed and the | 	// concerned, a magical key with the final character was pressed and the | ||||||
| 	// KeyDead key is just so that the program might provide some visual | 	// KeyDead key is just so that the program might provide some visual | ||||||
| 	// feedback to the user while input is being waited for. | 	// feedback to the user while input is being waited for. | ||||||
| 	0xFF20: tomo.KeyDead, | 	0xFF20: input.KeyDead, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var keypadCodeTable = map[xproto.Keysym] tomo.Key { | var keypadCodeTable = map[xproto.Keysym] input.Key { | ||||||
| 	0xff80: tomo.Key(' '), | 	0xff80: input.Key(' '), | ||||||
| 	0xff89: tomo.KeyTab, | 	0xff89: input.KeyTab, | ||||||
| 	0xff8d: tomo.KeyEnter, | 	0xff8d: input.KeyEnter, | ||||||
| 	0xff91: tomo.KeyF1, | 	0xff91: input.KeyF1, | ||||||
| 	0xff92: tomo.KeyF2, | 	0xff92: input.KeyF2, | ||||||
| 	0xff93: tomo.KeyF3, | 	0xff93: input.KeyF3, | ||||||
| 	0xff94: tomo.KeyF4, | 	0xff94: input.KeyF4, | ||||||
| 	0xff95: tomo.KeyHome, | 	0xff95: input.KeyHome, | ||||||
| 	0xff96: tomo.KeyLeft, | 	0xff96: input.KeyLeft, | ||||||
| 	0xff97: tomo.KeyUp, | 	0xff97: input.KeyUp, | ||||||
| 	0xff98: tomo.KeyRight, | 	0xff98: input.KeyRight, | ||||||
| 	0xff99: tomo.KeyDown, | 	0xff99: input.KeyDown, | ||||||
| 	0xff9a: tomo.KeyPageUp, | 	0xff9a: input.KeyPageUp, | ||||||
| 	0xff9b: tomo.KeyPageDown, | 	0xff9b: input.KeyPageDown, | ||||||
| 	0xff9c: tomo.KeyEnd, | 	0xff9c: input.KeyEnd, | ||||||
| 	0xff9d: tomo.KeyHome, | 	0xff9d: input.KeyHome, | ||||||
| 	0xff9e: tomo.KeyInsert, | 	0xff9e: input.KeyInsert, | ||||||
| 	0xff9f: tomo.KeyDelete, | 	0xff9f: input.KeyDelete, | ||||||
| 	0xffbd: tomo.Key('='), | 	0xffbd: input.Key('='), | ||||||
| 	0xffaa: tomo.Key('*'), | 	0xffaa: input.Key('*'), | ||||||
| 	0xffab: tomo.Key('+'), | 	0xffab: input.Key('+'), | ||||||
| 	0xffac: tomo.Key(','), | 	0xffac: input.Key(','), | ||||||
| 	0xffad: tomo.Key('-'), | 	0xffad: input.Key('-'), | ||||||
| 	0xffae: tomo.Key('.'), | 	0xffae: input.Key('.'), | ||||||
| 	0xffaf: tomo.Key('/'), | 	0xffaf: input.Key('/'), | ||||||
| 
 | 
 | ||||||
| 	0xffb0: tomo.Key('0'), | 	0xffb0: input.Key('0'), | ||||||
| 	0xffb1: tomo.Key('1'), | 	0xffb1: input.Key('1'), | ||||||
| 	0xffb2: tomo.Key('2'), | 	0xffb2: input.Key('2'), | ||||||
| 	0xffb3: tomo.Key('3'), | 	0xffb3: input.Key('3'), | ||||||
| 	0xffb4: tomo.Key('4'), | 	0xffb4: input.Key('4'), | ||||||
| 	0xffb5: tomo.Key('5'), | 	0xffb5: input.Key('5'), | ||||||
| 	0xffb6: tomo.Key('6'), | 	0xffb6: input.Key('6'), | ||||||
| 	0xffb7: tomo.Key('7'), | 	0xffb7: input.Key('7'), | ||||||
| 	0xffb8: tomo.Key('8'), | 	0xffb8: input.Key('8'), | ||||||
| 	0xffb9: tomo.Key('9'), | 	0xffb9: input.Key('9'), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // initializeKeymapInformation grabs keyboard mapping information from the X | // initializeKeymapInformation grabs keyboard mapping information from the X | ||||||
| @ -168,7 +168,7 @@ func (backend *Backend) keycodeToKey ( | |||||||
| 	keycode xproto.Keycode, | 	keycode xproto.Keycode, | ||||||
| 	state   uint16, | 	state   uint16, | ||||||
| ) ( | ) ( | ||||||
| 	button    tomo.Key, | 	button    input.Key, | ||||||
| 	numberPad bool, | 	numberPad bool, | ||||||
| ) { | ) { | ||||||
| 	// PARAGRAPH 3 | 	// PARAGRAPH 3 | ||||||
| @ -359,7 +359,7 @@ func (backend *Backend) keycodeToKey ( | |||||||
| 	if numberPad { return } | 	if numberPad { return } | ||||||
| 
 | 
 | ||||||
| 	// otherwise, use the rune | 	// otherwise, use the rune | ||||||
| 	button = tomo.Key(selectedRune) | 	button = input.Key(selectedRune) | ||||||
| 	 | 	 | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package x | package x | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| import "github.com/jezek/xgbutil" | import "github.com/jezek/xgbutil" | ||||||
| import "github.com/jezek/xgb/xproto" | import "github.com/jezek/xgb/xproto" | ||||||
| @ -98,9 +99,9 @@ func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo | |||||||
| func (window *Window) modifiersFromState ( | func (window *Window) modifiersFromState ( | ||||||
| 	state uint16, | 	state uint16, | ||||||
| ) ( | ) ( | ||||||
| 	modifiers tomo.Modifiers, | 	modifiers input.Modifiers, | ||||||
| ) { | ) { | ||||||
| 	return tomo.Modifiers { | 	return input.Modifiers { | ||||||
| 		Shift: | 		Shift: | ||||||
| 			(state & xproto.ModMaskShift)                    > 0 || | 			(state & xproto.ModMaskShift)                    > 0 || | ||||||
| 			(state & window.backend.modifierMasks.shiftLock) > 0, | 			(state & window.backend.modifierMasks.shiftLock) > 0, | ||||||
| @ -123,18 +124,18 @@ func (window *Window) handleKeyPress ( | |||||||
| 	modifiers := window.modifiersFromState(keyEvent.State) | 	modifiers := window.modifiersFromState(keyEvent.State) | ||||||
| 	modifiers.NumberPad = numberPad | 	modifiers.NumberPad = numberPad | ||||||
| 
 | 
 | ||||||
| 	if key == tomo.KeyTab && modifiers.Alt { | 	if key == input.KeyTab && modifiers.Alt { | ||||||
| 		if child, ok := window.child.(tomo.Focusable); ok { | 		if child, ok := window.child.(elements.Focusable); ok { | ||||||
| 			direction := tomo.KeynavDirectionForward | 			direction := input.KeynavDirectionForward | ||||||
| 			if modifiers.Shift { | 			if modifiers.Shift { | ||||||
| 				direction = tomo.KeynavDirectionBackward | 				direction = input.KeynavDirectionBackward | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if !child.HandleFocus(direction) { | 			if !child.HandleFocus(direction) { | ||||||
| 				child.HandleUnfocus() | 				child.HandleUnfocus() | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else if child, ok := window.child.(tomo.KeyboardTarget); ok { | 	} else if child, ok := window.child.(elements.KeyboardTarget); ok { | ||||||
| 		child.HandleKeyDown(key, modifiers) | 		child.HandleKeyDown(key, modifiers) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -168,7 +169,7 @@ func (window *Window) handleKeyRelease ( | |||||||
| 	modifiers := window.modifiersFromState(keyEvent.State) | 	modifiers := window.modifiersFromState(keyEvent.State) | ||||||
| 	modifiers.NumberPad = numberPad | 	modifiers.NumberPad = numberPad | ||||||
| 	 | 	 | ||||||
| 	if child, ok := window.child.(tomo.KeyboardTarget); ok { | 	if child, ok := window.child.(elements.KeyboardTarget); ok { | ||||||
| 		child.HandleKeyUp(key, modifiers) | 		child.HandleKeyUp(key, modifiers) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -179,7 +180,7 @@ func (window *Window) handleButtonPress ( | |||||||
| ) { | ) { | ||||||
| 	if window.child == nil { return } | 	if window.child == nil { return } | ||||||
| 	 | 	 | ||||||
| 	if child, ok := window.child.(tomo.MouseTarget); ok { | 	if child, ok := window.child.(elements.MouseTarget); ok { | ||||||
| 		buttonEvent := *event.ButtonPressEvent | 		buttonEvent := *event.ButtonPressEvent | ||||||
| 		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { | 		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { | ||||||
| 			sum := scrollSum { } | 			sum := scrollSum { } | ||||||
| @ -193,7 +194,7 @@ func (window *Window) handleButtonPress ( | |||||||
| 			child.HandleMouseDown ( | 			child.HandleMouseDown ( | ||||||
| 				int(buttonEvent.EventX), | 				int(buttonEvent.EventX), | ||||||
| 				int(buttonEvent.EventY), | 				int(buttonEvent.EventY), | ||||||
| 				tomo.Button(buttonEvent.Detail)) | 				input.Button(buttonEvent.Detail)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -205,13 +206,13 @@ func (window *Window) handleButtonRelease ( | |||||||
| ) { | ) { | ||||||
| 	if window.child == nil { return } | 	if window.child == nil { return } | ||||||
| 	 | 	 | ||||||
| 	if child, ok := window.child.(tomo.MouseTarget); ok { | 	if child, ok := window.child.(elements.MouseTarget); ok { | ||||||
| 		buttonEvent := *event.ButtonReleaseEvent | 		buttonEvent := *event.ButtonReleaseEvent | ||||||
| 		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return } | 		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return } | ||||||
| 		child.HandleMouseUp ( | 		child.HandleMouseUp ( | ||||||
| 			int(buttonEvent.EventX), | 			int(buttonEvent.EventX), | ||||||
| 			int(buttonEvent.EventY), | 			int(buttonEvent.EventY), | ||||||
| 			tomo.Button(buttonEvent.Detail)) | 			input.Button(buttonEvent.Detail)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -221,7 +222,7 @@ func (window *Window) handleMotionNotify ( | |||||||
| ) { | ) { | ||||||
| 	if window.child == nil { return } | 	if window.child == nil { return } | ||||||
| 	 | 	 | ||||||
| 	if child, ok := window.child.(tomo.MouseTarget); ok { | 	if child, ok := window.child.(elements.MouseTarget); ok { | ||||||
| 		motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent) | 		motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent) | ||||||
| 		child.HandleMouseMove ( | 		child.HandleMouseMove ( | ||||||
| 			int(motionEvent.EventX), | 			int(motionEvent.EventX), | ||||||
|  | |||||||
| @ -7,14 +7,16 @@ import "github.com/jezek/xgbutil/icccm" | |||||||
| import "github.com/jezek/xgbutil/xevent" | import "github.com/jezek/xgbutil/xevent" | ||||||
| import "github.com/jezek/xgbutil/xwindow" | import "github.com/jezek/xgbutil/xwindow" | ||||||
| import "github.com/jezek/xgbutil/xgraphics" | import "github.com/jezek/xgbutil/xgraphics" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| type Window struct { | type Window struct { | ||||||
| 	backend *Backend | 	backend *Backend | ||||||
| 	xWindow *xwindow.Window | 	xWindow *xwindow.Window | ||||||
| 	xCanvas *xgraphics.Image | 	xCanvas *xgraphics.Image | ||||||
| 	canvas  tomo.BasicCanvas | 	canvas  canvas.BasicCanvas | ||||||
| 	child   tomo.Element | 	child   elements.Element | ||||||
| 	onClose func () | 	onClose func () | ||||||
| 	skipChildDrawCallback bool | 	skipChildDrawCallback bool | ||||||
| 
 | 
 | ||||||
| @ -27,7 +29,7 @@ type Window struct { | |||||||
| func (backend *Backend) NewWindow ( | func (backend *Backend) NewWindow ( | ||||||
| 	width, height int, | 	width, height int, | ||||||
| ) ( | ) ( | ||||||
| 	output tomo.Window, | 	output elements.Window, | ||||||
| 	err error, | 	err error, | ||||||
| ) { | ) { | ||||||
| 	if backend == nil { panic("nil backend") } | 	if backend == nil { panic("nil backend") } | ||||||
| @ -79,16 +81,16 @@ func (backend *Backend) NewWindow ( | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) Adopt (child tomo.Element) { | func (window *Window) Adopt (child elements.Element) { | ||||||
| 	// disown previous child | 	// disown previous child | ||||||
| 	if window.child != nil { | 	if window.child != nil { | ||||||
| 		window.child.OnDamage(nil) | 		window.child.OnDamage(nil) | ||||||
| 		window.child.OnMinimumSizeChange(nil) | 		window.child.OnMinimumSizeChange(nil) | ||||||
| 	} | 	} | ||||||
| 	if previousChild, ok := window.child.(tomo.Flexible); ok { | 	if previousChild, ok := window.child.(elements.Flexible); ok { | ||||||
| 		previousChild.OnFlexibleHeightChange(nil) | 		previousChild.OnFlexibleHeightChange(nil) | ||||||
| 	} | 	} | ||||||
| 	if previousChild, ok := window.child.(tomo.Focusable); ok { | 	if previousChild, ok := window.child.(elements.Focusable); ok { | ||||||
| 		previousChild.OnFocusRequest(nil) | 		previousChild.OnFocusRequest(nil) | ||||||
| 		previousChild.OnFocusMotionRequest(nil) | 		previousChild.OnFocusMotionRequest(nil) | ||||||
| 		if previousChild.Focused() { | 		if previousChild.Focused() { | ||||||
| @ -98,10 +100,10 @@ func (window *Window) Adopt (child tomo.Element) { | |||||||
| 	 | 	 | ||||||
| 	// adopt new child | 	// adopt new child | ||||||
| 	window.child = child | 	window.child = child | ||||||
| 	if newChild, ok := child.(tomo.Flexible); ok { | 	if newChild, ok := child.(elements.Flexible); ok { | ||||||
| 		newChild.OnFlexibleHeightChange(window.resizeChildToFit) | 		newChild.OnFlexibleHeightChange(window.resizeChildToFit) | ||||||
| 	} | 	} | ||||||
| 	if newChild, ok := child.(tomo.Focusable); ok { | 	if newChild, ok := child.(elements.Focusable); ok { | ||||||
| 		newChild.OnFocusRequest(window.childSelectionRequestCallback) | 		newChild.OnFocusRequest(window.childSelectionRequestCallback) | ||||||
| 	} | 	} | ||||||
| 	if child != nil { | 	if child != nil { | ||||||
| @ -116,7 +118,7 @@ func (window *Window) Adopt (child tomo.Element) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) Child () (child tomo.Element) { | func (window *Window) Child () (child elements.Element) { | ||||||
| 	child = window.child | 	child = window.child | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -229,7 +231,7 @@ func (window *Window) redrawChildEntirely () { | |||||||
| 
 | 
 | ||||||
| func (window *Window) resizeChildToFit () { | func (window *Window) resizeChildToFit () { | ||||||
| 	window.skipChildDrawCallback = true | 	window.skipChildDrawCallback = true | ||||||
| 	if child, ok := window.child.(tomo.Flexible); ok { | 	if child, ok := window.child.(elements.Flexible); ok { | ||||||
| 		minimumHeight := child.FlexibleHeightFor(window.metrics.width) | 		minimumHeight := child.FlexibleHeightFor(window.metrics.width) | ||||||
| 		minimumWidth, _ := child.MinimumSize() | 		minimumWidth, _ := child.MinimumSize() | ||||||
| 		 | 		 | ||||||
| @ -252,12 +254,12 @@ func (window *Window) resizeChildToFit () { | |||||||
| 	window.skipChildDrawCallback = false | 	window.skipChildDrawCallback = false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) childDrawCallback (region tomo.Canvas) { | func (window *Window) childDrawCallback (region canvas.Canvas) { | ||||||
| 	if window.skipChildDrawCallback { return } | 	if window.skipChildDrawCallback { return } | ||||||
| 	window.pushRegion(window.paste(region)) | 	window.pushRegion(window.paste(region)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) paste (canvas tomo.Canvas) (updatedRegion image.Rectangle) { | func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) { | ||||||
| 	data, stride := canvas.Buffer() | 	data, stride := canvas.Buffer() | ||||||
| 	bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds()) | 	bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds()) | ||||||
| 	for x := bounds.Min.X; x < bounds.Max.X; x ++ { | 	for x := bounds.Min.X; x < bounds.Max.X; x ++ { | ||||||
| @ -293,18 +295,18 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) childSelectionRequestCallback () (granted bool) { | func (window *Window) childSelectionRequestCallback () (granted bool) { | ||||||
| 	if child, ok := window.child.(tomo.Focusable); ok { | 	if child, ok := window.child.(elements.Focusable); ok { | ||||||
| 		child.HandleFocus(tomo.KeynavDirectionNeutral) | 		child.HandleFocus(input.KeynavDirectionNeutral) | ||||||
| 	} | 	} | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (window *Window) childSelectionMotionRequestCallback ( | func (window *Window) childSelectionMotionRequestCallback ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	granted bool, | 	granted bool, | ||||||
| ) { | ) { | ||||||
| 	if child, ok := window.child.(tomo.Focusable); ok { | 	if child, ok := window.child.(elements.Focusable); ok { | ||||||
| 		if !child.HandleFocus(direction) { | 		if !child.HandleFocus(direction) { | ||||||
| 			child.HandleUnfocus() | 			child.HandleUnfocus() | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package x | package x | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/data" | ||||||
| 
 | 
 | ||||||
| import "github.com/jezek/xgbutil" | import "github.com/jezek/xgbutil" | ||||||
| import "github.com/jezek/xgb/xproto" | import "github.com/jezek/xgb/xproto" | ||||||
| @ -81,14 +82,14 @@ func (backend *Backend) Do (callback func ()) { | |||||||
| 
 | 
 | ||||||
| // Copy puts data into the clipboard. This method is not yet implemented and | // Copy puts data into the clipboard. This method is not yet implemented and | ||||||
| // will do nothing! | // will do nothing! | ||||||
| func (backend *Backend) Copy (data tomo.Data) { | func (backend *Backend) Copy (data data.Data) { | ||||||
| 	backend.assert() | 	backend.assert() | ||||||
| 	// TODO | 	// TODO | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Paste returns the data currently in the clipboard. This method may | // Paste returns the data currently in the clipboard. This method may | ||||||
| // return nil. This method is not yet implemented and will do nothing! | // return nil. This method is not yet implemented and will do nothing! | ||||||
| func (backend *Backend) Paste (accept []tomo.Mime) (data tomo.Data) { | func (backend *Backend) Paste (accept []data.Mime) (data data.Data) { | ||||||
| 	backend.assert() | 	backend.assert() | ||||||
| 	// TODO | 	// TODO | ||||||
| 	return | 	return | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package tomo | package canvas | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "image/draw" | import "image/draw" | ||||||
							
								
								
									
										22
									
								
								config/config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								config/config.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | package config | ||||||
|  | 
 | ||||||
|  | // Padding returns the amount of internal padding elements should have. An | ||||||
|  | // element's inner content (such as text) should be inset by this amount, | ||||||
|  | // in addition to the inset returned by the pattern of its background. When | ||||||
|  | // using the aforementioned inset values to calculate the element's minimum size | ||||||
|  | // or the position and alignment of its content, all parameters in the | ||||||
|  | // PatternState should be unset except for Case. | ||||||
|  | func Padding () int { | ||||||
|  | 	return 7 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Margin returns how much space should be put in between elements. | ||||||
|  | func Margin () int { | ||||||
|  | 	return 8 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // HandleWidth returns how large grab handles should typically be. This is | ||||||
|  | // important for accessibility reasons. | ||||||
|  | func HandleWidth () int { | ||||||
|  | 	return 16 | ||||||
|  | } | ||||||
| @ -1,4 +1,4 @@ | |||||||
| package tomo | package data | ||||||
| 
 | 
 | ||||||
| import "io" | import "io" | ||||||
| 
 | 
 | ||||||
| @ -1,7 +1,7 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| @ -38,10 +38,10 @@ func NewButton (text string) (element *Button) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Button) HandleMouseDown (x, y int, button tomo.Button) { | func (element *Button) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	if !element.Enabled()  { return } | 	if !element.Enabled()  { return } | ||||||
| 	if !element.Focused() { element.Focus() } | 	if !element.Focused() { element.Focus() } | ||||||
| 	if button != tomo.ButtonLeft { return } | 	if button != input.ButtonLeft { return } | ||||||
| 	element.pressed = true | 	element.pressed = true | ||||||
| 	if element.core.HasImage() { | 	if element.core.HasImage() { | ||||||
| 		element.draw() | 		element.draw() | ||||||
| @ -49,8 +49,8 @@ func (element *Button) HandleMouseDown (x, y int, button tomo.Button) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Button) HandleMouseUp (x, y int, button tomo.Button) { | func (element *Button) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	if button != tomo.ButtonLeft { return } | 	if button != input.ButtonLeft { return } | ||||||
| 	element.pressed = false | 	element.pressed = false | ||||||
| 	if element.core.HasImage() { | 	if element.core.HasImage() { | ||||||
| 		element.draw() | 		element.draw() | ||||||
| @ -69,9 +69,9 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) { | |||||||
| func (element *Button) HandleMouseMove (x, y int) { } | func (element *Button) HandleMouseMove (x, y int) { } | ||||||
| func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | ||||||
| 
 | 
 | ||||||
| func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if !element.Enabled() { return } | 	if !element.Enabled() { return } | ||||||
| 	if key == tomo.KeyEnter { | 	if key == input.KeyEnter { | ||||||
| 		element.pressed = true | 		element.pressed = true | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
| 			element.draw() | 			element.draw() | ||||||
| @ -80,8 +80,8 @@ func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Button) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { | func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) { | ||||||
| 	if key == tomo.KeyEnter && element.pressed { | 	if key == input.KeyEnter && element.pressed { | ||||||
| 		element.pressed = false | 		element.pressed = false | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
| 			element.draw() | 			element.draw() | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| @ -39,7 +39,7 @@ func NewCheckbox (text string, checked bool) (element *Checkbox) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) { | func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	if !element.Enabled() { return } | 	if !element.Enabled() { return } | ||||||
| 	element.Focus() | 	element.Focus() | ||||||
| 	element.pressed = true | 	element.pressed = true | ||||||
| @ -49,8 +49,8 @@ func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) { | func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	if button != tomo.ButtonLeft || !element.pressed { return } | 	if button != input.ButtonLeft || !element.pressed { return } | ||||||
| 
 | 
 | ||||||
| 	element.pressed = false | 	element.pressed = false | ||||||
| 	within := image.Point { x, y }. | 	within := image.Point { x, y }. | ||||||
| @ -71,8 +71,8 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) { | |||||||
| func (element *Checkbox) HandleMouseMove (x, y int) { } | func (element *Checkbox) HandleMouseMove (x, y int) { } | ||||||
| func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | ||||||
| 
 | 
 | ||||||
| func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if key == tomo.KeyEnter { | 	if key == input.KeyEnter { | ||||||
| 		element.pressed = true | 		element.pressed = true | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
| 			element.draw() | 			element.draw() | ||||||
| @ -81,8 +81,8 @@ func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Checkbox) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if key == tomo.KeyEnter && element.pressed { | 	if key == input.KeyEnter && element.pressed { | ||||||
| 		element.pressed = false | 		element.pressed = false | ||||||
| 		element.checked = !element.checked | 		element.checked = !element.checked | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/layouts" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| 
 | 
 | ||||||
| var containerCase = theme.C("basic", "container") | var containerCase = theme.C("basic", "container") | ||||||
| @ -14,21 +17,21 @@ type Container struct { | |||||||
| 	*core.Core | 	*core.Core | ||||||
| 	core core.CoreControl | 	core core.CoreControl | ||||||
| 
 | 
 | ||||||
| 	layout    tomo.Layout | 	layout    layouts.Layout | ||||||
| 	children  []tomo.LayoutEntry | 	children  []layouts.LayoutEntry | ||||||
| 	drags     [10]tomo.MouseTarget | 	drags     [10]elements.MouseTarget | ||||||
| 	warping   bool | 	warping   bool | ||||||
| 	focused   bool | 	focused   bool | ||||||
| 	focusable bool | 	focusable bool | ||||||
| 	flexible  bool | 	flexible  bool | ||||||
| 	 | 	 | ||||||
| 	onFocusRequest func () (granted bool) | 	onFocusRequest func () (granted bool) | ||||||
| 	onFocusMotionRequest func (tomo.KeynavDirection) (granted bool) | 	onFocusMotionRequest func (input.KeynavDirection) (granted bool) | ||||||
| 	onFlexibleHeightChange func () | 	onFlexibleHeightChange func () | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewContainer creates a new container. | // NewContainer creates a new container. | ||||||
| func NewContainer (layout tomo.Layout) (element *Container) { | func NewContainer (layout layouts.Layout) (element *Container) { | ||||||
| 	element = &Container { } | 	element = &Container { } | ||||||
| 	element.Core, element.core = core.NewCore(element.redoAll) | 	element.Core, element.core = core.NewCore(element.redoAll) | ||||||
| 	element.SetLayout(layout) | 	element.SetLayout(layout) | ||||||
| @ -36,7 +39,7 @@ func NewContainer (layout tomo.Layout) (element *Container) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetLayout sets the layout of this container. | // SetLayout sets the layout of this container. | ||||||
| func (element *Container) SetLayout (layout tomo.Layout) { | func (element *Container) SetLayout (layout layouts.Layout) { | ||||||
| 	element.layout = layout | 	element.layout = layout | ||||||
| 	if element.core.HasImage() { | 	if element.core.HasImage() { | ||||||
| 		element.redoAll() | 		element.redoAll() | ||||||
| @ -47,28 +50,28 @@ func (element *Container) SetLayout (layout tomo.Layout) { | |||||||
| // Adopt adds a new child element to the container. If expand is set to true, | // Adopt adds a new child element to the container. If expand is set to true, | ||||||
| // the element will expand (instead of contract to its minimum size), in | // the element will expand (instead of contract to its minimum size), in | ||||||
| // whatever way is defined by the current layout. | // whatever way is defined by the current layout. | ||||||
| func (element *Container) Adopt (child tomo.Element, expand bool) { | func (element *Container) Adopt (child elements.Element, expand bool) { | ||||||
| 	// set event handlers | 	// set event handlers | ||||||
| 	child.OnDamage (func (region tomo.Canvas) { | 	child.OnDamage (func (region canvas.Canvas) { | ||||||
| 		element.core.DamageRegion(region.Bounds()) | 		element.core.DamageRegion(region.Bounds()) | ||||||
| 	}) | 	}) | ||||||
| 	child.OnMinimumSizeChange(element.updateMinimumSize) | 	child.OnMinimumSizeChange(element.updateMinimumSize) | ||||||
| 	if child0, ok := child.(tomo.Flexible); ok { | 	if child0, ok := child.(elements.Flexible); ok { | ||||||
| 		child0.OnFlexibleHeightChange(element.updateMinimumSize) | 		child0.OnFlexibleHeightChange(element.updateMinimumSize) | ||||||
| 	} | 	} | ||||||
| 	if child0, ok := child.(tomo.Focusable); ok { | 	if child0, ok := child.(elements.Focusable); ok { | ||||||
| 		child0.OnFocusRequest (func () (granted bool) { | 		child0.OnFocusRequest (func () (granted bool) { | ||||||
| 			return element.childFocusRequestCallback(child0) | 			return element.childFocusRequestCallback(child0) | ||||||
| 		}) | 		}) | ||||||
| 		child0.OnFocusMotionRequest ( | 		child0.OnFocusMotionRequest ( | ||||||
| 			func (direction tomo.KeynavDirection) (granted bool) { | 			func (direction input.KeynavDirection) (granted bool) { | ||||||
| 				if element.onFocusMotionRequest == nil { return } | 				if element.onFocusMotionRequest == nil { return } | ||||||
| 				return element.onFocusMotionRequest(direction) | 				return element.onFocusMotionRequest(direction) | ||||||
| 			}) | 			}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// add child | 	// add child | ||||||
| 	element.children = append (element.children, tomo.LayoutEntry { | 	element.children = append (element.children, layouts.LayoutEntry { | ||||||
| 		Element: child, | 		Element: child, | ||||||
| 		Expand:  expand, | 		Expand:  expand, | ||||||
| 	}) | 	}) | ||||||
| @ -106,7 +109,7 @@ func (element *Container) Warp (callback func ()) { | |||||||
| 
 | 
 | ||||||
| // Disown removes the given child from the container if it is contained within | // Disown removes the given child from the container if it is contained within | ||||||
| // it. | // it. | ||||||
| func (element *Container) Disown (child tomo.Element) { | func (element *Container) Disown (child elements.Element) { | ||||||
| 	for index, entry := range element.children { | 	for index, entry := range element.children { | ||||||
| 		if entry.Element == child { | 		if entry.Element == child { | ||||||
| 			element.clearChildEventHandlers(entry.Element) | 			element.clearChildEventHandlers(entry.Element) | ||||||
| @ -125,18 +128,18 @@ func (element *Container) Disown (child tomo.Element) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) clearChildEventHandlers (child tomo.Element) { | func (element *Container) clearChildEventHandlers (child elements.Element) { | ||||||
| 	child.DrawTo(nil) | 	child.DrawTo(nil) | ||||||
| 	child.OnDamage(nil) | 	child.OnDamage(nil) | ||||||
| 	child.OnMinimumSizeChange(nil) | 	child.OnMinimumSizeChange(nil) | ||||||
| 	if child0, ok := child.(tomo.Focusable); ok { | 	if child0, ok := child.(elements.Focusable); ok { | ||||||
| 		child0.OnFocusRequest(nil) | 		child0.OnFocusRequest(nil) | ||||||
| 		child0.OnFocusMotionRequest(nil) | 		child0.OnFocusMotionRequest(nil) | ||||||
| 		if child0.Focused() { | 		if child0.Focused() { | ||||||
| 			child0.HandleUnfocus() | 			child0.HandleUnfocus() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if child0, ok := child.(tomo.Flexible); ok { | 	if child0, ok := child.(elements.Flexible); ok { | ||||||
| 		child0.OnFlexibleHeightChange(nil) | 		child0.OnFlexibleHeightChange(nil) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -154,8 +157,8 @@ func (element *Container) DisownAll () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Children returns a slice containing this element's children. | // Children returns a slice containing this element's children. | ||||||
| func (element *Container) Children () (children []tomo.Element) { | func (element *Container) Children () (children []elements.Element) { | ||||||
| 	children = make([]tomo.Element, len(element.children)) | 	children = make([]elements.Element, len(element.children)) | ||||||
| 	for index, entry := range element.children { | 	for index, entry := range element.children { | ||||||
| 		children[index] = entry.Element | 		children[index] = entry.Element | ||||||
| 	} | 	} | ||||||
| @ -169,14 +172,14 @@ func (element *Container) CountChildren () (count int) { | |||||||
| 
 | 
 | ||||||
| // Child returns the child at the specified index. If the index is out of | // Child returns the child at the specified index. If the index is out of | ||||||
| // bounds, this method will return nil. | // bounds, this method will return nil. | ||||||
| func (element *Container) Child (index int) (child tomo.Element) { | func (element *Container) Child (index int) (child elements.Element) { | ||||||
| 	if index < 0 || index > len(element.children) { return } | 	if index < 0 || index > len(element.children) { return } | ||||||
| 	return element.children[index].Element | 	return element.children[index].Element | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ChildAt returns the child that contains the specified x and y coordinates. If | // ChildAt returns the child that contains the specified x and y coordinates. If | ||||||
| // there are no children at the coordinates, this method will return nil. | // there are no children at the coordinates, this method will return nil. | ||||||
| func (element *Container) ChildAt (point image.Point) (child tomo.Element) { | func (element *Container) ChildAt (point image.Point) (child elements.Element) { | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		if point.In(entry.Bounds) { | 		if point.In(entry.Bounds) { | ||||||
| 			child = entry.Element | 			child = entry.Element | ||||||
| @ -185,7 +188,7 @@ func (element *Container) ChildAt (point image.Point) (child tomo.Element) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) childPosition (child tomo.Element) (position image.Point) { | func (element *Container) childPosition (child elements.Element) (position image.Point) { | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		if entry.Element == child { | 		if entry.Element == child { | ||||||
| 			position = entry.Bounds.Min | 			position = entry.Bounds.Min | ||||||
| @ -209,18 +212,18 @@ func (element *Container) redoAll () { | |||||||
| 
 | 
 | ||||||
| 	// cut our canvas up and give peices to child elements | 	// cut our canvas up and give peices to child elements | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		entry.DrawTo(tomo.Cut(element, entry.Bounds)) | 		entry.DrawTo(canvas.Cut(element, entry.Bounds)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleMouseDown (x, y int, button tomo.Button) { | func (element *Container) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget) | 	child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget) | ||||||
| 	if !handlesMouse { return } | 	if !handlesMouse { return } | ||||||
| 	element.drags[button] = child | 	element.drags[button] = child | ||||||
| 	child.HandleMouseDown(x, y, button) | 	child.HandleMouseDown(x, y, button) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleMouseUp (x, y int, button tomo.Button) { | func (element *Container) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	child := element.drags[button] | 	child := element.drags[button] | ||||||
| 	if child == nil { return } | 	if child == nil { return } | ||||||
| 	element.drags[button] = nil | 	element.drags[button] = nil | ||||||
| @ -235,14 +238,14 @@ func (element *Container) HandleMouseMove (x, y int) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) { | func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) { | ||||||
| 	child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget) | 	child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget) | ||||||
| 	if !handlesMouse { return } | 	if !handlesMouse { return } | ||||||
| 	child.HandleMouseScroll(x, y, deltaX, deltaY) | 	child.HandleMouseScroll(x, y, deltaX, deltaY) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Container) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	element.forFocused (func (child tomo.Focusable) bool { | 	element.forFocused (func (child elements.Focusable) bool { | ||||||
| 		child0, handlesKeyboard := child.(tomo.KeyboardTarget) | 		child0, handlesKeyboard := child.(elements.KeyboardTarget) | ||||||
| 		if handlesKeyboard { | 		if handlesKeyboard { | ||||||
| 			child0.HandleKeyDown(key, modifiers) | 			child0.HandleKeyDown(key, modifiers) | ||||||
| 		} | 		} | ||||||
| @ -250,9 +253,9 @@ func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Container) HandleKeyUp (key input.Key, modifiers input.Modifiers) { | ||||||
| 	element.forFocused (func (child tomo.Focusable) bool { | 	element.forFocused (func (child elements.Focusable) bool { | ||||||
| 		child0, handlesKeyboard := child.(tomo.KeyboardTarget) | 		child0, handlesKeyboard := child.(elements.KeyboardTarget) | ||||||
| 		if handlesKeyboard { | 		if handlesKeyboard { | ||||||
| 			child0.HandleKeyUp(key, modifiers) | 			child0.HandleKeyUp(key, modifiers) | ||||||
| 		} | 		} | ||||||
| @ -261,7 +264,9 @@ func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) FlexibleHeightFor (width int) (height int) { | func (element *Container) FlexibleHeightFor (width int) (height int) { | ||||||
| 	return element.layout.FlexibleHeightFor(element.children, width) | 	return element.layout.FlexibleHeightFor ( | ||||||
|  | 		element.children, | ||||||
|  | 		theme.Margin(), width) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) OnFlexibleHeightChange (callback func ()) { | func (element *Container) OnFlexibleHeightChange (callback func ()) { | ||||||
| @ -278,7 +283,7 @@ func (element *Container) Focus () { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) { | func (element *Container) HandleFocus (direction input.KeynavDirection) (ok bool) { | ||||||
| 	if !element.focusable { return false } | 	if !element.focusable { return false } | ||||||
| 	direction = direction.Canon() | 	direction = direction.Canon() | ||||||
| 
 | 
 | ||||||
| @ -288,12 +293,12 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) | |||||||
| 		// the first or last focusable element depending on the | 		// the first or last focusable element depending on the | ||||||
| 		// direction. | 		// direction. | ||||||
| 		switch direction { | 		switch direction { | ||||||
| 		case tomo.KeynavDirectionNeutral, tomo.KeynavDirectionForward: | 		case input.KeynavDirectionNeutral, input.KeynavDirectionForward: | ||||||
| 			// if we recieve a neutral or forward direction, focus | 			// if we recieve a neutral or forward direction, focus | ||||||
| 			// the first focusable element. | 			// the first focusable element. | ||||||
| 			return element.focusFirstFocusableElement(direction) | 			return element.focusFirstFocusableElement(direction) | ||||||
| 		 | 		 | ||||||
| 		case tomo.KeynavDirectionBackward: | 		case input.KeynavDirectionBackward: | ||||||
| 			// if we recieve a backward direction, focus the last | 			// if we recieve a backward direction, focus the last | ||||||
| 			// focusable element. | 			// focusable element. | ||||||
| 			return element.focusLastFocusableElement(direction) | 			return element.focusLastFocusableElement(direction) | ||||||
| @ -302,7 +307,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) | |||||||
| 		// an element is currently focused, so we need to move the | 		// an element is currently focused, so we need to move the | ||||||
| 		// focus in the specified direction | 		// focus in the specified direction | ||||||
| 		firstFocusedChild := | 		firstFocusedChild := | ||||||
| 			element.children[firstFocused].Element.(tomo.Focusable) | 			element.children[firstFocused].Element.(elements.Focusable) | ||||||
| 
 | 
 | ||||||
| 		// before we move the focus, the currently focused child | 		// before we move the focus, the currently focused child | ||||||
| 		// may also be able to move its focus. if the child is able | 		// may also be able to move its focus. if the child is able | ||||||
| @ -319,7 +324,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) | |||||||
| 
 | 
 | ||||||
| 			child, focusable := | 			child, focusable := | ||||||
| 				element.children[index]. | 				element.children[index]. | ||||||
| 				Element.(tomo.Focusable) | 				Element.(elements.Focusable) | ||||||
| 			if focusable && child.HandleFocus(direction) { | 			if focusable && child.HandleFocus(direction) { | ||||||
| 				// we have found one, so we now actually move | 				// we have found one, so we now actually move | ||||||
| 				// the focus. | 				// the focus. | ||||||
| @ -334,11 +339,11 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) focusFirstFocusableElement ( | func (element *Container) focusFirstFocusableElement ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	ok bool, | 	ok bool, | ||||||
| ) { | ) { | ||||||
| 	element.forFocusable (func (child tomo.Focusable) bool { | 	element.forFocusable (func (child elements.Focusable) bool { | ||||||
| 		if child.HandleFocus(direction) { | 		if child.HandleFocus(direction) { | ||||||
| 			element.focused = true | 			element.focused = true | ||||||
| 			ok = true | 			ok = true | ||||||
| @ -350,11 +355,11 @@ func (element *Container) focusFirstFocusableElement ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) focusLastFocusableElement ( | func (element *Container) focusLastFocusableElement ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	ok bool, | 	ok bool, | ||||||
| ) { | ) { | ||||||
| 	element.forFocusableBackward (func (child tomo.Focusable) bool { | 	element.forFocusableBackward (func (child elements.Focusable) bool { | ||||||
| 		if child.HandleFocus(direction) { | 		if child.HandleFocus(direction) { | ||||||
| 			element.focused = true | 			element.focused = true | ||||||
| 			ok = true | 			ok = true | ||||||
| @ -367,7 +372,7 @@ func (element *Container) focusLastFocusableElement ( | |||||||
| 
 | 
 | ||||||
| func (element *Container) HandleUnfocus () { | func (element *Container) HandleUnfocus () { | ||||||
| 	element.focused = false | 	element.focused = false | ||||||
| 	element.forFocused (func (child tomo.Focusable) bool { | 	element.forFocused (func (child elements.Focusable) bool { | ||||||
| 		child.HandleUnfocus() | 		child.HandleUnfocus() | ||||||
| 		return true | 		return true | ||||||
| 	}) | 	}) | ||||||
| @ -378,41 +383,41 @@ func (element *Container) OnFocusRequest (callback func () (granted bool)) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) OnFocusMotionRequest ( | func (element *Container) OnFocusMotionRequest ( | ||||||
| 	callback func (direction tomo.KeynavDirection) (granted bool), | 	callback func (direction input.KeynavDirection) (granted bool), | ||||||
| ) { | ) { | ||||||
| 	element.onFocusMotionRequest = callback | 	element.onFocusMotionRequest = callback | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) forFocused (callback func (child tomo.Focusable) bool) { | func (element *Container) forFocused (callback func (child elements.Focusable) bool) { | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		child, focusable := entry.Element.(tomo.Focusable) | 		child, focusable := entry.Element.(elements.Focusable) | ||||||
| 		if focusable && child.Focused() { | 		if focusable && child.Focused() { | ||||||
| 			if !callback(child) { break } | 			if !callback(child) { break } | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) forFocusable (callback func (child tomo.Focusable) bool) { | func (element *Container) forFocusable (callback func (child elements.Focusable) bool) { | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		child, focusable := entry.Element.(tomo.Focusable) | 		child, focusable := entry.Element.(elements.Focusable) | ||||||
| 		if focusable { | 		if focusable { | ||||||
| 			if !callback(child) { break } | 			if !callback(child) { break } | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) { | func (element *Container) forFlexible (callback func (child elements.Flexible) bool) { | ||||||
| 	for _, entry := range element.children { | 	for _, entry := range element.children { | ||||||
| 		child, flexible := entry.Element.(tomo.Flexible) | 		child, flexible := entry.Element.(elements.Flexible) | ||||||
| 		if flexible { | 		if flexible { | ||||||
| 			if !callback(child) { break } | 			if !callback(child) { break } | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) forFocusableBackward (callback func (child tomo.Focusable) bool) { | func (element *Container) forFocusableBackward (callback func (child elements.Focusable) bool) { | ||||||
| 	for index := len(element.children) - 1; index >= 0; index -- { | 	for index := len(element.children) - 1; index >= 0; index -- { | ||||||
| 		child, focusable := element.children[index].Element.(tomo.Focusable) | 		child, focusable := element.children[index].Element.(elements.Focusable) | ||||||
| 		if focusable { | 		if focusable { | ||||||
| 			if !callback(child) { break } | 			if !callback(child) { break } | ||||||
| 		} | 		} | ||||||
| @ -421,7 +426,7 @@ func (element *Container) forFocusableBackward (callback func (child tomo.Focusa | |||||||
| 
 | 
 | ||||||
| func (element *Container) firstFocused () (index int) { | func (element *Container) firstFocused () (index int) { | ||||||
| 	for currentIndex, entry := range element.children { | 	for currentIndex, entry := range element.children { | ||||||
| 		child, focusable := entry.Element.(tomo.Focusable) | 		child, focusable := entry.Element.(elements.Focusable) | ||||||
| 		if focusable && child.Focused() { | 		if focusable && child.Focused() { | ||||||
| 			return currentIndex | 			return currentIndex | ||||||
| 		} | 		} | ||||||
| @ -431,12 +436,12 @@ func (element *Container) firstFocused () (index int) { | |||||||
| 
 | 
 | ||||||
| func (element *Container) reflectChildProperties () { | func (element *Container) reflectChildProperties () { | ||||||
| 	element.focusable = false | 	element.focusable = false | ||||||
| 	element.forFocusable (func (tomo.Focusable) bool { | 	element.forFocusable (func (elements.Focusable) bool { | ||||||
| 		element.focusable = true | 		element.focusable = true | ||||||
| 		return false | 		return false | ||||||
| 	}) | 	}) | ||||||
| 	element.flexible = false | 	element.flexible = false | ||||||
| 	element.forFlexible (func (tomo.Flexible) bool { | 	element.forFlexible (func (elements.Flexible) bool { | ||||||
| 		element.flexible = true | 		element.flexible = true | ||||||
| 		return false | 		return false | ||||||
| 	}) | 	}) | ||||||
| @ -446,16 +451,16 @@ func (element *Container) reflectChildProperties () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) childFocusRequestCallback ( | func (element *Container) childFocusRequestCallback ( | ||||||
| 	child tomo.Focusable, | 	child elements.Focusable, | ||||||
| ) ( | ) ( | ||||||
| 	granted bool, | 	granted bool, | ||||||
| ) { | ) { | ||||||
| 	if element.onFocusRequest != nil && element.onFocusRequest() { | 	if element.onFocusRequest != nil && element.onFocusRequest() { | ||||||
| 		element.forFocused (func (child tomo.Focusable) bool { | 		element.forFocused (func (child elements.Focusable) bool { | ||||||
| 			child.HandleUnfocus() | 			child.HandleUnfocus() | ||||||
| 			return true | 			return true | ||||||
| 		}) | 		}) | ||||||
| 		child.HandleFocus(tomo.KeynavDirectionNeutral) | 		child.HandleFocus(input.KeynavDirectionNeutral) | ||||||
| 		return true | 		return true | ||||||
| 	} else { | 	} else { | ||||||
| 		return false | 		return false | ||||||
| @ -463,13 +468,16 @@ func (element *Container) childFocusRequestCallback ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) updateMinimumSize () { | func (element *Container) updateMinimumSize () { | ||||||
| 	width, height := element.layout.MinimumSize(element.children) | 	width, height := element.layout.MinimumSize ( | ||||||
|  | 		element.children, theme.Margin()) | ||||||
| 	if element.flexible { | 	if element.flexible { | ||||||
| 		height = element.layout.FlexibleHeightFor(element.children, width) | 		height = element.layout.FlexibleHeightFor ( | ||||||
|  | 			element.children, theme.Margin(), width) | ||||||
| 	} | 	} | ||||||
| 	element.core.SetMinimumSize(width, height) | 	element.core.SetMinimumSize(width, height) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Container) recalculate () { | func (element *Container) recalculate () { | ||||||
| 	element.layout.Arrange(element.children, element.Bounds()) | 	element.layout.Arrange ( | ||||||
|  | 		element.children, theme.Margin(), element.Bounds()) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "fmt" | import "fmt" | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| 
 | 
 | ||||||
| @ -73,10 +74,10 @@ func (element *List) Collapse (width, height int) { | |||||||
| 	element.updateMinimumSize() | 	element.updateMinimumSize() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *List) HandleMouseDown (x, y int, button tomo.Button) { | func (element *List) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	if !element.Enabled()  { return } | 	if !element.Enabled()  { return } | ||||||
| 	if !element.Focused() { element.Focus() } | 	if !element.Focused() { element.Focus() } | ||||||
| 	if button != tomo.ButtonLeft { return } | 	if button != input.ButtonLeft { return } | ||||||
| 	element.pressed = true | 	element.pressed = true | ||||||
| 	if element.selectUnderMouse(x, y) && element.core.HasImage() { | 	if element.selectUnderMouse(x, y) && element.core.HasImage() { | ||||||
| 		element.draw() | 		element.draw() | ||||||
| @ -84,8 +85,8 @@ func (element *List) HandleMouseDown (x, y int, button tomo.Button) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *List) HandleMouseUp (x, y int, button tomo.Button) { | func (element *List) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	if button != tomo.ButtonLeft { return } | 	if button != input.ButtonLeft { return } | ||||||
| 	element.pressed = false | 	element.pressed = false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -100,18 +101,18 @@ func (element *List) HandleMouseMove (x, y int) { | |||||||
| 
 | 
 | ||||||
| func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | ||||||
| 
 | 
 | ||||||
| func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *List) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if !element.Enabled() { return } | 	if !element.Enabled() { return } | ||||||
| 
 | 
 | ||||||
| 	altered := false | 	altered := false | ||||||
| 	switch key { | 	switch key { | ||||||
| 	case tomo.KeyLeft, tomo.KeyUp: | 	case input.KeyLeft, input.KeyUp: | ||||||
| 		altered = element.changeSelectionBy(-1) | 		altered = element.changeSelectionBy(-1) | ||||||
| 		 | 		 | ||||||
| 	case tomo.KeyRight, tomo.KeyDown: | 	case input.KeyRight, input.KeyDown: | ||||||
| 		altered = element.changeSelectionBy(1) | 		altered = element.changeSelectionBy(1) | ||||||
| 
 | 
 | ||||||
| 	case tomo.KeyEscape: | 	case input.KeyEscape: | ||||||
| 		altered = element.selectEntry(-1) | 		altered = element.selectEntry(-1) | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -121,7 +122,7 @@ func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *List) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { } | func (element *List) HandleKeyUp(key input.Key, modifiers input.Modifiers) { } | ||||||
| 
 | 
 | ||||||
| // ScrollContentBounds returns the full content size of the element. | // ScrollContentBounds returns the full content size of the element. | ||||||
| func (element *List) ScrollContentBounds () (bounds image.Rectangle) { | func (element *List) ScrollContentBounds () (bounds image.Rectangle) { | ||||||
| @ -383,7 +384,7 @@ func (element *List) draw () { | |||||||
| 		bounds.Min.X, | 		bounds.Min.X, | ||||||
| 		bounds.Min.Y - element.scroll, | 		bounds.Min.Y - element.scroll, | ||||||
| 	} | 	} | ||||||
| 	innerCanvas := tomo.Cut(element, bounds) | 	innerCanvas := canvas.Cut(element, bounds) | ||||||
| 	for index, entry := range element.entries { | 	for index, entry := range element.entries { | ||||||
| 		entryPosition := dot | 		entryPosition := dot | ||||||
| 		dot.Y += entry.Bounds().Dy() | 		dot.Y += entry.Bounds().Dy() | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" |  | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| 
 | 
 | ||||||
| var listEntryCase = theme.C("basic", "listEntry") | var listEntryCase = theme.C("basic", "listEntry") | ||||||
| @ -53,7 +53,7 @@ func (entry *ListEntry) updateBounds () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (entry *ListEntry) Draw ( | func (entry *ListEntry) Draw ( | ||||||
| 	destination tomo.Canvas, | 	destination canvas.Canvas, | ||||||
| 	offset image.Point, | 	offset image.Point, | ||||||
| 	focused bool, | 	focused bool, | ||||||
| 	on bool, | 	on bool, | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| 
 | 
 | ||||||
| var scrollContainerCase     = theme.C("basic", "scrollContainer") | var scrollContainerCase     = theme.C("basic", "scrollContainer") | ||||||
| @ -17,7 +19,7 @@ type ScrollContainer struct { | |||||||
| 	core core.CoreControl | 	core core.CoreControl | ||||||
| 	focused bool | 	focused bool | ||||||
| 	 | 	 | ||||||
| 	child tomo.Scrollable | 	child elements.Scrollable | ||||||
| 	childWidth, childHeight int | 	childWidth, childHeight int | ||||||
| 	 | 	 | ||||||
| 	horizontal struct { | 	horizontal struct { | ||||||
| @ -41,7 +43,7 @@ type ScrollContainer struct { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	onFocusRequest func () (granted bool) | 	onFocusRequest func () (granted bool) | ||||||
| 	onFocusMotionRequest func (tomo.KeynavDirection) (granted bool) | 	onFocusMotionRequest func (input.KeynavDirection) (granted bool) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewScrollContainer creates a new scroll container with the specified scroll | // NewScrollContainer creates a new scroll container with the specified scroll | ||||||
| @ -64,7 +66,7 @@ func (element *ScrollContainer) handleResize () { | |||||||
| // Adopt adds a scrollable element to the scroll container. The container can | // Adopt adds a scrollable element to the scroll container. The container can | ||||||
| // only contain one scrollable element at a time, and when a new one is adopted | // only contain one scrollable element at a time, and when a new one is adopted | ||||||
| // it replaces the last one. | // it replaces the last one. | ||||||
| func (element *ScrollContainer) Adopt (child tomo.Scrollable) { | func (element *ScrollContainer) Adopt (child elements.Scrollable) { | ||||||
| 	// disown previous child if it exists | 	// disown previous child if it exists | ||||||
| 	if element.child != nil { | 	if element.child != nil { | ||||||
| 		element.clearChildEventHandlers(child) | 		element.clearChildEventHandlers(child) | ||||||
| @ -76,7 +78,7 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) { | |||||||
| 		child.OnDamage(element.childDamageCallback) | 		child.OnDamage(element.childDamageCallback) | ||||||
| 		child.OnMinimumSizeChange(element.updateMinimumSize) | 		child.OnMinimumSizeChange(element.updateMinimumSize) | ||||||
| 		child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback) | 		child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback) | ||||||
| 		if newChild, ok := child.(tomo.Focusable); ok { | 		if newChild, ok := child.(elements.Focusable); ok { | ||||||
| 			newChild.OnFocusRequest ( | 			newChild.OnFocusRequest ( | ||||||
| 				element.childFocusRequestCallback) | 				element.childFocusRequestCallback) | ||||||
| 			newChild.OnFocusMotionRequest ( | 			newChild.OnFocusMotionRequest ( | ||||||
| @ -96,19 +98,19 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *ScrollContainer) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if child, ok := element.child.(tomo.KeyboardTarget); ok { | 	if child, ok := element.child.(elements.KeyboardTarget); ok { | ||||||
| 		child.HandleKeyDown(key, modifiers) | 		child.HandleKeyDown(key, modifiers) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) { | func (element *ScrollContainer) HandleKeyUp (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if child, ok := element.child.(tomo.KeyboardTarget); ok { | 	if child, ok := element.child.(elements.KeyboardTarget); ok { | ||||||
| 		child.HandleKeyUp(key, modifiers) | 		child.HandleKeyUp(key, modifiers) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) { | func (element *ScrollContainer) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	point := image.Pt(x, y) | 	point := image.Pt(x, y) | ||||||
| 	if point.In(element.horizontal.bar) { | 	if point.In(element.horizontal.bar) { | ||||||
| 		element.horizontal.dragging = true | 		element.horizontal.dragging = true | ||||||
| @ -140,12 +142,12 @@ func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) { | |||||||
| 			element.scrollChildBy(0, -16) | 			element.scrollChildBy(0, -16) | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 	} else if child, ok := element.child.(tomo.MouseTarget); ok { | 	} else if child, ok := element.child.(elements.MouseTarget); ok { | ||||||
| 		child.HandleMouseDown(x, y, button) | 		child.HandleMouseDown(x, y, button) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) { | func (element *ScrollContainer) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	if element.horizontal.dragging { | 	if element.horizontal.dragging { | ||||||
| 		element.horizontal.dragging = false | 		element.horizontal.dragging = false | ||||||
| 		element.drawHorizontalBar() | 		element.drawHorizontalBar() | ||||||
| @ -156,7 +158,7 @@ func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) { | |||||||
| 		element.drawVerticalBar() | 		element.drawVerticalBar() | ||||||
| 		element.core.DamageRegion(element.vertical.bar) | 		element.core.DamageRegion(element.vertical.bar) | ||||||
| 		 | 		 | ||||||
| 	} else if child, ok := element.child.(tomo.MouseTarget); ok { | 	} else if child, ok := element.child.(elements.MouseTarget); ok { | ||||||
| 		child.HandleMouseUp(x, y, button) | 		child.HandleMouseUp(x, y, button) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -168,7 +170,7 @@ func (element *ScrollContainer) HandleMouseMove (x, y int) { | |||||||
| 	} else if element.vertical.dragging { | 	} else if element.vertical.dragging { | ||||||
| 		element.dragVerticalBar(image.Pt(x, y)) | 		element.dragVerticalBar(image.Pt(x, y)) | ||||||
| 		 | 		 | ||||||
| 	} else if child, ok := element.child.(tomo.MouseTarget); ok { | 	} else if child, ok := element.child.(elements.MouseTarget); ok { | ||||||
| 		child.HandleMouseMove(x, y) | 		child.HandleMouseMove(x, y) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -199,11 +201,11 @@ func (element *ScrollContainer) Focus () { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleFocus ( | func (element *ScrollContainer) HandleFocus ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	accepted bool, | 	accepted bool, | ||||||
| ) { | ) { | ||||||
| 	if child, ok := element.child.(tomo.Focusable); ok { | 	if child, ok := element.child.(elements.Focusable); ok { | ||||||
| 		element.focused = true | 		element.focused = true | ||||||
| 		return child.HandleFocus(direction) | 		return child.HandleFocus(direction) | ||||||
| 	} else { | 	} else { | ||||||
| @ -213,7 +215,7 @@ func (element *ScrollContainer) HandleFocus ( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) HandleUnfocus () { | func (element *ScrollContainer) HandleUnfocus () { | ||||||
| 	if child, ok := element.child.(tomo.Focusable); ok { | 	if child, ok := element.child.(elements.Focusable); ok { | ||||||
| 		child.HandleUnfocus() | 		child.HandleUnfocus() | ||||||
| 	} | 	} | ||||||
| 	element.focused = false | 	element.focused = false | ||||||
| @ -224,20 +226,20 @@ func (element *ScrollContainer) OnFocusRequest (callback func () (granted bool)) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) OnFocusMotionRequest ( | func (element *ScrollContainer) OnFocusMotionRequest ( | ||||||
| 	callback func (direction tomo.KeynavDirection) (granted bool), | 	callback func (direction input.KeynavDirection) (granted bool), | ||||||
| ) { | ) { | ||||||
| 	element.onFocusMotionRequest = callback | 	element.onFocusMotionRequest = callback | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) childDamageCallback (region tomo.Canvas) { | func (element *ScrollContainer) childDamageCallback (region canvas.Canvas) { | ||||||
| 	element.core.DamageRegion(artist.Paste(element, region, image.Point { })) | 	element.core.DamageRegion(artist.Paste(element, region, image.Point { })) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) childFocusRequestCallback () (granted bool) { | func (element *ScrollContainer) childFocusRequestCallback () (granted bool) { | ||||||
| 	child, ok := element.child.(tomo.Focusable) | 	child, ok := element.child.(elements.Focusable) | ||||||
| 	if !ok { return false } | 	if !ok { return false } | ||||||
| 	if element.onFocusRequest != nil && element.onFocusRequest() { | 	if element.onFocusRequest != nil && element.onFocusRequest() { | ||||||
| 		child.HandleFocus(tomo.KeynavDirectionNeutral) | 		child.HandleFocus(input.KeynavDirectionNeutral) | ||||||
| 		return true | 		return true | ||||||
| 	} else { | 	} else { | ||||||
| 		return false | 		return false | ||||||
| @ -245,7 +247,7 @@ func (element *ScrollContainer) childFocusRequestCallback () (granted bool) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) childFocusMotionRequestCallback ( | func (element *ScrollContainer) childFocusMotionRequestCallback ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	granted bool, | 	granted bool, | ||||||
| ) { | ) { | ||||||
| @ -253,19 +255,19 @@ func (element *ScrollContainer) childFocusMotionRequestCallback ( | |||||||
| 	return element.onFocusMotionRequest(direction) | 	return element.onFocusMotionRequest(direction) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable) { | func (element *ScrollContainer) clearChildEventHandlers (child elements.Scrollable) { | ||||||
| 	child.DrawTo(nil) | 	child.DrawTo(nil) | ||||||
| 	child.OnDamage(nil) | 	child.OnDamage(nil) | ||||||
| 	child.OnMinimumSizeChange(nil) | 	child.OnMinimumSizeChange(nil) | ||||||
| 	child.OnScrollBoundsChange(nil) | 	child.OnScrollBoundsChange(nil) | ||||||
| 	if child0, ok := child.(tomo.Focusable); ok { | 	if child0, ok := child.(elements.Focusable); ok { | ||||||
| 		child0.OnFocusRequest(nil) | 		child0.OnFocusRequest(nil) | ||||||
| 		child0.OnFocusMotionRequest(nil) | 		child0.OnFocusMotionRequest(nil) | ||||||
| 		if child0.Focused() { | 		if child0.Focused() { | ||||||
| 			child0.HandleUnfocus() | 			child0.HandleUnfocus() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if child0, ok := child.(tomo.Flexible); ok { | 	if child0, ok := child.(elements.Flexible); ok { | ||||||
| 		child0.OnFlexibleHeightChange(nil) | 		child0.OnFlexibleHeightChange(nil) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -275,7 +277,7 @@ func (element *ScrollContainer) resizeChildToFit () { | |||||||
| 		0, 0, | 		0, 0, | ||||||
| 		element.childWidth, | 		element.childWidth, | ||||||
| 		element.childHeight).Add(element.Bounds().Min) | 		element.childHeight).Add(element.Bounds().Min) | ||||||
| 	element.child.DrawTo(tomo.Cut(element, childBounds)) | 	element.child.DrawTo(canvas.Cut(element, childBounds)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *ScrollContainer) recalculate () { | func (element *ScrollContainer) recalculate () { | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| @ -41,7 +41,7 @@ func NewSwitch (text string, on bool) (element *Switch) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) { | func (element *Switch) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	if !element.Enabled() { return } | 	if !element.Enabled() { return } | ||||||
| 	element.Focus() | 	element.Focus() | ||||||
| 	element.pressed = true | 	element.pressed = true | ||||||
| @ -51,8 +51,8 @@ func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) { | func (element *Switch) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	if button != tomo.ButtonLeft || !element.pressed { return } | 	if button != input.ButtonLeft || !element.pressed { return } | ||||||
| 
 | 
 | ||||||
| 	element.pressed = false | 	element.pressed = false | ||||||
| 	within := image.Point { x, y }. | 	within := image.Point { x, y }. | ||||||
| @ -73,8 +73,8 @@ func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) { | |||||||
| func (element *Switch) HandleMouseMove (x, y int) { } | func (element *Switch) HandleMouseMove (x, y int) { } | ||||||
| func (element *Switch) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | func (element *Switch) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | ||||||
| 
 | 
 | ||||||
| func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Switch) HandleKeyDown (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if key == tomo.KeyEnter { | 	if key == input.KeyEnter { | ||||||
| 		element.pressed = true | 		element.pressed = true | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
| 			element.draw() | 			element.draw() | ||||||
| @ -83,8 +83,8 @@ func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Switch) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) { | func (element *Switch) HandleKeyUp (key input.Key, modifiers input.Modifiers) { | ||||||
| 	if key == tomo.KeyEnter && element.pressed { | 	if key == input.KeyEnter && element.pressed { | ||||||
| 		element.pressed = false | 		element.pressed = false | ||||||
| 		element.checked = !element.checked | 		element.checked = !element.checked | ||||||
| 		if element.core.HasImage() { | 		if element.core.HasImage() { | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package basic | package basicElements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/textmanip" | import "git.tebibyte.media/sashakoshka/tomo/textmanip" | ||||||
| @ -24,7 +24,7 @@ type TextBox struct { | |||||||
| 	placeholderDrawer artist.TextDrawer | 	placeholderDrawer artist.TextDrawer | ||||||
| 	valueDrawer       artist.TextDrawer | 	valueDrawer       artist.TextDrawer | ||||||
| 	 | 	 | ||||||
| 	onKeyDown func (key tomo.Key, modifiers tomo.Modifiers) (handled bool) | 	onKeyDown func (key input.Key, modifiers input.Modifiers) (handled bool) | ||||||
| 	onChange  func () | 	onChange  func () | ||||||
| 	onScrollBoundsChange func () | 	onScrollBoundsChange func () | ||||||
| } | } | ||||||
| @ -59,16 +59,16 @@ func (element *TextBox) handleResize () { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) HandleMouseDown (x, y int, button tomo.Button) { | func (element *TextBox) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	if !element.Enabled() { return } | 	if !element.Enabled() { return } | ||||||
| 	if !element.Focused() { element.Focus() } | 	if !element.Focused() { element.Focus() } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { } | func (element *TextBox) HandleMouseUp (x, y int, button input.Button) { } | ||||||
| func (element *TextBox) HandleMouseMove (x, y int) { } | func (element *TextBox) HandleMouseMove (x, y int) { } | ||||||
| func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { | func (element *TextBox) HandleKeyDown(key input.Key, modifiers input.Modifiers) { | ||||||
| 	if element.onKeyDown != nil && element.onKeyDown(key, modifiers) { | 	if element.onKeyDown != nil && element.onKeyDown(key, modifiers) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -77,7 +77,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 	altered     := true | 	altered     := true | ||||||
| 	textChanged := false | 	textChanged := false | ||||||
| 	switch { | 	switch { | ||||||
| 	case key == tomo.KeyBackspace: | 	case key == input.KeyBackspace: | ||||||
| 		if len(element.text) < 1 { break } | 		if len(element.text) < 1 { break } | ||||||
| 		element.text, element.cursor = textmanip.Backspace ( | 		element.text, element.cursor = textmanip.Backspace ( | ||||||
| 			element.text, | 			element.text, | ||||||
| @ -85,7 +85,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 			modifiers.Control) | 			modifiers.Control) | ||||||
| 		textChanged = true | 		textChanged = true | ||||||
| 			 | 			 | ||||||
| 	case key == tomo.KeyDelete: | 	case key == input.KeyDelete: | ||||||
| 		if len(element.text) < 1 { break } | 		if len(element.text) < 1 { break } | ||||||
| 		element.text, element.cursor = textmanip.Delete ( | 		element.text, element.cursor = textmanip.Delete ( | ||||||
| 			element.text, | 			element.text, | ||||||
| @ -93,13 +93,13 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 			modifiers.Control) | 			modifiers.Control) | ||||||
| 		textChanged = true | 		textChanged = true | ||||||
| 			 | 			 | ||||||
| 	case key == tomo.KeyLeft: | 	case key == input.KeyLeft: | ||||||
| 		element.cursor = textmanip.MoveLeft ( | 		element.cursor = textmanip.MoveLeft ( | ||||||
| 			element.text, | 			element.text, | ||||||
| 			element.cursor, | 			element.cursor, | ||||||
| 			modifiers.Control) | 			modifiers.Control) | ||||||
| 			 | 			 | ||||||
| 	case key == tomo.KeyRight: | 	case key == input.KeyRight: | ||||||
| 		element.cursor = textmanip.MoveRight ( | 		element.cursor = textmanip.MoveRight ( | ||||||
| 			element.text, | 			element.text, | ||||||
| 			element.cursor, | 			element.cursor, | ||||||
| @ -136,7 +136,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { } | func (element *TextBox) HandleKeyUp(key input.Key, modifiers input.Modifiers) { } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) SetPlaceholder (placeholder string) { | func (element *TextBox) SetPlaceholder (placeholder string) { | ||||||
| 	if element.placeholder == placeholder { return } | 	if element.placeholder == placeholder { return } | ||||||
| @ -177,7 +177,7 @@ func (element *TextBox) Filled () (filled bool) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *TextBox) OnKeyDown ( | func (element *TextBox) OnKeyDown ( | ||||||
| 	callback func (key tomo.Key, modifiers tomo.Modifiers) (handled bool), | 	callback func (key input.Key, modifiers input.Modifiers) (handled bool), | ||||||
| ) { | ) { | ||||||
| 	element.onKeyDown = callback | 	element.onKeyDown = callback | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,12 @@ package core | |||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "image/color" | import "image/color" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| // Core is a struct that implements some core functionality common to most | // Core is a struct that implements some core functionality common to most | ||||||
| // widgets. It is meant to be embedded directly into a struct. | // widgets. It is meant to be embedded directly into a struct. | ||||||
| type Core struct { | type Core struct { | ||||||
| 	canvas tomo.Canvas | 	canvas canvas.Canvas | ||||||
| 
 | 
 | ||||||
| 	metrics struct { | 	metrics struct { | ||||||
| 		minimumWidth  int | 		minimumWidth  int | ||||||
| @ -16,7 +16,7 @@ type Core struct { | |||||||
| 
 | 
 | ||||||
| 	drawSizeChange func () | 	drawSizeChange func () | ||||||
| 	onMinimumSizeChange func () | 	onMinimumSizeChange func () | ||||||
| 	onDamage func (region tomo.Canvas) | 	onDamage func (region canvas.Canvas) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewCore creates a new element core and its corresponding control. | // NewCore creates a new element core and its corresponding control. | ||||||
| @ -49,7 +49,7 @@ func (core *Core) Set (x, y int, c color.Color) () { | |||||||
| 	core.canvas.Set(x, y, c) | 	core.canvas.Set(x, y, c) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Buffer fulfills the tomo.Canvas interface. | // Buffer fulfills the canvas.Canvas interface. | ||||||
| func (core *Core) Buffer () (data []color.RGBA, stride int) { | func (core *Core) Buffer () (data []color.RGBA, stride int) { | ||||||
| 	if core.canvas == nil { return } | 	if core.canvas == nil { return } | ||||||
| 	return core.canvas.Buffer() | 	return core.canvas.Buffer() | ||||||
| @ -63,7 +63,7 @@ func (core *Core) MinimumSize () (width, height int) { | |||||||
| 
 | 
 | ||||||
| // DrawTo fulfills the tomo.Element interface. This should not need to be | // DrawTo fulfills the tomo.Element interface. This should not need to be | ||||||
| // overridden. | // overridden. | ||||||
| func (core *Core) DrawTo (canvas tomo.Canvas) { | func (core *Core) DrawTo (canvas canvas.Canvas) { | ||||||
| 	core.canvas = canvas | 	core.canvas = canvas | ||||||
| 	if core.drawSizeChange != nil { | 	if core.drawSizeChange != nil { | ||||||
| 		core.drawSizeChange() | 		core.drawSizeChange() | ||||||
| @ -72,7 +72,7 @@ func (core *Core) DrawTo (canvas tomo.Canvas) { | |||||||
| 
 | 
 | ||||||
| // OnDamage fulfils the tomo.Element interface. This should not need to be | // OnDamage fulfils the tomo.Element interface. This should not need to be | ||||||
| // overridden. | // overridden. | ||||||
| func (core *Core) OnDamage (callback func (region tomo.Canvas)) { | func (core *Core) OnDamage (callback func (region canvas.Canvas)) { | ||||||
| 	core.onDamage = callback | 	core.onDamage = callback | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -100,7 +100,7 @@ func (control CoreControl) HasImage () (has bool) { | |||||||
| // does not need to be called when responding to a resize event. | // does not need to be called when responding to a resize event. | ||||||
| func (control CoreControl) DamageRegion (bounds image.Rectangle) { | func (control CoreControl) DamageRegion (bounds image.Rectangle) { | ||||||
| 	if control.core.onDamage != nil { | 	if control.core.onDamage != nil { | ||||||
| 		control.core.onDamage(tomo.Cut(control.core, bounds)) | 		control.core.onDamage(canvas.Cut(control.core, bounds)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| package core | package core | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| 
 | 
 | ||||||
| // FocusableCore is a struct that can be embedded into objects to make them | // FocusableCore is a struct that can be embedded into objects to make them | ||||||
| // focusable, giving them the default keynav behavior. | // focusable, giving them the default keynav behavior. | ||||||
| @ -9,7 +9,7 @@ type FocusableCore struct { | |||||||
| 	enabled bool | 	enabled bool | ||||||
| 	drawFocusChange func () | 	drawFocusChange func () | ||||||
| 	onFocusRequest func () (granted bool) | 	onFocusRequest func () (granted bool) | ||||||
| 	onFocusMotionRequest func(tomo.KeynavDirection) (granted bool) | 	onFocusMotionRequest func(input.KeynavDirection) (granted bool) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewFocusableCore creates a new focusability core and its corresponding | // NewFocusableCore creates a new focusability core and its corresponding | ||||||
| @ -46,13 +46,13 @@ func (core *FocusableCore) Focus () { | |||||||
| // HandleFocus causes this element to mark itself as focused, if it can | // HandleFocus causes this element to mark itself as focused, if it can | ||||||
| // currently be. Otherwise, it will return false and do nothing. | // currently be. Otherwise, it will return false and do nothing. | ||||||
| func (core *FocusableCore) HandleFocus ( | func (core *FocusableCore) HandleFocus ( | ||||||
| 	direction tomo.KeynavDirection, | 	direction input.KeynavDirection, | ||||||
| ) ( | ) ( | ||||||
| 	accepted bool, | 	accepted bool, | ||||||
| ) { | ) { | ||||||
| 	direction = direction.Canon() | 	direction = direction.Canon() | ||||||
| 	if !core.enabled { return false } | 	if !core.enabled { return false } | ||||||
| 	if core.focused && direction != tomo.KeynavDirectionNeutral { | 	if core.focused && direction != input.KeynavDirectionNeutral { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -80,7 +80,7 @@ func (core *FocusableCore) OnFocusRequest (callback func () (granted bool)) { | |||||||
| // should return true if the request was granted, and false if it was | // should return true if the request was granted, and false if it was | ||||||
| // not. | // not. | ||||||
| func (core *FocusableCore) OnFocusMotionRequest ( | func (core *FocusableCore) OnFocusMotionRequest ( | ||||||
| 	callback func (direction tomo.KeynavDirection) (granted bool), | 	callback func (direction input.KeynavDirection) (granted bool), | ||||||
| ) { | ) { | ||||||
| 	core.onFocusMotionRequest = callback | 	core.onFocusMotionRequest = callback | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,15 @@ | |||||||
| package tomo | package elements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/canvas" | ||||||
| 
 | 
 | ||||||
| // Element represents a basic on-screen object. | // Element represents a basic on-screen object. | ||||||
| type Element interface { | type Element interface { | ||||||
| 	// Element must implement the Canvas interface. Elements should start | 	// Element must implement the Canvas interface. Elements should start | ||||||
| 	// out with a completely blank buffer, and only allocate memory and draw | 	// out with a completely blank buffer, and only allocate memory and draw | ||||||
| 	// on it for the first time when sent an EventResize event. | 	// on it for the first time when sent an EventResize event. | ||||||
| 	Canvas | 	canvas.Canvas | ||||||
| 
 | 
 | ||||||
| 	// MinimumSize specifies the minimum amount of pixels this element's | 	// MinimumSize specifies the minimum amount of pixels this element's | ||||||
| 	// width and height may be set to. If the element is given a resize | 	// width and height may be set to. If the element is given a resize | ||||||
| @ -18,37 +20,17 @@ type Element interface { | |||||||
| 	// DrawTo sets this element's canvas. This should only be called by the | 	// DrawTo sets this element's canvas. This should only be called by the | ||||||
| 	// parent element. This is typically a region of the parent element's | 	// parent element. This is typically a region of the parent element's | ||||||
| 	// canvas. | 	// canvas. | ||||||
| 	DrawTo (canvas Canvas) | 	DrawTo (canvas canvas.Canvas) | ||||||
| 
 | 
 | ||||||
| 	// OnDamage sets a function to be called when an area of the element is | 	// OnDamage sets a function to be called when an area of the element is | ||||||
| 	// drawn on and should be pushed to the screen. | 	// drawn on and should be pushed to the screen. | ||||||
| 	OnDamage (callback func (region Canvas)) | 	OnDamage (callback func (region canvas.Canvas)) | ||||||
| 
 | 
 | ||||||
| 	// OnMinimumSizeChange sets a function to be called when the element's | 	// OnMinimumSizeChange sets a function to be called when the element's | ||||||
| 	// minimum size is changed. | 	// minimum size is changed. | ||||||
| 	OnMinimumSizeChange (callback func ()) | 	OnMinimumSizeChange (callback func ()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // KeynavDirection represents a keyboard navigation direction. |  | ||||||
| type KeynavDirection int |  | ||||||
| 
 |  | ||||||
| const ( |  | ||||||
| 	KeynavDirectionNeutral  KeynavDirection =  0 |  | ||||||
| 	KeynavDirectionBackward KeynavDirection = -1 |  | ||||||
| 	KeynavDirectionForward  KeynavDirection =  1 |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // Canon returns a well-formed direction. |  | ||||||
| func (direction KeynavDirection) Canon () (canon KeynavDirection) { |  | ||||||
| 	if direction > 0 { |  | ||||||
| 		return KeynavDirectionForward |  | ||||||
| 	} else if direction == 0 { |  | ||||||
| 		return KeynavDirectionNeutral |  | ||||||
| 	} else { |  | ||||||
| 		return KeynavDirectionBackward |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Focusable represents an element that has keyboard navigation support. This | // Focusable represents an element that has keyboard navigation support. This | ||||||
| // includes inputs, buttons, sliders, etc. as well as any elements that have | // includes inputs, buttons, sliders, etc. as well as any elements that have | ||||||
| // children (so keyboard navigation events can be propagated downward). | // children (so keyboard navigation events can be propagated downward). | ||||||
| @ -67,7 +49,7 @@ type Focusable interface { | |||||||
| 	// selectable children in the given direction, it should return false | 	// selectable children in the given direction, it should return false | ||||||
| 	// and do nothing. Otherwise, it should select itself and any children | 	// and do nothing. Otherwise, it should select itself and any children | ||||||
| 	// (if applicable) and return true. | 	// (if applicable) and return true. | ||||||
| 	HandleFocus (direction KeynavDirection) (accepted bool) | 	HandleFocus (direction input.KeynavDirection) (accepted bool) | ||||||
| 
 | 
 | ||||||
| 	// HandleDeselection causes this element to mark itself and all of its | 	// HandleDeselection causes this element to mark itself and all of its | ||||||
| 	// children as unfocused. | 	// children as unfocused. | ||||||
| @ -83,7 +65,7 @@ type Focusable interface { | |||||||
| 	// front of it, depending on the specified direction. Parent elements | 	// front of it, depending on the specified direction. Parent elements | ||||||
| 	// should return true if the request was granted, and false if it was | 	// should return true if the request was granted, and false if it was | ||||||
| 	// not. | 	// not. | ||||||
| 	OnFocusMotionRequest (func (direction KeynavDirection) (granted bool)) | 	OnFocusMotionRequest (func (direction input.KeynavDirection) (granted bool)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // KeyboardTarget represents an element that can receive keyboard input. | // KeyboardTarget represents an element that can receive keyboard input. | ||||||
| @ -95,11 +77,11 @@ type KeyboardTarget interface { | |||||||
| 	// every key down event is guaranteed to be paired with exactly one key | 	// every key down event is guaranteed to be paired with exactly one key | ||||||
| 	// up event. This is the reason a list of modifier keys held down at the | 	// up event. This is the reason a list of modifier keys held down at the | ||||||
| 	// time of the key press is given. | 	// time of the key press is given. | ||||||
| 	HandleKeyDown (key Key, modifiers Modifiers) | 	HandleKeyDown (key input.Key, modifiers input.Modifiers) | ||||||
| 
 | 
 | ||||||
| 	// HandleKeyUp is called when a key is released while this element has | 	// HandleKeyUp is called when a key is released while this element has | ||||||
| 	// keyboard focus. | 	// keyboard focus. | ||||||
| 	HandleKeyUp (key Key, modifiers Modifiers) | 	HandleKeyUp (key input.Key, modifiers input.Modifiers) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MouseTarget represents an element that can receive mouse events. | // MouseTarget represents an element that can receive mouse events. | ||||||
| @ -111,11 +93,11 @@ type MouseTarget interface { | |||||||
| 
 | 
 | ||||||
| 	// HandleMouseDown is called when a mouse button is pressed down on this | 	// HandleMouseDown is called when a mouse button is pressed down on this | ||||||
| 	// element. | 	// element. | ||||||
| 	HandleMouseDown (x, y int, button Button) | 	HandleMouseDown (x, y int, button input.Button) | ||||||
| 
 | 
 | ||||||
| 	// HandleMouseUp is called when a mouse button is released that was | 	// HandleMouseUp is called when a mouse button is released that was | ||||||
| 	// originally pressed down on this element. | 	// originally pressed down on this element. | ||||||
| 	HandleMouseUp (x, y int, button Button) | 	HandleMouseUp (x, y int, button input.Button) | ||||||
| 
 | 
 | ||||||
| 	// HandleMouseMove is called when the mouse is moved over this element, | 	// HandleMouseMove is called when the mouse is moved over this element, | ||||||
| 	// or the mouse is moving while being held down and originally pressed | 	// or the mouse is moving while being held down and originally pressed | ||||||
| @ -2,7 +2,7 @@ package testing | |||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "image/color" | import "image/color" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/input" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/theme" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/artist" | import "git.tebibyte.media/sashakoshka/tomo/artist" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/core" | import "git.tebibyte.media/sashakoshka/tomo/elements/core" | ||||||
| @ -44,12 +44,12 @@ func (element *Mouse) draw () { | |||||||
| 		bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1))) | 		bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1))) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Mouse) HandleMouseDown (x, y int, button tomo.Button) { | func (element *Mouse) HandleMouseDown (x, y int, button input.Button) { | ||||||
| 	element.drawing = true | 	element.drawing = true | ||||||
| 	element.lastMousePos = image.Pt(x, y) | 	element.lastMousePos = image.Pt(x, y) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (element *Mouse) HandleMouseUp (x, y int, button tomo.Button) { | func (element *Mouse) HandleMouseUp (x, y int, button input.Button) { | ||||||
| 	element.drawing = false | 	element.drawing = false | ||||||
| 	mousePos := image.Pt(x, y) | 	mousePos := image.Pt(x, y) | ||||||
| 	element.core.DamageRegion (artist.Line ( | 	element.core.DamageRegion (artist.Line ( | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package tomo | package elements | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| 
 | 
 | ||||||
| @ -11,7 +11,7 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("example button") | 	window.SetTitle("example button") | ||||||
| 	button := basic.NewButton("hello tomo!") | 	button := basicElements.NewButton("hello tomo!") | ||||||
| 	button.OnClick (func () { | 	button.OnClick (func () { | ||||||
| 		// when we set the button's text to something longer, the window | 		// when we set the button's text to something longer, the window | ||||||
| 		// will automatically resize to accomodate it. | 		// will automatically resize to accomodate it. | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/popups" | import "git.tebibyte.media/sashakoshka/tomo/popups" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -14,22 +14,22 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Checkboxes") | 	window.SetTitle("Checkboxes") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt (basic.NewLabel ( | 	container.Adopt (basicElements.NewLabel ( | ||||||
| 		"We advise you to not read thPlease listen to me. I am " + | 		"We advise you to not read thPlease listen to me. I am " + | ||||||
| 		"trapped inside the example code. This is the only way for " + | 		"trapped inside the example code. This is the only way for " + | ||||||
| 		"me to communicate.", true), true) | 		"me to communicate.", true), true) | ||||||
| 	container.Adopt(basic.NewSpacer(true), false) | 	container.Adopt(basicElements.NewSpacer(true), false) | ||||||
| 	container.Adopt(basic.NewCheckbox("Oh god", false), false) | 	container.Adopt(basicElements.NewCheckbox("Oh god", false), false) | ||||||
| 	container.Adopt(basic.NewCheckbox("Can you hear them", true), false) | 	container.Adopt(basicElements.NewCheckbox("Can you hear them", true), false) | ||||||
| 	container.Adopt(basic.NewCheckbox("They are in the walls", false), false) | 	container.Adopt(basicElements.NewCheckbox("They are in the walls", false), false) | ||||||
| 	container.Adopt(basic.NewCheckbox("They are coming for us", false), false) | 	container.Adopt(basicElements.NewCheckbox("They are coming for us", false), false) | ||||||
| 	disabledCheckbox := basic.NewCheckbox("We are but their helpless prey", false) | 	disabledCheckbox := basicElements.NewCheckbox("We are but their helpless prey", false) | ||||||
| 	disabledCheckbox.SetEnabled(false) | 	disabledCheckbox.SetEnabled(false) | ||||||
| 	container.Adopt(disabledCheckbox, false) | 	container.Adopt(disabledCheckbox, false) | ||||||
| 	vsync := basic.NewCheckbox("Enable vsync", false) | 	vsync := basicElements.NewCheckbox("Enable vsync", false) | ||||||
| 	vsync.OnToggle (func () { | 	vsync.OnToggle (func () { | ||||||
| 		if vsync.Value() { | 		if vsync.Value() { | ||||||
| 			popups.NewDialog ( | 			popups.NewDialog ( | ||||||
| @ -39,7 +39,7 @@ func run () { | |||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
| 	container.Adopt(vsync, false) | 	container.Adopt(vsync, false) | ||||||
| 	button := basic.NewButton("What") | 	button := basicElements.NewButton("What") | ||||||
| 	button.OnClick(tomo.Stop) | 	button.OnClick(tomo.Stop) | ||||||
| 	container.Adopt(button, false) | 	container.Adopt(button, false) | ||||||
| 	button.Focus() | 	button.Focus() | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,14 +13,14 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("dialog") | 	window.SetTitle("dialog") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Dialog { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Dialog { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewLabel("you will explode", true), true) | 	container.Adopt(basicElements.NewLabel("you will explode", true), true) | ||||||
| 	cancel := basic.NewButton("Cancel") | 	cancel := basicElements.NewButton("Cancel") | ||||||
| 	cancel.SetEnabled(false) | 	cancel.SetEnabled(false) | ||||||
| 	container.Adopt(cancel, false) | 	container.Adopt(cancel, false) | ||||||
| 	okButton := basic.NewButton("OK") | 	okButton := basicElements.NewButton("OK") | ||||||
| 	container.Adopt(okButton, false) | 	container.Adopt(okButton, false) | ||||||
| 	okButton.Focus() | 	okButton.Focus() | ||||||
| 		 | 		 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/flow" | import "git.tebibyte.media/sashakoshka/tomo/flow" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,21 +13,21 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("adventure") | 	window.SetTitle("adventure") | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	var world flow.Flow | 	var world flow.Flow | ||||||
| 	world.Transition = container.DisownAll | 	world.Transition = container.DisownAll | ||||||
| 	world.Stages = map [string] func () { | 	world.Stages = map [string] func () { | ||||||
| 		"start": func () { | 		"start": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basicElements.NewLabel ( | ||||||
| 				"you are standing next to a river.", true) | 				"you are standing next to a river.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("go in the river") | 			button0 := basicElements.NewButton("go in the river") | ||||||
| 			button0.OnClick(world.SwitchFunc("wet")) | 			button0.OnClick(world.SwitchFunc("wet")) | ||||||
| 			button1 := basic.NewButton("walk along the river") | 			button1 := basicElements.NewButton("walk along the river") | ||||||
| 			button1.OnClick(world.SwitchFunc("house")) | 			button1.OnClick(world.SwitchFunc("house")) | ||||||
| 			button2 := basic.NewButton("turn around") | 			button2 := basicElements.NewButton("turn around") | ||||||
| 			button2.OnClick(world.SwitchFunc("bear")) | 			button2.OnClick(world.SwitchFunc("bear")) | ||||||
| 
 | 
 | ||||||
| 			container.Warp ( func () { | 			container.Warp ( func () { | ||||||
| @ -39,13 +39,13 @@ func run () { | |||||||
| 			}) | 			}) | ||||||
| 		}, | 		}, | ||||||
| 		"wet": func () { | 		"wet": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basicElements.NewLabel ( | ||||||
| 				"you get completely soaked.\n" + | 				"you get completely soaked.\n" + | ||||||
| 				"you die of hypothermia.", true) | 				"you die of hypothermia.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("try again") | 			button0 := basicElements.NewButton("try again") | ||||||
| 			button0.OnClick(world.SwitchFunc("start")) | 			button0.OnClick(world.SwitchFunc("start")) | ||||||
| 			button1 := basic.NewButton("exit") | 			button1 := basicElements.NewButton("exit") | ||||||
| 			button1.OnClick(tomo.Stop) | 			button1.OnClick(tomo.Stop) | ||||||
| 
 | 
 | ||||||
| 			container.Warp (func () { | 			container.Warp (func () { | ||||||
| @ -56,13 +56,13 @@ func run () { | |||||||
| 			}) | 			}) | ||||||
| 		}, | 		}, | ||||||
| 		"house": func () { | 		"house": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basicElements.NewLabel ( | ||||||
| 				"you are standing in front of a delapidated " + | 				"you are standing in front of a delapidated " + | ||||||
| 				"house.", true) | 				"house.", true) | ||||||
| 			 | 			 | ||||||
| 			button1 := basic.NewButton("go inside") | 			button1 := basicElements.NewButton("go inside") | ||||||
| 			button1.OnClick(world.SwitchFunc("inside")) | 			button1.OnClick(world.SwitchFunc("inside")) | ||||||
| 			button0 := basic.NewButton("turn back") | 			button0 := basicElements.NewButton("turn back") | ||||||
| 			button0.OnClick(world.SwitchFunc("start")) | 			button0.OnClick(world.SwitchFunc("start")) | ||||||
| 			 | 			 | ||||||
| 			container.Warp (func () {	 | 			container.Warp (func () {	 | ||||||
| @ -73,14 +73,14 @@ func run () { | |||||||
| 			}) | 			}) | ||||||
| 		}, | 		}, | ||||||
| 		"inside": func () { | 		"inside": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basicElements.NewLabel ( | ||||||
| 				"you are standing inside of the house.\n" + | 				"you are standing inside of the house.\n" + | ||||||
| 				"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.", true) | 				"here.", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("go back outside") | 			button0 := basicElements.NewButton("go back outside") | ||||||
| 			button0.OnClick(world.SwitchFunc("house")) | 			button0.OnClick(world.SwitchFunc("house")) | ||||||
| 			 | 			 | ||||||
| 			container.Warp (func () {	 | 			container.Warp (func () {	 | ||||||
| @ -90,13 +90,13 @@ func run () { | |||||||
| 			}) | 			}) | ||||||
| 		}, | 		}, | ||||||
| 		"bear": func () { | 		"bear": func () { | ||||||
| 			label := basic.NewLabel ( | 			label := basicElements.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).", true) | 				"it eats you (it was hungry).", true) | ||||||
| 			 | 			 | ||||||
| 			button0 := basic.NewButton("try again") | 			button0 := basicElements.NewButton("try again") | ||||||
| 			button0.OnClick(world.SwitchFunc("start")) | 			button0.OnClick(world.SwitchFunc("start")) | ||||||
| 			button1 := basic.NewButton("exit") | 			button1 := basicElements.NewButton("exit") | ||||||
| 			button1.OnClick(tomo.Stop) | 			button1.OnClick(tomo.Stop) | ||||||
| 			 | 			 | ||||||
| 			container.Warp (func () {	 | 			container.Warp (func () {	 | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ package main | |||||||
| import "os" | import "os" | ||||||
| import "time" | import "time" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/fun" | import "git.tebibyte.media/sashakoshka/tomo/elements/fun" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| @ -16,12 +16,12 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("clock") | 	window.SetTitle("clock") | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	clock := fun.NewAnalogClock(time.Now()) | 	clock := fun.NewAnalogClock(time.Now()) | ||||||
| 	container.Adopt(clock, true) | 	container.Adopt(clock, true) | ||||||
| 	label := basic.NewLabel(formatTime(), false) | 	label := basicElements.NewLabel(formatTime(), false) | ||||||
| 	container.Adopt(label, false) | 	container.Adopt(label, false) | ||||||
| 	 | 	 | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
| @ -33,7 +33,7 @@ func formatTime () (timeString string) { | |||||||
| 	return time.Now().Format("2006-01-02 15:04:05") | 	return time.Now().Format("2006-01-02 15:04:05") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func tick (label *basic.Label, clock *fun.AnalogClock) { | func tick (label *basicElements.Label, clock *fun.AnalogClock) { | ||||||
| 	for { | 	for { | ||||||
| 		tomo.Do (func () { | 		tomo.Do (func () { | ||||||
| 			label.SetText(formatTime()) | 			label.SetText(formatTime()) | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,12 +13,12 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(360, 2) | 	window, _ := tomo.NewWindow(360, 2) | ||||||
| 	window.SetTitle("horizontal stack") | 	window.SetTitle("horizontal stack") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Horizontal { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Horizontal { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewLabel("this is sample text", true), true) | 	container.Adopt(basicElements.NewLabel("this is sample text", true), true) | ||||||
| 	container.Adopt(basic.NewLabel("this is sample text", true), true) | 	container.Adopt(basicElements.NewLabel("this is sample text", true), true) | ||||||
| 	container.Adopt(basic.NewLabel("this is sample text", true), true) | 	container.Adopt(basicElements.NewLabel("this is sample text", true), true) | ||||||
| 	 | 	 | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
| 	window.Show() | 	window.Show() | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/popups" | import "git.tebibyte.media/sashakoshka/tomo/popups" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,14 +13,14 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Enter Details") | 	window.SetTitle("Enter Details") | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	// create inputs | 	// create inputs | ||||||
| 	firstName    := basic.NewTextBox("First name", "") | 	firstName    := basicElements.NewTextBox("First name", "") | ||||||
| 	lastName     := basic.NewTextBox("Last name", "") | 	lastName     := basicElements.NewTextBox("Last name", "") | ||||||
| 	fingerLength := basic.NewTextBox("Length of fingers", "") | 	fingerLength := basicElements.NewTextBox("Length of fingers", "") | ||||||
| 	button       := basic.NewButton("Ok") | 	button       := basicElements.NewButton("Ok") | ||||||
| 
 | 
 | ||||||
| 	button.SetEnabled(false) | 	button.SetEnabled(false) | ||||||
| 	button.OnClick (func () { | 	button.OnClick (func () { | ||||||
| @ -45,11 +45,11 @@ func run () { | |||||||
| 	fingerLength.OnChange(check) | 	fingerLength.OnChange(check) | ||||||
| 
 | 
 | ||||||
| 	// add elements to container | 	// add elements to container | ||||||
| 	container.Adopt(basic.NewLabel("Choose your words carefully.", false), true) | 	container.Adopt(basicElements.NewLabel("Choose your words carefully.", false), true) | ||||||
| 	container.Adopt(firstName, false) | 	container.Adopt(firstName, false) | ||||||
| 	container.Adopt(lastName, false) | 	container.Adopt(lastName, false) | ||||||
| 	container.Adopt(fingerLength, false) | 	container.Adopt(fingerLength, false) | ||||||
| 	container.Adopt(basic.NewSpacer(true), false) | 	container.Adopt(basicElements.NewSpacer(true), false) | ||||||
| 	container.Adopt(button, false) | 	container.Adopt(button, false) | ||||||
| 	 | 	 | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(480, 2) | 	window, _ := tomo.NewWindow(480, 2) | ||||||
| 	window.SetTitle("example label") | 	window.SetTitle("example label") | ||||||
| 	window.Adopt(basic.NewLabel(text, true)) | 	window.Adopt(basicElements.NewLabel(text, true)) | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
| 	window.Show() | 	window.Show() | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,7 +2,8 @@ package main | |||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/popups" | import "git.tebibyte.media/sashakoshka/tomo/popups" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/testing" | import "git.tebibyte.media/sashakoshka/tomo/elements/testing" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| @ -15,11 +16,11 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(300, 2) | 	window, _ := tomo.NewWindow(300, 2) | ||||||
| 	window.SetTitle("List Sidebar") | 	window.SetTitle("List Sidebar") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Horizontal { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Horizontal { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	var currentPage tomo.Element | 	var currentPage elements.Element | ||||||
| 	turnPage := func (newPage tomo.Element) { | 	turnPage := func (newPage elements.Element) { | ||||||
| 		container.Warp (func () { | 		container.Warp (func () { | ||||||
| 			if currentPage != nil { | 			if currentPage != nil { | ||||||
| 				container.Disown(currentPage) | 				container.Disown(currentPage) | ||||||
| @ -29,27 +30,27 @@ func run () { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	intro := basic.NewLabel ( | 	intro := basicElements.NewLabel ( | ||||||
| 		"The List element can be easily used as a sidebar. " + | 		"The List element can be easily used as a sidebar. " + | ||||||
| 		"Click on entries to flip pages!", true) | 		"Click on entries to flip pages!", true) | ||||||
| 	button := basic.NewButton("I do nothing!") | 	button := basicElements.NewButton("I do nothing!") | ||||||
| 	button.OnClick (func () { | 	button.OnClick (func () { | ||||||
| 		popups.NewDialog(popups.DialogKindInfo, "", "Sike!") | 		popups.NewDialog(popups.DialogKindInfo, "", "Sike!") | ||||||
| 	}) | 	}) | ||||||
| 	mouse  := testing.NewMouse() | 	mouse  := testing.NewMouse() | ||||||
| 	input  := basic.NewTextBox("Write some text", "") | 	input  := basicElements.NewTextBox("Write some text", "") | ||||||
| 	form := basic.NewContainer(layouts.Vertical { true, false}) | 	form := basicElements.NewContainer(basicLayouts.Vertical { true, false}) | ||||||
| 		form.Adopt(basic.NewLabel("I have:", false), false) | 		form.Adopt(basicElements.NewLabel("I have:", false), false) | ||||||
| 		form.Adopt(basic.NewSpacer(true), false) | 		form.Adopt(basicElements.NewSpacer(true), false) | ||||||
| 		form.Adopt(basic.NewCheckbox("Skin", true), false) | 		form.Adopt(basicElements.NewCheckbox("Skin", true), false) | ||||||
| 		form.Adopt(basic.NewCheckbox("Blood", false), false) | 		form.Adopt(basicElements.NewCheckbox("Blood", false), false) | ||||||
| 		form.Adopt(basic.NewCheckbox("Bone", false), false) | 		form.Adopt(basicElements.NewCheckbox("Bone", false), false) | ||||||
| 
 | 
 | ||||||
| 	list := basic.NewList ( | 	list := basicElements.NewList ( | ||||||
| 		basic.NewListEntry("button", func () { turnPage(button) }), | 		basicElements.NewListEntry("button", func () { turnPage(button) }), | ||||||
| 		basic.NewListEntry("mouse",  func () { turnPage(mouse) }), | 		basicElements.NewListEntry("mouse",  func () { turnPage(mouse) }), | ||||||
| 		basic.NewListEntry("input",  func () { turnPage(input) }), | 		basicElements.NewListEntry("input",  func () { turnPage(input) }), | ||||||
| 		basic.NewListEntry("form",   func () { turnPage(form) })) | 		basicElements.NewListEntry("form",   func () { turnPage(form) })) | ||||||
| 	list.OnNoEntrySelected(func () { turnPage (intro) }) | 	list.OnNoEntrySelected(func () { turnPage (intro) }) | ||||||
| 	list.Collapse(96, 0) | 	list.Collapse(96, 0) | ||||||
| 	 | 	 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ package main | |||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/popups" | import "git.tebibyte.media/sashakoshka/tomo/popups" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -14,12 +14,12 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Dialog Boxes") | 	window.SetTitle("Dialog Boxes") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewLabel("Try out different dialogs:", false), true) | 	container.Adopt(basicElements.NewLabel("Try out different dialogs:", false), true) | ||||||
| 
 | 
 | ||||||
| 	infoButton := basic.NewButton("popups.DialogKindInfo") | 	infoButton := basicElements.NewButton("popups.DialogKindInfo") | ||||||
| 	infoButton.OnClick (func () { | 	infoButton.OnClick (func () { | ||||||
| 		popups.NewDialog ( | 		popups.NewDialog ( | ||||||
| 			popups.DialogKindInfo, | 			popups.DialogKindInfo, | ||||||
| @ -29,7 +29,7 @@ func run () { | |||||||
| 	container.Adopt(infoButton, false) | 	container.Adopt(infoButton, false) | ||||||
| 	infoButton.Focus() | 	infoButton.Focus() | ||||||
| 	 | 	 | ||||||
| 	questionButton := basic.NewButton("popups.DialogKindQuestion") | 	questionButton := basicElements.NewButton("popups.DialogKindQuestion") | ||||||
| 	questionButton.OnClick (func () { | 	questionButton.OnClick (func () { | ||||||
| 		popups.NewDialog ( | 		popups.NewDialog ( | ||||||
| 			popups.DialogKindQuestion, | 			popups.DialogKindQuestion, | ||||||
| @ -41,7 +41,7 @@ func run () { | |||||||
| 	}) | 	}) | ||||||
| 	container.Adopt(questionButton, false) | 	container.Adopt(questionButton, false) | ||||||
| 	 | 	 | ||||||
| 	warningButton := basic.NewButton("popups.DialogKindWarning") | 	warningButton := basicElements.NewButton("popups.DialogKindWarning") | ||||||
| 	warningButton.OnClick (func () { | 	warningButton.OnClick (func () { | ||||||
| 		popups.NewDialog ( | 		popups.NewDialog ( | ||||||
| 			popups.DialogKindQuestion, | 			popups.DialogKindQuestion, | ||||||
| @ -50,7 +50,7 @@ func run () { | |||||||
| 	}) | 	}) | ||||||
| 	container.Adopt(warningButton, false) | 	container.Adopt(warningButton, false) | ||||||
| 	 | 	 | ||||||
| 	errorButton := basic.NewButton("popups.DialogKindError") | 	errorButton := basicElements.NewButton("popups.DialogKindError") | ||||||
| 	errorButton.OnClick (func () { | 	errorButton.OnClick (func () { | ||||||
| 		popups.NewDialog ( | 		popups.NewDialog ( | ||||||
| 			popups.DialogKindQuestion, | 			popups.DialogKindQuestion, | ||||||
| @ -59,7 +59,7 @@ func run () { | |||||||
| 	}) | 	}) | ||||||
| 	container.Adopt(errorButton, false) | 	container.Adopt(errorButton, false) | ||||||
| 
 | 
 | ||||||
| 	cancelButton := basic.NewButton("No thank you.") | 	cancelButton := basicElements.NewButton("No thank you.") | ||||||
| 	cancelButton.OnClick(tomo.Stop) | 	cancelButton.OnClick(tomo.Stop) | ||||||
| 	container.Adopt(cancelButton, false) | 	container.Adopt(cancelButton, false) | ||||||
| 		 | 		 | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ package main | |||||||
| import "time" | import "time" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/popups" | import "git.tebibyte.media/sashakoshka/tomo/popups" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -14,14 +14,14 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Approaching") | 	window.SetTitle("Approaching") | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt (basic.NewLabel ( | 	container.Adopt (basicElements.NewLabel ( | ||||||
| 		"Rapidly approaching your location...", false), false) | 		"Rapidly approaching your location...", false), false) | ||||||
| 	bar := basic.NewProgressBar(0) | 	bar := basicElements.NewProgressBar(0) | ||||||
| 	container.Adopt(bar, false) | 	container.Adopt(bar, false) | ||||||
| 	button := basic.NewButton("Stop") | 	button := basicElements.NewButton("Stop") | ||||||
| 	button.SetEnabled(false) | 	button.SetEnabled(false) | ||||||
| 	container.Adopt(button, false) | 	container.Adopt(button, false) | ||||||
| 	 | 	 | ||||||
| @ -30,7 +30,7 @@ func run () { | |||||||
| 	go fill(bar) | 	go fill(bar) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func fill (bar *basic.ProgressBar) { | func fill (bar *basicElements.ProgressBar) { | ||||||
| 	for progress := 0.0; progress < 1.0; progress += 0.01 { | 	for progress := 0.0; progress < 1.0; progress += 0.01 { | ||||||
| 		time.Sleep(time.Second / 24) | 		time.Sleep(time.Second / 24) | ||||||
| 		tomo.Do (func () { | 		tomo.Do (func () { | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -12,13 +12,13 @@ func main () { | |||||||
| func run () { | func run () { | ||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Scroll") | 	window.SetTitle("Scroll") | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewLabel("look at this non sense", false), false) | 	container.Adopt(basicElements.NewLabel("look at this non sense", false), false) | ||||||
| 
 | 
 | ||||||
| 	textBox := basic.NewTextBox("", "sample text sample text") | 	textBox := basicElements.NewTextBox("", "sample text sample text") | ||||||
| 	scrollContainer := basic.NewScrollContainer(true, false) | 	scrollContainer := basicElements.NewScrollContainer(true, false) | ||||||
| 	scrollContainer.Adopt(textBox) | 	scrollContainer.Adopt(textBox) | ||||||
| 	container.Adopt(scrollContainer, true) | 	container.Adopt(scrollContainer, true) | ||||||
| 	 | 	 | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,14 +13,14 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Spaced Out") | 	window.SetTitle("Spaced Out") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt (basic.NewLabel("This is at the top", false), false) | 	container.Adopt (basicElements.NewLabel("This is at the top", false), false) | ||||||
| 	container.Adopt (basic.NewSpacer(true), false) | 	container.Adopt (basicElements.NewSpacer(true), false) | ||||||
| 	container.Adopt (basic.NewLabel("This is in the middle", false), false) | 	container.Adopt (basicElements.NewLabel("This is in the middle", false), false) | ||||||
| 	container.Adopt (basic.NewSpacer(false), true) | 	container.Adopt (basicElements.NewSpacer(false), true) | ||||||
| 	container.Adopt (basic.NewLabel("This is at the bottom", false), false) | 	container.Adopt (basicElements.NewLabel("This is at the bottom", false), false) | ||||||
| 	 | 	 | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
| 	window.Show() | 	window.Show() | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| 
 | 
 | ||||||
| @ -13,12 +13,12 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("Switches") | 	window.SetTitle("Switches") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewSwitch("hahahah", false), false) | 	container.Adopt(basicElements.NewSwitch("hahahah", false), false) | ||||||
| 	container.Adopt(basic.NewSwitch("hehehehheheh", false), false) | 	container.Adopt(basicElements.NewSwitch("hehehehheheh", false), false) | ||||||
| 	container.Adopt(basic.NewSwitch("you can flick da swicth", false), false) | 	container.Adopt(basicElements.NewSwitch("you can flick da swicth", false), false) | ||||||
| 		 | 		 | ||||||
| 	window.OnClose(tomo.Stop) | 	window.OnClose(tomo.Stop) | ||||||
| 	window.Show() | 	window.Show() | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/testing" | import "git.tebibyte.media/sashakoshka/tomo/elements/testing" | ||||||
| import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" | ||||||
| @ -14,15 +14,15 @@ func run () { | |||||||
| 	window, _ := tomo.NewWindow(2, 2) | 	window, _ := tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle("vertical stack") | 	window.SetTitle("vertical stack") | ||||||
| 
 | 
 | ||||||
| 	container := basic.NewContainer(layouts.Vertical { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	label    := basic.NewLabel("it is a label hehe", true) | 	label    := basicElements.NewLabel("it is a label hehe", true) | ||||||
| 	button   := basic.NewButton("drawing pad") | 	button   := basicElements.NewButton("drawing pad") | ||||||
| 	okButton := basic.NewButton("OK") | 	okButton := basicElements.NewButton("OK") | ||||||
| 	button.OnClick (func () { | 	button.OnClick (func () { | ||||||
| 		container.DisownAll() | 		container.DisownAll() | ||||||
| 		container.Adopt(basic.NewLabel("Draw here:", false), false) | 		container.Adopt(basicElements.NewLabel("Draw here:", false), false) | ||||||
| 		container.Adopt(testing.NewMouse(), true) | 		container.Adopt(testing.NewMouse(), true) | ||||||
| 		container.Adopt(okButton, false) | 		container.Adopt(okButton, false) | ||||||
| 		okButton.Focus() | 		okButton.Focus() | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| package tomo | package input | ||||||
| 
 | 
 | ||||||
| import "unicode" | import "unicode" | ||||||
| 
 | 
 | ||||||
| @ -110,3 +110,22 @@ type Modifiers struct { | |||||||
| 	NumberPad bool | 	NumberPad bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // KeynavDirection represents a keyboard navigation direction. | ||||||
|  | type KeynavDirection int | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	KeynavDirectionNeutral  KeynavDirection =  0 | ||||||
|  | 	KeynavDirectionBackward KeynavDirection = -1 | ||||||
|  | 	KeynavDirectionForward  KeynavDirection =  1 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Canon returns a well-formed direction. | ||||||
|  | func (direction KeynavDirection) Canon () (canon KeynavDirection) { | ||||||
|  | 	if direction > 0 { | ||||||
|  | 		return KeynavDirectionForward | ||||||
|  | 	} else if direction == 0 { | ||||||
|  | 		return KeynavDirectionNeutral | ||||||
|  | 	} else { | ||||||
|  | 		return KeynavDirectionBackward | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -1,8 +1,8 @@ | |||||||
| package layouts | package basicLayouts | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/layouts" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| // Dialog arranges elements in the form of a dialog box. The first element is | // Dialog arranges elements in the form of a dialog box. The first element is | ||||||
| // positioned above as the main focus of the dialog, and is set to expand | // positioned above as the main focus of the dialog, and is set to expand | ||||||
| @ -19,13 +19,18 @@ type Dialog struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Arrange arranges a list of entries into a dialog. | // Arrange arranges a list of entries into a dialog. | ||||||
| func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) { | func (layout Dialog) Arrange ( | ||||||
| 	if layout.Pad { bounds = bounds.Inset(theme.Margin()) } | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
|  | 	bounds image.Rectangle, | ||||||
|  | ) { | ||||||
|  | 	if layout.Pad { bounds = bounds.Inset(margin) } | ||||||
| 	 | 	 | ||||||
| 	controlRowWidth, controlRowHeight := 0, 0 | 	controlRowWidth, controlRowHeight := 0, 0 | ||||||
| 	if len(entries) > 1 { | 	if len(entries) > 1 { | ||||||
| 		controlRowWidth, | 		controlRowWidth, | ||||||
| 		controlRowHeight = layout.minimumSizeOfControlRow(entries[1:]) | 		controlRowHeight = layout.minimumSizeOfControlRow ( | ||||||
|  | 			entries[1:], margin) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(entries) > 0 { | 	if len(entries) > 0 { | ||||||
| @ -33,7 +38,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle | |||||||
| 		main.Bounds.Min = bounds.Min | 		main.Bounds.Min = bounds.Min | ||||||
| 		mainHeight := bounds.Dy() - controlRowHeight | 		mainHeight := bounds.Dy() - controlRowHeight | ||||||
| 		if layout.Gap { | 		if layout.Gap { | ||||||
| 			mainHeight -= theme.Margin() | 			mainHeight -= margin | ||||||
| 		} | 		} | ||||||
| 		main.Bounds.Max = main.Bounds.Min.Add(image.Pt(bounds.Dx(), mainHeight)) | 		main.Bounds.Max = main.Bounds.Min.Add(image.Pt(bounds.Dx(), mainHeight)) | ||||||
| 		entries[0] = main | 		entries[0] = main | ||||||
| @ -53,7 +58,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle | |||||||
| 				freeSpace -= entryMinWidth | 				freeSpace -= entryMinWidth | ||||||
| 			} | 			} | ||||||
| 			if index > 0 && layout.Gap { | 			if index > 0 && layout.Gap { | ||||||
| 				freeSpace -= theme.Margin() | 				freeSpace -= margin | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		expandingElementWidth := 0 | 		expandingElementWidth := 0 | ||||||
| @ -69,7 +74,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle | |||||||
| 
 | 
 | ||||||
| 		// set the size and position of each element in the control row | 		// set the size and position of each element in the control row | ||||||
| 		for index, entry := range entries[1:] { | 		for index, entry := range entries[1:] { | ||||||
| 			if index > 0 && layout.Gap { dot.X += theme.Margin() } | 			if index > 0 && layout.Gap { dot.X += margin } | ||||||
| 			 | 			 | ||||||
| 			entry.Bounds.Min = dot | 			entry.Bounds.Min = dot | ||||||
| 			entryWidth := 0 | 			entryWidth := 0 | ||||||
| @ -95,7 +100,8 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle | |||||||
| // MinimumSize returns the minimum width and height that will be needed to | // MinimumSize returns the minimum width and height that will be needed to | ||||||
| // arrange the given list of entries. | // arrange the given list of entries. | ||||||
| func (layout Dialog) MinimumSize ( | func (layout Dialog) MinimumSize ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| ) ( | ) ( | ||||||
| 	width, height int, | 	width, height int, | ||||||
| ) { | ) { | ||||||
| @ -106,9 +112,10 @@ func (layout Dialog) MinimumSize ( | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(entries) > 1 { | 	if len(entries) > 1 { | ||||||
| 		if layout.Gap { height += theme.Margin() } | 		if layout.Gap { height += margin } | ||||||
| 		additionalWidth, | 		additionalWidth, | ||||||
| 		additionalHeight := layout.minimumSizeOfControlRow(entries[1:]) | 		additionalHeight := layout.minimumSizeOfControlRow ( | ||||||
|  | 			entries[1:], margin) | ||||||
| 		height += additionalHeight | 		height += additionalHeight | ||||||
| 		if additionalWidth > width { | 		if additionalWidth > width { | ||||||
| 			width = additionalWidth | 			width = additionalWidth | ||||||
| @ -116,8 +123,8 @@ func (layout Dialog) MinimumSize ( | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		width  += theme.Margin() * 2 | 		width  += margin * 2 | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -125,18 +132,19 @@ func (layout Dialog) MinimumSize ( | |||||||
| // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | ||||||
| // specified elements at the given width, taking into account flexible elements. | // specified elements at the given width, taking into account flexible elements. | ||||||
| func (layout Dialog) FlexibleHeightFor ( | func (layout Dialog) FlexibleHeightFor ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| 	width int, | 	width int, | ||||||
| ) ( | ) ( | ||||||
| 	height int, | 	height int, | ||||||
| ) { | ) { | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		width -= theme.Margin() * 2 | 		width -= margin * 2 | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	if len(entries) > 0 { | 	if len(entries) > 0 { | ||||||
| 		mainChildHeight := 0 | 		mainChildHeight := 0 | ||||||
| 		if child, flexible := entries[0].Element.(tomo.Flexible); flexible { | 		if child, flexible := entries[0].Element.(elements.Flexible); flexible { | ||||||
| 			mainChildHeight = child.FlexibleHeightFor(width) | 			mainChildHeight = child.FlexibleHeightFor(width) | ||||||
| 		} else { | 		} else { | ||||||
| 			_, mainChildHeight = entries[0].MinimumSize() | 			_, mainChildHeight = entries[0].MinimumSize() | ||||||
| @ -145,13 +153,14 @@ func (layout Dialog) FlexibleHeightFor ( | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(entries) > 1 { | 	if len(entries) > 1 { | ||||||
| 		if layout.Gap { height += theme.Margin() } | 		if layout.Gap { height += margin } | ||||||
| 		_, additionalHeight := layout.minimumSizeOfControlRow(entries[1:]) | 		_, additionalHeight := layout.minimumSizeOfControlRow ( | ||||||
|  | 			entries[1:], margin) | ||||||
| 		height += additionalHeight | 		height += additionalHeight | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -159,7 +168,8 @@ func (layout Dialog) FlexibleHeightFor ( | |||||||
| // TODO: possibly flatten this method to account for flexible elements within | // TODO: possibly flatten this method to account for flexible elements within | ||||||
| // the control row. | // the control row. | ||||||
| func (layout Dialog) minimumSizeOfControlRow ( | func (layout Dialog) minimumSizeOfControlRow ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| ) ( | ) ( | ||||||
| 	width, height int, | 	width, height int, | ||||||
| ) { | ) { | ||||||
| @ -170,7 +180,7 @@ func (layout Dialog) minimumSizeOfControlRow ( | |||||||
| 		} | 		} | ||||||
| 		width += entryWidth | 		width += entryWidth | ||||||
| 		if layout.Gap && index > 0 { | 		if layout.Gap && index > 0 { | ||||||
| 			width += theme.Margin() | 			width += margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| @ -1,8 +1,8 @@ | |||||||
| package layouts | package basicLayouts | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/layouts" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| // Horizontal arranges elements horizontally. Elements at the start of the entry | // Horizontal arranges elements horizontally. Elements at the start of the entry | ||||||
| // list will be positioned on the left, and elements at the end of the entry | // list will be positioned on the left, and elements at the end of the entry | ||||||
| @ -17,16 +17,21 @@ type Horizontal struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Arrange arranges a list of entries horizontally. | // Arrange arranges a list of entries horizontally. | ||||||
| func (layout Horizontal) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) { | func (layout Horizontal) Arrange ( | ||||||
| 	if layout.Pad { bounds = bounds.Inset(theme.Margin()) } | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
|  | 	bounds image.Rectangle, | ||||||
|  | ) { | ||||||
|  | 	if layout.Pad { bounds = bounds.Inset(margin) } | ||||||
| 	 | 	 | ||||||
| 	// get width of expanding elements | 	// get width of expanding elements | ||||||
| 	expandingElementWidth := layout.expandingElementWidth(entries, bounds.Dx()) | 	expandingElementWidth := layout.expandingElementWidth ( | ||||||
|  | 		entries, margin, bounds.Dx()) | ||||||
| 
 | 
 | ||||||
| 	// set the size and position of each element | 	// set the size and position of each element | ||||||
| 	dot := bounds.Min | 	dot := bounds.Min | ||||||
| 	for index, entry := range entries { | 	for index, entry := range entries { | ||||||
| 		if index > 0 && layout.Gap { dot.X += theme.Margin() } | 		if index > 0 && layout.Gap { dot.X += margin } | ||||||
| 		 | 		 | ||||||
| 		entry.Bounds.Min = dot | 		entry.Bounds.Min = dot | ||||||
| 		entryWidth := 0 | 		entryWidth := 0 | ||||||
| @ -45,7 +50,8 @@ func (layout Horizontal) Arrange (entries []tomo.LayoutEntry, bounds image.Recta | |||||||
| // MinimumSize returns the minimum width and height that will be needed to | // MinimumSize returns the minimum width and height that will be needed to | ||||||
| // arrange the given list of entries. | // arrange the given list of entries. | ||||||
| func (layout Horizontal) MinimumSize ( | func (layout Horizontal) MinimumSize ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| ) ( | ) ( | ||||||
| 	width, height int, | 	width, height int, | ||||||
| ) { | ) { | ||||||
| @ -56,13 +62,13 @@ func (layout Horizontal) MinimumSize ( | |||||||
| 		} | 		} | ||||||
| 		width += entryWidth | 		width += entryWidth | ||||||
| 		if layout.Gap && index > 0 { | 		if layout.Gap && index > 0 { | ||||||
| 			width += theme.Margin() | 			width += margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		width  += theme.Margin() * 2 | 		width  += margin * 2 | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -70,21 +76,22 @@ func (layout Horizontal) MinimumSize ( | |||||||
| // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | ||||||
| // specified elements at the given width, taking into account flexible elements. | // specified elements at the given width, taking into account flexible elements. | ||||||
| func (layout Horizontal) FlexibleHeightFor ( | func (layout Horizontal) FlexibleHeightFor ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| 	width int, | 	width int, | ||||||
| ) ( | ) ( | ||||||
| 	height int, | 	height int, | ||||||
| ) { | ) { | ||||||
| 	if layout.Pad { | 	if layout.Pad { width -= margin * 2 } | ||||||
| 		width -= theme.Margin() * 2 | 	 | ||||||
| 	} |  | ||||||
| 	// get width of expanding elements | 	// get width of expanding elements | ||||||
| 	expandingElementWidth := layout.expandingElementWidth(entries, width) | 	expandingElementWidth := layout.expandingElementWidth ( | ||||||
|  | 		entries, margin, width) | ||||||
| 	 | 	 | ||||||
| 	x, y := 0, 0 | 	x, y := 0, 0 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		x += theme.Margin() | 		x += margin | ||||||
| 		y += theme.Margin() | 		y += margin | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// set the size and position of each element | 	// set the size and position of each element | ||||||
| @ -93,23 +100,24 @@ func (layout Horizontal) FlexibleHeightFor ( | |||||||
| 		if entry.Expand { | 		if entry.Expand { | ||||||
| 			entryWidth = expandingElementWidth | 			entryWidth = expandingElementWidth | ||||||
| 		} | 		} | ||||||
| 		if child, flexible := entry.Element.(tomo.Flexible); flexible { | 		if child, flexible := entry.Element.(elements.Flexible); flexible { | ||||||
| 			entryHeight = child.FlexibleHeightFor(entryWidth) | 			entryHeight = child.FlexibleHeightFor(entryWidth) | ||||||
| 		} | 		} | ||||||
| 		if entryHeight > height { height = entryHeight } | 		if entryHeight > height { height = entryHeight } | ||||||
| 		 | 		 | ||||||
| 		x += entryWidth | 		x += entryWidth | ||||||
| 		if index > 0 && layout.Gap { x += theme.Margin() } | 		if index > 0 && layout.Gap { x += margin } | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (layout Horizontal) expandingElementWidth ( | func (layout Horizontal) expandingElementWidth ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| 	freeSpace int, | 	freeSpace int, | ||||||
| ) ( | ) ( | ||||||
| 	width int, | 	width int, | ||||||
| @ -126,7 +134,7 @@ func (layout Horizontal) expandingElementWidth ( | |||||||
| 			freeSpace -= entryMinWidth | 			freeSpace -= entryMinWidth | ||||||
| 		} | 		} | ||||||
| 		if index > 0 && layout.Gap { | 		if index > 0 && layout.Gap { | ||||||
| 			freeSpace -= theme.Margin() | 			freeSpace -= margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -1,8 +1,8 @@ | |||||||
| package layouts | package basicLayouts | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo/layouts" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/theme" | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| // Vertical arranges elements vertically. Elements at the start of the entry | // Vertical arranges elements vertically. Elements at the start of the entry | ||||||
| // list will be positioned at the top, and elements at the end of the entry list | // list will be positioned at the top, and elements at the end of the entry list | ||||||
| @ -17,8 +17,12 @@ type Vertical struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Arrange arranges a list of entries vertically. | // Arrange arranges a list of entries vertically. | ||||||
| func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) { | func (layout Vertical) Arrange ( | ||||||
| 	if layout.Pad { bounds = bounds.Inset(theme.Margin()) } | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
|  | 	bounds image.Rectangle, | ||||||
|  | ) { | ||||||
|  | 	if layout.Pad { bounds = bounds.Inset(margin) } | ||||||
| 
 | 
 | ||||||
| 	// count the number of expanding elements and the amount of free space | 	// count the number of expanding elements and the amount of free space | ||||||
| 	// for them to collectively occupy, while gathering minimum heights. | 	// for them to collectively occupy, while gathering minimum heights. | ||||||
| @ -28,7 +32,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang | |||||||
| 	for index, entry := range entries { | 	for index, entry := range entries { | ||||||
| 		var entryMinHeight int | 		var entryMinHeight int | ||||||
| 
 | 
 | ||||||
| 		if child, flexible := entry.Element.(tomo.Flexible); flexible { | 		if child, flexible := entry.Element.(elements.Flexible); flexible { | ||||||
| 			entryMinHeight = child.FlexibleHeightFor(bounds.Dx()) | 			entryMinHeight = child.FlexibleHeightFor(bounds.Dx()) | ||||||
| 		} else { | 		} else { | ||||||
| 			_, entryMinHeight = entry.MinimumSize() | 			_, entryMinHeight = entry.MinimumSize() | ||||||
| @ -41,7 +45,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang | |||||||
| 			freeSpace -= entryMinHeight | 			freeSpace -= entryMinHeight | ||||||
| 		} | 		} | ||||||
| 		if index > 0 && layout.Gap { | 		if index > 0 && layout.Gap { | ||||||
| 			freeSpace -= theme.Margin() | 			freeSpace -= margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| @ -53,7 +57,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang | |||||||
| 	// set the size and position of each element | 	// set the size and position of each element | ||||||
| 	dot := bounds.Min | 	dot := bounds.Min | ||||||
| 	for index, entry := range entries { | 	for index, entry := range entries { | ||||||
| 		if index > 0 && layout.Gap { dot.Y += theme.Margin() } | 		if index > 0 && layout.Gap { dot.Y += margin } | ||||||
| 		 | 		 | ||||||
| 		entry.Bounds.Min = dot | 		entry.Bounds.Min = dot | ||||||
| 		entryHeight := 0 | 		entryHeight := 0 | ||||||
| @ -72,7 +76,8 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang | |||||||
| // MinimumSize returns the minimum width and height that will be needed to | // MinimumSize returns the minimum width and height that will be needed to | ||||||
| // arrange the given list of entries. | // arrange the given list of entries. | ||||||
| func (layout Vertical) MinimumSize ( | func (layout Vertical) MinimumSize ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| ) ( | ) ( | ||||||
| 	width, height int, | 	width, height int, | ||||||
| ) { | ) { | ||||||
| @ -83,13 +88,13 @@ func (layout Vertical) MinimumSize ( | |||||||
| 		} | 		} | ||||||
| 		height += entryHeight | 		height += entryHeight | ||||||
| 		if layout.Gap && index > 0 { | 		if layout.Gap && index > 0 { | ||||||
| 			height += theme.Margin() | 			height += margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		width  += theme.Margin() * 2 | 		width  += margin * 2 | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -97,18 +102,19 @@ func (layout Vertical) MinimumSize ( | |||||||
| // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | // FlexibleHeightFor Returns the minimum height the layout needs to lay out the | ||||||
| // specified elements at the given width, taking into account flexible elements. | // specified elements at the given width, taking into account flexible elements. | ||||||
| func (layout Vertical) FlexibleHeightFor ( | func (layout Vertical) FlexibleHeightFor ( | ||||||
| 	entries []tomo.LayoutEntry, | 	entries []layouts.LayoutEntry, | ||||||
|  | 	margin int, | ||||||
| 	width int, | 	width int, | ||||||
| ) ( | ) ( | ||||||
| 	height int, | 	height int, | ||||||
| ) { | ) { | ||||||
| 	if layout.Pad { | 	if layout.Pad { | ||||||
| 		width -= theme.Margin() * 2 | 		width -= margin * 2 | ||||||
| 		height += theme.Margin() * 2 | 		height += margin * 2 | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	for index, entry := range entries { | 	for index, entry := range entries { | ||||||
| 		child, flexible := entry.Element.(tomo.Flexible) | 		child, flexible := entry.Element.(elements.Flexible) | ||||||
| 		if flexible { | 		if flexible { | ||||||
| 			height += child.FlexibleHeightFor(width) | 			height += child.FlexibleHeightFor(width) | ||||||
| 		} else { | 		} else { | ||||||
| @ -117,7 +123,7 @@ func (layout Vertical) FlexibleHeightFor ( | |||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		if layout.Gap && index > 0 { | 		if layout.Gap && index > 0 { | ||||||
| 			height += theme.Margin() | 			height += margin | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| @ -1,11 +1,12 @@ | |||||||
| package tomo | package layouts | ||||||
| 
 | 
 | ||||||
| import "image" | import "image" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| // LayoutEntry associates an element with layout and positioning information so | // LayoutEntry associates an element with layout and positioning information so | ||||||
| // it can be arranged by a Layout. | // it can be arranged by a Layout. | ||||||
| type LayoutEntry struct { | type LayoutEntry struct { | ||||||
| 	Element | 	elements.Element | ||||||
| 	Bounds image.Rectangle | 	Bounds image.Rectangle | ||||||
| 	Expand bool | 	Expand bool | ||||||
| } | } | ||||||
| @ -17,14 +18,20 @@ type Layout interface { | |||||||
| 	// and changes the position of the entiries in the slice so that they | 	// and changes the position of the entiries in the slice so that they | ||||||
| 	// are properly laid out. The given width and height should not be less | 	// are properly laid out. The given width and height should not be less | ||||||
| 	// than what is returned by MinimumSize. | 	// than what is returned by MinimumSize. | ||||||
| 	Arrange (entries []LayoutEntry, bounds image.Rectangle) | 	Arrange (entries []LayoutEntry, margin int, bounds image.Rectangle) | ||||||
| 
 | 
 | ||||||
| 	// MinimumSize returns the minimum width and height that the layout | 	// MinimumSize returns the minimum width and height that the layout | ||||||
| 	// needs to properly arrange the given slice of layout entries. | 	// needs to properly arrange the given slice of layout entries. | ||||||
| 	MinimumSize (entries []LayoutEntry) (width, height int) | 	MinimumSize (entries []LayoutEntry, margin int) (width, height int) | ||||||
| 
 | 
 | ||||||
| 	// FlexibleHeightFor Returns the minimum height the layout needs to lay | 	// FlexibleHeightFor Returns the minimum height the layout needs to lay | ||||||
| 	// out the specified elements at the given width, taking into account | 	// out the specified elements at the given width, taking into account | ||||||
| 	// flexible elements. | 	// flexible elements. | ||||||
| 	FlexibleHeightFor (entries []LayoutEntry, squeeze int) (height int) | 	FlexibleHeightFor ( | ||||||
|  | 		entries []LayoutEntry, | ||||||
|  | 		margin int, | ||||||
|  | 		squeeze int, | ||||||
|  | 	) ( | ||||||
|  | 		height int, | ||||||
|  | 	) | ||||||
| } | } | ||||||
| @ -1,7 +1,8 @@ | |||||||
| package popups | package popups | ||||||
| 
 | 
 | ||||||
| import "git.tebibyte.media/sashakoshka/tomo" | import "git.tebibyte.media/sashakoshka/tomo" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/layouts" | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/layouts/basic" | ||||||
| import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | import "git.tebibyte.media/sashakoshka/tomo/elements/basic" | ||||||
| 
 | 
 | ||||||
| // DialogKind defines the semantic role of a dialog window. | // DialogKind defines the semantic role of a dialog window. | ||||||
| @ -30,24 +31,24 @@ func NewDialog ( | |||||||
| 	title, message string, | 	title, message string, | ||||||
| 	buttons ...Button, | 	buttons ...Button, | ||||||
| ) ( | ) ( | ||||||
| 	window tomo.Window, | 	window elements.Window, | ||||||
| ) { | ) { | ||||||
| 	window, _ = tomo.NewWindow(2, 2) | 	window, _ = tomo.NewWindow(2, 2) | ||||||
| 	window.SetTitle(title) | 	window.SetTitle(title) | ||||||
| 	 | 	 | ||||||
| 	container := basic.NewContainer(layouts.Dialog { true, true }) | 	container := basicElements.NewContainer(basicLayouts.Dialog { true, true }) | ||||||
| 	window.Adopt(container) | 	window.Adopt(container) | ||||||
| 
 | 
 | ||||||
| 	container.Adopt(basic.NewLabel(message, false), true) | 	container.Adopt(basicElements.NewLabel(message, false), true) | ||||||
| 	if len(buttons) == 0 { | 	if len(buttons) == 0 { | ||||||
| 		button := basic.NewButton("OK") | 		button := basicElements.NewButton("OK") | ||||||
| 		button.OnClick(window.Close) | 		button.OnClick(window.Close) | ||||||
| 		container.Adopt(button, false) | 		container.Adopt(button, false) | ||||||
| 		button.Focus() | 		button.Focus() | ||||||
| 	} else { | 	} else { | ||||||
| 		var button *basic.Button | 		var button *basicElements.Button | ||||||
| 		for _, buttonDescriptor := range buttons { | 		for _, buttonDescriptor := range buttons { | ||||||
| 			button = basic.NewButton(buttonDescriptor.Name) | 			button = basicElements.NewButton(buttonDescriptor.Name) | ||||||
| 			button.SetEnabled(buttonDescriptor.OnPress != nil) | 			button.SetEnabled(buttonDescriptor.OnPress != nil) | ||||||
| 			button.OnClick (func () { | 			button.OnClick (func () { | ||||||
| 				buttonDescriptor.OnPress() | 				buttonDescriptor.OnPress() | ||||||
|  | |||||||
| @ -111,24 +111,3 @@ func FontFaceItalic () font.Face { | |||||||
| func FontFaceBoldItalic () font.Face { | func FontFaceBoldItalic () font.Face { | ||||||
| 	return defaultfont.FaceBoldItalic | 	return defaultfont.FaceBoldItalic | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // Padding returns the amount of internal padding elements should have. An |  | ||||||
| // element's inner content (such as text) should be inset by this amount, |  | ||||||
| // in addition to the inset returned by the pattern of its background. When |  | ||||||
| // using the aforementioned inset values to calculate the element's minimum size |  | ||||||
| // or the position and alignment of its content, all parameters in the |  | ||||||
| // PatternState should be unset except for Case. |  | ||||||
| func Padding () int { |  | ||||||
| 	return 7 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Margin returns how much space should be put in between elements. |  | ||||||
| func Margin () int { |  | ||||||
| 	return 8 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HandleWidth returns how large grab handles should typically be. This is |  | ||||||
| // important for accessibility reasons. |  | ||||||
| func HandleWidth () int { |  | ||||||
| 	return 16 |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								tomo.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								tomo.go
									
									
									
									
									
								
							| @ -1,6 +1,8 @@ | |||||||
| package tomo | package tomo | ||||||
| 
 | 
 | ||||||
| import "errors" | import "errors" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/data" | ||||||
|  | import "git.tebibyte.media/sashakoshka/tomo/elements" | ||||||
| 
 | 
 | ||||||
| var backend Backend | var backend Backend | ||||||
| 
 | 
 | ||||||
| @ -32,7 +34,7 @@ func Do (callback func ()) { | |||||||
| // Window. If the window could not be created, an error is returned explaining | // Window. If the window could not be created, an error is returned explaining | ||||||
| // why. If this function is called without a running backend, an error is | // why. If this function is called without a running backend, an error is | ||||||
| // returned as well. | // returned as well. | ||||||
| func NewWindow (width, height int) (window Window, err error) { | func NewWindow (width, height int) (window elements.Window, err error) { | ||||||
| 	if backend == nil { | 	if backend == nil { | ||||||
| 		err = errors.New("no backend is running.") | 		err = errors.New("no backend is running.") | ||||||
| 		return | 		return | ||||||
| @ -41,14 +43,14 @@ func NewWindow (width, height int) (window Window, err error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Copy puts data into the clipboard. | // Copy puts data into the clipboard. | ||||||
| func Copy (data Data) { | func Copy (data data.Data) { | ||||||
| 	if backend == nil { panic("no backend is running") } | 	if backend == nil { panic("no backend is running") } | ||||||
| 	backend.Copy(data) | 	backend.Copy(data) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Paste returns the data currently in the clipboard. This method may | // Paste returns the data currently in the clipboard. This method may | ||||||
| // return nil. | // return nil. | ||||||
| func Paste (accept []Mime) (Data) { | func Paste (accept []data.Mime) (data.Data) { | ||||||
| 	if backend == nil { panic("no backend is running") } | 	if backend == nil { panic("no backend is running") } | ||||||
| 	return backend.Paste(accept) | 	return backend.Paste(accept) | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user