I’ve been doing some work with ListBox, TableListBox, and their respective models lately, and have been disappointed in them compared to many of the other Juce classes. I haven’t fully tested everything yet, but I’m at a good point to throw this all out there for comments from Jules and anyone else who might have some insight. Since I’m not intimately familiar with the Juce code base, I’m expecting to hear that there is something wrong with these changes, but hopefully they’re not all bad.
Change # 1
ListBox has the getComponentForRow() method, so I added the (oddly) lacking getComponentForCell() to TableListBox.
[code]juce_TableListBox.h line 288
/** Finds the cell component for a given row and column in the table.
The component returned will have been created using refreshComponentForCell().
If the component for this cell is off-screen or if the cell is out-of-range,
this will return 0.
@see ListBox::getComponentForRowNumber
/
Component getComponentForCell(int rowNumber, int columnId);
juce_TableListBox.h line 288
Component* TableListBox::getComponentForCell(int rowNumber, int columnId){
TableListRowComp rowComp= dynamic_cast<TableListRowComp>(getComponentForRowNumber(rowNumber));
jassert(rowComp);
return rowComp->findChildComponentForColumn(columnId);
}
[/code]
Change # 2
I added a ListBox pointer to ListBoxModel. I know this makes them more tightly coupled than perhaps desired, but it seems that the model almost always needs to deal with row selections. It’s tedious and error prone to add this pointer to each derived model, and I don’t particularly like the multiple inheritance solution I’ve seen elsewhere. I like my suggested solution because I can keep all the data handling code in the one derived model class, and display it in a standard ListBox. (I did the same for TableListBox/TableListBoxModel)
Change # 3
I’ve noticed that when using a ListBoxModel that has custom components, mouse handling becomes very laborious. Ideally, the ListBox and ListBoxModel would respond to clicks as normal, and any special mouse handling could then be passed to the row’s component(s) via the listBoxItemClicked() method. Digging around in the Juce code, I implemented something that seems to work.
–In Component, I added a ComponentFlag allowParentToHandleMouse and appropriate getter/setter.
–In MouseInputSourceInternal, I added the following method and called it in each of the sendMouseXXX methods.
[code]Component* bubbleUpToParent(Component *originator)
{
Component *sendToComp= originator;
while(sendToComp && sendToComp->allowParentToHandleMouse()) sendToComp= sendToComp->getParentComponent();
if(sendToComp == NULL) sendToComp= originator;
return sendToComp;
}
void sendMouseEnter (Component* const comp, const Point<int>& screenPos, const int64 time)
{
Component *actual= bubbleUpToParent(comp);
//DBG ("Mouse " + JuceString (source.getIndex()) + " enter: " + comp->globalPositionToRelative (screenPos).toString() + " - Comp: " + JuceString::toHexString ((int) comp));
actual->internalMouseEnter (source, actual->globalPositionToRelative (screenPos), time);
}[/code]--In ComboBox, I overrode setAllowParentToHandleMouse to additionally be called on the ComboBox's label. Also in ComboBox::lookAndFeelChanged(), I called that setter on the new label.
–In the TableDemo code, I added the following, which causes the row to be selected and the combobox to be activated with the same click.
[code]//Added to TableDemoComponent
void cellClicked(int rowNumber, int columnId, const MouseEvent& e){
Component *comp= parentTableListBox->getComponentForCell(rowNumber, columnId);
RatingColumnCustomComponent wrapper= dynamic_cast<RatingColumnCustomComponent>(comp);
if(wrapper){
wrapper->getComboBox()->mouseDown(e);
}
}
// Added to RatingColumnCustomComponent…
ComboBox* getComboBox() {
return comboBox;
}
//…and in its constructor
setAllowParentToHandleClicks(true);
comboBox->setAllowParentToHandleClicks(true);
[/code]
