ListBox updateContent() doesn't repaint if the number of rows hasn't changed

Hi,
I’m using a ListBox in my plugin preset browser to show the list of presets. The presets are organized in two groups: factory and user. When switching between the user and factory group, updateContent() is called and the ListBoxModel pulls the relevant list of presets. This normally triggers a repaint, but if both factory and user lists are the same size, I have to call repaint() manually for it to refresh. Is it a bug or a feature? Now I can compare the sizes and do a manual repaint() for this special case, but this does sound like a workaround…

Here’s a relevant bit of code:

class ListBoxModelBase : public ListBoxModel {
public:
    virtual String getTextForRowNumber(int rowNumber) = 0;

    void paintListBoxItem(int rowNumber,
                          Graphics& g,
                          int width, int height,
                          bool rowIsSelected) final override {
        // Background
        g.setColour(rowIsSelected ? Theme::Colours::accent : Theme::Colours::comboBoxBackground);
        g.fillRect(g.getClipBounds().withTrimmedBottom(1));

        // Text
        g.setFont(Theme::listBoxFontHeight);
        g.setColour(Theme::Colours::normalLight);
        g.drawText(getTextForRowNumber(rowNumber), 5, 0, width, height, Justification::centredLeft, true);
    };

    std::function<void(int lastRowSelected)> onSelectedRowsChanged = nullptr;
};

#pragma mark -

class SourcesListBoxModel : public ListBoxModelBase {
public:
    SourcesListBoxModel(PresetManager& presetManager) : presetManager(presetManager) {}

    int getNumRows() final override {
        return static_cast<decltype(getNumRows())>(presetManager.presetSourceNames.size());
    }

    String getTextForRowNumber(int rowNumber) final override {
        return presetManager.presetSourceNames[rowNumber];
    }

    void selectedRowsChanged(int lastRowSelected) final override {
        if (lastRowSelected < PresetManager::Source::Factory
            || lastRowSelected > PresetManager::Source::User) {
            return;
        }

        if (onSelectedRowsChanged) {
            onSelectedRowsChanged(lastRowSelected);
        }
    }

    PresetManager& presetManager;
};

#pragma mark -

class PresetsListBoxModel : public ListBoxModelBase {
public:
    PresetsListBoxModel(PresetManager& presetManager) : presetManager(presetManager) {}

    int getNumRows() final override {
        currentPresets = presetManager.getCurrentPresets();
        return static_cast<decltype(getNumRows())>(currentPresets.size());
    };

    String getTextForRowNumber(int rowNumber) final override {
        return currentPresets[rowNumber].getName();
    }

    void selectedRowsChanged(int lastRowSelected) final override {
        if (lastRowSelected > 0) {
            presetManager.loadPreset(currentPresets[lastRowSelected]);
        }
    }

    PresetManager& presetManager;
    std::vector<Preset> currentPresets;
};

#pragma mark -

class PresetBrowser : public Component {
public:
    PresetBrowser(PresetManager& presetManager)
        : Component()
        , presetManager(presetManager)
        , sourcesListBoxModel(presetManager)
        , presetsListBoxModel(presetManager)
    {
        sourcesListBoxModel.onSelectedRowsChanged = [&] (int lastRowSelected) {
            presetManager.setCurrentSource(static_cast<PresetManager::Source>(lastRowSelected));
            presetsListBox.updateContent();
        };

        sourcesListBox.setModel(&sourcesListBoxModel);
        sourcesListBox.setRowHeight(Theme::listBoxRowHeight);
        addAndMakeVisible(sourcesListBox);

        presetsListBox.setModel(&presetsListBoxModel);
        presetsListBox.setRowHeight(Theme::listBoxRowHeight);
        addAndMakeVisible(presetsListBox);

        addAndMakeVisible(deleteButton);
        addAndMakeVisible(saveButton);
    }

    void paint(Graphics& g) final override {
        /// ...
    }

    void resized() final override {
        /// ...
    }

private:
    PresetManager& presetManager;

    SourcesListBoxModel sourcesListBoxModel;
    ListBox sourcesListBox;

    PresetsListBoxModel presetsListBoxModel;
    ListBox presetsListBox;

    TextButton deleteButton { "Delete" };
    TextButton saveButton { "Save" };
};
2 Likes