One of the things Swift (especailly for iOS) is lacking is a “listbox/datagrid” like control… yeah it has UITableview, but that is really good for one column without getting really complex and fragile. So I have embarked on a custom control the is actually based on a UIView not a UITableView or even an UICollectionView. It consists of 3 primary dictionaries. One for Rowdata (such as Height, Tag and default color), one for ColumnData (width, header, alignment etc), and one for the Cells. Each dictionary only has an entry if it needs it… ie. “Sparse Array”
But here is my question for which I would like your opinion.
The Xojo List box has a FONT (name/Size) assigned to the control… and each cell uses that (barring an override by CellTextPaint). I want to expand the “default” behaviour…
I could
Add ONE font class like the Xojo Listbox … and force the developer to use “CellTextPaint” for anything “different”
Add one to the RowClass, the ColClass and the CellClass… and have it use the CellClass if there was one, else inherit from ColClass if it had one, else inherit from RowClass… This way it would be most flexible, but incur more overhead both in storage and in drawing time.
Basically I want my “Listbox” to be able to display basic text in any font/size/color while leaving CellBackground/CellTextPaint for those “special” needs.
per cell would be nice
but what do you do if you have a font assigned to a row and to a column ? which one supercedes the other and why ? there’s no specific reason to assume that a font setting for a row might be preferred over one for column or vice versa.
I almost think there has to be real clarity where there are ambiguous edges like this
You are quite correct… which is something I have been struggling with… to figure out the “best” way. Right now my thinking is (as to why?.. just kinda “why not” I guess)
Cell assigned font if there is one
Column assigned font next, if there is one
Row assigned font, next if there is one
finally Control assigned font, which there will be enforced to be one
Similar logic will be applied to other aspects such as background color
So if a row and column are assigned different values and the cell at the intersection must have the “row” value in preference to the “col” value, then it must be assigned a specific cell value… The object is to assign visual aspects to as few dictionary entries as possible, but get the best result…
Like I said, I’m looking for opinions on alternative methods…
what if assigning to row or column didnt actually assign to those but to all the cells in that row or col instead ?
that would make it more a convenience method than one that stores data per row or column for itself
and “last one wins” would apply
however it would make it hard to assign them ahead of actually stuffing any data in there since there would be no cells to apply it to (unless you put some kind of time stamp on them and could prefer ‘the last one assigned’ which to me makes a lot of sense)
personally that would be my preference as, like I said, theres no good reason to prefer row over column or vice versa so in your list 2 and 3 could be reversed “just because”
and I personally hate that kind of explanation as it seems capricious
I understand your idea… and while it makes sense… .it also requires the “creation” of potentially empty cells… but the issue is. since the “spreadsheet” is virtual, there is no finite point at which to say you’ve filled a row
lb.cell[5,5]="data" // creates a single entry, in the cell dictionary
lb.row[5].font="menlo" // how many cells on on the row? Don't know
The above example would create a spreadsheet of technically infinite width, but with only a single filled data cell. Any attempt to read from an non existant cell would simply return a default cell value (think hasKey)
let s as string=cell[10,10] // returns '' because there is no dictionary entry with that key
Not sure it requires creating the cells
Just holding the font setting with a timestamp so you can tell which one was applied last and then when, if, a cell is created in that row or column you can apply the “last” one
here’s a sample of what I’m thinking as a xojo listbox subclass
all the cells just draw the name of the font they would use (other properties are certainly possible)
note that row 1 has both menlo & futura as the font but since futura was assigned to the column after the rows font was assigned the column setting would prevail (and if you switch the order then the effect is the other way round as I expect)
and since the cell (3,1) has a specific font setting it takes on that setting
the rest of the cells do no so they draw in whatever font the listbox was set to by default
fwiw I used a dictionary to store the font info data that way I did not have to add another class that a person might need to add to their projet IF they wanted to use this
Norm… perhaps you missed the key point in the OP… this is NOT a subclass of anything that Xojo has or does… . This is a SWIFT from scratch control, with 3 dictionaries as the datastore and a UIView as the presentaion layer.
for example here are the classes that each dictionary can hold
class dataCELL : NSObject {
private var delegate : listBoxProtocol?
var cellText : String = ""
var cellBorderBottom : myListbox.border = .DEFAULT
var cellBorderLeft : myListbox.border = .DEFAULT
var cellBorderTop : myListbox.border = .DEFAULT
var cellBorderRight : myListbox.border = .DEFAULT
var cellType : myListbox.typeCell = .normal
var cellCheck : Bool = false
var cellAlignment : myListbox.align = .DEFAULT
var cellFont : UIFont? = nil
var cellBold : Bool = false
var cellItalic : Bool = false
var cellBackgroundColor : UIColor = UIColor.clear
var cellTextColor : UIColor = UIColor.clear
var tag : String = ""
//
func invalidateCell(row:Int,col:Int) { self.delegate?.invalidateCell(row: row,col: col) }
}
class dataROW : NSObject {
private var delegate : listBoxProtocol?
var rowHeight : CGFloat = -1
var rowTag : String = ""
var rowBackgroundColor : UIColor = UIColor.clear
var rowTextColor : UIColor = UIColor.black
func invalidateRow(row:Int) { self.delegate?.invalidateRow(row: row) }
}
class dataCOLUMN : NSObject {
private var delegate : listBoxProtocol?
var columnWidth : CGFloat = -1
var columntag : String = ""
var columnHeading : String = ""
var columnAlignment : myListbox.align = .left
var columnType : myListbox.typeCell = .normal
var columnFont : UIFont? = nil
var columnBackgroundColor : UIColor = UIColor.clear
var columnTextColor : UIColor = UIColor.black
func invalidateColumn(column:Int) { self.delegate?.invalidateColumn(col: column) }
}
again… there are only entries in any/all of those dictionaries IF there is a need to define a property beyond the predetermined default values (ie. white background, black text, standard font no borders)
No I got that
I happened to USE a listbox subclass to demonstrate the idea I was talking about - how to set row column and cell fonts and have them apply in the order they were set
Everything else about “theres only an entry IF you want to define it” applies to what I did