diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8206c4da..febac7ec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,13 +30,13 @@ jobs: sudo apt-get --allow-releaseinfo-change update sudo apt-get install -y libgtk-3-dev libasound2-dev libxxf86vm-dev - name: Set up Go environment - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: 1.21.x id: go - name: Cache Go modules - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml index 8f274bda..3c1ce47d 100644 --- a/.github/workflows/golangci-lint.yaml +++ b/.github/workflows/golangci-lint.yaml @@ -20,12 +20,12 @@ jobs: uses: actions/checkout@v4 - name: Setup - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true - name: Lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: version: v1.54.2 diff --git a/ExtraWidgets.go b/ExtraWidgets.go index f031583d..fe017a72 100644 --- a/ExtraWidgets.go +++ b/ExtraWidgets.go @@ -365,17 +365,27 @@ func (l *ListBoxWidget) Build() { var _ Widget = &DatePickerWidget{} +// DatePickerLabels represents a label string in date picker. +type DatePickerLabels string + +// These constants hold strings for translations of day/month/year +const ( + DatePickerLabelMonth DatePickerLabels = "Month:" + DatePickerLabelYear DatePickerLabels = " Year:" +) + // DatePickerWidget is a simple Calender widget. // It allow user to select a day and convert it to time.Time go type. // It consists of a Combo widget which (after opening) contains // a calender-like table. type DatePickerWidget struct { - id string - date *time.Time - width float32 - onChange func() - format string - startOfWeek time.Weekday + id string + date *time.Time + width float32 + onChange func() + format string + startOfWeek time.Weekday + translations map[DatePickerLabels]string } // DatePicker creates new DatePickerWidget. @@ -386,6 +396,10 @@ func DatePicker(id string, date *time.Time) *DatePickerWidget { width: 100, startOfWeek: time.Sunday, onChange: func() {}, // small hack - prevent giu from setting nil cb (skip nil check later) + translations: map[DatePickerLabels]string{ + DatePickerLabelMonth: string(DatePickerLabelMonth), + DatePickerLabelYear: string(DatePickerLabelYear), + }, } } @@ -419,6 +433,12 @@ func (d *DatePickerWidget) StartOfWeek(weekday time.Weekday) *DatePickerWidget { return d } +// Translation sets a translation to specified label type +func (d *DatePickerWidget) Translation(label DatePickerLabels, value string) *DatePickerWidget { + d.translations[label] = value + return d +} + func (d *DatePickerWidget) getFormat() string { if d.format == "" { return "2006-01-02" // default @@ -451,37 +471,46 @@ func (d *DatePickerWidget) Build() { } if imgui.BeginComboV(d.id+"##Combo", d.date.Format(d.getFormat()), imgui.ComboFlagsHeightLargest) { - // --- [Build year widget] --- + // --- [Build year/month widget] --- imgui.AlignTextToFramePadding() const yearButtonSize = 25 - Row( - Label(Context.FontAtlas.RegisterString(" Year")), - Labelf("%14d", d.date.Year()), - Button("-##"+d.id+"year").OnClick(func() { - *d.date = d.date.AddDate(-1, 0, 0) - d.onChange() - }).Size(yearButtonSize, yearButtonSize), - Button("+##"+d.id+"year").OnClick(func() { - *d.date = d.date.AddDate(1, 0, 0) - d.onChange() - }).Size(yearButtonSize, yearButtonSize), - ).Build() - - // --- [Build month widgets] --- - Row( - Label("Month"), - Labelf("%10s(%02d)", d.date.Month().String(), d.date.Month()), - Button("-##"+d.id+"month").OnClick(func() { - *d.date = d.date.AddDate(0, -1, 0) - d.onChange() - }).Size(yearButtonSize, yearButtonSize), - Button("+##"+d.id+"month").OnClick(func() { - *d.date = d.date.AddDate(0, 1, 0) - d.onChange() - }).Size(yearButtonSize, yearButtonSize), - ).Build() + Table(). + Size(0, 50). + Flags(0). + Columns( + TableColumn("##"+d.id+"col1").Flags(TableColumnFlags(imgui.TableColumnFlagsNoHeaderLabel)), + TableColumn("##"+d.id+"col2").Flags(TableColumnFlags(imgui.TableColumnFlagsNoHeaderLabel)), + TableColumn("##"+d.id+"col3").Flags(TableColumnFlags(imgui.TableColumnFlagsNoHeaderLabel)|TableColumnFlagsWidthFixed).InnerWidthOrWeight(100), + TableColumn("##"+d.id+"col4").Flags(TableColumnFlags(imgui.TableColumnFlagsNoHeaderLabel)), + ). + Rows( + TableRow( + Label(d.translations[DatePickerLabelYear]), + ArrowButton(DirectionLeft).ID(d.id+"year-").OnClick(func() { + *d.date = d.date.AddDate(-1, 0, 0) + d.onChange() + }), + Labelf("%d", d.date.Year()), + ArrowButton(DirectionRight).ID(d.id+"year+").OnClick(func() { + *d.date = d.date.AddDate(1, 0, 0) + d.onChange() + }), + ), + TableRow( + Label(d.translations[DatePickerLabelMonth]), + ArrowButton(DirectionLeft).ID(d.id+"month-").OnClick(func() { + *d.date = d.date.AddDate(0, -1, 0) + d.onChange() + }), + Labelf("%s (%02d)", d.date.Month().String(), d.date.Month()), + ArrowButton(DirectionRight).ID(d.id+"month+").OnClick(func() { + *d.date = d.date.AddDate(0, 1, 0) + d.onChange() + }), + ), + ).Build() // --- [Build day widgets] --- days := d.getDaysGroups() diff --git a/ImageWidgets.go b/ImageWidgets.go index 92398fcf..d0086ad0 100644 --- a/ImageWidgets.go +++ b/ImageWidgets.go @@ -6,6 +6,7 @@ import ( "image" "image/color" "net/http" + "reflect" "time" imgui "github.com/AllenDang/cimgui-go" @@ -108,6 +109,7 @@ type imageState struct { failure bool cancel ctx.CancelFunc texture *Texture + img *image.RGBA } // Dispose cleans imageState (implements Disposable interface). @@ -127,7 +129,7 @@ var _ Widget = &ImageWithRgbaWidget{} // display it in giu. type ImageWithRgbaWidget struct { id string - rgba image.Image + rgba *image.RGBA img *ImageWidget } @@ -135,7 +137,7 @@ type ImageWithRgbaWidget struct { func ImageWithRgba(rgba image.Image) *ImageWithRgbaWidget { return &ImageWithRgbaWidget{ id: GenAutoID("ImageWithRgba"), - rgba: rgba, + rgba: ImageToRgba(rgba), img: Image(nil), } } @@ -162,7 +164,7 @@ func (i *ImageWithRgbaWidget) OnClick(cb func()) *ImageWithRgbaWidget { func (i *ImageWithRgbaWidget) Build() { if i.rgba != nil { var imgState *imageState - if imgState = GetState[imageState](Context, i.id); imgState == nil { + if imgState = GetState[imageState](Context, i.id); imgState == nil || !reflect.DeepEqual(i.rgba, imgState.img) { imgState = &imageState{} SetState(Context, i.id, imgState) diff --git a/Plot.go b/Plot.go index 4f73f563..b7b26398 100644 --- a/Plot.go +++ b/Plot.go @@ -1,9 +1,8 @@ package giu import ( - "image" - imgui "github.com/AllenDang/cimgui-go" + "image" ) // PlotWidget is implemented by all the particular plots, which can be used @@ -191,24 +190,22 @@ func (p *PlotCanvasWidget) Build() { ) if len(p.xTicksValue) > 0 { - imgui.PlotSetupAxisTicksdoubleV( + imgui.PlotSetupAxisTicksdoublePtrV( imgui.AxisX1, - p.xTicksValue[0], - p.xTicksValue[1], // <- TODO: why is it so strangely saved? - -1, // TODO: implement + &p.xTicksValue, + int32(len(p.xTicksValue)), p.xTicksLabel, p.xTicksShowDefault, ) } if len(p.yTicksValue) > 0 { - imgui.PlotSetupAxisTicksdoubleV( + imgui.PlotSetupAxisTicksdoublePtrV( imgui.AxisY1, - p.xTicksValue[0], - p.xTicksValue[1], // <- TODO: why is it so strangely saved? - -1, // TODO: implement - p.xTicksLabel, - p.xTicksShowDefault, + &p.yTicksValue, + int32(len(p.yTicksValue)), + p.yTicksLabel, + p.yTicksShowDefault, ) } @@ -292,7 +289,7 @@ func (p *BarPlot) Plot() { p.shift, 0, // TODO: implement int32(p.offset), - 0, // TODO: implement + 8, // sizeof(double) = 8 ) } @@ -394,19 +391,20 @@ func (p *LinePlot) Offset(offset int) *LinePlot { // Plot implements Plot interface. func (p *LinePlot) Plot() { - imgui.PlotSetupAxis( + imgui.PlotSetAxis( imgui.PlotAxisEnum(p.yAxis), ) - // TODO: no idea what should it be... - // imgui.PlotDragLineX(Context.FontAtlas.RegisterString(p.title), p.values, p.xScale, p.x0, p.offset) - // imgui.PlotDragLineX( - // Context.FontAtlas.RegisterString(p.title), - // p.values, - // p.xScale, - // p.x0, - // p.offset, - //) + imgui.PlotPlotLinedoublePtrIntV( + Context.FontAtlas.RegisterString(p.title), + &p.values, + int32(len(p.values)), + p.xScale, + p.x0, + 0, // flags + int32(p.offset), + 8, // sizeof(double) = 8 + ) } // LineXYPlot adds XY plot line. @@ -441,9 +439,16 @@ func (p *LineXYPlot) Offset(offset int) *LineXYPlot { // Plot implements Plot interface. func (p *LineXYPlot) Plot() { - // TODO: migrate this - // imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis)) - // imgui.ImPlotLineXY(Context.FontAtlas.RegisterString(p.title), p.xs, p.ys, p.offset) + imgui.PlotSetAxis(imgui.PlotAxisEnum(p.yAxis)) + imgui.PlotPlotLinedoublePtrdoublePtrV( + Context.FontAtlas.RegisterString(p.title), + &p.xs, + &p.ys, + int32(len(p.xs)), + 0, // flags + int32(p.offset), + 8, // sizeof(double) = 8 + ) } // PieChartPlot represents a pie chart. @@ -542,7 +547,7 @@ func (p *ScatterPlot) Plot() { p.x0, 0, // TODO: implement flags int32(p.offset), - 0, // TODO: implement + 8, // sizeof(double) = 8 ) } @@ -574,6 +579,6 @@ func (p *ScatterXYPlot) Plot() { int32(len(p.xs)), 0, // TODO: implement int32(p.offset), - 0, // TODO: implement + 8, // sizeof(double) = 8 ) } diff --git a/TableWidgets.go b/TableWidgets.go index d314ce44..534ba8dd 100644 --- a/TableWidgets.go +++ b/TableWidgets.go @@ -169,7 +169,12 @@ func (t *TableWidget) Flags(flags TableFlags) *TableWidget { func (t *TableWidget) Build() { colCount := len(t.columns) if colCount == 0 { - colCount = len(t.rows[0].layout) + if len(t.rows) > 0 { + colCount = len(t.rows[0].layout) + } else { + // No rows or columns, pass a single column to BeginTable + colCount = 1 + } } if imgui.BeginTableV(t.id, int32(colCount), imgui.TableFlags(t.flags), t.size, float32(t.innerWidth)) { diff --git a/go.mod b/go.mod index 52f77d83..ab67bd9c 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/sahilm/fuzzy v0.1.0 github.com/stretchr/testify v1.8.4 golang.design/x/hotkey v0.4.1 - golang.org/x/image v0.14.0 + golang.org/x/image v0.15.0 gopkg.in/eapache/queue.v1 v1.1.0 ) diff --git a/go.sum b/go.sum index d14e5915..14273d5e 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ golang.design/x/hotkey v0.4.1 h1:zLP/2Pztl4WjyxURdW84GoZ5LUrr6hr69CzJFJ5U1go= golang.design/x/hotkey v0.4.1/go.mod h1:M8SGcwFYHnKRa83FpTFQoZvPO5vVT+kWPztFqTQKmXA= golang.design/x/mainthread v0.3.0 h1:UwFus0lcPodNpMOGoQMe87jSFwbSsEY//CA7yVmu4j8= golang.design/x/mainthread v0.3.0/go.mod h1:vYX7cF2b3pTJMGM/hc13NmN6kblKnf4/IyvHeu259L0= -golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= -golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/sys v0.0.0-20201022201747-fb209a7c41cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=