Skip to content

Commit

Permalink
Reliability improvements, Various object rendering fixes
Browse files Browse the repository at this point in the history
Fixed issue with some containers' visible state being incorrect.
Greatly improved reliability of capturing mouse events in the data mask render area.
Fixed an off-by-one issue when rendering input list options.
Added drawing and clicking of input booleans.
Fixed working set child objects always being placed at 0,0.
Fixed working set child objects not getting periodically redrawn.
Fixed output polygons with no fill being filled as black.
Fixed output rectangles not accounting for "fill with line colour".
Fixed working set selector not handling working set master timeouts.
Fixed an exception when removing a timed-out working set.
Added some copyright headers to the cpp files.
  • Loading branch information
ad3154 committed Nov 15, 2023
1 parent 8740d0d commit 369fc9d
Show file tree
Hide file tree
Showing 28 changed files with 422 additions and 194 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Supported features:
- Containers
- Object Pointers
- Input numbers
- Input Boolean
- Output numbers
- Output rectangles
- Output ellipse
Expand All @@ -46,7 +47,6 @@ Unimplemented features (for now)
- Output Lists
- Output arched bar graph
- Logging
- Input Boolean
- Graphics contexts
- Pointing events
- TAN
Expand Down
2 changes: 2 additions & 0 deletions include/WorkingSetSelectorComponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class WorkingSetSelectorComponent : public Component
void paint(Graphics &g) override;
void resized() override;

void redraw();

private:
struct SELECTOR_CHILD_OBJECTS_STRUCT
{
Expand Down
5 changes: 5 additions & 0 deletions src/AlarmMaskComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file AlarmMaskComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "AlarmMaskComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"

Expand Down
5 changes: 5 additions & 0 deletions src/ButtonComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file ButtonComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "ButtonComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"

Expand Down
7 changes: 7 additions & 0 deletions src/ContainerComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file ContainerComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "ContainerComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"

Expand Down Expand Up @@ -44,6 +49,7 @@ void ContainerComponent::paint(Graphics &)
child->setVisible(false);
}
}
this->setVisible(false);
}
else
{
Expand All @@ -54,5 +60,6 @@ void ContainerComponent::paint(Graphics &)
child->setVisible(true);
}
}
this->setVisible(true);
}
}
5 changes: 5 additions & 0 deletions src/DataMaskComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file DataMaskComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "DataMaskComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"

