Comments (12)
So when I create a new row, I create it in dbCache and tmpAssetData, but nothing triggers for it to redraw with the newly added row
I have not tested it, but I'd try the following flow on successful row addition: 1) update dbCache
and add a new data row to it 2) set new row count with SetRowCount
3) call screen refresh with ui.PutEvent(ui.Event{Type: ui.EventRedraw})
from clui.
Neither worked and just gave an out of range error
What failed? I have no clue what the error was and what line if crashed. Only gueses:
absIndex := firstRow + i
...
d.data[i] = make([]string, columnInTable, columnInTable)
d.data[i][0] = tmpAssetData[absIndex].AssetCode`
- Do you have enough items in
tmpAssetData
, solen(tmpAssetData)
isfirstRow+rowCount-1
? - Have you pre-filled
tmpAssetData
?
If you set TableView row and col count to the same values(rowCount, colCount), you do not need to write anything for ActionNew
from clui.
No, sorry, there is nothing in there at the time. I removed the data I created by hand in code. I am trying to find out how to create a new row if there are 0 rows. Pretend it's a brand new application with 0 data or rows. I am trying to figure out how to use "add new row" action to start fresh and add data to an empty dataset.
from clui.
I see. I'll try this case myself
from clui.
Here is what I have been attempting to come up with:
I feel like I might be close, but I am just not quite sure.
case ui.TableActionNew:
//action = "Add new row"
c := ev.Col
r := ev.Row
var editVal = TableEdit{Row: r, Col: c}
dlg := CreateEditableDialog(fmt.Sprintf("%s:", TxtNewAssetCodeValue), "") // --- A custom popup I made so I can make more adjustments than the default one had
dlg.View.SetSize(35, 10)
dlg.OnClose(func() {
switch dlg.Result() {
case ui.DialogButton1:
editVal.NewVal = dlg.EditResult()
if tmpAssetData == nil {
var newInfo = ui.ColumnDrawInfo{Row: 0, Col: 0}
cache.data = make([][]string, rowCount, rowCount) // ------ I have this because in preload I have at the beginning if tmpAssetData == nil { return }
(func(info *ui.ColumnDrawInfo) {
cache.data[newInfo.Row][newInfo.Col] = editVal.NewVal // ------------------------------195
info.Text = cache.data[newInfo.Row][newInfo.Col]
})(&newInfo)
//cache.NewValue(0, 0, editVal.NewVal)
} else {
cache.NewValue(len(tmpAssetData), 0, editVal.NewVal)
}
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
}
})
panic: runtime error: index out of range
goroutine 1 [running]:
github.com/instance-id/GoUI/elements.CreateTableDialog.func3.3.1(...)
/home/mosthated/_dev/programming/go/src/github.com/instance-id/GoUI/elements/CreateTableDialog.go:195
github.com/instance-id/GoUI/elements.CreateTableDialog.func3.3()
/home/mosthated/_dev/programming/go/src/github.com/instance-id/GoUI/elements/CreateTableDialog.go:197 +0x22a
----------- This was my whole table page, just to give it some context.
package elements
import (
"fmt"
. "github.com/instance-id/GoUI/text"
. "github.com/instance-id/GoUI/utils"
ui "github.com/instance-id/clui"
term "github.com/nsf/termbox-go"
)
var tmpAssetData []*AssetDetails
type dbCache struct {
firstRow int // previous first visible row
rowCount int // previous visible row count
data [][]string // cache - contains at least 'rowCount' rows from DB
}
const columnInTable = 7
func (d *dbCache) preload(firstRow, rowCount int) {
if tmpAssetData == nil {
return
}
if firstRow == d.firstRow && rowCount == d.rowCount {
// fast path: view area is the same, return immediately
return
}
d.data = make([][]string, rowCount, rowCount)
for i := 0; i < rowCount; i++ {
absIndex := firstRow + i
d.data[i] = make([]string, columnInTable, columnInTable)
d.data[i][0] = tmpAssetData[absIndex].AssetCode
d.data[i][1] = tmpAssetData[absIndex].AssetName
d.data[i][2] = tmpAssetData[absIndex].AssetApiKey
d.data[i][3] = tmpAssetData[absIndex].AssetRole
d.data[i][4] = tmpAssetData[absIndex].AssetVersion
d.data[i][5] = tmpAssetData[absIndex].AssetReplaced
d.data[i][6] = tmpAssetData[absIndex].ReplaceDate
}
// do not forget to save the last values
d.firstRow = firstRow
d.rowCount = rowCount
}
// --- Custom function for editing place ---------------------------------
func (d *dbCache) NewValue(row, col int, newText string) {
d.data[row][col] = newText
}
func (d *dbCache) value(row, col int) string {
rowId := row - d.firstRow
if rowId >= len(d.data) {
return ""
}
rowValues := d.data[rowId]
if col >= len(rowValues) {
return ""
}
return rowValues[col]
}
// --- Window type for data table ----------------------------------------
func CreateTableDialog(btn *ui.ButtonNoShadow, tableTitle string) {
tableDialog := new(TableDialog)
// --- Obtain terminal overall size ----------------------------------
cw, ch := term.Size()
// --- Save current values to temp value until saved -----------------
tmpAssetData = Asset
// --- Create new popup window for table data ------------------------
tableDialog.View = ui.AddWindow(cw/2-75, ch/2-16, ui.AutoSize, ui.AutoSize, TxtAssetDetails)
ui.WindowManager().BeginUpdate()
defer ui.WindowManager().EndUpdate()
tableDialog.View.SetGaps(1, ui.KeepValue)
tableDialog.View.SetModal(true)
tableDialog.View.SetPack(ui.Vertical)
tableDialog.Frame = NewFramedWindowInput(tableDialog.View, "", nil)
// --- Create data table ---------------------------------------------
td := ui.CreateTableView(tableDialog.Frame, 145, 15, 1)
ui.ActivateControl(tableDialog.Frame, td)
cache := &dbCache{firstRow: -1}
rowCount := len(Asset)
td.SetShowLines(true)
td.SetShowRowNumber(true)
td.SetRowCount(rowCount)
cols := []ui.Column{
ui.Column{Title: "Asset Code", Width: 5, Alignment: ui.AlignLeft},
ui.Column{Title: "Asset Name", Width: 50, Alignment: ui.AlignLeft},
ui.Column{Title: "Asset APIKey", Width: 30, Alignment: ui.AlignLeft},
ui.Column{Title: "Asset RoleId", Width: 20, Alignment: ui.AlignLeft},
ui.Column{Title: "Version", Width: 7, Alignment: ui.AlignLeft},
ui.Column{Title: "Replaced?", Width: 10, Alignment: ui.AlignLeft},
ui.Column{Title: "Replace Date", Width: 12, Alignment: ui.AlignLeft},
}
td.SetColumns(cols)
td.OnBeforeDraw(func(col, row, colCnt, rowCnt int) {
cache.preload(row, rowCnt)
l, t, w, h := td.VisibleArea()
tableDialog.Frame.SetTitle(fmt.Sprintf("Caching: %d:%d - %dx%d", l, t, w, h))
})
td.OnDrawCell(func(info *ui.ColumnDrawInfo) {
info.Text = cache.value(info.Row, info.Col)
})
td.OnAction(func(ev ui.TableEvent) {
// btns := []string{TxtApplyBtn, TxtCancelBtn}
//var action string
switch ev.Action {
case ui.TableActionSort:
//action = "Sort table"
case ui.TableActionEdit:
c := ev.Col
r := ev.Row
var newInfo = ui.ColumnDrawInfo{Row: r, Col: c}
var editVal = TableEdit{Row: r, Col: c}
(func(info *ui.ColumnDrawInfo) {
editVal.OldVal = cache.value(info.Row, info.Col)
})(&newInfo)
dlg := CreateEditableDialog(fmt.Sprintf("%s: %s", TxtEditing, editVal.OldVal), editVal.OldVal)
dlg.View.SetSize(35, 10)
dlg.View.BaseControl.SetSize(35, 10)
dlg.OnClose(func() {
switch dlg.Result() {
case ui.DialogButton1:
editVal.NewVal = dlg.EditResult()
cache.NewValue(editVal.Row, editVal.Col, editVal.NewVal)
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
}
})
return
case ui.TableActionNew:
//action = "Add new row"
c := ev.Col
r := ev.Row
var editVal = TableEdit{Row: r, Col: c}
dlg := CreateEditableDialog(fmt.Sprintf("%s:", TxtNewAssetCodeValue), "")
dlg.View.SetSize(35, 10)
dlg.View.BaseControl.SetSize(35, 10)
dlg.OnClose(func() {
switch dlg.Result() {
case ui.DialogButton1:
editVal.NewVal = dlg.EditResult()
if tmpAssetData == nil {
var newInfo = ui.ColumnDrawInfo{Row: 0, Col: 0}
cache.data = make([][]string, rowCount, rowCount)
(func(info *ui.ColumnDrawInfo) {
cache.data[newInfo.Row][newInfo.Col] = editVal.NewVal
info.Text = cache.data[newInfo.Row][newInfo.Col]
})(&newInfo)
} else {
cache.NewValue(len(tmpAssetData), 0, editVal.NewVal)
}
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
}
})
case ui.TableActionDelete:
//action = "Delete row"
default:
//action = "Unknown action"
}
//dlg := ui.CreateConfirmationDialog(
// "<c:blue>"+action,
// "Click any button or press <c:yellow>SPACE<c:> to close the dialog",
// btns, ui.DialogButton1)
//dlg.OnClose(func() {})
})
btnFrame := ui.CreateFrame(tableDialog.Frame, 1, 1, ui.BorderNone, ui.Fixed)
btnFrame.SetPaddings(1, 1)
textFrame := ui.CreateFrame(btnFrame, 1, 1, ui.BorderNone, ui.Fixed)
textFrame.SetPack(ui.Vertical)
ui.CreateLabel(textFrame, ui.AutoSize, ui.AutoSize, TxtInstructs1, ui.Fixed)
ui.CreateLabel(textFrame, ui.AutoSize, ui.AutoSize, TxtInstructs2, ui.Fixed)
ui.CreateLabel(textFrame, ui.AutoSize, ui.AutoSize, TxtInstructs3, ui.Fixed)
// --- Window Controls -----------------------------------------------
ui.CreateFrame(btnFrame, 1, 1, ui.BorderNone, 1)
BtnSave := ui.CreateButton(btnFrame, 15, 1, TxtSaveBtn, ui.Fixed)
BtnSave.OnClick(func(ev ui.Event) {
Asset = tmpAssetData
btn.SetEnabled(true)
})
BtnClose := ui.CreateButton(btnFrame, 15, 1, TxtCloseBtn, ui.Fixed)
BtnClose.OnClick(func(ev ui.Event) {
ui.WindowManager().DestroyWindow(tableDialog.View)
btn.SetEnabled(true)
})
BtnSave.SetActive(false)
BtnClose.SetActive(false)
}
from clui.
Thanks for the sources, but it is still unclear:
- It displays error at L195-197. If I copy-paste the source, in my editor it is:
195
196 // --- Window Controls -----------------------------------------------
197 ui.CreateFrame(btnFrame, 1, 1, ui.BorderNone, 1)
That looks incorrect.
- How big is
Asset
? I seerowCount := len(Asset)
, and ifAsset
has fewer items than 7, it may fail insidepreload
at any line that is liked.data[i][N] = tmpAssetData[absIndex].AssetCode
(L36-L42)
from clui.
Oh, sorry. I just opened your message in email and saw that you had marked the line that fails :)
But the question #2 is still unclear: What the size of Asset
? since rowcCount=len(Asset)
. if it is empty than it is clear why L195 panics.
Another point. Quotation from your code:
cache.data = make([][]string, rowCount, rowCount)
(func(info *ui.ColumnDrawInfo) {
cache.data[newInfo.Row][newInfo.Col] = editVal.NewVal // ------------------------------195
you allocated memory for parent slice. But where is allocation for the nested one? I mean something like this:
cache.data = make([][]string, rowCount, rowCount)
cache.data[0] = make([]string, colCount, colCount)
from clui.
It is no worries. I think I almost got it. There were a few things I had to change. I think I should get it worked out shortly though!
from clui.
I am super close. I have adding a new row working if at least some data exists. I just have to make it so it can add one if none exists. At least I am on the right track. : D
It is definitely not the most clean, I will have to go back through and clean it up. I noticed I forgot to ever actually update the tmpAssetData when I was updating the table. I was only updating d.data, so I had to create a way to update that, as well as the tables data. (It will probably never be more than 7 rows, most of the time it will be 1-2 at most anyways). I had to add another struct as a container for AssetData and create the test data first a new way.
type AssetContainer struct {
AD []AssetDetails
}
Asset = &AssetContainer{AD: []AssetDetails{
{AssetCode: "UFPS1",
AssetName: "UFPS : Ultimate FPS",
AssetApiKey: "123123112312312323123123123",
AssetRole: "123123123123123123",
AssetReplaced: "Yes",
AssetVersion: "1",
ReplaceDate: "2018-06-06"},
{
AssetCode: "UFPS2",
AssetName: "UFP2 : Ultimate FPS",
AssetApiKey: "123123112312312323123123123",
AssetRole: "123123123123123123",
AssetReplaced: "Yes",
AssetVersion: "1",
ReplaceDate: "2018-06-06"}},
}
Once I did that, when I updated the data from within the table I had to update both the actual data and the tables display of the data.
// --- This is in the TableActionEdit ----------------------------------------
dlg.OnClose(func() {
switch dlg.Result() {
case ui.DialogButton1:
editVal.NewVal = dlg.EditResult()
cache.UpdateData(editVal.Row, editVal.Col, editVal.NewVal)
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
}
})
// --- This updates both the table and tmpAssetData ---------------------------
// -- There may be a cleaner / smaller way of doing this ----------------------
func (d *dbCache) UpdateData(row int, col int, data string) []AssetDetails {
switch col {
case 0:
tmpAssetData.AD[row].AssetCode = data
d.data[row][col] = tmpAssetData.AD[row].AssetCode
case 1:
tmpAssetData.AD[row].AssetName = data
d.data[row][col] = tmpAssetData.AD[row].AssetName
case 2:
tmpAssetData.AD[row].AssetApiKey = data
d.data[row][col] = tmpAssetData.AD[row].AssetApiKey
case 3:
tmpAssetData.AD[row].AssetRole = data
d.data[row][col] = tmpAssetData.AD[row].AssetRole
case 4:
tmpAssetData.AD[row].AssetVersion = data
d.data[row][col] = tmpAssetData.AD[row].AssetVersion
case 5:
tmpAssetData.AD[row].AssetReplaced = data
d.data[row][col] = tmpAssetData.AD[row].AssetReplaced
case 6:
tmpAssetData.AD[row].ReplaceDate = data
d.data[row][col] = tmpAssetData.AD[row].ReplaceDate
}
return tmpAssetData.AD
}
Creating the container for the actual AssetData then allowed me to do this:
func (a *AssetContainer) AddNewAsset(asset AssetDetails) []AssetDetails {
a.AD = append(a.AD, asset)
return a.AD
}
So now in TableACtionNew, I have this:
dlg.OnClose(func() {
switch dlg.Result() {
case ui.DialogButton1:
editVal.NewVal = dlg.EditResult()
if tmpAssetData.AD == nil {
var newInfo = ui.ColumnDrawInfo{Row: 0, Col: 0}
cache.data = make([][]string, rowCount, rowCount)
data := cache.UpdateData(newInfo.Row, newInfo.Col, editVal.NewVal)
tmpAssetData.AD = data
} else {
details := AssetDetails{AssetCode: editVal.NewVal}
tmpAssetData.AddNewAsset(details)
cache.AddNewRow(editVal.NewVal)
}
}
Seems to work pretty well in adding a new row. That 3rd one in the pic is the new one. I used this code to add it to the table:
func (d *dbCache) AddNewRow(newAsset string) {
data := []string{newAsset, "", "", "", "", "", ""}
d.data = append(d.data, data)
}
from clui.
EDIT -- Nevermind about my question below, I created a work around that ends up doing pretty much the same thing by doing the following:
var newInfo = ui.ColumnDrawInfo{Row: 0, Col: 0}
var restrictor = 0
td.OnActive(func(active bool) {
if (func(info *ui.ColumnDrawInfo) string {
return cache.value(info.Row, info.Col)
})(&newInfo) == "" {
if restrictor == 0 {
cache.CreateNewData(tmpAssetData)
restrictor = 1
}
}
})
Is it possible to force a table event manually?
I tried this:
if Asset == nil {
func() ui.TableAction {
event := ui.TableEvent{Action: ui.TableAction(ui.TableActionNew)}
return event.Action
}()
}
I was hoping that if Asset didn't have data upon opening the table, before the data was populated and what not that I could trigger the TableActionNew event. I tried to use ui.SendEventToChild()
but it seems that table actions are not the right kind of action to be able to send that.
from clui.
I can't seem to find a way to redraw the table with current data. I read that things like OnBeforeDraw
and OnDrawCell
are callbacks, but I am not sure what is actually telling the table to draw a new row. I add data to dbCache (as well as my tmpAssetData), but I always have to save (which takes the data from tmpAssetData and writes it to AssetData) close the table and reopen it (which then takes any data that is in AssetData and puts it into tmpAssetData, which then the table uses for its data to draw with initially.
So when I create a new row, I create it in dbCache and tmpAssetData, but nothing triggers for it to redraw with the newly added row. I tried to manually call Draw()
, td.OnBeforeDraw()
, td.OnDrawCell()
, cache.preload()
separetly, just to see if it would add the new column after I use ui.TableActionNew
but I am stumped on how to do it without closing and reopening the window.
Is there a way somehow in dlg.OnClose(func())
I can force it to happen once I add my new row? I could technically force the entire table window to close and reopen, but that would require saving the new row from tmpAssetData to AssetData automatically so that when the table opens again it can load the new row back into tmpAssetData because that gets wiped out when the table closes. Saving it automatically and opening/closing again quickly would defeat the purpose of having a manual save button, and storing values in tmpAssetData (which is in case the user adds a row, but then decides to cancel the action, they have to save manually with the button)
from clui.
Looks like that did the job. Thanks!
from clui.
Related Issues (20)
- Unable to edit table HOT 2
- Popup/new windows seems to tear, quickly disappear/reappear, and go off frame occasionally for fraction of second when clcking on moving it. HOT 2
- Another question about editing database fields HOT 2
- Display formatted text? HOT 4
- I tried to create a pull request, but it was not working properly. HOT 1
- Explicitly place cursor in field so it is ready to begin typing? HOT 2
- Please create the 1.2.1 release HOT 1
- Cant get button to be black HOT 1
- [Question] OnClick() event for base_control? HOT 3
- Menu Implementation HOT 5
- Optimal TableView Real State Management HOT 3
- Window Borders HOT 2
- Missing OnActivate() HOT 2
- Change bg color after selection[TableView] HOT 5
- What is the correct way to redraw a control? HOT 1
- Name of widget HOT 1
- horizontal scrollbar HOT 3
- view.OnKeyDown ? HOT 1
- Autosized labels incorrectly sized
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from clui.