diff --git a/.golangci-lint.yaml b/.github/workflows/golangci-lint.yaml similarity index 99% rename from .golangci-lint.yaml rename to .github/workflows/golangci-lint.yaml index b130b67e..b98af243 100644 --- a/.golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -5,6 +5,7 @@ on: - v* branches: - master + - main pull_request: jobs: diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..53f878ee --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,101 @@ +--- +linters-settings: + dupl: + threshold: 100 + funlen: + lines: 100 + statements: 50 + goconst: + min-len: 2 + min-occurrences: 2 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + gocyclo: + min-complexity: 15 + goimports: + local-prefixes: github.com/AllenDang/giu + govet: + check-shadowing: true + lll: + line-length: 140 + maligned: + suggest-new: true + misspell: + locale: US + +linters: + disable-all: true + enable: + - asciicheck + - bodyclose + - deadcode + - depguard + - dogsled + - dupl + - errcheck + - errorlint + - exportloopref + #- forcetypeassert + #- funlen + - gci + #- godot + #- gochecknoglobals + #- gochecknoinits + - gocognit + - goconst + - gocritic + - gocyclo + #- godox + - goerr113 + - gofmt + - gofumpt + - goheader + - goimports + #- gomnd + - goprintffuncname + - gosec + - gosimple + - govet + - ifshort + - importas + - ineffassign + - lll + - makezero + - misspell + - nakedret + - nilerr + - nolintlint + - prealloc + - predeclared + - promlinter + #- revive + - rowserrcheck + - staticcheck + - structcheck + - stylecheck + - typecheck + - unconvert + - unparam + - unused + - varcheck + - wastedassign + - whitespace + #- wrapcheck + #- wsl + +run: + timeout: 5m + skip-dirs: + - .github + - build + - web + +issues: + max-same-issues: 0 + exclude-use-default: false diff --git a/Alignment.go b/Alignment.go index 6344bfc1..f961f224 100644 --- a/Alignment.go +++ b/Alignment.go @@ -35,11 +35,14 @@ func Align(at AlignmentType) *AlignmentSetter { } } +// To sets a layout, alignment should be applied to func (a *AlignmentSetter) To(widgets ...Widget) *AlignmentSetter { a.layout = Layout(widgets) return a } +// ID allows to manually set AlignmentSetter ID (it shouldn't be used +// in a normal conditions) func (a *AlignmentSetter) ID(id string) *AlignmentSetter { a.id = id return a @@ -59,6 +62,7 @@ func (a *AlignmentSetter) Build() { } // exclude some widgets from alignment process + // nolint:gocritic // could have more cases later switch item.(type) { case *CustomWidget: item.Build() @@ -84,9 +88,9 @@ func (a *AlignmentSetter) Build() { case AlignLeft: SetCursorPos(currentPos) case AlignCenter: - SetCursorPos(image.Pt(int(availableW/2-w/2), int(currentPos.Y))) + SetCursorPos(image.Pt(int(availableW/2-w/2), currentPos.Y)) case AlignRight: - SetCursorPos(image.Pt(int(availableW-w), int(currentPos.Y))) + SetCursorPos(image.Pt(int(availableW-w), currentPos.Y)) default: panic(fmt.Sprintf("giu: (*AlignSetter).Build: unknown align type %d", a.alignType)) } diff --git a/Canvas.go b/Canvas.go index 5de1526e..1403c745 100644 --- a/Canvas.go +++ b/Canvas.go @@ -7,77 +7,105 @@ import ( "github.com/AllenDang/imgui-go" ) +// Canvas represents imgui.DrawList +// for more details see examples/canvas type Canvas struct { drawlist imgui.DrawList } +// GetCanvas creates new Canvas func GetCanvas() *Canvas { return &Canvas{ drawlist: imgui.GetWindowDrawList(), } } -func (c *Canvas) AddLine(p1, p2 image.Point, color color.RGBA, thickness float32) { - c.drawlist.AddLine(ToVec2(p1), ToVec2(p2), ToVec4Color(color), thickness) +// AddLine draws a line (from p1 to p2) +func (c *Canvas) AddLine(p1, p2 image.Point, col color.RGBA, thickness float32) { + c.drawlist.AddLine(ToVec2(p1), ToVec2(p2), ToVec4Color(col), thickness) } +// DrawFlags represents imgui.DrawFlags type DrawFlags int +// draw flags enum: const ( - DrawFlagsNone DrawFlags = 0 - DrawFlagsClosed DrawFlags = 1 << 0 // PathStroke(), AddPolyline(): specify that shape should be closed (portant: this is always == 1 for legacy reason) - DrawFlagsRoundCornersTopLeft DrawFlags = 1 << 4 // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. - DrawFlagsRoundCornersTopRight DrawFlags = 1 << 5 // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. - DrawFlagsRoundCornersBottomLeft DrawFlags = 1 << 6 // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. - DrawFlagsRoundCornersBottomRight DrawFlags = 1 << 7 // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. - DrawFlagsRoundCornersNone DrawFlags = 1 << 8 // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! - DrawFlagsRoundCornersTop DrawFlags = DrawFlagsRoundCornersTopLeft | DrawFlagsRoundCornersTopRight - DrawFlagsRoundCornersBottom DrawFlags = DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersBottomRight - DrawFlagsRoundCornersLeft DrawFlags = DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersTopLeft - DrawFlagsRoundCornersRight DrawFlags = DrawFlagsRoundCornersBottomRight | DrawFlagsRoundCornersTopRight - DrawFlagsRoundCornersAll DrawFlags = DrawFlagsRoundCornersTopLeft | DrawFlagsRoundCornersTopRight | DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersBottomRight - DrawFlagsRoundCornersDefault DrawFlags = DrawFlagsRoundCornersAll // Default to ALL corners if none of the RoundCornersXX flags are specified. - DrawFlagsRoundCornersMask DrawFlags = DrawFlagsRoundCornersAll | DrawFlagsRoundCornersNone + DrawFlagsNone DrawFlags = 0 + // PathStroke(), AddPolyline(): specify that shape should be closed (portant: this is always == 1 for legacy reason) + DrawFlagsClosed DrawFlags = 1 << 0 + // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). + // Was 0x01. + DrawFlagsRoundCornersTopLeft DrawFlags = 1 << 4 + // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). + // Was 0x02. + DrawFlagsRoundCornersTopRight DrawFlags = 1 << 5 + // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). + // Was 0x04. + DrawFlagsRoundCornersBottomLeft DrawFlags = 1 << 6 + // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, + // we default to all corners). Wax 0x08. + DrawFlagsRoundCornersBottomRight DrawFlags = 1 << 7 + // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! + DrawFlagsRoundCornersNone DrawFlags = 1 << 8 + DrawFlagsRoundCornersTop DrawFlags = DrawFlagsRoundCornersTopLeft | DrawFlagsRoundCornersTopRight + DrawFlagsRoundCornersBottom DrawFlags = DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersBottomRight + DrawFlagsRoundCornersLeft DrawFlags = DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersTopLeft + DrawFlagsRoundCornersRight DrawFlags = DrawFlagsRoundCornersBottomRight | DrawFlagsRoundCornersTopRight + DrawFlagsRoundCornersAll DrawFlags = DrawFlagsRoundCornersTopLeft | DrawFlagsRoundCornersTopRight | + DrawFlagsRoundCornersBottomLeft | DrawFlagsRoundCornersBottomRight + // Default to ALL corners if none of the RoundCornersXX flags are specified. + DrawFlagsRoundCornersDefault DrawFlags = DrawFlagsRoundCornersAll + DrawFlagsRoundCornersMask DrawFlags = DrawFlagsRoundCornersAll | DrawFlagsRoundCornersNone ) -func (c *Canvas) AddRect(pMin, pMax image.Point, color color.RGBA, rounding float32, rounding_corners DrawFlags, thickness float32) { - c.drawlist.AddRect(ToVec2(pMin), ToVec2(pMax), ToVec4Color(color), rounding, int(rounding_corners), thickness) +// AddRect draws a rectangle +func (c *Canvas) AddRect(pMin, pMax image.Point, col color.RGBA, rounding float32, roundingCorners DrawFlags, thickness float32) { + c.drawlist.AddRect(ToVec2(pMin), ToVec2(pMax), ToVec4Color(col), rounding, int(roundingCorners), thickness) } -func (c *Canvas) AddRectFilled(pMin, pMax image.Point, color color.RGBA, rounding float32, rounding_corners DrawFlags) { - c.drawlist.AddRectFilled(ToVec2(pMin), ToVec2(pMax), ToVec4Color(color), rounding, int(rounding_corners)) +// AddRectFilled draws a rectangle filled with `col` +func (c *Canvas) AddRectFilled(pMin, pMax image.Point, col color.RGBA, rounding float32, roundingCorners DrawFlags) { + c.drawlist.AddRectFilled(ToVec2(pMin), ToVec2(pMax), ToVec4Color(col), rounding, int(roundingCorners)) } -func (c *Canvas) AddText(pos image.Point, color color.RGBA, text string) { - c.drawlist.AddText(ToVec2(pos), ToVec4Color(color), tStr(text)) +// AddText draws text +func (c *Canvas) AddText(pos image.Point, col color.RGBA, text string) { + c.drawlist.AddText(ToVec2(pos), ToVec4Color(col), tStr(text)) } -func (c *Canvas) AddBezierCubic(pos0, cp0, cp1, pos1 image.Point, color color.RGBA, thickness float32, num_segments int) { - c.drawlist.AddBezierCubic(ToVec2(pos0), ToVec2(cp0), ToVec2(cp1), ToVec2(pos1), ToVec4Color(color), thickness, num_segments) +// AddBezierCubic draws bezier cubic +func (c *Canvas) AddBezierCubic(pos0, cp0, cp1, pos1 image.Point, col color.RGBA, thickness float32, numSegments int) { + c.drawlist.AddBezierCubic(ToVec2(pos0), ToVec2(cp0), ToVec2(cp1), ToVec2(pos1), ToVec4Color(col), thickness, numSegments) } -func (c *Canvas) AddTriangle(p1, p2, p3 image.Point, color color.RGBA, thickness float32) { - c.drawlist.AddTriangle(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec4Color(color), thickness) +// AddTriangle draws a triangle +func (c *Canvas) AddTriangle(p1, p2, p3 image.Point, col color.RGBA, thickness float32) { + c.drawlist.AddTriangle(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec4Color(col), thickness) } -func (c *Canvas) AddTriangleFilled(p1, p2, p3 image.Point, color color.RGBA) { - c.drawlist.AddTriangleFilled(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec4Color(color)) +// AddTriangleFilled draws a filled triangle +func (c *Canvas) AddTriangleFilled(p1, p2, p3 image.Point, col color.RGBA) { + c.drawlist.AddTriangleFilled(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec4Color(col)) } -func (c *Canvas) AddCircle(center image.Point, radius float32, color color.RGBA, segments int, thickness float32) { - c.drawlist.AddCircle(ToVec2(center), radius, ToVec4Color(color), segments, thickness) +// AddCircle draws a circle +func (c *Canvas) AddCircle(center image.Point, radius float32, col color.RGBA, segments int, thickness float32) { + c.drawlist.AddCircle(ToVec2(center), radius, ToVec4Color(col), segments, thickness) } -func (c *Canvas) AddCircleFilled(center image.Point, radius float32, color color.RGBA) { - c.drawlist.AddCircleFilled(ToVec2(center), radius, ToVec4Color(color)) +// AddCircleFilled draws a filled circle +func (c *Canvas) AddCircleFilled(center image.Point, radius float32, col color.RGBA) { + c.drawlist.AddCircleFilled(ToVec2(center), radius, ToVec4Color(col)) } -func (c *Canvas) AddQuad(p1, p2, p3, p4 image.Point, color color.RGBA, thickness float32) { - c.drawlist.AddQuad(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec2(p4), ToVec4Color(color), thickness) +// AddQuad draws a quad +func (c *Canvas) AddQuad(p1, p2, p3, p4 image.Point, col color.RGBA, thickness float32) { + c.drawlist.AddQuad(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec2(p4), ToVec4Color(col), thickness) } -func (c *Canvas) AddQuadFilled(p1, p2, p3, p4 image.Point, color color.RGBA) { - c.drawlist.AddQuadFilled(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec2(p4), ToVec4Color(color)) +// AddQuadFilled draws a filled quad +func (c *Canvas) AddQuadFilled(p1, p2, p3, p4 image.Point, col color.RGBA) { + c.drawlist.AddQuadFilled(ToVec2(p1), ToVec2(p2), ToVec2(p3), ToVec2(p4), ToVec4Color(col)) } // Stateful path API, add points then finish with PathFillConvex() or PathStroke() @@ -94,30 +122,30 @@ func (c *Canvas) PathLineToMergeDuplicate(pos image.Point) { c.drawlist.PathLineToMergeDuplicate(ToVec2(pos)) } -func (c *Canvas) PathFillConvex(color color.RGBA) { - c.drawlist.PathFillConvex(ToVec4Color(color)) +func (c *Canvas) PathFillConvex(col color.RGBA) { + c.drawlist.PathFillConvex(ToVec4Color(col)) } -func (c *Canvas) PathStroke(color color.RGBA, closed bool, thickness float32) { - c.drawlist.PathStroke(ToVec4Color(color), closed, thickness) +func (c *Canvas) PathStroke(col color.RGBA, closed bool, thickness float32) { + c.drawlist.PathStroke(ToVec4Color(col), closed, thickness) } -func (c *Canvas) PathArcTo(center image.Point, radius, a_min, a_max float32, num_segments int) { - c.drawlist.PathArcTo(ToVec2(center), radius, a_min, a_max, num_segments) +func (c *Canvas) PathArcTo(center image.Point, radius, min, max float32, numSegments int) { + c.drawlist.PathArcTo(ToVec2(center), radius, min, max, numSegments) } -func (c *Canvas) PathArcToFast(center image.Point, radius float32, a_min_of_12, a_max_of_12 int) { - c.drawlist.PathArcToFast(ToVec2(center), radius, a_min_of_12, a_max_of_12) +func (c *Canvas) PathArcToFast(center image.Point, radius float32, min12, max12 int) { + c.drawlist.PathArcToFast(ToVec2(center), radius, min12, max12) } -func (c *Canvas) PathBezierCubicCurveTo(p1, p2, p3 image.Point, num_segments int) { - c.drawlist.PathBezierCubicCurveTo(ToVec2(p1), ToVec2(p2), ToVec2(p3), num_segments) +func (c *Canvas) PathBezierCubicCurveTo(p1, p2, p3 image.Point, numSegments int) { + c.drawlist.PathBezierCubicCurveTo(ToVec2(p1), ToVec2(p2), ToVec2(p3), numSegments) } func (c *Canvas) AddImage(texture *Texture, pMin, pMax image.Point) { c.drawlist.AddImage(texture.id, ToVec2(pMin), ToVec2(pMax)) } -func (c *Canvas) AddImageV(texture *Texture, pMin, pMax image.Point, uvMin, uvMax image.Point, color color.RGBA) { - c.drawlist.AddImageV(texture.id, ToVec2(pMin), ToVec2(pMax), ToVec2(uvMin), ToVec2(uvMax), ToVec4Color(color)) +func (c *Canvas) AddImageV(texture *Texture, pMin, pMax, uvMin, uvMax image.Point, col color.RGBA) { + c.drawlist.AddImageV(texture.id, ToVec2(pMin), ToVec2(pMax), ToVec2(uvMin), ToVec2(uvMax), ToVec4Color(col)) } diff --git a/CodeEditor.go b/CodeEditor.go index ecde14b0..e0dcef8d 100644 --- a/CodeEditor.go +++ b/CodeEditor.go @@ -6,8 +6,10 @@ import ( "github.com/AllenDang/imgui-go" ) +// LanguageDefinition represents code editor's language definition type LanguageDefinition byte +// language definitions: const ( LanguageDefinitionSQL LanguageDefinition = iota LanguageDefinitionCPP @@ -15,14 +17,21 @@ const ( LanguageDefinitionC ) +var _ Disposable = &codeEditorState{} + type codeEditorState struct { editor imgui.TextEditor } +// Dispose implements Disposable interface func (s *codeEditorState) Dispose() { // noop } +// static check if code editor implements Widget interface +var _ Widget = &CodeEditorWidget{} + +// CodeEditorWidget represents imgui.TextEditor type CodeEditorWidget struct { title string width, @@ -43,16 +52,19 @@ func (ce *CodeEditorWidget) ID(id string) *CodeEditorWidget { return ce } +// ShowWhitespaces sets if whitespaces are shown in code editor func (ce *CodeEditorWidget) ShowWhitespaces(s bool) *CodeEditorWidget { ce.getState().editor.SetShowWhitespaces(s) return ce } +// TabSize sets editor's tab size func (ce *CodeEditorWidget) TabSize(size int) *CodeEditorWidget { ce.getState().editor.SetTabSize(size) return ce } +// LanguageDefinition sets code editor language definition func (ce *CodeEditorWidget) LanguageDefinition(definition LanguageDefinition) *CodeEditorWidget { s := ce.getState() lookup := map[LanguageDefinition]func(){ @@ -72,63 +84,77 @@ func (ce *CodeEditorWidget) LanguageDefinition(definition LanguageDefinition) *C return ce } +// Text sets editor's text func (ce *CodeEditorWidget) Text(str string) *CodeEditorWidget { ce.getState().editor.SetText(str) return ce } +// ErrorMarkers sets error markers func (ce *CodeEditorWidget) ErrorMarkers(markers imgui.ErrorMarkers) *CodeEditorWidget { ce.getState().editor.SetErrorMarkers(markers) return ce } +// HandleKeyboardInputs sets if editor should handle keyboard input func (ce *CodeEditorWidget) HandleKeyboardInputs(b bool) *CodeEditorWidget { ce.getState().editor.SetHandleKeyboardInputs(b) return ce } +// Size sets editor's size func (ce *CodeEditorWidget) Size(w, h float32) *CodeEditorWidget { ce.width, ce.height = w, h return ce } +// Border sets editors borders func (ce *CodeEditorWidget) Border(border bool) *CodeEditorWidget { ce.border = border return ce } +// HasSelection returns true if some text is selected func (ce *CodeEditorWidget) HasSelection() bool { return ce.getState().editor.HasSelection() } +// GetSelectedText returns selected text func (ce *CodeEditorWidget) GetSelectedText() string { return ce.getState().editor.GetSelectedText() } +// GetText returns whole text from editor func (ce *CodeEditorWidget) GetText() string { return ce.getState().editor.GetText() } +// GetCurrentLineText returns current line func (ce *CodeEditorWidget) GetCurrentLineText() string { return ce.getState().editor.GetCurrentLineText() } -func (ce *CodeEditorWidget) GetCursorPos() (int, int) { +// GetCursorPos returns cursor position +func (ce *CodeEditorWidget) GetCursorPos() (x, y int) { return ce.getState().editor.GetCursorPos() } -func (ce *CodeEditorWidget) GetSelectionStart() (int, int) { +// GetSelectionStart returns star pos of selection +func (ce *CodeEditorWidget) GetSelectionStart() (x, y int) { return ce.getState().editor.GetSelectionStart() } +// InsertText inserts the `text` func (ce *CodeEditorWidget) InsertText(text string) { ce.getState().editor.InsertText(text) } +// GetWordUnderCursor returns the word under the cursor func (ce *CodeEditorWidget) GetWordUnderCursor() string { return ce.getState().editor.GetWordUnderCursor() } +// SelectWordUnderCursor selects the word under cursor func (ce *CodeEditorWidget) SelectWordUnderCursor() { ce.getState().editor.SelectWordUnderCursor() } @@ -137,26 +163,31 @@ func (ce *CodeEditorWidget) IsTextChanged() bool { return ce.getState().editor.IsTextChanged() } -func (ce *CodeEditorWidget) GetScreenCursorPos() (int, int) { +func (ce *CodeEditorWidget) GetScreenCursorPos() (x, y int) { return ce.getState().editor.GetScreenCursorPos() } +// Copy copies selection func (ce *CodeEditorWidget) Copy() { ce.getState().editor.Copy() } +// Cut cuts selection func (ce *CodeEditorWidget) Cut() { ce.getState().editor.Cut() } +// Paste does the same as Ctrl+V func (ce *CodeEditorWidget) Paste() { ce.getState().editor.Paste() } +// Delete deletes the selection func (ce *CodeEditorWidget) Delete() { ce.getState().editor.Delete() } +// Build implements Widget interface func (ce *CodeEditorWidget) Build() { s := ce.getState() diff --git a/Context.go b/Context.go index ab106fca..ad19d6ec 100644 --- a/Context.go +++ b/Context.go @@ -84,6 +84,6 @@ func (c *context) GetState(id string) interface{} { // Get widget index for current layout func (c *context) GetWidgetIndex() int { i := c.widgetIndexCounter - c.widgetIndexCounter += 1 + c.widgetIndexCounter++ return i } diff --git a/Direction.go b/Direction.go index 41bdc859..60ecd0de 100644 --- a/Direction.go +++ b/Direction.go @@ -1,7 +1,9 @@ package giu +// Direction represents a ArrowButton direction type Direction uint8 +// directions const ( DirectionLeft Direction = iota DirectionRight diff --git a/EventHandler.go b/EventHandler.go index 50821c1c..74f6b482 100644 --- a/EventHandler.go +++ b/EventHandler.go @@ -1,9 +1,12 @@ package giu +var _ Disposable = &eventHandlerState{} + type eventHandlerState struct { isActive bool } +// Dispose implements Disposable interface func (s *eventHandlerState) Dispose() { // noop } @@ -20,6 +23,8 @@ type keyEvent struct { cond func(Key) bool } +var _ Widget = &EventHandler{} + // EventHandler is a universal event handler for giu widgets. // put giu.Event()... after any widget to handle any event type EventHandler struct { @@ -30,6 +35,7 @@ type EventHandler struct { onDeactivate func() } +// Event adds a new event to widget above func Event() *EventHandler { return &EventHandler{ mouseEvents: make([]mouseEvent, 0), @@ -37,16 +43,19 @@ func Event() *EventHandler { } } +// OnHover sets callback when item gets hovered func (eh *EventHandler) OnHover(onHover func()) *EventHandler { eh.hover = onHover return eh } +// OnActivate sets callback when item gets activated func (eh *EventHandler) OnActivate(cb func()) *EventHandler { eh.onActivate = cb return eh } +// OnDeactivate sets callback when item gets deactivated func (eh *EventHandler) OnDeactivate(cb func()) *EventHandler { eh.onDeactivate = cb return eh @@ -54,16 +63,19 @@ func (eh *EventHandler) OnDeactivate(cb func()) *EventHandler { // Key events +// OnKeyDown sets callback when key `key` is down func (eh *EventHandler) OnKeyDown(key Key, cb func()) *EventHandler { eh.keyEvents = append(eh.keyEvents, keyEvent{key, cb, IsKeyDown}) return eh } +// OnKeyPressed sets callback when key `key` is pressed func (eh *EventHandler) OnKeyPressed(key Key, cb func()) *EventHandler { eh.keyEvents = append(eh.keyEvents, keyEvent{key, cb, IsKeyPressed}) return eh } +// OnKeyReleased sets callback when key `key` is released func (eh *EventHandler) OnKeyReleased(key Key, cb func()) *EventHandler { eh.keyEvents = append(eh.keyEvents, keyEvent{key, cb, IsKeyReleased}) return eh @@ -71,26 +83,32 @@ func (eh *EventHandler) OnKeyReleased(key Key, cb func()) *EventHandler { // Mouse events +// OnClick sets callback when mouse button `mouseButton` is clicked func (eh *EventHandler) OnClick(mouseButton MouseButton, callback func()) *EventHandler { eh.mouseEvents = append(eh.mouseEvents, mouseEvent{mouseButton, callback, IsMouseClicked}) return eh } +// OnDClick sets callback when mouse button `mouseButton` is double-clicked func (eh *EventHandler) OnDClick(mouseButton MouseButton, callback func()) *EventHandler { eh.mouseEvents = append(eh.mouseEvents, mouseEvent{mouseButton, callback, IsMouseDoubleClicked}) return eh } +// OnMouseDown sets callback when mouse button `mouseButton` is down func (eh *EventHandler) OnMouseDown(mouseButton MouseButton, callback func()) *EventHandler { eh.mouseEvents = append(eh.mouseEvents, mouseEvent{mouseButton, callback, IsMouseDown}) return eh } +// OnMouseReleased sets callback when mouse button `mouseButton` is released func (eh *EventHandler) OnMouseReleased(mouseButton MouseButton, callback func()) *EventHandler { eh.mouseEvents = append(eh.mouseEvents, mouseEvent{mouseButton, callback, IsMouseReleased}) return eh } +// Build implements Widget interface +// nolint:gocognit,gocyclo // will fix later func (eh *EventHandler) Build() { if eh.onActivate != nil || eh.onDeactivate != nil { isActive := IsItemActive() diff --git a/Events.go b/Events.go index 98c6e274..509c3aed 100644 --- a/Events.go +++ b/Events.go @@ -14,54 +14,70 @@ func IsItemHovered() bool { return imgui.IsItemHovered() } +// IsItemClicked returns true if mouse is clicked +// NOTE: if you're looking for clicking detection, see EventHandler.go func IsItemClicked(mouseButton MouseButton) bool { return imgui.IsItemClicked(int(mouseButton)) } +// IsItemActive returns true if item is active func IsItemActive() bool { return imgui.IsItemActive() } +// IsKeyDown returns true if key `key` is down func IsKeyDown(key Key) bool { return imgui.IsKeyDown(int(key)) } +// IsKeyPressed returns true if key `key` is pressed func IsKeyPressed(key Key) bool { return imgui.IsKeyPressed(int(key)) } +// IsKeyReleased returns true if key `key` is released func IsKeyReleased(key Key) bool { return imgui.IsKeyReleased(int(key)) } +// IsMouseDown returns true if mouse button `button` is down func IsMouseDown(button MouseButton) bool { return imgui.IsMouseDown(int(button)) } +// IsMouseClicked returns true if mouse button `button` is clicked +// NOTE: if you're looking for clicking detection, see EventHandler.go func IsMouseClicked(button MouseButton) bool { return imgui.IsMouseClicked(int(button)) } +// IsMouseReleased returns true if mouse button `button` is released func IsMouseReleased(button MouseButton) bool { return imgui.IsMouseReleased(int(button)) } +// IsMouseDoubleClicked returns true if mouse button `button` is double clicked func IsMouseDoubleClicked(button MouseButton) bool { return imgui.IsMouseDoubleClicked(int(button)) } +// IsWindowAppearing returns true if window is appearing func IsWindowAppearing() bool { return imgui.IsWindowAppearing() } +// IsWindowCollapsed returns true if window is disappearing func IsWindowCollapsed() bool { return imgui.IsWindowCollapsed() } +// IsWindowFocused returns true if window is focused +// NOTE: see also (*Window).HasFocus and (*Window).BringToFront func IsWindowFocused(flags FocusedFlags) bool { return imgui.IsWindowFocused(int(flags)) } +// IsWindowHovered returns true if the window is hovered func IsWindowHovered(flags HoveredFlags) bool { return imgui.IsWindowHovered(int(flags)) } diff --git a/Flags.go b/Flags.go index 931a39c2..b51b7bd1 100644 --- a/Flags.go +++ b/Flags.go @@ -3,27 +3,53 @@ package giu type InputTextFlags int const ( - InputTextFlagsNone InputTextFlags = 0 - InputTextFlagsCharsDecimal InputTextFlags = 1 << 0 // Allow 0123456789.+-*/ - InputTextFlagsCharsHexadecimal InputTextFlags = 1 << 1 // Allow 0123456789ABCDEFabcdef - InputTextFlagsCharsUppercase InputTextFlags = 1 << 2 // Turn a..z into A..Z - InputTextFlagsCharsNoBlank InputTextFlags = 1 << 3 // Filter out spaces, tabs - InputTextFlagsAutoSelectAll InputTextFlags = 1 << 4 // Select entire text when first taking mouse focus - InputTextFlagsEnterReturnsTrue InputTextFlags = 1 << 5 // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. - InputTextFlagsCallbackCompletion InputTextFlags = 1 << 6 // Callback on pressing TAB (for completion handling) - InputTextFlagsCallbackHistory InputTextFlags = 1 << 7 // Callback on pressing Up/Down arrows (for history handling) - InputTextFlagsCallbackAlways InputTextFlags = 1 << 8 // Callback on each iteration. User code may query cursor position, modify text buffer. - InputTextFlagsCallbackCharFilter InputTextFlags = 1 << 9 // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. - InputTextFlagsAllowTabInput InputTextFlags = 1 << 10 // Pressing TAB input a '\t' character into the text field - InputTextFlagsCtrlEnterForNewLine InputTextFlags = 1 << 11 // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). - InputTextFlagsNoHorizontalScroll InputTextFlags = 1 << 12 // Disable following the cursor horizontally - InputTextFlagsAlwaysOverwrite InputTextFlags = 1 << 13 // Overwrite mode - InputTextFlagsReadOnly InputTextFlags = 1 << 14 // Read-only mode - InputTextFlagsPassword InputTextFlags = 1 << 15 // Password mode, display all characters as '*' - InputTextFlagsNoUndoRedo InputTextFlags = 1 << 16 // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). - InputTextFlagsCharsScientific InputTextFlags = 1 << 17 // Allow 0123456789.+-*/eE (Scientific notation input) - InputTextFlagsCallbackResize InputTextFlags = 1 << 18 // Callback on buffer capacity changes request (beyond 'bufsize' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imguistdlib.h for an example of using this) - InputTextFlagsCallbackEdit InputTextFlags = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + InputTextFlagsNone InputTextFlags = 0 + // Allow 0123456789.+-*/ + InputTextFlagsCharsDecimal InputTextFlags = 1 << 0 + // Allow 0123456789ABCDEFabcdef + InputTextFlagsCharsHexadecimal InputTextFlags = 1 << 1 + // Turn a..z into A..Z + InputTextFlagsCharsUppercase InputTextFlags = 1 << 2 + // Filter out spaces, tabs + InputTextFlagsCharsNoBlank InputTextFlags = 1 << 3 + // Select entire text when first taking mouse focus + InputTextFlagsAutoSelectAll InputTextFlags = 1 << 4 + // Return 'true' when Enter is pressed (as opposed to every time the value was modified). + // Consider looking at the IsItemDeactivatedAfterEdit() function. + InputTextFlagsEnterReturnsTrue InputTextFlags = 1 << 5 + // Callback on pressing TAB (for completion handling) + InputTextFlagsCallbackCompletion InputTextFlags = 1 << 6 + // Callback on pressing Up/Down arrows (for history handling) + InputTextFlagsCallbackHistory InputTextFlags = 1 << 7 + // Callback on each iteration. User code may query cursor position, modify text buffer. + InputTextFlagsCallbackAlways InputTextFlags = 1 << 8 + // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + InputTextFlagsCallbackCharFilter InputTextFlags = 1 << 9 + // Pressing TAB input a '\t' character into the text field + InputTextFlagsAllowTabInput InputTextFlags = 1 << 10 + // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter + // (default is opposite: unfocus with Ctrl+Enter, add line with Enter). + InputTextFlagsCtrlEnterForNewLine InputTextFlags = 1 << 11 + // Disable following the cursor horizontally + InputTextFlagsNoHorizontalScroll InputTextFlags = 1 << 12 + // Overwrite mode + InputTextFlagsAlwaysOverwrite InputTextFlags = 1 << 13 + // Read-only mode + InputTextFlagsReadOnly InputTextFlags = 1 << 14 + // Password mode, display all characters as '*' + InputTextFlagsPassword InputTextFlags = 1 << 15 + // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo + // stack you need e.g. to call ClearActiveID(). + InputTextFlagsNoUndoRedo InputTextFlags = 1 << 16 + // Allow 0123456789.+-*/eE (Scientific notation input) + InputTextFlagsCharsScientific InputTextFlags = 1 << 17 + // Callback on buffer capacity changes request (beyond 'bufsize' parameter value), allowing the string to grow. + // Notify when the string wants to be resized (for string types which hold a cache of their Size). + // You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imguistdlib.h for an example of using this) + InputTextFlagsCallbackResize InputTextFlags = 1 << 18 + // Callback on any edit (note that InputText() already returns true on edit, + // the callback is useful mainly to manipulate the underlying buffer while focus is active) + InputTextFlagsCallbackEdit InputTextFlags = 1 << 19 ) type WindowFlags int @@ -112,6 +138,7 @@ const ( ComboFlagNoPreview ComboFlags = 1 << 6 ) +// SelectableFlags represents imgui.SelectableFlags type SelectableFlags int const ( @@ -127,6 +154,7 @@ const ( SelectableFlagsDisabled SelectableFlags = 1 << 3 ) +// TabItemFlags represents tab item flags type TabItemFlags int const ( @@ -177,6 +205,7 @@ const ( TabBarFlagsFittingPolicyDefault TabBarFlags = TabBarFlagsFittingPolicyResizeDown ) +// TreeNodeFlags represents tree node widget flags type TreeNodeFlags int const ( @@ -222,6 +251,7 @@ const ( TreeNodeFlagsCollapsingHeader TreeNodeFlags = TreeNodeFlagsFramed | TreeNodeFlagsNoTreePushOnOpen | TreeNodeFlagsNoAutoOpenOnLog ) +// FocusedFlags represents imgui.FocusedFlags type FocusedFlags int const ( @@ -237,10 +267,12 @@ const ( FocusedFlagsRootAndChildWindows = FocusedFlagsRootWindow | FocusedFlagsChildWindows ) +// HoveredFlags represents a hovered flags type HoveredFlags int const ( - // HoveredFlagsNone is the default and matches if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + // HoveredFlagsNone is the default and matches if directly over the item/window, + // not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. HoveredFlagsNone HoveredFlags = 0 // HoveredFlagsChildWindows is for IsWindowHovered() and matches if any children of the window is hovered HoveredFlagsChildWindows HoveredFlags = 1 << 0 @@ -250,16 +282,20 @@ const ( HoveredFlagsAnyWindow HoveredFlags = 1 << 2 // HoveredFlagsAllowWhenBlockedByPopup matches even if a popup window is normally blocking access to this item/window HoveredFlagsAllowWhenBlockedByPopup HoveredFlags = 1 << 3 - // HoveredFlagsAllowWhenBlockedByModal matches even if a modal popup window is normally blocking access to this item/window. UNIMPLEMENTED in imgui. + // HoveredFlagsAllowWhenBlockedByModal matches even if a modal popup window is normally blocking access to this item/window. + // UNIMPLEMENTED in imgui. // HoveredFlagsAllowWhenBlockedByModal HoveredFlags = 1 << 4 - // HoveredFlagsAllowWhenBlockedByActiveItem matches true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + // HoveredFlagsAllowWhenBlockedByActiveItem matches true even if an active item is blocking access to this item/window. + // Useful for Drag and Drop patterns. HoveredFlagsAllowWhenBlockedByActiveItem HoveredFlags = 1 << 5 // HoveredFlagsAllowWhenOverlapped matches even if the position is obstructed or overlapped by another window HoveredFlagsAllowWhenOverlapped HoveredFlags = 1 << 6 // HoveredFlagsAllowWhenDisabled matches even if the item is disabled HoveredFlagsAllowWhenDisabled HoveredFlags = 1 << 7 - // HoveredFlagsRectOnly combines HoveredFlagsAllowWhenBlockedByPopup, HoveredFlagsAllowWhenBlockedByActiveItem, and HoveredFlagsAllowWhenOverlapped. - HoveredFlagsRectOnly HoveredFlags = HoveredFlagsAllowWhenBlockedByPopup | HoveredFlagsAllowWhenBlockedByActiveItem | HoveredFlagsAllowWhenOverlapped + // HoveredFlagsRectOnly combines HoveredFlagsAllowWhenBlockedByPopup, + // HoveredFlagsAllowWhenBlockedByActiveItem, and HoveredFlagsAllowWhenOverlapped. + HoveredFlagsRectOnly HoveredFlags = HoveredFlagsAllowWhenBlockedByPopup | + HoveredFlagsAllowWhenBlockedByActiveItem | HoveredFlagsAllowWhenOverlapped // HoveredFlagsRootAndChildWindows combines HoveredFlagsRootWindow and HoveredFlagsChildWindows. HoveredFlagsRootAndChildWindows HoveredFlags = HoveredFlagsRootWindow | HoveredFlagsChildWindows ) @@ -325,143 +361,256 @@ const ( ColorEditFlagsInputHSV ColorEditFlags = 1 << 28 ) +// TableFlags represents table flags type TableFlags int +// Table flags enum: const ( // Features - TableFlagsNone TableFlags = 0 - TableFlagsResizable TableFlags = 1 << 0 // Enable resizing columns. - TableFlagsReorderable TableFlags = 1 << 1 // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) - TableFlagsHideable TableFlags = 1 << 2 // Enable hiding/disabling columns in context menu. - TableFlagsSortable TableFlags = 1 << 3 // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see TableFlagsSortMulti and TableFlagsSortTristate. - TableFlagsNoSavedSettings TableFlags = 1 << 4 // Disable persisting columns order, width and sort settings in the .ini file. - TableFlagsContextMenuInBody TableFlags = 1 << 5 // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + + TableFlagsNone TableFlags = 0 + // Enable resizing columns. + TableFlagsResizable TableFlags = 1 << 0 + // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) + TableFlagsReorderable TableFlags = 1 << 1 + // Enable hiding/disabling columns in context menu. + TableFlagsHideable TableFlags = 1 << 2 + // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see TableFlagsSortMulti and TableFlagsSortTristate. + TableFlagsSortable TableFlags = 1 << 3 + // Disable persisting columns order, width and sort settings in the .ini file. + TableFlagsNoSavedSettings TableFlags = 1 << 4 + // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + TableFlagsContextMenuInBody TableFlags = 1 << 5 // Decorations - TableFlagsRowBg TableFlags = 1 << 6 // Set each RowBg color with ColTableRowBg or ColTableRowBgAlt (equivalent of calling TableSetBgColor with TableBgFlagsRowBg0 on each row manually) - TableFlagsBordersInnerH TableFlags = 1 << 7 // Draw horizontal borders between rows. - TableFlagsBordersOuterH TableFlags = 1 << 8 // Draw horizontal borders at the top and bottom. - TableFlagsBordersInnerV TableFlags = 1 << 9 // Draw vertical borders between columns. - TableFlagsBordersOuterV TableFlags = 1 << 10 // Draw vertical borders on the left and right sides. - TableFlagsBordersH TableFlags = TableFlagsBordersInnerH | TableFlagsBordersOuterH // Draw horizontal borders. - TableFlagsBordersV TableFlags = TableFlagsBordersInnerV | TableFlagsBordersOuterV // Draw vertical borders. - TableFlagsBordersInner TableFlags = TableFlagsBordersInnerV | TableFlagsBordersInnerH // Draw inner borders. - TableFlagsBordersOuter TableFlags = TableFlagsBordersOuterV | TableFlagsBordersOuterH // Draw outer borders. - TableFlagsBorders TableFlags = TableFlagsBordersInner | TableFlagsBordersOuter // Draw all borders. - TableFlagsNoBordersInBody TableFlags = 1 << 11 // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style - TableFlagsNoBordersInBodyUntilResizeTableFlags TableFlags = 1 << 12 // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style + + // Set each RowBg color with ColTableRowBg or ColTableRowBgAlt + // (equivalent of calling TableSetBgColor with TableBgFlagsRowBg0 on each row manually) + TableFlagsRowBg TableFlags = 1 << 6 + // Draw horizontal borders between rows. + TableFlagsBordersInnerH TableFlags = 1 << 7 + // Draw horizontal borders at the top and bottom. + TableFlagsBordersOuterH TableFlags = 1 << 8 + // Draw vertical borders between columns. + TableFlagsBordersInnerV TableFlags = 1 << 9 + // Draw vertical borders on the left and right sides. + TableFlagsBordersOuterV TableFlags = 1 << 10 + // Draw horizontal borders. + TableFlagsBordersH TableFlags = TableFlagsBordersInnerH | TableFlagsBordersOuterH + // Draw vertical borders. + TableFlagsBordersV TableFlags = TableFlagsBordersInnerV | TableFlagsBordersOuterV + // Draw inner borders. + TableFlagsBordersInner TableFlags = TableFlagsBordersInnerV | TableFlagsBordersInnerH + // Draw outer borders. + TableFlagsBordersOuter TableFlags = TableFlagsBordersOuterV | TableFlagsBordersOuterH + // Draw all borders. + TableFlagsBorders TableFlags = TableFlagsBordersInner | TableFlagsBordersOuter + // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style + TableFlagsNoBordersInBody TableFlags = 1 << 11 + // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style + TableFlagsNoBordersInBodyUntilResizeTableFlags TableFlags = 1 << 12 // Sizing Policy (read above for defaults)TableFlags - TableFlagsSizingFixedFit TableFlags = 1 << 13 // Columns default to WidthFixed or WidthAuto (if resizable or not resizable), matching contents width. - TableFlagsSizingFixedSame TableFlags = 2 << 13 // Columns default to WidthFixed or WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable TableFlagsNoKeepColumnsVisible. - TableFlagsSizingStretchProp TableFlags = 3 << 13 // Columns default to WidthStretch with default weights proportional to each columns contents widths. - TableFlagsSizingStretchSame TableFlags = 4 << 13 // Columns default to WidthStretch with default weights all equal, unless overriden by TableSetupColumn(). + + // Columns default to WidthFixed or WidthAuto (if resizable or not resizable), matching contents width. + TableFlagsSizingFixedFit TableFlags = 1 << 13 + // Columns default to WidthFixed or WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. + // Implicitly enable TableFlagsNoKeepColumnsVisible. + TableFlagsSizingFixedSame TableFlags = 2 << 13 + // Columns default to WidthStretch with default weights proportional to each columns contents widths. + TableFlagsSizingStretchProp TableFlags = 3 << 13 + // Columns default to WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). + TableFlagsSizingStretchSame TableFlags = 4 << 13 // Sizing Extra Options - TableFlagsNoHostExtendX TableFlags = 1 << 16 // Make outer width auto-fit to columns, overriding outersize.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. - TableFlagsNoHostExtendY TableFlags = 1 << 17 // Make outer height stop exactly at outersize.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. - TableFlagsNoKeepColumnsVisible TableFlags = 1 << 18 // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. - TableFlagsPreciseWidths TableFlags = 1 << 19 // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + + // Make outer width auto-fit to columns, overriding outersize.x value. + // Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. + TableFlagsNoHostExtendX TableFlags = 1 << 16 + // Make outer height stop exactly at outersize.y (prevent auto-extending table past the limit). + // Only available when ScrollX/ScrollY are disabled. + // Data below the limit will be clipped and not visible. + TableFlagsNoHostExtendY TableFlags = 1 << 17 + // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. + TableFlagsNoKeepColumnsVisible TableFlags = 1 << 18 + // Disable distributing remainder width to stretched columns + // (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). + // With larger number of columns, resizing will appear to be less smooth. + TableFlagsPreciseWidths TableFlags = 1 << 19 + // Clipping - TableFlagsNoClip TableFlags = 1 << 20 // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + + // Disable clipping rectangle for every individual columns (reduce draw command count, + // items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + TableFlagsNoClip TableFlags = 1 << 20 // Padding - TableFlagsPadOuterX TableFlags = 1 << 21 // Default if BordersOuterV is on. Enable outer-most padding. Generally desirable if you have headers. - TableFlagsNoPadOuterX TableFlags = 1 << 22 // Default if BordersOuterV is off. Disable outer-most padding. - TableFlagsNoPadInnerX TableFlags = 1 << 23 // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + + // Default if BordersOuterV is on. Enable outer-most padding. Generally desirable if you have headers. + TableFlagsPadOuterX TableFlags = 1 << 21 + // Default if BordersOuterV is off. Disable outer-most padding. + TableFlagsNoPadOuterX TableFlags = 1 << 22 + // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + TableFlagsNoPadInnerX TableFlags = 1 << 23 + // Scrolling - TableFlagsScrollX TableFlags = 1 << 24 // Enable horizontal scrolling. Require 'outersize' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. - TableFlagsScrollY TableFlags = 1 << 25 // Enable vertical scrolling. Require 'outersize' parameter of BeginTable() to specify the container size. + + // Enable horizontal scrolling. Require 'outersize' parameter of BeginTable() to specify the container size. + // Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. + TableFlagsScrollX TableFlags = 1 << 24 + // Enable vertical scrolling. Require 'outersize' parameter of BeginTable() to specify the container size. + TableFlagsScrollY TableFlags = 1 << 25 // Sorting - TableFlagsSortMulti TableFlags = 1 << 26 // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). - TableFlagsSortTristate TableFlags = 1 << 27 // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + + // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). + TableFlagsSortMulti TableFlags = 1 << 26 + // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + TableFlagsSortTristate TableFlags = 1 << 27 // [Internal] Combinations and masks - TableFlagsSizingMask TableFlags = TableFlagsSizingFixedFit | TableFlagsSizingFixedSame | TableFlagsSizingStretchProp | TableFlagsSizingStretchSame + TableFlagsSizingMask TableFlags = TableFlagsSizingFixedFit | TableFlagsSizingFixedSame | + TableFlagsSizingStretchProp | TableFlagsSizingStretchSame ) type TableRowFlags int const ( - TableRowFlagsNone TableRowFlags = 0 - TableRowFlagsHeaders TableRowFlags = 1 << 0 // Identify header row (set default background color + width of its contents accounted different for auto column width) + TableRowFlagsNone TableRowFlags = 0 + // Identify header row (set default background color + width of its contents accounted different for auto column width) + TableRowFlagsHeaders TableRowFlags = 1 << 0 ) type TableColumnFlags int const ( // Input configuration flags - TableColumnFlagsNone TableColumnFlags = 0 - TableColumnFlagsDefaultHide TableColumnFlags = 1 << 0 // Default as a hidden/disabled column. - TableColumnFlagsDefaultSort TableColumnFlags = 1 << 1 // Default as a sorting column. - TableColumnFlagsWidthStretch TableColumnFlags = 1 << 2 // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is SizingStretchSame or SizingStretchProp). - TableColumnFlagsWidthFixed TableColumnFlags = 1 << 3 // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is SizingFixedFit and table is resizable). - TableColumnFlagsNoResize TableColumnFlags = 1 << 4 // Disable manual resizing. - TableColumnFlagsNoReorder TableColumnFlags = 1 << 5 // Disable manual reordering this column, this will also prevent other columns from crossing over this column. - TableColumnFlagsNoHide TableColumnFlags = 1 << 6 // Disable ability to hide/disable this column. - TableColumnFlagsNoClip TableColumnFlags = 1 << 7 // Disable clipping for this column (all NoClip columns will render in a same draw command). - TableColumnFlagsNoSort TableColumnFlags = 1 << 8 // Disable ability to sort on this field (even if TableFlagsSortable is set on the table). - TableColumnFlagsNoSortAscending TableColumnFlags = 1 << 9 // Disable ability to sort in the ascending direction. - TableColumnFlagsNoSortDescending TableColumnFlags = 1 << 10 // Disable ability to sort in the descending direction. - TableColumnFlagsNoHeaderWidth TableColumnFlags = 1 << 11 // Disable header text width contribution to automatic column width. - TableColumnFlagsPreferSortAscending TableColumnFlags = 1 << 12 // Make the initial sort direction Ascending when first sorting on this column (default). - TableColumnFlagsPreferSortDescending TableColumnFlags = 1 << 13 // Make the initial sort direction Descending when first sorting on this column. - TableColumnFlagsIndentEnable TableColumnFlags = 1 << 14 // Use current Indent value when entering cell (default for column 0). - TableColumnFlagsIndentDisable TableColumnFlags = 1 << 15 // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes within the cell will still be honored. + TableColumnFlagsNone TableColumnFlags = 0 + // Default as a hidden/disabled column. + TableColumnFlagsDefaultHide TableColumnFlags = 1 << 0 + // Default as a sorting column. + TableColumnFlagsDefaultSort TableColumnFlags = 1 << 1 + // Column will stretch. Preferable with horizontal scrolling disabled + // (default if table sizing policy is SizingStretchSame or SizingStretchProp). + TableColumnFlagsWidthStretch TableColumnFlags = 1 << 2 + // Column will not stretch. Preferable with horizontal scrolling enabled + // (default if table sizing policy is SizingFixedFit and table is resizable). + TableColumnFlagsWidthFixed TableColumnFlags = 1 << 3 + // Disable manual resizing. + TableColumnFlagsNoResize TableColumnFlags = 1 << 4 + // Disable manual reordering this column, this will also prevent other columns from crossing over this column. + TableColumnFlagsNoReorder TableColumnFlags = 1 << 5 + // Disable ability to hide/disable this column. + TableColumnFlagsNoHide TableColumnFlags = 1 << 6 + // Disable clipping for this column (all NoClip columns will render in a same draw command). + TableColumnFlagsNoClip TableColumnFlags = 1 << 7 + // Disable ability to sort on this field (even if TableFlagsSortable is set on the table). + TableColumnFlagsNoSort TableColumnFlags = 1 << 8 + // Disable ability to sort in the ascending direction. + TableColumnFlagsNoSortAscending TableColumnFlags = 1 << 9 + // Disable ability to sort in the descending direction. + TableColumnFlagsNoSortDescending TableColumnFlags = 1 << 10 + // Disable header text width contribution to automatic column width. + TableColumnFlagsNoHeaderWidth TableColumnFlags = 1 << 11 + // Make the initial sort direction Ascending when first sorting on this column (default). + TableColumnFlagsPreferSortAscending TableColumnFlags = 1 << 12 + // Make the initial sort direction Descending when first sorting on this column. + TableColumnFlagsPreferSortDescending TableColumnFlags = 1 << 13 + // Use current Indent value when entering cell (default for column 0). + TableColumnFlagsIndentEnable TableColumnFlags = 1 << 14 + // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes within the cell will still be honored. + TableColumnFlagsIndentDisable TableColumnFlags = 1 << 15 // Output status flags read-only via TableGetColumnFlags() - TableColumnFlagsIsEnabled TableColumnFlags = 1 << 20 // Status: is enabled == not hidden by user/api (referred to as "Hide" in DefaultHide and NoHide) flags. - TableColumnFlagsIsVisible TableColumnFlags = 1 << 21 // Status: is visible == is enabled AND not clipped by scrolling. - TableColumnFlagsIsSorted TableColumnFlags = 1 << 22 // Status: is currently part of the sort specs - TableColumnFlagsIsHovered TableColumnFlags = 1 << 23 // Status: is hovered by mouse + // Status: is enabled == not hidden by user/api (referred to as "Hide" in DefaultHide and NoHide) flags. + TableColumnFlagsIsEnabled TableColumnFlags = 1 << 20 + // Status: is visible == is enabled AND not clipped by scrolling. + TableColumnFlagsIsVisible TableColumnFlags = 1 << 21 + // Status: is currently part of the sort specs + TableColumnFlagsIsSorted TableColumnFlags = 1 << 22 + // Status: is hovered by mouse + TableColumnFlagsIsHovered TableColumnFlags = 1 << 23 // [Internal] Combinations and masks - TableColumnFlagsWidthMask TableColumnFlags = TableColumnFlagsWidthStretch | TableColumnFlagsWidthFixed - TableColumnFlagsIndentMask TableColumnFlags = TableColumnFlagsIndentEnable | TableColumnFlagsIndentDisable - TableColumnFlagsStatusMask TableColumnFlags = TableColumnFlagsIsEnabled | TableColumnFlagsIsVisible | TableColumnFlagsIsSorted | TableColumnFlagsIsHovered - TableColumnFlagsNoDirectResize TableColumnFlags = 1 << 30 // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) + TableColumnFlagsWidthMask TableColumnFlags = TableColumnFlagsWidthStretch | TableColumnFlagsWidthFixed + TableColumnFlagsIndentMask TableColumnFlags = TableColumnFlagsIndentEnable | TableColumnFlagsIndentDisable + TableColumnFlagsStatusMask TableColumnFlags = TableColumnFlagsIsEnabled | + TableColumnFlagsIsVisible | TableColumnFlagsIsSorted | TableColumnFlagsIsHovered + // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) + TableColumnFlagsNoDirectResize TableColumnFlags = 1 << 30 ) type SliderFlags int const ( - SliderFlagsNone SliderFlags = 0 - SliderFlagsAlwaysClamp SliderFlags = 1 << 4 // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. - SliderFlagsLogarithmic SliderFlags = 1 << 5 // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlagsNoRoundToFormat with this if using a format-string with small amount of digits. - SliderFlagsNoRoundToFormat SliderFlags = 1 << 6 // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) - SliderFlagsNoInput SliderFlags = 1 << 7 // Disable CTRL+Click or Enter key allowing to input text directly into the widget - SliderFlagsInvalidMask SliderFlags = 0x7000000F // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + SliderFlagsNone SliderFlags = 0 + // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. + SliderFlagsAlwaysClamp SliderFlags = 1 << 4 + // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlagsNoRoundToFormat with this if using + // a format-string with small amount of digits. + SliderFlagsLogarithmic SliderFlags = 1 << 5 + // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) + SliderFlagsNoRoundToFormat SliderFlags = 1 << 6 + // Disable CTRL+Click or Enter key allowing to input text directly into the widget + SliderFlagsNoInput SliderFlags = 1 << 7 + // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast + // to this enum, and will trigger an assert if needed. + SliderFlagsInvalidMask SliderFlags = 0x7000000F ) type PlotFlags int const ( - PlotFlagsNone PlotFlags = 0 // default - PlotFlagsNoTitle PlotFlags = 1 << 0 // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot") - PlotFlagsNoLegend PlotFlags = 1 << 1 // the legend will not be displayed - PlotFlagsNoMenus PlotFlags = 1 << 2 // the user will not be able to open context menus with right-click - PlotFlagsNoBoxSelect PlotFlags = 1 << 3 // the user will not be able to box-select with right-click drag - PlotFlagsNoMousePos PlotFlags = 1 << 4 // the mouse position, in plot coordinates, will not be displayed inside of the plot - PlotFlagsNoHighlight PlotFlags = 1 << 5 // plot items will not be highlighted when their legend entry is hovered - PlotFlagsNoChild PlotFlags = 1 << 6 // a child window region will not be used to capture mouse scroll (can boost performance for single Gui window applications) - PlotFlagsEqual PlotFlags = 1 << 7 // primary x and y axes will be constrained to have the same units/pixel (does not apply to auxiliary y-axes) - PlotFlagsYAxis2 PlotFlags = 1 << 8 // enable a 2nd y-axis on the right side - PlotFlagsYAxis3 PlotFlags = 1 << 9 // enable a 3rd y-axis on the right side - PlotFlagsQuery PlotFlags = 1 << 10 // the user will be able to draw query rects with middle-mouse or CTRL + right-click drag - PlotFlagsCrosshairs PlotFlags = 1 << 11 // the default mouse cursor will be replaced with a crosshair when hovered - PlotFlagsAntiAliased PlotFlags = 1 << 12 // plot lines will be software anti-aliased (not recommended for high density plots, prefer MSAA) + // default + PlotFlagsNone PlotFlags = 0 + // the plot title will not be displayed (titles are also hidden if preceded by double hashes, e.g. "##MyPlot") + PlotFlagsNoTitle PlotFlags = 1 << 0 + // the legend will not be displayed + PlotFlagsNoLegend PlotFlags = 1 << 1 + // the user will not be able to open context menus with right-click + PlotFlagsNoMenus PlotFlags = 1 << 2 + // the user will not be able to box-select with right-click drag + PlotFlagsNoBoxSelect PlotFlags = 1 << 3 + // the mouse position, in plot coordinates, will not be displayed inside of the plot + PlotFlagsNoMousePos PlotFlags = 1 << 4 + // plot items will not be highlighted when their legend entry is hovered + PlotFlagsNoHighlight PlotFlags = 1 << 5 + // a child window region will not be used to capture mouse scroll (can boost performance for single Gui window applications) + PlotFlagsNoChild PlotFlags = 1 << 6 + // primary x and y axes will be constrained to have the same units/pixel (does not apply to auxiliary y-axes) + PlotFlagsEqual PlotFlags = 1 << 7 + // enable a 2nd y-axis on the right side + PlotFlagsYAxis2 PlotFlags = 1 << 8 + // enable a 3rd y-axis on the right side + PlotFlagsYAxis3 PlotFlags = 1 << 9 + // the user will be able to draw query rects with middle-mouse or CTRL + right-click drag + PlotFlagsQuery PlotFlags = 1 << 10 + // the default mouse cursor will be replaced with a crosshair when hovered + PlotFlagsCrosshairs PlotFlags = 1 << 11 + // plot lines will be software anti-aliased (not recommended for high density plots, prefer MSAA) + PlotFlagsAntiAliased PlotFlags = 1 << 12 PlotFlagsCanvasOnly PlotFlags = PlotFlagsNoTitle | PlotFlagsNoLegend | PlotFlagsNoMenus | PlotFlagsNoBoxSelect | PlotFlagsNoMousePos ) type PlotAxisFlags int const ( - PlotAxisFlagsNone PlotAxisFlags = 0 // default - PlotAxisFlagsNoLabel PlotAxisFlags = 1 << 0 // the axis label will not be displayed (axis labels also hidden if the supplied string name is NULL) - PlotAxisFlagsNoGridLines PlotAxisFlags = 1 << 1 // the axis grid lines will not be displayed - PlotAxisFlagsNoTickMarks PlotAxisFlags = 1 << 2 // the axis tick marks will not be displayed - PlotAxisFlagsNoTickLabels PlotAxisFlags = 1 << 3 // the axis tick labels will not be displayed - PlotAxisFlagsLogScale PlotAxisFlags = 1 << 4 // a logartithmic (base 10) axis scale will be used (mutually exclusive with PlotAxisFlagsTime) - PlotAxisFlagsTime PlotAxisFlags = 1 << 5 // axis will display date/time formatted labels (mutually exclusive with PlotAxisFlagsLogScale) - PlotAxisFlagsInvert PlotAxisFlags = 1 << 6 // the axis will be inverted - PlotAxisFlagsLockMin PlotAxisFlags = 1 << 7 // the axis minimum value will be locked when panning/zooming - PlotAxisFlagsLockMax PlotAxisFlags = 1 << 8 // the axis maximum value will be locked when panning/zooming + // default + PlotAxisFlagsNone PlotAxisFlags = 0 + // the axis label will not be displayed (axis labels also hidden if the supplied string name is NULL) + PlotAxisFlagsNoLabel PlotAxisFlags = 1 << 0 + // the axis grid lines will not be displayed + PlotAxisFlagsNoGridLines PlotAxisFlags = 1 << 1 + // the axis tick marks will not be displayed + PlotAxisFlagsNoTickMarks PlotAxisFlags = 1 << 2 + // the axis tick labels will not be displayed + PlotAxisFlagsNoTickLabels PlotAxisFlags = 1 << 3 + // a logartithmic (base 10) axis scale will be used (mutually exclusive with PlotAxisFlagsTime) + PlotAxisFlagsLogScale PlotAxisFlags = 1 << 4 + // axis will display date/time formatted labels (mutually exclusive with PlotAxisFlagsLogScale) + PlotAxisFlagsTime PlotAxisFlags = 1 << 5 + // the axis will be inverted + PlotAxisFlagsInvert PlotAxisFlags = 1 << 6 + // the axis minimum value will be locked when panning/zooming + PlotAxisFlagsLockMin PlotAxisFlags = 1 << 7 + // the axis maximum value will be locked when panning/zooming + PlotAxisFlagsLockMax PlotAxisFlags = 1 << 8 PlotAxisFlagsLock PlotAxisFlags = PlotAxisFlagsLockMin | PlotAxisFlagsLockMax - PlotAxisFlagsNoDecorations PlotAxisFlags = PlotAxisFlagsNoLabel | PlotAxisFlagsNoGridLines | PlotAxisFlagsNoTickMarks | PlotAxisFlagsNoTickLabels + PlotAxisFlagsNoDecorations PlotAxisFlags = PlotAxisFlagsNoLabel | PlotAxisFlagsNoGridLines | + PlotAxisFlagsNoTickMarks | PlotAxisFlagsNoTickLabels ) diff --git a/FontAtlasProsessor.go b/FontAtlasProsessor.go index 524e964b..85c0d406 100644 --- a/FontAtlasProsessor.go +++ b/FontAtlasProsessor.go @@ -23,6 +23,8 @@ const ( preRegisterString = "\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" ) +// FontInfo represents a the font. +// type FontInfo struct { fontName string fontPath string @@ -76,7 +78,7 @@ func init() { } } -// Change default font +// SetDefaultFont changes default font func SetDefaultFont(fontName string, size float32) { fontPath, err := findfont.Find(fontName) if err != nil { @@ -88,7 +90,7 @@ func SetDefaultFont(fontName string, size float32) { defaultFonts = append([]FontInfo{fontInfo}, defaultFonts...) } -// Change default font by bytes of the font file +// SetDefaultFontFromBytes changes default font by bytes of the font file. func SetDefaultFontFromBytes(fontBytes []byte, size float32) { defaultFonts = append([]FontInfo{ { @@ -98,7 +100,7 @@ func SetDefaultFontFromBytes(fontBytes []byte, size float32) { }, defaultFonts...) } -// Add font by name, if the font is found, return *FontInfo, otherwise return nil. +// AddFont adds font by name, if the font is found, return *FontInfo, otherwise return nil. // To use added font, use giu.Style().SetFont(...). func AddFont(fontName string, size float32) *FontInfo { fontPath, err := findfont.Find(fontName) @@ -118,6 +120,7 @@ func AddFont(fontName string, size float32) *FontInfo { return &fi } +// AddFontFromBytes does similar to AddFont, but using data from memory func AddFontFromBytes(fontName string, fontBytes []byte, size float32) *FontInfo { fi := FontInfo{ fontName: fontName, diff --git a/InputHandler.go b/InputHandler.go index cb458321..303b5586 100644 --- a/InputHandler.go +++ b/InputHandler.go @@ -1,6 +1,6 @@ -// input menager is used to register a keyboard shortcuts in an app package giu +// input menager is used to register a keyboard shortcuts in an app import ( "github.com/go-gl/glfw/v3.3/glfw" ) @@ -83,6 +83,8 @@ func handler(key glfw.Key, mod glfw.ModifierKey, action glfw.Action) { } } +// WindowShortcut represents a window-level shortcut +// could be used as an argument to (*Window).RegisterKeyboardShortcuts type WindowShortcut struct { Key Key Modifier Modifier diff --git a/Keycode.go b/Keycode.go index 9f55d881..b898a0b4 100644 --- a/Keycode.go +++ b/Keycode.go @@ -2,8 +2,8 @@ package giu import "github.com/go-gl/glfw/v3.3/glfw" -type Key int -type Modifier int +// Key represents a glfw key +type Key glfw.Key // These key codes are inspired by the USB HID Usage Tables v1.12 (p. 53-60), // but re-arranged to map to 7-bit ASCII for printable keys (function keys are @@ -133,6 +133,10 @@ const ( KeyLast Key = Key(glfw.KeyLast) ) +// Modifier represents glfw.Modifier +type Modifier glfw.ModifierKey + +// modifier keys const ( ModNone Modifier = iota ModControl Modifier = Modifier(glfw.ModControl) diff --git a/Layout.go b/Layout.go index 85703895..e43cabb0 100644 --- a/Layout.go +++ b/Layout.go @@ -5,6 +5,9 @@ const ( Auto float32 = -1 ) +// Widget is a base unit of giu rendering system. +// each widget just needs to implement Build method which is called, +// when widget needs to be rendered. type Widget interface { Build() } @@ -14,8 +17,11 @@ var ( _ Splitable = Layout{} ) +// Layout is a set of widgets. It implements Widget interface so +// Layout can be used as a widget. type Layout []Widget +// Build implements Widget interface func (l Layout) Build() { for _, w := range l { if w != nil { diff --git a/MasterWindow.go b/MasterWindow.go index 98fd68e0..f8214465 100644 --- a/MasterWindow.go +++ b/MasterWindow.go @@ -5,11 +5,11 @@ import ( "image/color" "time" - "github.com/faiface/mainthread" - "github.com/AllenDang/imgui-go" + "github.com/faiface/mainthread" ) +// MasterWindowFlags wrapps imgui.GLFWWindowFlags type MasterWindowFlags imgui.GLFWWindowFlags const ( @@ -25,10 +25,11 @@ const ( MasterWindowFlagsTransparent MasterWindowFlags = MasterWindowFlags(imgui.GLFWWindowFlagsTransparent) ) -var ( - DontCare int = imgui.GlfwDontCare -) +// DontCare could be used as an argument to (*MasterWindow).SetSizeLimits +var DontCare int = imgui.GlfwDontCare +// MasterWindow represents a glfw master window +// It is a base for a windows (see Window.go) type MasterWindow struct { width int height int @@ -41,6 +42,9 @@ type MasterWindow struct { updateFunc func() } +// NewMasterWindow creates a new master window and initializes GLFW. +// it should be called in main function. For more details and use cases, +// see examples/helloworld/ func NewMasterWindow(title string, width, height int, flags MasterWindowFlags) *MasterWindow { context := imgui.CreateContext(nil) imgui.ImPlotCreateContext() @@ -166,9 +170,14 @@ func (w *MasterWindow) setTheme() { style.ScaleAllSizes(scale) } -// Set background color of master window. -func (w *MasterWindow) SetBgColor(color color.RGBA) { - w.clearColor = [4]float32{float32(color.R) / 255.0, float32(color.G) / 255.0, float32(color.B) / 255.0, float32(color.A) / 255.0} +// SetBgColor sets background color of master window. +func (w *MasterWindow) SetBgColor(bgColor color.RGBA) { + w.clearColor = [4]float32{ + float32(bgColor.R) / 255.0, + float32(bgColor.G) / 255.0, + float32(bgColor.B) / 255.0, + float32(bgColor.A) / 255.0, + } } func (w *MasterWindow) sizeChange(width, height int) { @@ -214,7 +223,7 @@ func (w *MasterWindow) run() { } } -// Return size of master window. +// GetSize return size of master window. func (w *MasterWindow) GetSize() (width, height int) { if w.platform != nil { if glfwPlatform, ok := w.platform.(*imgui.GLFW); ok { @@ -225,7 +234,7 @@ func (w *MasterWindow) GetSize() (width, height int) { return w.width, w.height } -// Return position of master window. +// GetPos return position of master window. func (w *MasterWindow) GetPos() (x, y int) { if w.platform != nil { if glfwPlatform, ok := w.platform.(*imgui.GLFW); ok { @@ -236,7 +245,7 @@ func (w *MasterWindow) GetPos() (x, y int) { return } -// Set position of master window. +// SetPos sets position of master window. func (w *MasterWindow) SetPos(x, y int) { if w.platform != nil { if glfwPlatform, ok := w.platform.(*imgui.GLFW); ok { @@ -245,6 +254,7 @@ func (w *MasterWindow) SetPos(x, y int) { } } +// SetSize sets size of master window func (w *MasterWindow) SetSize(x, y int) { if w.platform != nil { if glfwPlatform, ok := w.platform.(*imgui.GLFW); ok { @@ -272,8 +282,10 @@ func (w *MasterWindow) SetDropCallback(cb func([]string)) { w.platform.SetDropCallback(cb) } -// Call the main loop. +// Run runs the main loop. // loopFunc will be used to construct the ui. +// Run should be called at the end of main function, after setting +// up the master window. func (w *MasterWindow) Run(loopFunc func()) { mainthread.Run(func() { w.updateFunc = loopFunc @@ -295,6 +307,7 @@ func (w *MasterWindow) Run(loopFunc func()) { }) } +// RegisterKeyboardShortcuts registers a global - master window - keyboard shortcuts func (w *MasterWindow) RegisterKeyboardShortcuts(s ...WindowShortcut) *MasterWindow { for _, shortcut := range s { RegisterKeyboardShortcuts(Shortcut{ @@ -334,6 +347,7 @@ func (w *MasterWindow) SetSizeLimits(minw, minh, maxw, maxh int) { w.platform.SetSizeLimits(minw, minh, maxw, maxh) } +// SetTitle updates master window's title func (w *MasterWindow) SetTitle(title string) { w.platform.SetTitle(title) } diff --git a/Msgbox.go b/Msgbox.go index 769da792..aee36675 100644 --- a/Msgbox.go +++ b/Msgbox.go @@ -2,8 +2,11 @@ package giu import "fmt" +// DialogResult represents dialog result +// dialog resullt is bool. if OK/Yes it is true, else (Cancel/No) - false type DialogResult bool +// dialog results const ( DialogResultOK DialogResult = true DialogResultCancel DialogResult = false @@ -12,17 +15,25 @@ const ( DialogResultNo = DialogResultCancel ) +// MsgboxButtons determines which buttons are in the dialog. type MsgboxButtons uint8 +// button sets const ( + // Yes-No question MsgboxButtonsYesNo MsgboxButtons = 1 << iota + // Ok / Cancel dialog MsgboxButtonsOkCancel + // info MsgboxButtonsOk ) +// DialogResultCallback is a callback for dialogs type DialogResultCallback func(DialogResult) -type MsgboxState struct { +var _ Disposable = &msgboxState{} + +type msgboxState struct { title string content string resultCallback DialogResultCallback @@ -30,7 +41,8 @@ type MsgboxState struct { open bool } -func (ms *MsgboxState) Dispose() { +// Dispose implements disposable interface +func (ms *msgboxState) Dispose() { // Nothing to do here. } @@ -80,33 +92,35 @@ func buildMsgboxButtons(buttons MsgboxButtons, callback DialogResultCallback) La } } -const msgboxId string = "###Msgbox" +const msgboxID string = "###Msgbox" -// Embed various Msgboxs to layout. Invoke this function in the same layout level where you call g.Msgbox. +// PrepareMsgbox should be invoked in function in the same layout level where you call g.Msgbox. +// BUG: calling this more than 1 time per frame causes unexpected +// merging msgboxes layouts (see https://github.com/AllenDang/giu/issues/290) func PrepareMsgbox() Layout { return Layout{ Custom(func() { - var state *MsgboxState + var state *msgboxState // Register state. - stateRaw := Context.GetState(msgboxId) + stateRaw := Context.GetState(msgboxID) if stateRaw == nil { - state = &MsgboxState{title: "Info", content: "Content", buttons: MsgboxButtonsOk, resultCallback: nil, open: false} - Context.SetState(msgboxId, state) + state = &msgboxState{title: "Info", content: "Content", buttons: MsgboxButtonsOk, resultCallback: nil, open: false} + Context.SetState(msgboxID, state) } else { - state = stateRaw.(*MsgboxState) + state = stateRaw.(*msgboxState) } if state.open { - OpenPopup(msgboxId) + OpenPopup(msgboxID) state.open = false } SetNextWindowSize(300, 0) - PopupModal(fmt.Sprintf("%s%s", state.title, msgboxId)).Layout( + PopupModal(fmt.Sprintf("%s%s", state.title, msgboxID)).Layout( Custom(func() { // Ensure the state is valid. - Context.GetState(msgboxId) + Context.GetState(msgboxID) }), Label(state.content).Wrapped(true), buildMsgboxButtons(state.buttons, state.resultCallback), @@ -115,17 +129,21 @@ func PrepareMsgbox() Layout { } } +// MsgboxWidget represents message dialog type MsgboxWidget struct{} -func (m *MsgboxWidget) getState() *MsgboxState { - stateRaw := Context.GetState(msgboxId) +func (m *MsgboxWidget) getState() *msgboxState { + stateRaw := Context.GetState(msgboxID) if stateRaw == nil { panic("Msgbox is not prepared. Invoke giu.PrepareMsgbox in the end of the layout.") } - return stateRaw.(*MsgboxState) + return stateRaw.(*msgboxState) } +// Msgbox opens message box. +// call it whenever you want to open popup with +// question / info func Msgbox(title, content string) *MsgboxWidget { result := &MsgboxWidget{} @@ -141,12 +159,14 @@ func Msgbox(title, content string) *MsgboxWidget { return result } +// Buttons sets which buttons should be possible func (m *MsgboxWidget) Buttons(buttons MsgboxButtons) *MsgboxWidget { s := m.getState() s.buttons = buttons return m } +// ResultCallback sets result callback func (m *MsgboxWidget) ResultCallback(cb DialogResultCallback) *MsgboxWidget { s := m.getState() s.resultCallback = cb diff --git a/Plot.go b/Plot.go index e1538837..4b86432d 100644 --- a/Plot.go +++ b/Plot.go @@ -6,23 +6,29 @@ import ( "github.com/AllenDang/imgui-go" ) +// PlotWidget is implemented by all the particular plots, which can be used +// in (*PlotCanvasWidget).Plots type PlotWidget interface { Plot() } +// ImPlotYAxis represents y axis settings type ImPlotYAxis int +// ImPlotYAxis enum: const ( ImPlotYAxisLeft ImPlotYAxis = 0 // left (default) ImPlotYAxisFirstOnRight ImPlotYAxis = 1 // first on right side ImPlotYAxisSecondOnRight ImPlotYAxis = 2 // second on right side ) +// PlotTicker represents axis ticks type PlotTicker struct { Position float64 Label string } +// PlotCanvasWidget represents a giu plot widget. type PlotCanvasWidget struct { title string xLabel string @@ -43,6 +49,7 @@ type PlotCanvasWidget struct { plots []PlotWidget } +// Plot adds creates a new plot widget. func Plot(title string) *PlotCanvasWidget { return &PlotCanvasWidget{ title: title, @@ -68,6 +75,7 @@ func Plot(title string) *PlotCanvasWidget { } } +// AxisLimits sets X and Y axis limits func (p *PlotCanvasWidget) AxisLimits(xmin, xmax, ymin, ymax float64, cond ExecCondition) *PlotCanvasWidget { p.xMin = xmin p.xMax = xmax @@ -78,6 +86,7 @@ func (p *PlotCanvasWidget) AxisLimits(xmin, xmax, ymin, ymax float64, cond ExecC return p } +// XTicks sets x axis ticks func (p *PlotCanvasWidget) XTicks(ticks []PlotTicker, showDefault bool) *PlotCanvasWidget { length := len(ticks) if length == 0 { @@ -98,6 +107,7 @@ func (p *PlotCanvasWidget) XTicks(ticks []PlotTicker, showDefault bool) *PlotCan return p } +// YTicks sets y axis ticks func (p *PlotCanvasWidget) YTicks(ticks []PlotTicker, showDefault bool, yAxis ImPlotYAxis) *PlotCanvasWidget { length := len(ticks) if length == 0 { @@ -119,16 +129,19 @@ func (p *PlotCanvasWidget) YTicks(ticks []PlotTicker, showDefault bool, yAxis Im return p } +// Flags sets plot canvas flags func (p *PlotCanvasWidget) Flags(flags PlotFlags) *PlotCanvasWidget { p.flags = flags return p } +// XAxeFlags sets x axis fags func (p *PlotCanvasWidget) XAxeFlags(flags PlotAxisFlags) *PlotCanvasWidget { p.xFlags = flags return p } +// YAxeFlags sets y axis flags func (p *PlotCanvasWidget) YAxeFlags(yFlags, y2Flags, y3Flags PlotAxisFlags) *PlotCanvasWidget { p.yFlags = yFlags p.y2Flags = y2Flags @@ -136,17 +149,20 @@ func (p *PlotCanvasWidget) YAxeFlags(yFlags, y2Flags, y3Flags PlotAxisFlags) *Pl return p } +// Plots adds plots to plot canvas func (p *PlotCanvasWidget) Plots(plots ...PlotWidget) *PlotCanvasWidget { p.plots = plots return p } +// Size set canvas size func (p *PlotCanvasWidget) Size(width, height int) *PlotCanvasWidget { p.width = width p.height = height return p } +// Build implements Widget interface func (p *PlotCanvasWidget) Build() { if len(p.plots) > 0 { imgui.ImPlotSetNextPlotLimits(p.xMin, p.xMax, p.yMin, p.yMax, imgui.Condition(p.axisLimitCondition)) @@ -159,7 +175,13 @@ func (p *PlotCanvasWidget) Build() { imgui.ImPlotSetNextPlotTicksY(p.yTicksValue, p.yTicksLabel, p.yTicksShowDefault, int(p.yTicksYAxis)) } - if imgui.ImPlotBegin(tStr(p.title), tStr(p.xLabel), tStr(p.yLabel), ToVec2(image.Pt(p.width, p.height)), imgui.ImPlotFlags(p.flags), imgui.ImPlotAxisFlags(p.xFlags), imgui.ImPlotAxisFlags(p.yFlags), imgui.ImPlotAxisFlags(p.y2Flags), imgui.ImPlotAxisFlags(p.y3Flags), tStr(p.y2Label), tStr(p.y3Label)) { + if imgui.ImPlotBegin( + tStr(p.title), tStr(p.xLabel), + tStr(p.yLabel), ToVec2(image.Pt(p.width, p.height)), + imgui.ImPlotFlags(p.flags), imgui.ImPlotAxisFlags(p.xFlags), + imgui.ImPlotAxisFlags(p.yFlags), imgui.ImPlotAxisFlags(p.y2Flags), + imgui.ImPlotAxisFlags(p.y3Flags), tStr(p.y2Label), tStr(p.y3Label), + ) { for _, plot := range p.plots { plot.Plot() } @@ -168,6 +190,7 @@ func (p *PlotCanvasWidget) Build() { } } +// PlotBarWidget adds bar plot (column chart) to the canvas type PlotBarWidget struct { title string data []float64 @@ -176,6 +199,7 @@ type PlotBarWidget struct { offset int } +// PlotBar adds a plot bar (column chart) func PlotBar(title string, data []float64) *PlotBarWidget { return &PlotBarWidget{ title: title, @@ -186,25 +210,30 @@ func PlotBar(title string, data []float64) *PlotBarWidget { } } +// Width sets bar width func (p *PlotBarWidget) Width(width float64) *PlotBarWidget { p.width = width return p } +// Shift sets shift of the bar func (p *PlotBarWidget) Shift(shift float64) *PlotBarWidget { p.shift = shift return p } +// Offset sets bar's offset func (p *PlotBarWidget) Offset(offset int) *PlotBarWidget { p.offset = offset return p } +// Plot implements Plot interface func (p *PlotBarWidget) Plot() { imgui.ImPlotBars(p.title, p.data, p.width, p.shift, p.offset) } +// PlotBarHWidget represents a column chart on Y axis type PlotBarHWidget struct { title string data []float64 @@ -213,6 +242,7 @@ type PlotBarHWidget struct { offset int } +// PlotBarH adds plot bars on y axis func PlotBarH(title string, data []float64) *PlotBarHWidget { return &PlotBarHWidget{ title: title, @@ -223,25 +253,30 @@ func PlotBarH(title string, data []float64) *PlotBarHWidget { } } +// Height sets bar height (in fact bars' width) func (p *PlotBarHWidget) Height(height float64) *PlotBarHWidget { p.height = height return p } +// Shift sets shift func (p *PlotBarHWidget) Shift(shift float64) *PlotBarHWidget { p.shift = shift return p } +// Offset sets offset func (p *PlotBarHWidget) Offset(offset int) *PlotBarHWidget { p.offset = offset return p } +// Plot implements plot interface func (p *PlotBarHWidget) Plot() { imgui.ImPlotBarsH(tStr(p.title), p.data, p.height, p.shift, p.offset) } +// PlotLineWidget represents a plot line (linear chart) type PlotLineWidget struct { title string values []float64 @@ -250,6 +285,7 @@ type PlotLineWidget struct { yAxis ImPlotYAxis } +// PlotLine adds a new plot line to the canvas func PlotLine(title string, values []float64) *PlotLineWidget { return &PlotLineWidget{ title: title, @@ -260,37 +296,44 @@ func PlotLine(title string, values []float64) *PlotLineWidget { } } +// SetPlotYAxis sets yAxis parameters func (p *PlotLineWidget) SetPlotYAxis(yAxis ImPlotYAxis) *PlotLineWidget { p.yAxis = yAxis return p } +// XScale sets x-axis-scale func (p *PlotLineWidget) XScale(scale float64) *PlotLineWidget { p.xScale = scale return p } +// X0 sets a start position on x axis func (p *PlotLineWidget) X0(x0 float64) *PlotLineWidget { p.x0 = x0 return p } +// Offset sets chart offset func (p *PlotLineWidget) Offset(offset int) *PlotLineWidget { p.offset = offset return p } +// Plot implements Plot interface func (p *PlotLineWidget) Plot() { imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis)) imgui.ImPlotLine(tStr(p.title), p.values, p.xScale, p.x0, p.offset) } +// PlotLineXYWidget adds XY plot line type PlotLineXYWidget struct { title string xs, ys []float64 offset int } +// PlotLineXY adds XY plot line to canvas func PlotLineXY(title string, xvalues, yvalues []float64) *PlotLineXYWidget { return &PlotLineXYWidget{ title: title, @@ -300,15 +343,18 @@ func PlotLineXY(title string, xvalues, yvalues []float64) *PlotLineXYWidget { } } +// Offset sets chart's offset func (p *PlotLineXYWidget) Offset(offset int) *PlotLineXYWidget { p.offset = offset return p } +// Plot implements Plot interface func (p *PlotLineXYWidget) Plot() { imgui.ImPlotLineXY(tStr(p.title), p.xs, p.ys, p.offset) } +// PlotPieChartWidget represents a pie chart type PlotPieChartWidget struct { labels []string values []float64 @@ -318,6 +364,7 @@ type PlotPieChartWidget struct { angle0 float64 } +// PlotPieChart adds pie chart to the canvas func PlotPieChart(labels []string, values []float64, x, y, radius float64) *PlotPieChartWidget { return &PlotPieChartWidget{ labels: labels, @@ -336,6 +383,7 @@ func (p *PlotPieChartWidget) Normalize(n bool) *PlotPieChartWidget { return p } +// LabelFormat sets format of labels func (p *PlotPieChartWidget) LabelFormat(fmtStr string) *PlotPieChartWidget { p.labelFormat = fmtStr return p diff --git a/ProgressIndicator.go b/ProgressIndicator.go index bdd77bd8..e5fe2c1c 100644 --- a/ProgressIndicator.go +++ b/ProgressIndicator.go @@ -8,12 +8,14 @@ import ( "github.com/AllenDang/imgui-go" ) -type ProgressIndicatorState struct { +var _ Disposable = &progressIndicatorState{} + +type progressIndicatorState struct { angle float64 stop bool } -func (ps *ProgressIndicatorState) Update() { +func (ps *progressIndicatorState) update() { ticker := time.NewTicker(time.Second / 60) for !ps.stop { if ps.angle > 6.2 { @@ -28,21 +30,28 @@ func (ps *ProgressIndicatorState) Update() { ticker.Stop() } -func (ps *ProgressIndicatorState) Dispose() { +// Dispose implements Disposable interface +func (ps *progressIndicatorState) Dispose() { ps.stop = true } +// static check to ensure if ProgressIndicatorWidget implements Widget interface +var _ Widget = &ProgressIndicatorWidget{} + +// ProgressIndicatorWidget represents progress indicator widget +// see examples/extrawidgets/ type ProgressIndicatorWidget struct { - internalId string + internalID string width float32 height float32 radius float32 label string } +// ProgressIndicator creates a new ProgressIndicatorWidget func ProgressIndicator(label string, width, height, radius float32) *ProgressIndicatorWidget { return &ProgressIndicatorWidget{ - internalId: "###giu-progress-indicator", + internalID: "###giu-progress-indicator", width: width * Context.GetPlatform().GetContentScale(), height: height * Context.GetPlatform().GetContentScale(), radius: radius * Context.GetPlatform().GetContentScale(), @@ -50,15 +59,16 @@ func ProgressIndicator(label string, width, height, radius float32) *ProgressInd } } +// Build implements Widget interface func (p *ProgressIndicatorWidget) Build() { // State exists - if s := Context.GetState(p.internalId); s == nil { + if s := Context.GetState(p.internalID); s == nil { // Register state and start go routine - ps := ProgressIndicatorState{angle: 0.0, stop: false} - Context.SetState(p.internalId, &ps) - go ps.Update() + ps := progressIndicatorState{angle: 0.0, stop: false} + Context.SetState(p.internalID, &ps) + go ps.update() } else { - state := s.(*ProgressIndicatorState) + state := s.(*progressIndicatorState) child := Child().Border(false).Size(p.width, p.height).Layout(Layout{ Custom(func() { @@ -78,8 +88,8 @@ func (p *ProgressIndicatorWidget) Build() { color := imgui.CurrentStyle().GetColor(imgui.StyleColorText) rgba := Vec4ToRGBA(color) - canvas.AddCircle(centerPt, float32(p.radius), rgba, int(p.radius), float32(p.radius/20.0)) - canvas.AddCircleFilled(centerPt2, float32(p.radius/5), rgba) + canvas.AddCircle(centerPt, p.radius, rgba, int(p.radius), p.radius/20.0) + canvas.AddCircleFilled(centerPt2, p.radius/5, rgba) // Draw text if len(p.label) > 0 { diff --git a/SplitLayout.go b/SplitLayout.go index 5f312edf..853e1103 100644 --- a/SplitLayout.go +++ b/SplitLayout.go @@ -13,11 +13,14 @@ const ( DirectionVertical ) +var _ Disposable = &SplitLayoutState{} + type SplitLayoutState struct { delta float32 sashPos float32 } +// Dispose implements Disposable interface func (s *SplitLayoutState) Dispose() { // Nothing to do here. } @@ -88,10 +91,10 @@ func (s *SplitLayoutWidget) Build() { var splitLayoutState *SplitLayoutState // Register state - stateId := fmt.Sprintf("SplitLayout_%s", s.id) - if state := Context.GetState(stateId); state == nil { + stateID := fmt.Sprintf("SplitLayout_%s", s.id) + if state := Context.GetState(stateID); state == nil { splitLayoutState = &SplitLayoutState{delta: 0.0, sashPos: s.sashPos} - Context.SetState(stateId, splitLayoutState) + Context.SetState(stateID, splitLayoutState) } else { splitLayoutState = state.(*SplitLayoutState) } diff --git a/StackWidget.go b/StackWidget.go index 496fdfd4..e2e5e4d5 100644 --- a/StackWidget.go +++ b/StackWidget.go @@ -16,7 +16,7 @@ type StackWidget struct { func Stack(visible int32, layouts ...Widget) *StackWidget { return &StackWidget{ visible: visible, - layouts: []Widget(layouts), + layouts: layouts, } } @@ -26,13 +26,14 @@ func (s *StackWidget) Build() { // build visible layout // NOTE: it is important to build the visiblely showed layout before - // building another ones, becouse the interactive layout widgets + // building another ones, because the interactive layout widgets // (e.g. buttons) should be rendered on top of `stack` - var layouts []Widget = s.layouts + layouts := s.layouts if s.visible >= 0 && s.visible < int32(len(s.layouts)) { s.layouts[s.visible].Build() // remove visible layout from layouts list + // nolint:gocritic // remove visible widget layouts = append(s.layouts[:s.visible], s.layouts[:s.visible+1]...) } diff --git a/Style.go b/Style.go index 75b79bc0..db98ba18 100644 --- a/Style.go +++ b/Style.go @@ -6,6 +6,9 @@ import ( "github.com/AllenDang/imgui-go" ) +// PushFont sets font to "font" +// NOTE: PopFont has to be called +// NOTE: Don't use PushFont. use StyleSetter instead func PushFont(font *FontInfo) bool { if f, ok := extraFontMap[font.String()]; ok { imgui.PushFont(*f) @@ -14,86 +17,117 @@ func PushFont(font *FontInfo) bool { return false } +// PopFont pops the font (should be called after PushFont) func PopFont() { imgui.PopFont() } +// PushStyleColor wrapps imgui.PushStyleColor +// NOTE: don't forget to call PopStyleColor()! func PushStyleColor(id StyleColorID, col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorID(id), ToVec4Color(col)) } +// PushColorText calls PushStyleColor(StyleColorText,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorText(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorText, ToVec4Color(col)) } +// PushColorTextDisabled calls PushStyleColor(StyleColorTextDisabled,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorTextDisabled(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorTextDisabled, ToVec4Color(col)) } +// PushColorWindowBg calls PushStyleColor(StyleColorWindowBg,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorWindowBg(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorWindowBg, ToVec4Color(col)) } +// PushColorFrameBg calls PushStyleColor(StyleColorFrameBg,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorFrameBg(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorFrameBg, ToVec4Color(col)) } +// PushColorButton calls PushStyleColor(StyleColorButton,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorButton(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorButton, ToVec4Color(col)) } +// PushColorButtonHovered calls PushStyleColor(StyleColorButtonHovered,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorButtonHovered(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorButtonHovered, ToVec4Color(col)) } +// PushColorButtonActive calls PushStyleColor(StyleColorButtonActive,...) +// NOTE: don't forget to call PopStyleColor()! func PushColorButtonActive(col color.RGBA) { imgui.PushStyleColor(imgui.StyleColorButtonActive, ToVec4Color(col)) } +// PushWindowPadding calls PushStyleVar(StyleWindowPadding,...) func PushWindowPadding(width, height float32) { width *= Context.GetPlatform().GetContentScale() height *= Context.GetPlatform().GetContentScale() imgui.PushStyleVarVec2(imgui.StyleVarWindowPadding, imgui.Vec2{X: width, Y: height}) } +// PushFramePadding calls PushStyleVar(StyleFramePadding,...) func PushFramePadding(width, height float32) { width *= Context.GetPlatform().GetContentScale() height *= Context.GetPlatform().GetContentScale() imgui.PushStyleVarVec2(imgui.StyleVarFramePadding, imgui.Vec2{X: width, Y: height}) } +// PushItemSpacing calls PushStyleVar(StyleVarItemSpacing,...) func PushItemSpacing(width, height float32) { width *= Context.GetPlatform().GetContentScale() height *= Context.GetPlatform().GetContentScale() imgui.PushStyleVarVec2(imgui.StyleVarItemSpacing, imgui.Vec2{X: width, Y: height}) } -// Alignment for button text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. +// PushButtonTextAlign sets alignment for button text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. func PushButtonTextAlign(width, height float32) { width *= Context.GetPlatform().GetContentScale() height *= Context.GetPlatform().GetContentScale() imgui.PushStyleVarVec2(imgui.StyleVarButtonTextAlign, imgui.Vec2{X: width, Y: height}) } -// Alignment for selectable text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. +// PushSelectableTextAlign sets alignment for selectable text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. func PushSelectableTextAlign(width, height float32) { width *= Context.GetPlatform().GetContentScale() height *= Context.GetPlatform().GetContentScale() imgui.PushStyleVarVec2(imgui.StyleVarSelectableTextAlign, imgui.Vec2{X: width, Y: height}) } +// PopStyle should be called to stop applying style. +// It should be called as much times, as you Called PushStyle... +// NOTE: If you don't call PopStyle imgui will panic func PopStyle() { imgui.PopStyleVar() } +// PopStyleV does similarly to PopStyle, but allows to specify number +// of styles you're going to pop func PopStyleV(count int) { imgui.PopStyleVarV(count) } +// PopStyleColor is used to stop applying colors styles. +// It should be called after each PushStyleColor... (for each push) +// If PopStyleColor wasn't called after PushColor... or was called +// inproperly, imgui will panic func PopStyleColor() { imgui.PopStyleColor() } +// PopStyleColorV does similar to PopStyleColor, but allows to specify +// how much style colors would you like to pop func PopStyleColorV(count int) { imgui.PopStyleColorV(count) } @@ -105,11 +139,16 @@ func AlignTextToFramePadding() { imgui.AlignTextToFramePadding() } +// PushItemWidth sets following item's widths +// NOTE: don't forget to call PopItemWidth! If you don't do so, imgui +// will panic func PushItemWidth(width float32) { width *= Context.GetPlatform().GetContentScale() imgui.PushItemWidth(width) } +// PopItemWidth should be called to stop applying PushItemWidth effect +// If it isn't called imgui will panic func PopItemWidth() { imgui.PopItemWidth() } @@ -122,6 +161,7 @@ func PopTextWrapPos() { imgui.PopTextWrapPos() } +// MouseCursorType represents a type (layout) of mouse cursor type MouseCursorType int const ( @@ -146,26 +186,31 @@ const ( MouseCursorCount MouseCursorType = 8 ) +// SetMouseCursor sets mouse cursor layout func SetMouseCursor(cursor MouseCursorType) { imgui.SetMouseCursor(int(cursor)) } -func GetWindowPadding() (float32, float32) { +// GetWindowPadding returns window padding +func GetWindowPadding() (x, y float32) { vec2 := imgui.CurrentStyle().WindowPadding() return vec2.X, vec2.Y } -func GetItemSpacing() (float32, float32) { +// GetItemSpacing returns current item spacing +func GetItemSpacing() (w, h float32) { vec2 := imgui.CurrentStyle().ItemSpacing() return vec2.X, vec2.Y } -func GetItemInnerSpacing() (float32, float32) { +// GetItemInnerSpacing returns current item inner spacing +func GetItemInnerSpacing() (w, h float32) { vec2 := imgui.CurrentStyle().ItemInnerSpacing() return vec2.X, vec2.Y } -func GetFramePadding() (float32, float32) { +// GetFramePadding returns current frame padding +func GetFramePadding() (x, y float32) { vec2 := imgui.CurrentStyle().FramePadding() return vec2.X, vec2.Y } @@ -234,6 +279,7 @@ const ( // StyleVarID identifies a style variable in the UI style. type StyleVarID int +// Style IDs const ( // StyleVarAlpha is a float StyleVarAlpha StyleVarID = iota @@ -285,6 +331,9 @@ const ( StyleVarSelectableTextAlign ) +var _ Widget = &StyleSetter{} + +// StyleSetter is a user-friendly way to manage imgui styles type StyleSetter struct { colors map[StyleColorID]color.RGBA styles map[StyleVarID]imgui.Vec2 @@ -293,6 +342,7 @@ type StyleSetter struct { layout Layout } +// Style initializes a style setter (see examples/setstyle) func Style() *StyleSetter { var ss StyleSetter ss.colors = make(map[StyleColorID]color.RGBA) @@ -301,31 +351,37 @@ func Style() *StyleSetter { return &ss } -func (ss *StyleSetter) SetColor(colorId StyleColorID, col color.RGBA) *StyleSetter { - ss.colors[colorId] = col +// SetColor sets colorID's color +func (ss *StyleSetter) SetColor(colorID StyleColorID, col color.RGBA) *StyleSetter { + ss.colors[colorID] = col return ss } -func (ss *StyleSetter) SetStyle(varId StyleVarID, width, height float32) *StyleSetter { - ss.styles[varId] = imgui.Vec2{X: width, Y: height} +// SetStyle sets styleVarID to width and height +func (ss *StyleSetter) SetStyle(varID StyleVarID, width, height float32) *StyleSetter { + ss.styles[varID] = imgui.Vec2{X: width, Y: height} return ss } +// SetFont sets font func (ss *StyleSetter) SetFont(font *FontInfo) *StyleSetter { ss.font = font return ss } +// SetDisabled sets if items are disabled func (ss *StyleSetter) SetDisabled(d bool) *StyleSetter { ss.disabled = d return ss } +// To allows to specify a layout, StyleSetter should apply style for func (ss *StyleSetter) To(widgets ...Widget) *StyleSetter { ss.layout = widgets return ss } +// Build implements Widget func (ss *StyleSetter) Build() { if ss.layout == nil || len(ss.layout) == 0 { return diff --git a/Texture.go b/Texture.go index a9b2594f..f7ee73ce 100644 --- a/Texture.go +++ b/Texture.go @@ -5,9 +5,8 @@ import ( "image" "runtime" - "github.com/faiface/mainthread" - "github.com/AllenDang/imgui-go" + "github.com/faiface/mainthread" ) type Texture struct { @@ -24,14 +23,14 @@ func NewTextureFromRgba(rgba image.Image, loadCallback func(*Texture)) { go func() { Update() result := mainthread.CallVal(func() interface{} { - texId, err := Context.renderer.LoadImage(ImageToRgba(rgba)) - return &loadImageResult{id: texId, err: err} + texID, err := Context.renderer.LoadImage(ImageToRgba(rgba)) + return &loadImageResult{id: texID, err: err} }) tid, ok := result.(*loadImageResult) switch { case !ok: - panic("giu: NewTextureFromRgba: unexpected error occured") + panic("giu: NewTextureFromRgba: unexpected error occurred") case tid.err != nil: panic(fmt.Sprintf("giu: NewTextureFromRgba: error loading texture: %v", tid.err)) } diff --git a/Utils.go b/Utils.go index 40a8cbb5..7d48ef52 100644 --- a/Utils.go +++ b/Utils.go @@ -1,21 +1,30 @@ package giu import ( + "fmt" "image" "image/color" "image/draw" "image/png" "os" + "path/filepath" "github.com/AllenDang/imgui-go" ) +// LoadImage loads image from file and returns *image.RGBA func LoadImage(imgPath string) (*image.RGBA, error) { - imgFile, err := os.Open(imgPath) + imgFile, err := os.Open(filepath.Clean(imgPath)) if err != nil { return nil, err } - defer imgFile.Close() + + defer func() { + // nolint:govet // we want to reuse this err variable here + if err := imgFile.Close(); err != nil { + panic(fmt.Sprintf("error closing image file: %s", imgPath)) + } + }() img, err := png.Decode(imgFile) if err != nil { @@ -25,6 +34,7 @@ func LoadImage(imgPath string) (*image.RGBA, error) { return ImageToRgba(img), nil } +// ImageToRgba converts image.Image to *image.RGBA func ImageToRgba(img image.Image) *image.RGBA { switch trueImg := img.(type) { case *image.RGBA: @@ -36,6 +46,7 @@ func ImageToRgba(img image.Image) *image.RGBA { } } +// ToVec4Color converts rgba color to imgui.Vec4 func ToVec4Color(col color.RGBA) imgui.Vec4 { return imgui.Vec4{ X: float32(col.R) / 255, @@ -45,6 +56,7 @@ func ToVec4Color(col color.RGBA) imgui.Vec4 { } } +// ToVec2 converts image.Point to imgui.Vec2 func ToVec2(pt image.Point) imgui.Vec2 { return imgui.Vec2{ X: float32(pt.X), @@ -52,6 +64,7 @@ func ToVec2(pt image.Point) imgui.Vec2 { } } +// Vec4ToRGBA converts imgui's Vec4 to golang rgba color func Vec4ToRGBA(vec4 imgui.Vec4) color.RGBA { return color.RGBA{ R: uint8(vec4.X * 255), @@ -61,6 +74,11 @@ func Vec4ToRGBA(vec4 imgui.Vec4) color.RGBA { } } +// Update updates giu app +// it is done by default after each frame. +// Hoeever because frames stops rendering, when no user +// action is done, it may be necessary to +// Update ui manually at some point. func Update() { if Context.isAlive { Context.platform.Update() @@ -68,24 +86,29 @@ func Update() { } } +// GetCursorScreenPos returns imgui drawing cursor on the screen func GetCursorScreenPos() image.Point { pos := imgui.CursorScreenPos() return image.Pt(int(pos.X), int(pos.Y)) } +// SetCursorScreenPos sets imgui drawing cursor on the screen func SetCursorScreenPos(pos image.Point) { imgui.SetCursorScreenPos(imgui.Vec2{X: float32(pos.X), Y: float32(pos.Y)}) } +// GetCursorPos gets imgui drawing cursor inside of current window func GetCursorPos() image.Point { pos := imgui.CursorPos() return image.Pt(int(pos.X), int(pos.Y)) } +// SetCursorPos sets imgui drawing cursor inside of current window func SetCursorPos(pos image.Point) { imgui.SetCursorPos(imgui.Vec2{X: float32(pos.X), Y: float32(pos.Y)}) } +// GetMousePos returns mouse position func GetMousePos() image.Point { pos := imgui.MousePos() return image.Pt(int(pos.X), int(pos.Y)) @@ -96,21 +119,26 @@ func GetAvailableRegion() (width, height float32) { return region.X, region.Y } +// CalcTextSize calls CalcTextSizeV(text, false, -1) func CalcTextSize(text string) (width, height float32) { return CalcTextSizeV(text, false, -1) } +// CalcTextSizeV calculates text dimensions func CalcTextSizeV(text string, hideAfterDoubleHash bool, wrapWidth float32) (w, h float32) { size := imgui.CalcTextSize(text, hideAfterDoubleHash, wrapWidth) return size.X, size.Y } +// SetNextWindowSize sets size of the next window func SetNextWindowSize(width, height float32) { imgui.SetNextWindowSize(imgui.Vec2{X: width * Context.platform.GetContentScale(), Y: height * Context.platform.GetContentScale()}) } +// ExecCondition represents imgui.Condition type ExecCondition imgui.Condition +// imgui conditions const ( ConditionAlways ExecCondition = ExecCondition(imgui.ConditionAlways) ConditionOnce ExecCondition = ExecCondition(imgui.ConditionOnce) @@ -118,18 +146,28 @@ const ( ConditionAppearing ExecCondition = ExecCondition(imgui.ConditionAppearing) ) +// SetNextWindowPos sets position of next window func SetNextWindowPos(x, y float32) { imgui.SetNextWindowPos(imgui.Vec2{X: x, Y: y}) } +// SetNextWindowSizeV does similar to SetNextWIndowSize but allows to specify imgui.Condition func SetNextWindowSizeV(width, height float32, condition ExecCondition) { - imgui.SetNextWindowSizeV(imgui.Vec2{X: width * Context.platform.GetContentScale(), Y: height * Context.platform.GetContentScale()}, imgui.Condition(condition)) + imgui.SetNextWindowSizeV( + imgui.Vec2{ + X: width * Context.platform.GetContentScale(), + Y: height * Context.platform.GetContentScale(), + }, + imgui.Condition(condition), + ) } +// SetItemDefaultFocus set the item focused by default func SetItemDefaultFocus() { imgui.SetItemDefaultFocus() } +// SetKeyboardFocusHere sets keyboard focus at the widget func SetKeyboardFocusHere() { SetKeyboardFocusHereV(0) } diff --git a/Widgets.go b/Widgets.go index a046cf1d..5e634e64 100644 --- a/Widgets.go +++ b/Widgets.go @@ -14,20 +14,27 @@ import ( "github.com/sahilm/fuzzy" ) +// GenAutoID automatically generates fidget's id func GenAutoID(id string) string { return fmt.Sprintf("%s##%d", id, Context.GetWidgetIndex()) } +var _ Widget = &RowWidget{} + +// RowWidget joins a layout into one line +// calls imgui.SameLine() type RowWidget struct { widgets Layout } +// Row creates RowWidget func Row(widgets ...Widget) *RowWidget { return &RowWidget{ widgets: widgets, } } +// Build implements Widget interface func (l *RowWidget) Build() { isFirst := true l.widgets.Range(func(w Widget) { @@ -37,8 +44,7 @@ func (l *RowWidget) Build() { *PopupWidget, *TabItemWidget: // noop default: - switch w.(type) { - case *LabelWidget: + if _, isLabel := w.(*LabelWidget); isLabel { AlignTextToFramePadding() } @@ -53,10 +59,16 @@ func (l *RowWidget) Build() { }) } +// SameLine wrapps imgui.SomeLine +// Don't use if you don't have to (use RowWidget instead) func SameLine() { imgui.SameLine() } +var _ Widget = &InputTextMultilineWidget{} + +// InputTextMultilineWidget represents multiline text input widget +// see examples/widgets/ type InputTextMultilineWidget struct { label string text *string @@ -66,6 +78,7 @@ type InputTextMultilineWidget struct { onChange func() } +// InputTextMultiline creates InputTextMultilineWidget func InputTextMultiline(text *string) *InputTextMultilineWidget { return &InputTextMultilineWidget{ text: text, @@ -77,17 +90,20 @@ func InputTextMultiline(text *string) *InputTextMultilineWidget { } } +// Label sets input field label func (i *InputTextMultilineWidget) Label(label string) *InputTextMultilineWidget { i.label = tStr(label) return i } +// Labelf is formatting version of Label func (i *InputTextMultilineWidget) Labelf(format string, args ...interface{}) *InputTextMultilineWidget { return i.Label(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (i *InputTextMultilineWidget) Build() { - if len(i.label) == 0 { + if i.label == "" { i.label = GenAutoID(i.label) } @@ -117,6 +133,8 @@ func (i *InputTextMultilineWidget) Size(width, height float32) *InputTextMultili return i } +var _ Widget = &ButtonWidget{} + type ButtonWidget struct { id string width float32 @@ -125,6 +143,7 @@ type ButtonWidget struct { onClick func() } +// Build implements Widget interface func (b *ButtonWidget) Build() { if b.disabled { imgui.BeginDisabled(true) @@ -165,16 +184,21 @@ func Buttonf(format string, args ...interface{}) *ButtonWidget { return Button(fmt.Sprintf(format, args...)) } +var _ Widget = &BulletWidget{} + type BulletWidget struct{} func Bullet() *BulletWidget { return &BulletWidget{} } +// Build implements Widget interface func (b *BulletWidget) Build() { imgui.Bullet() } +var _ Widget = &BulletTextWidget{} + type BulletTextWidget struct { text string } @@ -189,10 +213,13 @@ func BulletTextf(format string, args ...interface{}) *BulletTextWidget { return BulletText(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (bt *BulletTextWidget) Build() { imgui.BulletText(bt.text) } +var _ Widget = &ArrowButtonWidget{} + type ArrowButtonWidget struct { id string dir Direction @@ -212,17 +239,20 @@ func ArrowButton(dir Direction) *ArrowButtonWidget { } } -func (ab *ArrowButtonWidget) ID(id string) *ArrowButtonWidget { - ab.id = id - return ab +func (b *ArrowButtonWidget) ID(id string) *ArrowButtonWidget { + b.id = id + return b } -func (ab *ArrowButtonWidget) Build() { - if imgui.ArrowButton(ab.id, uint8(ab.dir)) && ab.onClick != nil { - ab.onClick() +// Build implements Widget interface +func (b *ArrowButtonWidget) Build() { + if imgui.ArrowButton(b.id, uint8(b.dir)) && b.onClick != nil { + b.onClick() } } +var _ Widget = &SmallButtonWidget{} + type SmallButtonWidget struct { id string onClick func() @@ -244,12 +274,15 @@ func SmallButtonf(format string, args ...interface{}) *SmallButtonWidget { return SmallButton(fmt.Sprintf(format, args...)) } -func (sb *SmallButtonWidget) Build() { - if imgui.SmallButton(GenAutoID(sb.id)) && sb.onClick != nil { - sb.onClick() +// Build implements Widget interface +func (b *SmallButtonWidget) Build() { + if imgui.SmallButton(GenAutoID(b.id)) && b.onClick != nil { + b.onClick() } } +var _ Widget = &InvisibleButtonWidget{} + type InvisibleButtonWidget struct { id string width float32 @@ -282,12 +315,15 @@ func InvisibleButton() *InvisibleButtonWidget { } } -func (ib *InvisibleButtonWidget) Build() { - if imgui.InvisibleButton(tStr(ib.id), imgui.Vec2{X: ib.width, Y: ib.height}) && ib.onClick != nil { - ib.onClick() +// Build implements Widget interface +func (b *InvisibleButtonWidget) Build() { + if imgui.InvisibleButton(tStr(b.id), imgui.Vec2{X: b.width, Y: b.height}) && b.onClick != nil { + b.onClick() } } +var _ Widget = &ImageButtonWidget{} + type ImageButtonWidget struct { texture *Texture width float32 @@ -300,19 +336,20 @@ type ImageButtonWidget struct { onClick func() } -func (i *ImageButtonWidget) Build() { - if i.texture == nil && i.texture.id == 0 { +// Build implements Widget interface +func (b *ImageButtonWidget) Build() { + if b.texture == nil && b.texture.id == 0 { return } if imgui.ImageButtonV( - i.texture.id, - imgui.Vec2{X: i.width, Y: i.height}, - ToVec2(i.uv0), ToVec2(i.uv1), - i.framePadding, ToVec4Color(i.bgColor), - ToVec4Color(i.tintColor), - ) && i.onClick != nil { - i.onClick() + b.texture.id, + imgui.Vec2{X: b.width, Y: b.height}, + ToVec2(b.uv0), ToVec2(b.uv1), + b.framePadding, ToVec4Color(b.bgColor), + ToVec4Color(b.tintColor), + ) && b.onClick != nil { + b.onClick() } } @@ -361,6 +398,8 @@ func ImageButton(texture *Texture) *ImageButtonWidget { } } +var _ Widget = &ImageButtonWithRgbaWidget{} + type ImageButtonWithRgbaWidget struct { *ImageButtonWidget rgba image.Image @@ -405,27 +444,31 @@ func (b *ImageButtonWithRgbaWidget) FramePadding(padding int) *ImageButtonWithRg return b } -func (i *ImageButtonWithRgbaWidget) Build() { - if state := Context.GetState(i.id); state == nil { - Context.SetState(i.id, &ImageState{}) +// Build implements Widget interface +func (b *ImageButtonWithRgbaWidget) Build() { + if state := Context.GetState(b.id); state == nil { + Context.SetState(b.id, &ImageState{}) - NewTextureFromRgba(i.rgba, func(tex *Texture) { - Context.SetState(i.id, &ImageState{texture: tex}) + NewTextureFromRgba(b.rgba, func(tex *Texture) { + Context.SetState(b.id, &ImageState{texture: tex}) }) } else { imgState := state.(*ImageState) - i.ImageButtonWidget.texture = imgState.texture + b.ImageButtonWidget.texture = imgState.texture } - i.ImageButtonWidget.Build() + b.ImageButtonWidget.Build() } +var _ Widget = &CheckboxWidget{} + type CheckboxWidget struct { text string selected *bool onChange func() } +// Build implements Widget interface func (c *CheckboxWidget) Build() { if imgui.Checkbox(GenAutoID(c.text), c.selected) && c.onChange != nil { c.onChange() @@ -445,12 +488,15 @@ func Checkbox(text string, selected *bool) *CheckboxWidget { } } +var _ Widget = &RadioButtonWidget{} + type RadioButtonWidget struct { text string active bool onChange func() } +// Build implements Widget interface func (r *RadioButtonWidget) Build() { if imgui.RadioButton(GenAutoID(r.text), r.active) && r.onChange != nil { r.onChange() @@ -470,6 +516,8 @@ func RadioButton(text string, active bool) *RadioButtonWidget { } } +var _ Widget = &ChildWidget{} + type ChildWidget struct { width float32 height float32 @@ -478,6 +526,7 @@ type ChildWidget struct { layout Layout } +// Build implements Widget interface func (c *ChildWidget) Build() { if imgui.BeginChildV(GenAutoID("Child"), imgui.Vec2{X: c.width, Y: c.height}, c.border, int(c.flags)) { c.layout.Build() @@ -517,6 +566,8 @@ func Child() *ChildWidget { } } +var _ Widget = &ComboCustomWidget{} + type ComboCustomWidget struct { label string previewValue string @@ -550,6 +601,7 @@ func (cc *ComboCustomWidget) Size(width float32) *ComboCustomWidget { return cc } +// Build implements Widget interface func (cc *ComboCustomWidget) Build() { if cc.width > 0 { imgui.PushItemWidth(cc.width) @@ -562,6 +614,8 @@ func (cc *ComboCustomWidget) Build() { } } +var _ Widget = &ComboWidget{} + type ComboWidget struct { label string previewValue string @@ -589,6 +643,7 @@ func (c *ComboWidget) Flags(flags ComboFlags) *ComboWidget { return c } +// Build implements Widget interface func (c *ComboWidget) Build() { if c.width > 0 { imgui.PushItemWidth(c.width) @@ -619,6 +674,8 @@ func (c *ComboWidget) OnChange(onChange func()) *ComboWidget { return c } +var _ Widget = &ContextMenuWidget{} + type ContextMenuWidget struct { id string mouseButton MouseButton @@ -648,6 +705,7 @@ func (c *ContextMenuWidget) ID(id string) *ContextMenuWidget { return c } +// Build implements Widget interface func (c *ContextMenuWidget) Build() { if imgui.BeginPopupContextItemV(c.id, int(c.mouseButton)) { c.layout.Build() @@ -655,6 +713,8 @@ func (c *ContextMenuWidget) Build() { } } +var _ Widget = &DragIntWidget{} + type DragIntWidget struct { label string value *int32 @@ -685,10 +745,13 @@ func (d *DragIntWidget) Format(format string) *DragIntWidget { return d } +// Build implements Widget interface func (d *DragIntWidget) Build() { imgui.DragIntV(GenAutoID(d.label), d.value, d.speed, d.min, d.max, d.format) } +var _ Widget = &ColumnWidget{} + type ColumnWidget struct { widgets Layout } @@ -700,6 +763,7 @@ func Column(widgets ...Widget) *ColumnWidget { } } +// Build implements Widget interface func (g *ColumnWidget) Build() { imgui.BeginGroup() @@ -708,6 +772,8 @@ func (g *ColumnWidget) Build() { imgui.EndGroup() } +var _ Widget = &ImageWidget{} + type ImageWidget struct { texture *Texture width float32 @@ -755,6 +821,7 @@ func (i *ImageWidget) Size(width, height float32) *ImageWidget { return i } +// Build implements Widget interface func (i *ImageWidget) Build() { size := imgui.Vec2{X: i.width, Y: i.height} rect := imgui.ContentRegionAvail() @@ -799,6 +866,8 @@ func (is *ImageState) Dispose() { } } +var _ Widget = &ImageWithRgbaWidget{} + type ImageWithRgbaWidget struct { id string rgba image.Image @@ -823,6 +892,7 @@ func (i *ImageWithRgbaWidget) OnClick(cb func()) *ImageWithRgbaWidget { return i } +// Build implements Widget interface func (i *ImageWithRgbaWidget) Build() { if i.rgba != nil { var imgState *ImageState @@ -843,6 +913,8 @@ func (i *ImageWithRgbaWidget) Build() { i.img.Build() } +var _ Widget = &ImageWithFileWidget{} + type ImageWithFileWidget struct { id string imgPath string @@ -867,6 +939,7 @@ func (i *ImageWithFileWidget) OnClick(cb func()) *ImageWithFileWidget { return i } +// Build implements Widget interface func (i *ImageWithFileWidget) Build() { imgState := &ImageState{} if state := Context.GetState(i.id); state == nil { @@ -887,9 +960,11 @@ func (i *ImageWithFileWidget) Build() { i.img.Build() } -type ImageWithUrlWidget struct { +var _ Widget = &ImageWithURLWidget{} + +type ImageWithURLWidget struct { id string - imgUrl string + imgURL string downloadTimeout time.Duration whenLoading Layout whenFailure Layout @@ -898,10 +973,10 @@ type ImageWithUrlWidget struct { img *ImageWidget } -func ImageWithUrl(url string) *ImageWithUrlWidget { - return &ImageWithUrlWidget{ - id: fmt.Sprintf("ImageWithUrl_%s", url), - imgUrl: url, +func ImageWithURL(url string) *ImageWithURLWidget { + return &ImageWithURLWidget{ + id: fmt.Sprintf("ImageWithURL_%s", url), + imgURL: url, downloadTimeout: 10 * time.Second, whenLoading: Layout{Dummy(100, 100)}, whenFailure: Layout{Dummy(100, 100)}, @@ -909,44 +984,46 @@ func ImageWithUrl(url string) *ImageWithUrlWidget { } } -// Event trigger when image is downloaded and ready to display. -func (i *ImageWithUrlWidget) OnReady(onReady func()) *ImageWithUrlWidget { +// OnReady sets event trigger when image is downloaded and ready to display. +func (i *ImageWithURLWidget) OnReady(onReady func()) *ImageWithURLWidget { i.onReady = onReady return i } -func (i *ImageWithUrlWidget) OnFailure(onFailure func(error)) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) OnFailure(onFailure func(error)) *ImageWithURLWidget { i.onFailure = onFailure return i } -func (i *ImageWithUrlWidget) OnClick(cb func()) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) OnClick(cb func()) *ImageWithURLWidget { i.img.OnClick(cb) return i } -func (i *ImageWithUrlWidget) Timeout(downloadTimeout time.Duration) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) Timeout(downloadTimeout time.Duration) *ImageWithURLWidget { i.downloadTimeout = downloadTimeout return i } -func (i *ImageWithUrlWidget) Size(width, height float32) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) Size(width, height float32) *ImageWithURLWidget { i.img.Size(width, height) return i } -func (i *ImageWithUrlWidget) LayoutForLoading(widgets ...Widget) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) LayoutForLoading(widgets ...Widget) *ImageWithURLWidget { i.whenLoading = Layout(widgets) return i } -func (i *ImageWithUrlWidget) LayoutForFailure(widgets ...Widget) *ImageWithUrlWidget { +func (i *ImageWithURLWidget) LayoutForFailure(widgets ...Widget) *ImageWithURLWidget { i.whenFailure = Layout(widgets) return i } -func (i *ImageWithUrlWidget) Build() { - var imgState *ImageState = &ImageState{} +// Build implements Widget interface +func (i *ImageWithURLWidget) Build() { + imgState := &ImageState{} + if state := Context.GetState(i.id); state == nil { Context.SetState(i.id, imgState) @@ -958,7 +1035,7 @@ func (i *ImageWithUrlWidget) Build() { // Load image from url client := resty.New() client.SetTimeout(i.downloadTimeout) - resp, err := client.R().SetContext(downloadContext).Get(i.imgUrl) + resp, err := client.R().SetContext(downloadContext).Get(i.imgURL) if err != nil { Context.SetState(i.id, &ImageState{failure: true}) @@ -1012,6 +1089,8 @@ func (i *ImageWithUrlWidget) Build() { } } +var _ Widget = &InputTextWidget{} + type InputTextWidget struct { label string hint string @@ -1052,7 +1131,7 @@ func (i *InputTextWidget) Labelf(format string, args ...interface{}) *InputTextW return i.Label(fmt.Sprintf(format, args...)) } -// Enable auto complete popup by using fuzzy search of current value agains candidates +// AutoComplete enables auto complete popup by using fuzzy search of current value against candidates // Press enter to confirm the first candidate func (i *InputTextWidget) AutoComplete(candidates []string) *InputTextWidget { i.candidates = candidates @@ -1084,6 +1163,7 @@ func (i *InputTextWidget) OnChange(onChange func()) *InputTextWidget { return i } +// Build implements Widget interface func (i *InputTextWidget) Build() { // Get state var state *inputTextState @@ -1138,6 +1218,8 @@ func (i *InputTextWidget) Build() { } } +var _ Widget = &InputIntWidget{} + type InputIntWidget struct { label string value *int32 @@ -1180,6 +1262,7 @@ func (i *InputIntWidget) OnChange(onChange func()) *InputIntWidget { return i } +// Build implements Widget interface func (i *InputIntWidget) Build() { if i.width != 0 { PushItemWidth(i.width) @@ -1191,6 +1274,8 @@ func (i *InputIntWidget) Build() { } } +var _ Widget = &InputFloatWidget{} + type InputFloatWidget struct { label string value *float32 @@ -1240,6 +1325,7 @@ func (i *InputFloatWidget) OnChange(onChange func()) *InputFloatWidget { return i } +// Build implements Widget interface func (i *InputFloatWidget) Build() { if i.width != 0 { PushItemWidth(i.width) @@ -1251,6 +1337,8 @@ func (i *InputFloatWidget) Build() { } } +var _ Widget = &LabelWidget{} + type LabelWidget struct { label string fontInfo *FontInfo @@ -1278,6 +1366,7 @@ func (l *LabelWidget) Font(font *FontInfo) *LabelWidget { return l } +// Build implements Widget interface func (l *LabelWidget) Build() { if l.wrapped { PushTextWrapPos() @@ -1293,6 +1382,8 @@ func (l *LabelWidget) Build() { imgui.Text(l.label) } +var _ Widget = &MainMenuBarWidget{} + type MainMenuBarWidget struct { layout Layout } @@ -1308,6 +1399,7 @@ func (m *MainMenuBarWidget) Layout(widgets ...Widget) *MainMenuBarWidget { return m } +// Build implements Widget interface func (m *MainMenuBarWidget) Build() { if imgui.BeginMainMenuBar() { m.layout.Build() @@ -1315,6 +1407,8 @@ func (m *MainMenuBarWidget) Build() { } } +var _ Widget = &MenuBarWidget{} + type MenuBarWidget struct { layout Layout } @@ -1330,6 +1424,7 @@ func (m *MenuBarWidget) Layout(widgets ...Widget) *MenuBarWidget { return m } +// Build implements Widget interface func (m *MenuBarWidget) Build() { if imgui.BeginMenuBar() { m.layout.Build() @@ -1337,6 +1432,8 @@ func (m *MenuBarWidget) Build() { } } +var _ Widget = &MenuItemWidget{} + type MenuItemWidget struct { label string selected bool @@ -1372,12 +1469,15 @@ func (m *MenuItemWidget) OnClick(onClick func()) *MenuItemWidget { return m } +// Build implements Widget interface func (m *MenuItemWidget) Build() { if imgui.MenuItemV(GenAutoID(m.label), "", m.selected, m.enabled) && m.onClick != nil { m.onClick() } } +var _ Widget = &MenuWidget{} + type MenuWidget struct { label string enabled bool @@ -1406,6 +1506,7 @@ func (m *MenuWidget) Layout(widgets ...Widget) *MenuWidget { return m } +// Build implements Widget interface func (m *MenuWidget) Build() { if imgui.BeginMenuV(GenAutoID(m.label), m.enabled) { m.layout.Build() @@ -1413,6 +1514,8 @@ func (m *MenuWidget) Build() { } } +var _ Widget = &PopupWidget{} + type PopupWidget struct { name string flags WindowFlags @@ -1437,6 +1540,7 @@ func (p *PopupWidget) Layout(widgets ...Widget) *PopupWidget { return p } +// Build implements Widget interface func (p *PopupWidget) Build() { if imgui.BeginPopup(p.name, int(p.flags)) { p.layout.Build() @@ -1444,6 +1548,8 @@ func (p *PopupWidget) Build() { } } +var _ Widget = &PopupModalWidget{} + type PopupModalWidget struct { name string open *bool @@ -1475,6 +1581,7 @@ func (p *PopupModalWidget) Layout(widgets ...Widget) *PopupModalWidget { return p } +// Build implements Widget interface func (p *PopupModalWidget) Build() { if imgui.BeginPopupModalV(p.name, p.open, int(p.flags)) { p.layout.Build() @@ -1490,6 +1597,8 @@ func CloseCurrentPopup() { imgui.CloseCurrentPopup() } +var _ Widget = &ProgressBarWidget{} + type ProgressBarWidget struct { fraction float32 width float32 @@ -1521,10 +1630,13 @@ func (p *ProgressBarWidget) Overlayf(format string, args ...interface{}) *Progre return p.Overlay(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (p *ProgressBarWidget) Build() { imgui.ProgressBarV(p.fraction, imgui.Vec2{X: p.width, Y: p.height}, p.overlay) } +var _ Widget = &SelectableWidget{} + type SelectableWidget struct { label string selected bool @@ -1571,13 +1683,14 @@ func (s *SelectableWidget) OnClick(onClick func()) *SelectableWidget { return s } -// Handle mouse left button's double click event. +// OnDClick handles mouse left button's double click event. // SelectableFlagsAllowDoubleClick will set once tonDClick callback is notnull func (s *SelectableWidget) OnDClick(onDClick func()) *SelectableWidget { s.onDClick = onDClick return s } +// Build implements Widget interface func (s *SelectableWidget) Build() { // If onDClick is set, check flags and set related flag when necessary if s.onDClick != nil && s.flags&SelectableFlagsAllowDoubleClick != 0 { @@ -1593,8 +1706,11 @@ func (s *SelectableWidget) Build() { } } +var _ Widget = &SeparatorWidget{} + type SeparatorWidget struct{} +// Build implements Widget interface func (s *SeparatorWidget) Build() { imgui.Separator() } @@ -1603,6 +1719,8 @@ func Separator() *SeparatorWidget { return &SeparatorWidget{} } +var _ Widget = &SliderIntWidget{} + type SliderIntWidget struct { label string value *int32 @@ -1650,6 +1768,7 @@ func (s *SliderIntWidget) Labelf(format string, args ...interface{}) *SliderIntW return s.Label(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (s *SliderIntWidget) Build() { if s.width != 0 { PushItemWidth(s.width) @@ -1661,6 +1780,8 @@ func (s *SliderIntWidget) Build() { } } +var _ Widget = &VSliderIntWidget{} + type VSliderIntWidget struct { label string width float32 @@ -1715,6 +1836,7 @@ func (vs *VSliderIntWidget) Labelf(format string, args ...interface{}) *VSliderI return vs.Label(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (vs *VSliderIntWidget) Build() { if imgui.VSliderIntV( GenAutoID(vs.label), @@ -1729,6 +1851,8 @@ func (vs *VSliderIntWidget) Build() { } } +var _ Widget = &SliderFloatWidget{} + type SliderFloatWidget struct { label string value *float32 @@ -1751,9 +1875,9 @@ func SliderFloat(value *float32, min, max float32) *SliderFloatWidget { } } -func (s *SliderFloatWidget) Format(format string) *SliderFloatWidget { - s.format = format - return s +func (sf *SliderFloatWidget) Format(format string) *SliderFloatWidget { + sf.format = format + return sf } func (sf *SliderFloatWidget) OnChange(onChange func()) *SliderFloatWidget { @@ -1776,6 +1900,7 @@ func (sf *SliderFloatWidget) Labelf(format string, args ...interface{}) *SliderF return sf.Label(fmt.Sprintf(format, args...)) } +// Build implements Widget interface func (sf *SliderFloatWidget) Build() { if sf.width != 0 { PushItemWidth(sf.width) @@ -1787,11 +1912,14 @@ func (sf *SliderFloatWidget) Build() { } } +var _ Widget = &DummyWidget{} + type DummyWidget struct { width float32 height float32 } +// Build implements Widget interface func (d *DummyWidget) Build() { w, h := GetAvailableRegion() @@ -1813,6 +1941,8 @@ func Dummy(width, height float32) *DummyWidget { } } +var _ Widget = &HSplitterWidget{} + type HSplitterWidget struct { id string width float32 @@ -1853,6 +1983,8 @@ func (h *HSplitterWidget) ID(id string) *HSplitterWidget { return h } +// Build implements Widget interface +// nolint:dupl // will fix later func (h *HSplitterWidget) Build() { // Calc line position. width := int(40 * Context.GetPlatform().GetContentScale()) @@ -1867,7 +1999,7 @@ func (h *HSplitterWidget) Build() { ptMax := image.Pt(centerX+width/2, centerY+height/2) style := imgui.CurrentStyle() - color := Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrab)) + c := Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrab)) // Place a invisible button to capture event. imgui.InvisibleButton(h.id, imgui.Vec2{X: h.width, Y: h.height}) @@ -1878,14 +2010,16 @@ func (h *HSplitterWidget) Build() { } if imgui.IsItemHovered() { imgui.SetMouseCursor(imgui.MouseCursorResizeNS) - color = Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrabActive)) + c = Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrabActive)) } // Draw a line in the very center canvas := GetCanvas() - canvas.AddRectFilled(pt.Add(ptMin), pt.Add(ptMax), color, 0, 0) + canvas.AddRectFilled(pt.Add(ptMin), pt.Add(ptMax), c, 0, 0) } +var _ Widget = &VSplitterWidget{} + type VSplitterWidget struct { id string width float32 @@ -1926,6 +2060,8 @@ func (v *VSplitterWidget) ID(id string) *VSplitterWidget { return v } +// Build implements Widget interface +// nolint:dupl // will fix later func (v *VSplitterWidget) Build() { // Calc line position. width := int(2 * Context.GetPlatform().GetContentScale()) @@ -1940,7 +2076,7 @@ func (v *VSplitterWidget) Build() { ptMax := image.Pt(centerX+width/2, centerY+height/2) style := imgui.CurrentStyle() - color := Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrab)) + c := Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrab)) // Place a invisible button to capture event. imgui.InvisibleButton(v.id, imgui.Vec2{X: v.width, Y: v.height}) @@ -1951,14 +2087,16 @@ func (v *VSplitterWidget) Build() { } if imgui.IsItemHovered() { imgui.SetMouseCursor(imgui.MouseCursorResizeEW) - color = Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrabActive)) + c = Vec4ToRGBA(style.GetColor(imgui.StyleColorScrollbarGrabActive)) } // Draw a line in the very center canvas := GetCanvas() - canvas.AddRectFilled(pt.Add(ptMin), pt.Add(ptMax), color, 0, 0) + canvas.AddRectFilled(pt.Add(ptMin), pt.Add(ptMax), c, 0, 0) } +var _ Widget = &TabItemWidget{} + type TabItemWidget struct { label string open *bool @@ -1994,6 +2132,7 @@ func (t *TabItemWidget) Layout(widgets ...Widget) *TabItemWidget { return t } +// Build implements Widget interface func (t *TabItemWidget) Build() { if imgui.BeginTabItemV(t.label, t.open, int(t.flags)) { t.layout.Build() @@ -2001,6 +2140,8 @@ func (t *TabItemWidget) Build() { } } +var _ Widget = &TabBarWidget{} + type TabBarWidget struct { id string flags TabBarFlags @@ -2028,12 +2169,13 @@ func (t *TabBarWidget) TabItems(items ...*TabItemWidget) *TabBarWidget { return t } +// Build implements Widget interface func (t *TabBarWidget) Build() { - buildingId := t.id - if len(buildingId) == 0 { - buildingId = GenAutoID("TabBar") + buildingID := t.id + if buildingID == "" { + buildingID = GenAutoID("TabBar") } - if imgui.BeginTabBarV(buildingId, int(t.flags)) { + if imgui.BeginTabBarV(buildingID, int(t.flags)) { for _, ti := range t.tabItems { ti.Build() } @@ -2041,6 +2183,8 @@ func (t *TabBarWidget) Build() { } } +var _ Widget = &TableRowWidget{} + type TableRowWidget struct { flags TableRowFlags minRowHeight float64 @@ -2072,6 +2216,7 @@ func (r *TableRowWidget) MinHeight(height float64) *TableRowWidget { return r } +// Build implements Widget interface func (r *TableRowWidget) Build() { imgui.TableNextRow(imgui.TableRowFlags(r.flags), r.minRowHeight) @@ -2092,11 +2237,13 @@ func (r *TableRowWidget) Build() { } } +var _ Widget = &TableColumnWidget{} + type TableColumnWidget struct { label string flags TableColumnFlags innerWidthOrWeight float32 - userId uint32 + userID uint32 } func TableColumn(label string) *TableColumnWidget { @@ -2104,7 +2251,7 @@ func TableColumn(label string) *TableColumnWidget { label: tStr(label), flags: 0, innerWidthOrWeight: 0, - userId: 0, + userID: 0, } } @@ -2118,15 +2265,18 @@ func (c *TableColumnWidget) InnerWidthOrWeight(w float32) *TableColumnWidget { return c } -func (c *TableColumnWidget) UserId(id uint32) *TableColumnWidget { - c.userId = id +func (c *TableColumnWidget) UserID(id uint32) *TableColumnWidget { + c.userID = id return c } +// Build implements Widget interface func (c *TableColumnWidget) Build() { - imgui.TableSetupColumn(c.label, imgui.TableColumnFlags(c.flags), c.innerWidthOrWeight, c.userId) + imgui.TableSetupColumn(c.label, imgui.TableColumnFlags(c.flags), c.innerWidthOrWeight, c.userID) } +var _ Widget = &TableWidget{} + type TableWidget struct { flags TableFlags size imgui.Vec2 @@ -2149,7 +2299,7 @@ func Table() *TableWidget { } } -// Display visible rows only to boost performance. +// FastMode Displays visible rows only to boost performance. func (t *TableWidget) FastMode(b bool) *TableWidget { t.fastMode = b return t @@ -2187,6 +2337,7 @@ func (t *TableWidget) Flags(flags TableFlags) *TableWidget { return t } +// Build implements Widget interface func (t *TableWidget) Build() { if len(t.rows) == 0 { return @@ -2231,6 +2382,8 @@ func (t *TableWidget) Build() { } } +var _ Widget = &TreeTableRowWidget{} + type TreeTableRowWidget struct { label string flags TreeNodeFlags @@ -2255,6 +2408,7 @@ func (ttr *TreeTableRowWidget) Flags(flags TreeNodeFlags) *TreeTableRowWidget { return ttr } +// Build implements Widget interface func (ttr *TreeTableRowWidget) Build() { imgui.TableNextRow(0, 0) imgui.TableNextColumn() @@ -2288,6 +2442,8 @@ func (ttr *TreeTableRowWidget) Build() { } } +var _ Widget = &TreeTableWidget{} + type TreeTableWidget struct { flags TableFlags size imgui.Vec2 @@ -2332,6 +2488,7 @@ func (tt *TreeTableWidget) Rows(rows ...*TreeTableRowWidget) *TreeTableWidget { return tt } +// Build implements Widget interface func (tt *TreeTableWidget) Build() { if len(tt.rows) == 0 { return @@ -2362,11 +2519,14 @@ func (tt *TreeTableWidget) Build() { } } +var _ Widget = &TooltipWidget{} + type TooltipWidget struct { tip string layout Layout } +// Build implements Widget interface func (t *TooltipWidget) Build() { if imgui.IsItemHovered() { if t.layout != nil { @@ -2395,6 +2555,8 @@ func (t *TooltipWidget) Layout(widgets ...Widget) *TooltipWidget { return t } +var _ Widget = &TreeNodeWidget{} + type TreeNodeWidget struct { label string flags TreeNodeFlags @@ -2420,7 +2582,7 @@ func (t *TreeNodeWidget) Flags(flags TreeNodeFlags) *TreeNodeWidget { return t } -// Create TreeNode with eventHandler +// Event create TreeNode with eventHandler // You could detect events (e.g. IsItemClicked IsMouseDoubleClicked etc...) and handle them for TreeNode inside eventHandler func (t *TreeNodeWidget) Event(handler func()) *TreeNodeWidget { t.eventHandler = handler @@ -2432,6 +2594,7 @@ func (t *TreeNodeWidget) Layout(widgets ...Widget) *TreeNodeWidget { return t } +// Build implements Widget interface func (t *TreeNodeWidget) Build() { open := imgui.TreeNodeV(t.label, int(t.flags)) @@ -2447,8 +2610,11 @@ func (t *TreeNodeWidget) Build() { } } +var _ Widget = &SpacingWidget{} + type SpacingWidget struct{} +// Build implements Widget interface func (s *SpacingWidget) Build() { imgui.Spacing() } @@ -2457,10 +2623,13 @@ func Spacing() *SpacingWidget { return &SpacingWidget{} } +var _ Widget = &CustomWidget{} + type CustomWidget struct { builder func() } +// Build implements Widget interface func (c *CustomWidget) Build() { if c.builder != nil { c.builder() @@ -2473,13 +2642,15 @@ func Custom(builder func()) *CustomWidget { } } +var _ Widget = &ConditionWidget{} + type ConditionWidget struct { cond bool layoutIf Layout layoutElse Layout } -func Condition(cond bool, layoutIf Layout, layoutElse Layout) *ConditionWidget { +func Condition(cond bool, layoutIf, layoutElse Layout) *ConditionWidget { return &ConditionWidget{ cond: cond, layoutIf: layoutIf, @@ -2487,6 +2658,7 @@ func Condition(cond bool, layoutIf Layout, layoutElse Layout) *ConditionWidget { } } +// Build implements Widget interface func (c *ConditionWidget) Build() { if c.cond { if c.layoutIf != nil { @@ -2499,7 +2671,7 @@ func (c *ConditionWidget) Build() { } } -// Batch create widgets and render only which is visible. +// RangeBuilder batch create widgets and render only which is visible. func RangeBuilder(id string, values []interface{}, builder func(int, interface{}) Widget) Layout { var layout Layout @@ -2526,6 +2698,8 @@ func (s *ListBoxState) Dispose() { // Nothing to do here. } +var _ Widget = &ListBoxWidget{} + type ListBoxWidget struct { id string width float32 @@ -2583,6 +2757,8 @@ func (l *ListBoxWidget) OnMenu(onMenu func(selectedIndex int, menu string)) *Lis return l } +// Build implements Widget interface +// nolint:gocognit // will fix later func (l *ListBoxWidget) Build() { var state *ListBoxState if s := Context.GetState(l.id); s == nil { @@ -2639,6 +2815,8 @@ func (l *ListBoxWidget) Build() { child.Build() } +var _ Widget = &DatePickerWidget{} + type DatePickerWidget struct { id string date *time.Time @@ -2667,6 +2845,7 @@ func (d *DatePickerWidget) OnChange(onChange func()) *DatePickerWidget { return d } +// Build implements Widget interface func (d *DatePickerWidget) Build() { if d.date == nil { return @@ -2821,6 +3000,8 @@ func (d *DatePickerWidget) calendarField(day int) Widget { }) } +var _ Widget = &ColorEditWidget{} + type ColorEditWidget struct { label string color *color.RGBA @@ -2829,10 +3010,10 @@ type ColorEditWidget struct { onChange func() } -func ColorEdit(label string, color *color.RGBA) *ColorEditWidget { +func ColorEdit(label string, c *color.RGBA) *ColorEditWidget { return &ColorEditWidget{ label: tStr(label), - color: color, + color: c, flags: ColorEditFlagsNone, } } @@ -2852,6 +3033,7 @@ func (ce *ColorEditWidget) Size(width float32) *ColorEditWidget { return ce } +// Build implements Widget interface func (ce *ColorEditWidget) Build() { c := ToVec4Color(*ce.color) col := [4]float32{ diff --git a/Window.go b/Window.go index aa8c99b3..e54ac2c4 100644 --- a/Window.go +++ b/Window.go @@ -6,6 +6,9 @@ import ( "github.com/AllenDang/imgui-go" ) +// SingleWindow creates one window filling all available space +// in MasterWindow. If SingleWindow is set up, no other windows can't be +// definied. func SingleWindow() *WindowWidget { size := Context.platform.DisplaySize() title := fmt.Sprintf("SingleWindow_%d", Context.GetWidgetIndex()) @@ -32,16 +35,23 @@ func SingleWindowWithMenuBar() *WindowWidget { imgui.WindowFlagsNoResize).Size(size[0], size[1]) } +var _ Disposable = &windowState{} + type windowState struct { hasFocus bool currentPosition, currentSize imgui.Vec2 } +// Dispose implements Disposable interface func (s *windowState) Dispose() { // noop } +// WindowWidget represents imgui.Window +// Windows are used to display ui widgets. +// They are in second place in the giu hierarchy (after the MasterWindow) +// NOTE: to disable multiple window, use SingleWindow type WindowWidget struct { title string open *bool @@ -51,32 +61,44 @@ type WindowWidget struct { bringToFront bool } +// Window creates a WindowWidget func Window(title string) *WindowWidget { return &WindowWidget{ title: title, } } +// IsOpen sets if window widget is `opened` (minimalized) func (w *WindowWidget) IsOpen(open *bool) *WindowWidget { w.open = open return w } +// Flags sets window flags func (w *WindowWidget) Flags(flags WindowFlags) *WindowWidget { w.flags = flags return w } +// Size sets window size +// NOTE: size can be changed by user, if you want to prevent +// user from changing window size, use NoResize flag func (w *WindowWidget) Size(width, height float32) *WindowWidget { w.width, w.height = width, height return w } +// Pos sets the window start position +// NOTE: The position could be changed by user later. +// To prevent user from changin window position use +// WIndowFlagsNoMove func (w *WindowWidget) Pos(x, y float32) *WindowWidget { w.x, w.y = x, y return w } +// Layout is a final step of the window setup. +// it should be called to add a layout to the window and build it. func (w *WindowWidget) Layout(widgets ...Widget) { if widgets == nil { return @@ -120,24 +142,30 @@ func (w *WindowWidget) Layout(widgets ...Widget) { imgui.End() } +// CurrentPosition returns a current position of the window func (w *WindowWidget) CurrentPosition() (x, y float32) { pos := w.getState().currentPosition return pos.X, pos.Y } +// CurrentSize returns current size of the window func (w *WindowWidget) CurrentSize() (width, height float32) { size := w.getState().currentSize return size.X, size.Y } +// BringToFront sets window focused func (w *WindowWidget) BringToFront() { w.bringToFront = true } +// HasFocus returns true if window is focused func (w *WindowWidget) HasFocus() bool { return w.getState().hasFocus } +// RegisterKeyboardShortcuts adds local (window-level) keyboard shortcuts +// see InputHandler.go func (w *WindowWidget) RegisterKeyboardShortcuts(s ...WindowShortcut) *WindowWidget { if w.HasFocus() { for _, shortcut := range s { diff --git a/cmd/gmdeploy/main.go b/cmd/gmdeploy/main.go index e43b1a73..56f3ea82 100644 --- a/cmd/gmdeploy/main.go +++ b/cmd/gmdeploy/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "log" "os" "os/exec" "path/filepath" @@ -29,7 +30,7 @@ func main() { flag.Parse() - if len(targetOS) == 0 { + if targetOS == "" { targetOS = runtime.GOOS } @@ -38,79 +39,89 @@ func main() { // Prepare build dir outputDir := filepath.Join(projectPath, "build", targetOS) - os.RemoveAll(outputDir) - MkdirAll(outputDir) + if err := os.RemoveAll(outputDir); err != nil { + log.Fatalf("error removing content of %s", outputDir) + } + + mkdirAll(outputDir) switch targetOS { case "darwin": - // Compile + const iconExtension = ".icns" + // nolint:gosec // Compile: cannot fix cmd := exec.Command("bash", "-c", fmt.Sprintf("go build -ldflags='-s -w' -o %s", appName)) cmd.Dir = projectPath - RunCmd(cmd) + runCmd(cmd) // Upx if upx { + // nolint:gosec // cannot fix cmd = exec.Command("upx", appName) - RunCmd(cmd) + runCmd(cmd) } // Bundle macOSPath := filepath.Join(outputDir, fmt.Sprintf("%s.app", appName), "Contents", "MacOS") - MkdirAll(macOSPath) + mkdirAll(macOSPath) // Copy compiled executable to build folder + // nolint:gosec // cannot fix cmd = exec.Command("mv", appName, macOSPath) - RunCmd(cmd) + runCmd(cmd) // Prepare Info.plist contentsPath := filepath.Join(outputDir, fmt.Sprintf("%s.app", appName), "Contents") - Save(filepath.Join(contentsPath, "Info.plist"), darwinPlist(appName)) + save(filepath.Join(contentsPath, "Info.plist"), darwinPlist(appName)) // Prepare PkgInfo - Save(filepath.Join(contentsPath, "PkgInfo"), darwinPkginfo()) + save(filepath.Join(contentsPath, "PkgInfo"), darwinPkginfo()) - if len(iconPath) > 0 && filepath.Ext(iconPath) == ".icns" { + if len(iconPath) > 0 && filepath.Ext(iconPath) == iconExtension { // Prepare icon resourcesPath := filepath.Join(contentsPath, "Resources") - MkdirAll(resourcesPath) + mkdirAll(resourcesPath) // Rename icon file name to [appName].icns - cmd = exec.Command("cp", iconPath, filepath.Join(resourcesPath, fmt.Sprintf("%s.icns", appName))) - RunCmd(cmd) + // nolint:gosec // cannot fix + cmd = exec.Command("cp", iconPath, filepath.Join(resourcesPath, fmt.Sprintf("%s%s", appName, iconExtension))) + runCmd(cmd) } fmt.Printf("%s.app is generated at %s/build/%s/\n", appName, projectPath, targetOS) case "linux": - // Compile + // nolint:gosec // Compile: cannot fix cmd := exec.Command("bash", "-c", fmt.Sprintf("go build -ldflags='-s -w' -o %s", filepath.Join(appName))) cmd.Dir = projectPath - RunCmd(cmd) + runCmd(cmd) // Bundle contentsPath := filepath.Join(outputDir, fmt.Sprintf("%s.app", appName)) binPath := filepath.Join(contentsPath, "bin") - MkdirAll(binPath) + mkdirAll(binPath) // Copy compiled executable to build folder + // nolint:gosec // rename command - cannot be fixed cmd = exec.Command("mv", appName, binPath) - RunCmd(cmd) + runCmd(cmd) // create desktop entry hasIcon := iconPath != "" && filepath.Ext(iconPath) == ".icns" desktopPath := filepath.Join(contentsPath, "share", "applications") - MkdirAll(desktopPath) + mkdirAll(desktopPath) - Save(filepath.Join(desktopPath, fmt.Sprintf("%s.desktop", appName)), linuxDesktop(appName, hasIcon)) + save(filepath.Join(desktopPath, fmt.Sprintf("%s.desktop", appName)), linuxDesktop(appName, hasIcon)) if hasIcon { // Prepare icon iconsPath := filepath.Join(contentsPath, "share", "icons") - MkdirAll(iconsPath) + mkdirAll(iconsPath) // Rename icon file name to [appName].icns - cmd = exec.Command("cp", iconPath, filepath.Join(iconsPath, fmt.Sprintf("%s.icns", appName))) - RunCmd(cmd) + newIconName := filepath.Join(iconsPath, fmt.Sprintf("%s.icns", appName)) + // nolint:gosec // cp comman - cannot fix + cmd = exec.Command("cp", iconPath, newIconName) + runCmd(cmd) } default: fmt.Printf("Sorry, %s is not supported yet.\n", targetOS) diff --git a/cmd/gmdeploy/utils.go b/cmd/gmdeploy/utils.go index ca264df3..c74ddd05 100644 --- a/cmd/gmdeploy/utils.go +++ b/cmd/gmdeploy/utils.go @@ -7,23 +7,22 @@ import ( "os/exec" ) -func Save(name, data string) { - err := ioutil.WriteFile(name, []byte(data), 0644) - if err != nil { +func save(name, data string) { + const newFileMode = 0o644 + if err := ioutil.WriteFile(name, []byte(data), newFileMode); err != nil { log.Fatalf("Failed to save %s:%v\n", name, err) } } -func MkdirAll(name string) { - err := os.MkdirAll(name, 0755) - if err != nil { +func mkdirAll(name string) { + const newDirMode = 0o755 + if err := os.MkdirAll(name, newDirMode); err != nil { log.Fatalf("Failed to make all dir, %s:%v\n", name, err) } } -func RunCmd(cmd *exec.Cmd) { - err := cmd.Run() - if err != nil { +func runCmd(cmd *exec.Cmd) { + if err := cmd.Run(); err != nil { log.Fatalf("Failed to execute command:%s with error %v\n", cmd.String(), err) } } diff --git a/doc.go b/doc.go new file mode 100644 index 00000000..e81dda83 --- /dev/null +++ b/doc.go @@ -0,0 +1,5 @@ +// Package giu - A rapid cross-platform GUI framework for Go based on Dear ImGui +// and the great Go binding imgui-go. +// +// for details and usage see README of the project. +package giu diff --git a/examples/loadimage/loadimage.go b/examples/loadimage/loadimage.go index 0843e879..0a1ff885 100644 --- a/examples/loadimage/loadimage.go +++ b/examples/loadimage/loadimage.go @@ -25,12 +25,12 @@ func loop() { }).Size(300, 200), g.Label("Display image from url (wait few seconds to download)"), - g.ImageWithUrl("https://png.pngitem.com/pimgs/s/3-36108_gopher-golang-hd-png-download.png").OnClick(func() { + g.ImageWithURL("https://png.pngitem.com/pimgs/s/3-36108_gopher-golang-hd-png-download.png").OnClick(func() { fmt.Println("image from url clicked") }).Size(300, 200), g.Label("Display images from url with loading and fallback"), - g.ImageWithUrl( + g.ImageWithURL( "https://png.pngitem.com/pimgs/s/424-4241958_transparent-gopher-png-golang-gopher-png-png-download.png"). Timeout(5*time.Second). Size(300, 200). @@ -47,12 +47,12 @@ func loop() { }), g.Label("Handle failure event"), - g.ImageWithUrl("http://x.y/z.jpg").Timeout(2*time.Second).OnFailure(func(err error) { + g.ImageWithURL("http://x.y/z.jpg").Timeout(2*time.Second).OnFailure(func(err error) { fmt.Printf("Failed to download image, Error msg is %s\n", err.Error()) }), g.Label("Display image from url without placeholder (no size when loading)"), - g.ImageWithUrl("https://www.pngitem.com/pimgs/m/424-4242405_go-lang-gopher-clipart-png-download-golang-gopher.png").Size(300, 200), + g.ImageWithURL("https://www.pngitem.com/pimgs/m/424-4242405_go-lang-gopher-clipart-png-download-golang-gopher.png").Size(300, 200), g.Label("Footer"), )