Expand Down
96 changes: 90 additions & 6 deletions src/DataMaskRenderAreaComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/*******************************************************************************
** @file DataMaskRenderAreaComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "DataMaskRenderAreaComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"
#include "ServerMainComponent.hpp"

DataMaskRenderAreaComponent::DataMaskRenderAreaComponent(ServerMainComponent &parentServer) :
ownerServer(parentServer)
{
addMouseListener(this, true);
}

void DataMaskRenderAreaComponent::on_change_active_mask(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet)
Expand Down Expand Up @@ -114,13 +118,15 @@ void DataMaskRenderAreaComponent::mouseUp(const MouseEvent &event)
{
auto clickedList = std::static_pointer_cast<isobus::InputList>(clickedObject);

if ((clickedList->get_option(isobus::InputList::Options::Enabled)) && (clickedList->get_number_children() > 1))
if ((clickedList->get_option(isobus::InputList::Options::Enabled)) &&
(clickedList->get_number_children() > 0) &&
clickedList->get_option(isobus::InputList::Options::Enabled))
{
// Need to display a modal combo selection
inputListModal.reset(new AlertWindow("Input List Selection", "Select a List Item, then press OK.", MessageBoxIconType::QuestionIcon));
inputListModal->addComboBox("Input List Combo", StringArray());
currentModalComponentCache.clear();
currentModalComponentCache.reserve(clickedList->get_number_children() - 1);
currentModalComponentCache.reserve(clickedList->get_number_children());

// In order to handle things that are not strings being allowed in an input list, grab the popup menu itself and shove custom components in there
auto combo = inputListModal->getComboBoxComponent("Input List Combo");
Expand All @@ -130,16 +136,60 @@ void DataMaskRenderAreaComponent::mouseUp(const MouseEvent &event)
{
auto child = clickedList->get_object_by_id(clickedList->get_child_id(static_cast<std::uint16_t>(i)));

if (0 != i)
if (nullptr != child)
{
currentModalComponentCache.push_back(JuceManagedWorkingSetCache::create_component(parentWorkingSet, child));
comboPopup->addCustomItem(i, *currentModalComponentCache.back().get(), currentModalComponentCache.back()->getWidth(), currentModalComponentCache.back()->getHeight(), true, nullptr, "Object " + std::to_string(clickedList->get_child_id(static_cast<std::uint16_t>(i))));
comboPopup->addCustomItem(i + 1, *currentModalComponentCache.back().get(), currentModalComponentCache.back()->getWidth(), currentModalComponentCache.back()->getHeight(), true, nullptr, "Object " + std::to_string(clickedList->get_child_id(static_cast<std::uint16_t>(i))));
}
}
inputListModal->addButton("OK", 0);
auto resultCallback = [this](int /*result*/) {
auto resultCallback = [this, clickedList](int result) {
auto combo = inputListModal->getComboBoxComponent("Input List Combo");
result = combo->getSelectedItemIndex();

// Remap the visible index to the actual index
std::uint16_t numberOfNonNullsSeen = 0;
for (std::uint16_t i = 0; i < clickedList->get_number_children(); i++)
{
if (isobus::NULL_OBJECT_ID != clickedList->get_child_id(i))
{
numberOfNonNullsSeen++;
}

if (numberOfNonNullsSeen == result + 1)
{
result = i;
break;
}
}

if (isobus::NULL_OBJECT_ID != clickedList->get_variable_reference())
{
auto child = clickedList->get_object_by_id(clickedList->get_variable_reference());

if (nullptr != child)
{
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
{
if (std::static_pointer_cast<isobus::NumberVariable>(child)->get_value() != static_cast<std::uint32_t>(result))
{
ownerServer.send_change_numeric_value_message(child->get_id(), result, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
}
std::static_pointer_cast<isobus::NumberVariable>(child)->set_value(result);
}
}
}
else
{
if (clickedList->get_value() != result)
{
ownerServer.send_change_numeric_value_message(clickedList->get_id(), result, ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
}
clickedList->set_value(static_cast<std::uint8_t>(result));
}
this->inputListModal->exitModalState();
inputListModal.reset();
repaint();
};
inputListModal->enterModalState(true, ModalCallbackFunction::create(std::move(resultCallback)), false);
}
Expand Down Expand Up @@ -231,6 +281,40 @@ void DataMaskRenderAreaComponent::mouseUp(const MouseEvent &event)
}
break;

case isobus::VirtualTerminalObjectType::InputBoolean:
{
auto clickedBool = std::static_pointer_cast<isobus::InputBoolean>(clickedObject);

if (clickedBool->get_enabled())
{
bool hasNumberVariable = false;

for (std::uint16_t i = 0; i < clickedBool->get_number_children(); i++)
{
auto child = clickedBool->get_object_by_id(clickedBool->get_child_id(i));

if (nullptr != child)
{
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
{
hasNumberVariable = true;
std::static_pointer_cast<isobus::NumberVariable>(child)->set_value(!(0 != std::static_pointer_cast<isobus::NumberVariable>(child)->get_value()));
ownerServer.send_change_numeric_value_message(child->get_id(), std::static_pointer_cast<isobus::NumberVariable>(child)->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
break;
}
}
}

if (!hasNumberVariable)
{
clickedBool->set_value(~clickedBool->get_value());
ownerServer.send_change_numeric_value_message(clickedBool->get_id(), clickedBool->get_value(), ownerServer.get_client_control_function_for_working_set(parentWorkingSet));
}
repaint();
}
}
break;

default:
break;
}
Expand Down
56 changes: 56 additions & 0 deletions src/InputBooleanComponent.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
/*******************************************************************************
** @file InputBooleanComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "InputBooleanComponent.hpp"

InputBooleanComponent::InputBooleanComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::InputBoolean sourceObject) :
isobus::InputBoolean(sourceObject),
parentWorkingSet(workingSet)
{
setOpaque(false);
setSize(get_width(), get_height());

setEnabled(get_enabled());
}

void InputBooleanComponent::paint(Graphics &g)
{
// Draw background
auto vtColour = colourTable.get_colour(get_background_color());
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
g.drawRect(0, 0, static_cast<int>(get_width()), static_cast<int>(get_height()), 0);

g.setColour(Colour::fromFloatRGBA(0.0f, 0.0f, 0.0f, 1.0f));
// Change colour to foreground colour if present
for (std::uint16_t i = 0; i < get_number_children(); i++)
{
auto child = get_object_by_id(get_child_id(i));

if ((nullptr != child) && (isobus::VirtualTerminalObjectType::FontAttributes == child->get_object_type()))
{
vtColour = colourTable.get_colour(std::static_pointer_cast<isobus::FontAttributes>(child)->get_background_color());
g.setColour(Colour::fromFloatRGBA(vtColour.r, vtColour.g, vtColour.b, 1.0f));
break;
}
}

bool isChecked = (0 != get_value());
// Change use number variable if one was provided
for (std::uint16_t i = 0; i < get_number_children(); i++)
{
auto child = get_object_by_id(get_child_id(i));

if ((nullptr != child) && (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type()))
{
isChecked = std::static_pointer_cast<isobus::NumberVariable>(child)->get_value();
break;
}
}

if (isChecked)
{
g.drawLine(0, get_height() / 2, get_width() / 2, get_height());
g.drawLine(get_width() / 2, get_height(), get_width(), 0);
}
}
52 changes: 23 additions & 29 deletions src/InputListComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
//================================================================================================
/// @file InputListComponent.cpp
///
/// @brief This is a class for drawing an input list.
/// @author Adrian Del Grosso
///
/// @copyright 2023 Adrian Del Grosso
//================================================================================================
/*******************************************************************************
** @file InputListComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "InputListComponent.hpp"
#include "JuceManagedWorkingSetCache.hpp"

Expand All @@ -26,35 +23,32 @@ void InputListComponent::onChanged(bool initial)
{
childComponent.reset();

if (get_number_children() > 1)
std::uint32_t selectedIndex = get_value();

if (isobus::NULL_OBJECT_ID != get_variable_reference())
{
std::uint32_t selectedIndex = get_value();
auto child = get_object_by_id(get_variable_reference());

for (std::uint16_t i = 0; i < get_number_children(); i++)
if (nullptr != child)
{
auto child = get_object_by_id(get_child_id(i));

if (nullptr != child)
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
{
if (isobus::VirtualTerminalObjectType::NumberVariable == child->get_object_type())
{
selectedIndex = std::static_pointer_cast<isobus::NumberVariable>(child)->get_value();
break;
}
selectedIndex = std::static_pointer_cast<isobus::NumberVariable>(child)->get_value();
}
}
}

if (selectedIndex < static_cast<std::uint32_t>(get_number_children() - 1))
{
// The number variable will always be the first one
auto listItem = get_object_by_id(get_child_id(static_cast<std::uint16_t>(selectedIndex + 1)));
childComponent = JuceManagedWorkingSetCache::create_component(parentWorkingSet, listItem);
if ((get_number_children() > 0) &&
(selectedIndex < static_cast<std::uint32_t>(get_number_children())))
{
// The number variable will always be the first one
auto listItem = get_object_by_id(get_child_id(static_cast<std::uint16_t>(selectedIndex)));
childComponent = JuceManagedWorkingSetCache::create_component(parentWorkingSet, listItem);

if (nullptr != childComponent)
{
addAndMakeVisible(*childComponent);
childComponent->setTopLeftPosition(0, 0);
}
if (nullptr != childComponent)
{
addAndMakeVisible(*childComponent);
childComponent->setTopLeftPosition(0, 0);
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/InputNumberComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file InputNumberComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "InputNumberComponent.hpp"

#include <iomanip>
Expand Down
17 changes: 16 additions & 1 deletion src/JuceManagedWorkingSetCache.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*******************************************************************************
** @file JuceManagedWorkingSetCache.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "JuceManagedWorkingSetCache.hpp"

#include "AlarmMaskComponent.hpp"
Expand Down Expand Up @@ -98,8 +103,13 @@ std::shared_ptr<Component> JuceManagedWorkingSetCache::create_component(std::sha
}
break;

case isobus::VirtualTerminalObjectType::KeyGroup:
case isobus::VirtualTerminalObjectType::InputBoolean:
{
retVal = std::make_shared<InputBooleanComponent>(workingSet, *std::static_pointer_cast<isobus::InputBoolean>(sourceObject));
}
break;

case isobus::VirtualTerminalObjectType::KeyGroup:
case isobus::VirtualTerminalObjectType::InputString:
{
}
Expand Down Expand Up @@ -217,5 +227,10 @@ std::shared_ptr<Component> JuceManagedWorkingSetCache::create_component(std::sha
break;
}
}

if (nullptr != retVal)
{
retVal->setInterceptsMouseClicks(false, false);
}
return retVal;
}
6 changes: 6 additions & 0 deletions src/KeyComponent.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
/*******************************************************************************
** @file KeyComponent.cpp
** @author Adrian Del Grosso
** @copyright The Open-Agriculture Developers
*******************************************************************************/
#include "KeyComponent.hpp"

#include "JuceManagedWorkingSetCache.hpp"

KeyComponent::KeyComponent(std::shared_ptr<isobus::VirtualTerminalServerManagedWorkingSet> workingSet, isobus::Key sourceObject) :
Expand Down
Loading

0 comments on commit 369fc9d

Please sign in to comment.