Listbox opinion

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.

Isn’t that already the answer to the question? :wink:

The question is … “In your opinion, how would YOU handle this design problem?”

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)

  1. Cell assigned font if there is one
  2. Column assigned font next, if there is one
  3. Row assigned font, next if there is one
  4. 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

Could you add an optional true/false rowOverride parameter for those who wanted the row to take precedence?

Hmmmm… an idea to be considered

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)

http://great-white-software.com/miscellaneous/listbox%20with%20per%20cell%20%2C%20per%20row%20%26%20per%20col%20font%20settings.zip

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 :slight_smile:

1 Like

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

You did look at it for ideas right ?