cue (short for cocos UI extensions) is a library for Geode mods that adds helpful and convenient UI nodes. WIP.
Currently available:
cue::ListNode- an extensive list class with user friendly interface. See below for a more in-depth showcase.cue::DropdownNode- an expandable list that can have dynamic and arbitrary contents.cue::RepeatingBackground- a customizable repeating background, similar to the one used in GD levels and MenuLayer, or some Globed layers.cue::attachBackground(node)- a handy util function that attaches a slightly darkgeode::NineSlicebehind the given node. All the details about it are customizable.- plus some other useful helper functions!
cue::PlayerIcon- a simple wrapper aroundSimplePlayerthat has a correct content size and makes it simple to set the displayed icon.cue::LoadingCircle- a properly functioningLoadingCirclecue::ProgressBar- a simple resizable progress bar class, similar to the one GD hascue::Slider- a convenient slider class, allows to set value range and resize freely, whereas the vanillaSliderclass has issues with thatcue::RadioLogic- a boilerplate-free way to create radio buttons
Add the following lines to your CMakeLists.txt
CPMAddPackage("gh:dankmeme01/cue#main") # prefer a specific commit over main
target_link_libraries(${PROJECT_NAME} PRIVATE cue)cue::ListNode is one of the easiest ways to create your own list element. For example here's how you would create a simple list of labels, in the comments style:
CCSize listSize { 240.f, 200.f };
auto list = cue::ListNode::create(listSize, cue::Brown, cue::ListBorderStyle::Comments);
for (size_t i = 0; i < 10; i++) {
list->addCell(CCLabelBMFont::create(fmt::format("Test {}", i).c_str(), "bigFont.fnt"));
}Performing various operations on the list is also very simple. Here are some examples:
Adding, removing, retrieving cells
// insert a new cell at the end
auto cell = list->addCell(CCNode::create());
// insert a new cell at the start
list->insertCell(CCNode::create(), 0);
// remove a cell
list->removeCell(cell);
// or do it by index!
list->removeCell(list->indexForCell(cell));
list->removeCell(0);
// remove all cells
list->clear();Sorting and shuffling
// shuffles the list, NOT IMPLEMENTED YET
list->shuffle();
// sorts the list with your custom comparator
list->sortAs<CCLabelBMFont>([&](CCLabelBMFont* a, CCLabelBMFont* b) {
return a->getZOrder() < b->getZOrder();
});Set how to align the list contents if they don't take the entire list width
list->setJustify(cue::Justify::Left); // elements will be aligned to the left side, default
list->setJustify(cue::Justify::Right); // elements will be aligned to the right side
list->setJustify(cue::Justify::Center); // elements will be aligned to the centerListNode automatically calls this->updateLayout whenever cells are added or removed. For massive lists, this can be a huge performance penalty. For that purpose, auto updating can be disabled.
// disable auto update to prevent excessive layout calculations
list->setAutoUpdate(false);
// add a huge amount of nodes
for (size_t i = 0; i < 65536; i++) {
list->addCell(CCNode::create());
}
// enable auto update back and update the list manually
list->setAutoUpdate(true);
list->updateLayout();The main class for creating radio buttons is RadioLogic. Internally it uses GD's CCMenuItemToggler, but saves you from writing all the boilerplate of ensuring choice exclusivity. The lifetime of the RadioLogic class is not important for the buttons to work - if you simply want to use the per-button callbacks, you don't need to store it after creating all buttons. However, it enables some additional convenience methods such as getting the currently selected button, tagging buttons with enums, etc.
cue::RadioLogic radio;
// create a standard checkbox toggler with optional callback and scale adjustment
auto toggler1 = radio.createToggler();
auto toggler2 = radio.createToggler(0.8f);
auto toggler3 = radio.createToggler(0.8f, [](CCMenuItemToggler* toggler) {
// called only when this toggler gets *enabled*
});
// `RadioLogic` internally uses `shared_ptr` and can be copied to refer to the same instance.
radio.setCallback([radio](CCMenuItemToggler* toggler) {
// this gets called when any toggler gets enabled
});
// get index of the selected toggler, 0 being the first added toggler
size_t sel = radio.getSelected();
// select the button of the given index. avoid calling inside callbacks for the same radio logic
radio.select(1);Note that none of this handles positioning - it's completely up to you to add these togglers to a node. RadioLogic handles only the actual logic behind toggler presses.
As said earlier, you can also assign enums to your togglers!
enum class Which {
First,
Second,
};
cue::RadioLogic<Which> radio;
// When a template argument is specified, first argument is of that type
auto toggler1 = radio.createToggler(Which::First);
auto toggler2 = radio.createToggler(Which::Second, 0.8f);
// The callback may also now have 3 signatures:
// * (CCMenuItemToggler*)
// * (CCMenuItemToggler*, Which)
// * (Which)
radio.setCallback([radio](Which which) {
// called with whatever button got enabled
});
Which sel = radio.getSelected();
radio.select(Which::Second);