Files
RP2350_MIDI_Lighter/Firmware/Display_Objects.c
Chris 89c875e38f - First complete version of firmware. Currently being tested in the rehearsal room
- Added bunch of screens, fonts and images
 - Added script to read out frame buffer (function currently disabled in Firmware)
2025-10-26 20:57:58 +01:00

1549 lines
49 KiB
C

/*
* Display_Objects.c
*
* Created: Fri Apr 02 2021 13:58:23
* Author Chris
*/
#include "Display.h"
#include "Display_Font.h"
#include "Display_Image.h"
#include "Display_Objects.h"
#include "Display_Message_Box_Icons.h"
#include "Hierarchical_Menu.h"
#include <string.h>
#include <math.h>
// ============================================================================================
// Defines
#define DEG2RAD (float)(M_PI / 180)
// ============================================================================================
// Variables
volatile Display_Color _Background_Color;
struct
{
Display_Object *Array;
size_t Used;
size_t Size;
} _Objects;
struct
{
Style *Array;
size_t Used;
size_t Size;
} _Styles;
struct
{
Animation *Array;
size_t Used;
size_t Size;
} _Animations;
struct
{
Font *Array;
size_t Used;
size_t Size;
} _Fonts;
// ============================================================================================
// Function Declarations
Object_ID Display_Objects_Add(Object_Type type, Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, void *data, Style_ID style_id, Animation_ID animation_id);
Style* Display_Objects_Style_From_ID(Style_ID style_id);
Animation* Display_Objects_Animation_From_ID(Animation_ID animation_id);
Font* Display_Objects_Font_From_ID(Font_ID font_id);
void Display_Objects_Update_Coordinates_Offset_And_Dimension(Display_Object *object, Anchor_Point anchor_point, Coordinates_Type coordinates_type);
void Display_Objects_Convert_Coordinates(Coordinates_Type coordinates_type, Coordinates* coordinates);
Dimension Display_Objects_Get_Content_Size(Display_Object *object);
Dimension Display_Objects_Get_Content_Size_From_Shape(Display_Object *object);
/*******************************************************************
Functions
*******************************************************************/
void Display_Objects_Init(Display_Color background_color)
{
_Objects.Array = NULL;
_Objects.Used = _Objects.Size = 0;
_Styles.Array = NULL;
_Styles.Used = _Styles.Size = 0;
Display_Objects_Background_Color_Set(background_color);
}
void Display_Objects_Background_Color_Set(Display_Color color)
{
_Background_Color = color;
}
Display_Color Display_Objects_Background_Color_Get(void)
{
return _Background_Color;
}
void Display_Objects_Clear(void)
{
Object_Value_Bar_Arc *VA;
Object_Menu_Ring *MR;
Object_Menu_Hierarchical* MH;
Object_Canvas *C;
for (uint i = 0; i < _Objects.Size; i++)
{
Display_Object* O = Display_Objects_Get_By_ID(i);
switch (O->Type)
{
case FLOAT:
free((Object_Float*)(O->Data));
break;
case INTEGER:
free((Object_Integer*)(O->Data));
break;
case TEXT:
free((Object_Text*)(O->Data));
break;
case VALUE_BAR_RECT:
free((Object_Value_Bar_Rect*)(O->Data));
break;
case VALUE_BAR_ARC:
VA = (Object_Value_Bar_Arc*)(O->Data);
free((Object_Shape*)(VA->Arc));
free(VA);
break;
case GRAPH:
free((Object_Graph*)(O->Data));
break;
case BUTTON:
free((Object_Button*)(O->Data));
break;
case IMAGE:
free((Object_Image_Color*)(O->Data));
break;
case BOOLEAN:
free((Object_Bool*)(O->Data));
break;
case SHAPE:
free((Object_Shape*)(O->Data));
break;
case CANVAS:
C = (Object_Canvas*)(O->Data);
free(C->Data);
free(C);
case MESSAGE_BOX:
free((Object_Message_Box*)(O->Data));
break;
case MENU_SELECT:
free((Object_Menu_Select*)(O->Data));
break;
case MENU_ICON_ROW:
free((Object_Menu_Icon_Row*)(O->Data));
break;
case MENU_RING:
MR = (Object_Menu_Ring*)(O->Data);
free(MR->Items);
free(MR->Item_Scales);
free(MR->Item_Glow_Intensity);
if (MR->Appear_Animation != NULL) {
free(MR->Appear_Animation);
}
free(MR);
break;
case MENU_HIERARCHICAL:
MH = (Object_Menu_Hierarchical*)(O->Data);
if (MH->Transition_Animation != NULL) {
free(MH->Transition_Animation);
}
free(MH);
break;
case SELECT_YESNO:
free((Object_Select_YesNo*)(O->Data));
break;
case SELECT_LIST:
free((Object_Select_List*)(O->Data));
break;
case SELECT_VALUE:
free((Object_Select_Value*)(O->Data));
break;
case SELECT_RGB:
free((Object_Select_RGB*)(O->Data));
break;
default:
break;
}
O->Data = NULL;
if (O->Animation_Status != NULL)
{
free(O->Animation_Status);
O->Animation_Status = NULL;
}
}
free(_Objects.Array);
_Objects.Array = NULL;
_Objects.Used = _Objects.Size = 0;
free(_Styles.Array);
_Styles.Array = NULL;
_Styles.Used = _Styles.Size = 0;
free(_Animations.Array);
_Animations.Array = NULL;
_Animations.Used = _Animations.Size = 0;
free(_Fonts.Array);
_Fonts.Array = NULL;
_Fonts.Used = _Fonts.Size = 0;
Display_Unselect_Object();
}
Style_ID Display_Objects_Add_Style(Display_Color background_color, Display_Color border_color, uint border_thickness, uint border_radius, uint padding_top, uint padding_right, uint padding_bottom, uint padding_left, float width_height_ratio)
{
Style Style;
Style.Background_Color = background_color;
Style.Border_Color = border_color;
Style.Border_Thickness = border_thickness;
Style.Border_Radius = border_radius;
Style.Padding[PADDING_TOP] = padding_top;
Style.Padding[PADDING_LEFT] = padding_left;
Style.Padding[PADDING_BOTTOM] = padding_bottom;
Style.Padding[PADDING_RIGHT] = padding_right;
Style.Width_Height_Ratio = width_height_ratio;
if (_Styles.Used == _Styles.Size)
{
_Styles.Size++;
_Styles.Array = realloc(_Styles.Array, _Styles.Size * sizeof(Style));
}
_Styles.Array[_Styles.Used++] = Style;
return (Style_ID)(_Styles.Used - 1);
}
Animation_ID Display_Objects_Add_Animation(int offset_x, int offset_y, uint tick_delay, uint tick_duration, Animation_Order start_condition)
{
Animation Animation;
Animation.Offset.X = offset_x;
Animation.Offset.Y = offset_y;
Animation.Tick_Delay = tick_delay;
Animation.Tick_Duration = tick_duration;
Animation.Animation_Start = start_condition;
if (_Animations.Used == _Animations.Size)
{
_Animations.Size++;
_Animations.Array = realloc(_Animations.Array, _Animations.Size * sizeof(Animation));
}
_Animations.Array[_Animations.Used++] = Animation;
return (Animation_ID)(_Animations.Used - 1);
}
Font_ID Display_Objects_Add_Font(const unsigned char *font, uint8_t character_spacing)
{
Font Font;
Font.Font = font;
Font.Character_Spacing = character_spacing;
if (_Fonts.Used == _Fonts.Size)
{
_Fonts.Size++;
_Fonts.Array = realloc(_Fonts.Array, _Fonts.Size * sizeof(Font));
}
_Fonts.Array[_Fonts.Used++] = Font;
return (Font_ID)(_Fonts.Used - 1);
}
size_t Display_Objects_Count(void)
{
return _Objects.Size;
}
Display_Object *Display_Objects_Get_By_ID(Object_ID id)
{
if (id < _Objects.Size)
{
return &(_Objects.Array[id]);
}
return NULL;
}
size_t Display_Objects_Get_Count_Canvas(void)
{
size_t Canvas_Count = 0;
for(uint i=0;i<Display_Objects_Count();i++)
{
if(Display_Objects_Get_By_ID(i)->Type == CANVAS)
{
Canvas_Count++;
}
}
return Canvas_Count;
}
Object_ID Display_Objects_Get_ID_From_Canvas_Number(uint canvas_number)
{
for(uint i=0;i<Display_Objects_Count();i++)
{
if(Display_Objects_Get_By_ID(i)->Type == CANVAS)
{
if(canvas_number == 0)
{
return i;
}
else
{
canvas_number--;
}
}
}
return -1;
}
Object_ID Display_Objects_Add_Float(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, float *value, char *format, Font_ID font, Display_Color color, Style_ID style_id, Animation_ID animation_id)
{
Object_Float *Number = malloc(sizeof(Object_Float));
Number->Font = Display_Objects_Font_From_ID(font);
Number->Color = color;
Number->Value = value;
sprintf(Number->Format, "%s", format);
return Display_Objects_Add(FLOAT, anchor_point, coordinates_type, x, y, selectable, (void *)Number, style_id, animation_id);
}
Object_ID Display_Objects_Add_Integer(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, int *value, char *format, Font_ID font, Display_Color color, Style_ID style_id, Animation_ID animation_id)
{
Object_Integer *Number = malloc(sizeof(Object_Integer));
Number->Font = Display_Objects_Font_From_ID(font);
Number->Color = color;
Number->Value = value;
sprintf(Number->Format, "%s", format);
return Display_Objects_Add(INTEGER, anchor_point, coordinates_type, x, y, selectable, (void *)Number, style_id, animation_id);
}
Object_ID Display_Objects_Add_Text(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, char *text, Font_ID font, Display_Color color, Style_ID style_id, Animation_ID animation_id)
{
Object_Text *Text = malloc(sizeof(Object_Text));
Text->Font = Display_Objects_Font_From_ID(font);
Text->Color = color;
Text->Length = sprintf(Text->Text, "%s", text);
return Display_Objects_Add(TEXT, anchor_point, coordinates_type, x, y, selectable, (void *)Text, style_id, animation_id);
}
Object_ID Display_Objects_Add_Value_Bar_Rect(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, uint32_t *value, uint32_t max, uint32_t min, Orientation orientation, Display_Color color, uint32_t width, uint32_t height, Style_ID style_id, Animation_ID animation_id)
{
Object_Value_Bar_Rect *Bar = malloc(sizeof(Object_Value_Bar_Rect));
Bar->Value = value;
Bar->Max = max;
Bar->Min = min;
Bar->Orientation = orientation;
Bar->Color = color;
Bar->Dimension.Width = width;
Bar->Dimension.Height = height;
return Display_Objects_Add(VALUE_BAR_RECT, anchor_point, coordinates_type, x, y, selectable, (void *)Bar, style_id, animation_id);
}
Object_ID Display_Objects_Add_Value_Bar_Arc(Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, uint32_t* value, uint32_t max, uint32_t min, uint32_t delta_inc, uint32_t delta_dec, Display_Color color, uint16_t radius, uint16_t thickness, uint16_t steps, int16_t angle_start, int16_t angle_end, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Arc = malloc(sizeof(Object_Shape));
Arc->Type = ARC;
Arc->Color = color;
Arc->Dimension.Width = 0;
Arc->Dimension.Height = 0;
Arc->Radius_Start = radius;
Arc->Radius_End = radius;
Arc->Thickness = thickness;
Arc->Draw_Steps = steps;
Arc->Angle_Start = angle_start;
Arc->Angle_End = angle_end;
Object_Value_Bar_Arc *Value_Bar = malloc(sizeof(Object_Value_Bar_Arc));
Value_Bar->Value = value;
Value_Bar->Max = max;
Value_Bar->Min = min;
Value_Bar->Current = *value;
Value_Bar->Delta_Inc = delta_inc;
Value_Bar->Delta_Dec = delta_dec;
Value_Bar->Arc = Arc;
Value_Bar->Angle_End = angle_end;
return Display_Objects_Add(VALUE_BAR_ARC, LEFT_TOP, coordinates_type, x, y, selectable, (void *)Value_Bar, style_id, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Graph(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, uint16_t *data, uint16_t data_length, uint max, uint min, Display_Color color, uint height, Style_ID style_id, Animation_ID animation_id)
{
Object_Graph *Graph = malloc(sizeof(Object_Graph));
Graph->Data = data;
Graph->Data_Length = data_length;
Graph->Max = max;
Graph->Min = min;
Graph->Color = color;
Graph->Dimension.Width = data_length;
Graph->Dimension.Height = height;
return Display_Objects_Add(GRAPH, anchor_point, coordinates_type, x, y, selectable, (void *)Graph, style_id, animation_id);
}
Object_ID Display_Objects_Add_Button(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, char *text, Font_ID font, uint return_value, Display_Color color, uint width, uint height, Style_ID style_id, Animation_ID animation_id)
{
Object_Button *Button = malloc(sizeof(Object_Button));
Button->Font = Display_Objects_Font_From_ID(font);
Button->Return_Value = return_value;
Button->Color = color;
Button->Length = sprintf(Button->Text, "%s", text);
Button->Dimension.Height = height;
Button->Dimension.Width = width;
return Display_Objects_Add(BUTTON, anchor_point, coordinates_type, x, y, selectable, (void *)Button, style_id, animation_id);
}
Object_ID Display_Objects_Add_Image(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Image_Color* image, uint16_t Rotation_Angle, Style_ID style_id, Animation_ID animation_id)
{
Object_Image_Color *Image = malloc(sizeof(Object_Image_Color));
Image->Image = image;
Image->Rotation_Angle = Rotation_Angle;
Image->Alpha = UINT8_MAX;
Image->Scale = 1.0f;
return Display_Objects_Add(IMAGE, anchor_point, coordinates_type, x, y, selectable, (void *)Image, style_id, animation_id);
}
Object_ID Display_Objects_Add_Bool(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, bool* value, char* text_true, Display_Color color_true, char* text_false, Display_Color color_false, Font_ID font , Style_ID style_id, Animation_ID animation_id)
{
Object_Bool *Bool = malloc(sizeof(Object_Bool));
Bool->Value = value;
Bool->Length_True = sprintf(Bool->Text_True , "%s", text_true);
Bool->Length_False = sprintf(Bool->Text_False , "%s", text_false);
Bool->Color_True = color_true;
Bool->Color_False = color_false;
Bool->Font = Display_Objects_Font_From_ID(font);
return Display_Objects_Add(BOOLEAN, anchor_point, coordinates_type, x, y, selectable, (void *)Bool, style_id, animation_id);
}
Object_ID Display_Objects_Add_Rectangle_Filled(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint32_t width, uint32_t height, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = RECTANGLE_FILLED;
Shape->Color = color;
Shape->Dimension.Width = width;
Shape->Dimension.Height = height;
Shape->Radius_Start = 0;
Shape->Radius_End = 0;
Shape->Thickness = 0;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
return Display_Objects_Add(SHAPE, anchor_point, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Rectangle_Frame(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint32_t width, uint32_t height, uint16_t border_thickness, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = RECTANGLE_FRAME;
Shape->Color = color;
Shape->Dimension.Width = width;
Shape->Dimension.Height = height;
Shape->Radius_Start = 0;
Shape->Radius_End = 0;
Shape->Thickness = border_thickness;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
return Display_Objects_Add(SHAPE, anchor_point, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Rounded_Rectangle_Filled(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint32_t width, uint32_t height, uint16_t radius, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = ROUNDED_RECTANGLE_FILLED;
Shape->Color = color;
Shape->Dimension.Width = width;
Shape->Dimension.Height = height;
Shape->Radius_Start = radius;
Shape->Radius_End = radius;
Shape->Thickness = 0;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
return Display_Objects_Add(SHAPE, anchor_point, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Rounded_Rectangle_Frame(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint32_t width, uint32_t height, uint16_t radius, uint16_t border_thickness, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = ROUNDED_RECTANGLE_FRAME;
Shape->Color = color;
Shape->Dimension.Width = width;
Shape->Dimension.Height = height;
Shape->Radius_Start = radius;
Shape->Radius_End = radius;
Shape->Thickness = border_thickness;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
return Display_Objects_Add(SHAPE, anchor_point, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Circle_Filled(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint16_t radius, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = CIRCLE_FILLED;
Shape->Color = color;
Shape->Dimension.Width = 0;
Shape->Dimension.Height = 0;
Shape->Radius_Start = radius;
Shape->Radius_End = radius;
Shape->Thickness = 0;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
Coordinates Coordinates_In_Px = { .X = x, .Y = y };
Display_Objects_Convert_Coordinates(coordinates_type, &Coordinates_In_Px);
return Display_Objects_Add(SHAPE, anchor_point, BOTH_IN_PIXEL, Coordinates_In_Px.X + radius, Coordinates_In_Px.Y + radius, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Circle_Frame(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint16_t radius, uint16_t thickness, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = CIRCLE_FRAME;
Shape->Color = color;
Shape->Dimension.Width = 0;
Shape->Dimension.Height = 0;
Shape->Radius_Start = radius;
Shape->Radius_End = radius;
Shape->Thickness = thickness;
Shape->Draw_Steps = 0;
Shape->Angle_Start = 0;
Shape->Angle_End = 0;
Coordinates Coordinates_In_Px = { .X = x, .Y = y };
Display_Objects_Convert_Coordinates(coordinates_type, &Coordinates_In_Px);
return Display_Objects_Add(SHAPE, anchor_point, BOTH_IN_PIXEL, Coordinates_In_Px.X + radius, Coordinates_In_Px.Y + radius, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Arc_Frame(Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint16_t radius, uint16_t thickness, uint16_t steps, int16_t angle_start, int16_t angle_end, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = ARC;
Shape->Color = color;
Shape->Dimension.Width = 0;
Shape->Dimension.Height = 0;
Shape->Radius_Start = radius;
Shape->Radius_End = radius;
Shape->Thickness = thickness;
Shape->Draw_Steps = steps;
Shape->Angle_Start = angle_start;
Shape->Angle_End = angle_end;
return Display_Objects_Add(SHAPE, LEFT_TOP, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Dispaly_Objects_Add_Line_XY(Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, int16_t x2, int16_t y2, uint16_t thickness, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = LINE_XY;
Shape->Color = color;
Shape->Dimension.Width = 0;
Shape->Dimension.Height = 0;
Shape->Radius_Start = 0;
Shape->Radius_End = 0;
Shape->Thickness = thickness;
Shape->Draw_Steps = 0;
Shape->Angle_Start = x2;
Shape->Angle_End = y2;
return Display_Objects_Add(SHAPE, LEFT_TOP, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Dispaly_Objects_Add_Line_Rad(Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint16_t radius_start, uint16_t radius_end, uint16_t thickness, int16_t angle, Style_ID style_id, Animation_ID animation_id)
{
Object_Shape *Shape = malloc(sizeof(Object_Shape));
Shape->Type = LINE_RAD;
Shape->Color = color;
Shape->Dimension.Width = 0;
Shape->Dimension.Height = 0;
Shape->Radius_Start = radius_start;
Shape->Radius_End = radius_end;
Shape->Thickness = thickness;
Shape->Draw_Steps = 0;
Shape->Angle_Start = angle;
Shape->Angle_End = 0;
return Display_Objects_Add(SHAPE, LEFT_TOP, coordinates_type, x, y, selectable, (void *)Shape, style_id, animation_id);
}
Object_ID Display_Objects_Add_Canvas(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, Display_Color color, uint width, uint height, Style_ID style_id, Animation_ID animation_id)
{
Object_Canvas *Canvas = malloc(sizeof(Object_Canvas));
Canvas->Dimension.Width = width;
Canvas->Dimension.Height = height;
Canvas->Data = (uint16_t*) malloc(width * height * sizeof(uint16_t));
for(uint y=0;y<height;y++)
{
for(uint x=0;x<width;x++)
{
Canvas->Data[y * width + x] = color;
}
}
return Display_Objects_Add(CANVAS, anchor_point, coordinates_type, x, y, selectable, (void *)Canvas, style_id, animation_id);
}
Object_ID Display_Objects_Add_Message_Box(Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, char* text, Object_Message_Box_Icon icon, const Message_Box_Style* style)
{
Object_Message_Box *Message_Box = malloc(sizeof(Object_Message_Box));
Message_Box->Length = sprintf(Message_Box->Text, "%s", text);
Message_Box->Icon = icon;
Message_Box->Style = style;
Message_Box->Show_Ticks_Left = 0;
return Display_Objects_Add(MESSAGE_BOX, anchor_point, coordinates_type, x, y, NOT_SELECTABLE, (void *)Message_Box, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Menu_Select(char* menu_titles, uint32_t menu_entry_count, uint32_t title_char_length, uint32_t* selected_entry, Configuration_Menu_Select* config)
{
Object_Menu_Select* Menu_Select = malloc(sizeof(Object_Menu_Select));
Menu_Select->Menu_Titles = menu_titles;
Menu_Select->Menu_Entry_Count = menu_entry_count;
Menu_Select->Title_Char_Length = title_char_length;
Menu_Select->Selected_Entry = selected_entry;
Menu_Select->Config = config;
return Display_Objects_Add(MENU_SELECT, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Menu_Select, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Menu_Icon_Row(Icon_Row_Item* items, uint32_t item_count, uint32_t* selected_item, const Configuration_Menu_Icon_Row* config)
{
Object_Menu_Icon_Row* Icon_Row = malloc(sizeof(Object_Menu_Icon_Row));
Icon_Row->Items = items;
Icon_Row->Item_Count = item_count;
Icon_Row->Selected_Item = selected_item;
Icon_Row->Config = config;
return Display_Objects_Add(MENU_ICON_ROW, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Icon_Row, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Menu_Ring(Menu_Ring_Item_Config* items, uint32_t item_count, uint32_t* selected_item, Configuration_Menu_Ring* config)
{
if (item_count == 0 || item_count > 16) { // Reasonable limits
return -1; // Invalid item count
}
Object_Menu_Ring* Menu_Ring = malloc(sizeof(Object_Menu_Ring));
// Allocate dynamic arrays
Menu_Ring->Items = malloc(sizeof(Menu_Ring_Item_Config) * item_count);
Menu_Ring->Item_Scales = malloc(sizeof(float) * item_count);
Menu_Ring->Item_Glow_Intensity = malloc(sizeof(uint8_t) * item_count);
// Copy item configurations and initialize states
for (uint32_t i = 0; i < item_count; i++) {
Menu_Ring->Items[i] = items[i];
Menu_Ring->Item_Scales[i] = (i == *selected_item) ? config->Selection_Scale : 1.0f;
Menu_Ring->Item_Glow_Intensity[i] = (i == *selected_item) ? 255 : 0;
}
Menu_Ring->Item_Count = item_count;
Menu_Ring->Selected_Item = selected_item;
Menu_Ring->Config = config;
// Initialize animation state
Menu_Ring->Animation_Counter = 0;
Menu_Ring->Idle_Rotation_Angle = 0.0f;
Menu_Ring->Selection_Animation_Progress = 0;
Menu_Ring->Animation_Target = *selected_item;
// Initialize appear animation
Menu_Ring->Appear_Animation = malloc(sizeof(Menu_Ring_Appear_Animation));
Menu_Ring->Appear_Animation->State = MENU_RING_APPEAR_STATE_IDLE;
Menu_Ring->Appear_Animation->Ring_Draw_Angle = 0.0f;
Menu_Ring->Appear_Animation->Center_Scale = 0.0f;
Menu_Ring->Appear_Animation->Ring_Draw_Counter = 0;
Menu_Ring->Appear_Animation->Center_Grow_Counter = 0;
Menu_Ring->Appear_Animation->Current_Item_Appearing = 0;
Menu_Ring->Appear_Animation->Current_Item_Scale = 0.0f;
Menu_Ring->Appear_Animation->Item_Pop_Counter = 0;
Menu_Ring->Appear_Animation->Item_Delay_Counter = 0;
// Calculate animation timing
Menu_Ring->Appear_Animation->Total_Ring_Draw_Frames = 360 / MENU_RING_APPEAR_CIRCLE_DRAW_SPEED;
Menu_Ring->Appear_Animation->Total_Center_Grow_Frames = MENU_RING_APPEAR_CIRCLE_GROW_SPEED;
Menu_Ring->Appear_Animation->Total_Item_Pop_Frames = MENU_RING_APPEAR_ITEM_POP_SPEED;
Menu_Ring->Appear_Animation->Total_Item_Delay_Frames = MENU_RING_APPEAR_ITEM_DELAY;
Menu_Ring->Appear_Animation_Active = false;
return Display_Objects_Add(MENU_RING, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, SELECTABLE, (void *)Menu_Ring, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Menu_Hierarchical(const Menu_List** current_list, int32_t* selected_item, int32_t* scroll_offset, const Configuration_Menu_Hierarchical* config)
{
Object_Menu_Hierarchical* Menu_Hierarchical = malloc(sizeof(Object_Menu_Hierarchical));
Menu_Hierarchical->Current_List = current_list;
Menu_Hierarchical->Selected_Item = selected_item;
Menu_Hierarchical->Scroll_Offset = scroll_offset;
Menu_Hierarchical->Config = config;
Menu_Hierarchical->Animation_Counter = 0;
Menu_Hierarchical->Transition_Progress = 0.0f;
Menu_Hierarchical->Last_Selected_Item = *selected_item;
Menu_Hierarchical->Last_Current_List = *current_list;
Menu_Hierarchical->Last_Selected_Item_Value = *selected_item;
Menu_Hierarchical->Last_Scroll_Offset_Value = *scroll_offset;
Menu_Hierarchical->Transition_Animation = malloc(sizeof(Menu_Hierarchical_Transition_Animation));
Menu_Hierarchical->Transition_Animation->State = MENU_HIERARCHICAL_TRANSITION_STATE_IDLE;
Menu_Hierarchical->Transition_Animation->Direction = MENU_TRANSITION_ENTER_SUBMENU;
Menu_Hierarchical->Transition_Animation->Transition_Counter = 0;
Menu_Hierarchical->Transition_Animation->Total_Transition_Frames = MENU_HIERARCHICAL_TRANSITION_FRAMES;
Menu_Hierarchical->Transition_Animation->Previous_List = NULL;
Menu_Hierarchical->Transition_Animation->Target_List = NULL;
Menu_Hierarchical->Transition_Animation->Current_Menu_X_Offset = 0;
Menu_Hierarchical->Transition_Animation->Target_Menu_X_Offset = 0;
Menu_Hierarchical->Transition_Animation_Active = false;
return Display_Objects_Add(MENU_HIERARCHICAL, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Menu_Hierarchical, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Select_YesNo(char* title, uint32_t title_length, bool* value, const Configuration_Select_YesNo* config)
{
Object_Select_YesNo* Select_YesNo = malloc(sizeof(Object_Select_YesNo));
Select_YesNo->Title = title;
Select_YesNo->Title_Length = title_length;
Select_YesNo->Value = value;
Select_YesNo->Config = config;
return Display_Objects_Add(SELECT_YESNO, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Select_YesNo, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Select_List(char* list_titles, uint32_t list_entry_count, uint32_t list_char_length, uint32_t* selected_entry, const Configuration_Select_List* config)
{
Object_Select_List* Select_List = malloc(sizeof(Object_Select_List));
Select_List->List_Titles = list_titles;
Select_List->List_Entry_Count = list_entry_count;
Select_List->List_Char_Length = list_char_length;
Select_List->Selected_Entry = selected_entry;
Select_List->Initial_Entry = *selected_entry;
Select_List->Config = config;
return Display_Objects_Add(SELECT_LIST, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Select_List, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Select_Value(char* title, uint32_t title_length, int32_t* value, int32_t max, int32_t min, char* format, const Configuration_Select_Value* config)
{
Object_Select_Value* Select_Value = malloc(sizeof(Object_Select_Value));
Select_Value->Title = title;
Select_Value->Title_Length = title_length;
Select_Value->Value = value;
Select_Value->Max = max;
Select_Value->Min = min;
sprintf(Select_Value->Format, "%s", format);
Select_Value->Config = config;
return Display_Objects_Add(SELECT_VALUE, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Select_Value, NO_STYLE, NO_ANIMATION);
}
Object_ID Display_Objects_Add_Select_RGB(LED_Data_t* color_value, uint8_t* current_component, const Configuration_Select_RGB* config)
{
if (color_value == NULL || config == NULL) {
return -1; // Invalid parameters
}
// Allocate memory for the RGB selector object
Object_Select_RGB* Select_RGB = malloc(sizeof(Object_Select_RGB));
if (Select_RGB == NULL) {
return -1; // Memory allocation failed
}
// Initialize RGB value pointer
Select_RGB->Color_Value = color_value;
// Set current state
Select_RGB->Current_Component = current_component;
// Initialize component labels
sprintf((char*)Select_RGB->Component_Labels[0], "RED");
sprintf((char*)Select_RGB->Component_Labels[1], "GREEN");
sprintf((char*)Select_RGB->Component_Labels[2], "BLUE");
// Initialize animation state
Select_RGB->Target_Value = Select_RGB->Color_Value->Array[*current_component]; // Array is R,G,B,A so: R=Array[0], G=Array[1], B=Array[2]
Select_RGB->Display_Value = Select_RGB->Target_Value;
Select_RGB->Animation_Counter = 0;
// UI Geometry
Select_RGB->Progress_Start_Angle = 270.0f; // 12 o'clock position
// Store configuration reference
Select_RGB->Config = config;
// Add to display objects system
// RGB selector is typically a full-screen interface, so use center positioning
return Display_Objects_Add(
SELECT_RGB, // Object type
LEFT_TOP, // Anchor point
BOTH_IN_PIXEL, // Coordinate type
0, //Select_RGB->Center_Position.X, // X position
0, //Select_RGB->Center_Position.Y, // Y position
SELECTABLE, // Not selectable for encoder input
(void*)Select_RGB, // Object data
NO_STYLE, // No style needed (custom rendering)
NO_ANIMATION // No standard animation (custom smooth transitions)
);
}
Object_ID Display_Objects_Add_Entry_Indicator(uint32_t entry_count, int32_t* entry_value, const Configuration_Entry_Indicator* config)
{
Object_Entry_Indicator* Entry_Indicator = malloc(sizeof(Object_Entry_Indicator));
Entry_Indicator->Entry_Count = entry_count;
Entry_Indicator->Entry_Value = entry_value;
Entry_Indicator->Config = config;
return Display_Objects_Add(ENTRY_INDICATOR, LEFT_TOP, BOTH_IN_PIXEL, 0, 0, NOT_SELECTABLE, (void *)Entry_Indicator, NO_STYLE, NO_ANIMATION);
}
void Display_Objects_Update_Coordinates(Object_ID id, Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
Object->Coordinates.X = x;
Object->Coordinates.Y = y;
Display_Objects_Update_Coordinates_Offset_And_Dimension(Object, anchor_point, coordinates_type);
}
void Display_Objects_Update_Enabled(Object_ID id, bool is_enabled)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
Object->Enabled = is_enabled;
}
void Display_Objects_Update_Color(Object_ID id, Display_Color color)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
switch(Object->Type)
{
case FLOAT:
((Object_Float*)(Object->Data))->Color = color;
break;
case INTEGER:
((Object_Integer*)(Object->Data))->Color = color;
break;
case TEXT:
((Object_Text*)(Object->Data))->Color = color;
break;
case VALUE_BAR_RECT:
((Object_Value_Bar_Rect*)(Object->Data))->Color = color;
break;
case BUTTON:
((Object_Button*)(Object->Data))->Color = color;
break;
case SHAPE:
((Object_Shape*)(Object->Data))->Color = color;
break;
case VALUE_BAR_ARC:
if(((Object_Value_Bar_Arc*)(Object->Data))->Arc != NULL) {
((Object_Value_Bar_Arc*)(Object->Data))->Arc->Color = color;
}
break;
default:
break;
}
}
void Display_Objects_Update_Text(Object_ID id, char* text)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
Object_Text* Text;
Object_Button* Button;
switch(Object->Type)
{
case TEXT:
Text = (Object_Text*)(Object->Data);
Text->Length = sprintf(Text->Text, "%s", text);
break;
case BUTTON:
Button = (Object_Button*)(Object->Data);
Button->Length = sprintf(Button->Text, "%s", text);
break;
default:
break;
}
}
void Display_Objects_Update_Image(Object_ID id, Image_Color* new_image)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL || new_image == NULL) {
return;
}
if(Object->Type != IMAGE) {
return;
}
Object_Image_Color* IM = (Object_Image_Color*)(Object->Data);
IM->Image = new_image;
}
void Display_Objects_Update_Alpha(Object_ID id, uint8_t new_alpha)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL || Object->Type != IMAGE) {
return;
}
Object_Image_Color* IM = (Object_Image_Color*)(Object->Data);
IM->Alpha = new_alpha;
}
void Display_Objects_Update_Scale(Object_ID id, float new_scale)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL || Object->Type != IMAGE || new_scale < 0.0f) {
return;
}
Object_Image_Color* IM = (Object_Image_Color*)(Object->Data);
IM->Scale = new_scale;
}
void Display_Objects_Update_Max_Min(Object_ID id, uint max, uint min)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
switch(Object->Type)
{
case VALUE_BAR_RECT:
((Object_Value_Bar_Rect*)Object->Data)->Max = max;
((Object_Value_Bar_Rect*)Object->Data)->Min = min;
break;
case VALUE_BAR_ARC:
((Object_Value_Bar_Arc*)Object->Data)->Max = max;
((Object_Value_Bar_Arc*)Object->Data)->Min = min;
break;
case GRAPH:
((Object_Graph*)Object->Data)->Max = max;
((Object_Graph*)Object->Data)->Min = min;
break;
default:
break;
}
}
int Display_Objects_Update_Pixel(Object_ID id, int16_t x, int16_t y, Display_Color color)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return OBJECT_NOT_FOUND;
}
Object_Canvas* C;
switch(Object->Type)
{
case CANVAS:
C = (Object_Canvas*)(Object->Data);
if(x<0 || x>=C->Dimension.Width) { return X_OUT_OF_RANGE; }
if(y<0 || y>=C->Dimension.Height) { return Y_OUT_OF_RANGE; }
C->Data[y * C->Dimension.Width + x] = color;
return CANVAS_UPDATE_OK;
default:
break;
}
return OBJECT_WRONG_TYPE;
}
void Display_Objects_Show_Message_Box(Object_ID id, uint32_t ticks)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
if (Object->Type != MESSAGE_BOX) {
return;
}
Object_Message_Box* M = (Object_Message_Box*)(Object->Data);
M->Show_Ticks_Max = ticks;
M->Show_Ticks_Left = ticks;
}
void Display_Objects_Update_Angles_Rel(Object_ID id, int16_t angle_delta)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
if (Object->Type == SHAPE)
{
Object_Shape* S = (Object_Shape*)(Object->Data);
if(S->Type != ARC && S->Type != LINE_RAD) {
return;
}
S->Angle_Start += angle_delta;
S->Angle_Start %= 360;
if(S->Angle_Start < 0) {
S->Angle_Start += 360;
}
S->Angle_End += angle_delta;
S->Angle_End %= 360;
if(S->Angle_End < 0) {
S->Angle_End += 360;
}
}
else if(Object->Type == IMAGE) {
Object_Image_Color* IM = (Object_Image_Color*)(Object->Data);
IM->Rotation_Angle += angle_delta;
IM->Rotation_Angle %= 360;
if(IM->Rotation_Angle < 0) {
IM->Rotation_Angle += 360;
}
}
}
void Display_Objects_Update_Angle_Start(Object_ID id, int16_t angle)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
if (Object->Type != SHAPE) {
return;
}
Object_Shape* S = (Object_Shape*)(Object->Data);
if(S->Type != ARC) {
return;
}
S->Angle_Start = angle;
S->Angle_Start %= 360;
if(S->Angle_Start < 0) {
S->Angle_Start += 360;
}
}
void Display_Objects_Update_Angle_End(Object_ID id, int16_t angle)
{
Display_Object* Object = Display_Objects_Get_By_ID(id);
if(Object == NULL) {
return;
}
if (Object->Type != SHAPE) {
return;
}
Object_Shape* S = (Object_Shape*)(Object->Data);
if(S->Type != ARC) {
return;
}
S->Angle_End = angle;
S->Angle_End %= 360;
if(S->Angle_End < 0) {
S->Angle_End += 360;
}
}
void Display_Objects_Menu_Ring_Start_Appear_Animation(Object_ID menu_ring_id)
{
Display_Object* Object = Display_Objects_Get_By_ID(menu_ring_id);
if (Object == NULL || Object->Type != MENU_RING) {
return;
}
Object_Menu_Ring* Menu_Ring = (Object_Menu_Ring*)Object->Data;
if(Menu_Ring->Config == NULL) {
return;
}
Menu_Ring->Config->Enable_Appear_Animation = true;
if (Menu_Ring->Appear_Animation != NULL) {
// Reset animation state
Menu_Ring->Appear_Animation->State = MENU_RING_APPEAR_STATE_DRAWING_RING;
Menu_Ring->Appear_Animation->Ring_Draw_Angle = 0.0f;
Menu_Ring->Appear_Animation->Center_Scale = 0.0f;
Menu_Ring->Appear_Animation->Ring_Draw_Counter = 0;
Menu_Ring->Appear_Animation->Center_Grow_Counter = 0;
Menu_Ring->Appear_Animation->Current_Item_Appearing = 0;
Menu_Ring->Appear_Animation->Current_Item_Scale = 0.0f;
Menu_Ring->Appear_Animation->Item_Pop_Counter = 0;
Menu_Ring->Appear_Animation->Item_Delay_Counter = 0;
Menu_Ring->Appear_Animation_Active = true;
// Hide all items initially during animation
for (uint32_t i = 0; i < Menu_Ring->Item_Count; i++) {
Menu_Ring->Item_Scales[i] = 0.0f;
Menu_Ring->Item_Glow_Intensity[i] = 0;
}
}
}
bool Display_Objects_Menu_Ring_Is_Appear_Animation_Active(Object_ID menu_ring_id)
{
Display_Object* Object = Display_Objects_Get_By_ID(menu_ring_id);
if (Object == NULL || Object->Type != MENU_RING) {
return false;
}
Object_Menu_Ring* Menu_Ring = (Object_Menu_Ring*)Object->Data;
return Menu_Ring->Appear_Animation_Active;
}
/*******************************************************************
Internal Functions
*******************************************************************/
Object_ID Display_Objects_Add(Object_Type type, Anchor_Point anchor_point, Coordinates_Type coordinates_type, int16_t x, int16_t y, bool selectable, void *data, Style_ID style_id, Animation_ID animation_id)
{
Display_Object Object;
Object.Type = type;
Object.Coordinates.X = x;
Object.Coordinates.Y = y;
Object.Content_Offset.X = 0;
Object.Content_Offset.Y = 0;
Object.Dimension.Height = 0;
Object.Dimension.Width = 0;
Object.Enabled = true;
Object.Selectable = selectable;
Object.Focused = false;
Object.Data = data;
Object.Style = Display_Objects_Style_From_ID(style_id);
Object.Animation = Display_Objects_Animation_From_ID(animation_id);
Object.Animation_Status = NULL;
Display_Objects_Update_Coordinates_Offset_And_Dimension(&Object, anchor_point, coordinates_type);
if (Object.Animation != NULL)
{
Object.Animation_Status = malloc(sizeof(Animation_Status));
Object.Animation_Status->State = NO_STARTED;
}
// _Objects->used is the number of used entries, because _Objects->array[_Objects->used++] updates _Objects->used only *after* the array has been accessed.
// Therefore a->used can go up to a->size
if (_Objects.Used == _Objects.Size)
{
_Objects.Size++;
_Objects.Array = realloc(_Objects.Array, _Objects.Size * sizeof(Display_Object));
}
_Objects.Array[_Objects.Used++] = Object;
return Display_Objects_Count() - 1;
}
Style *Display_Objects_Style_From_ID(Style_ID style_id)
{
if (style_id >= 0 && style_id < _Styles.Used)
{
return &_Styles.Array[style_id];
}
return NULL;
}
Animation *Display_Objects_Animation_From_ID(Animation_ID animation_id)
{
if (animation_id >= 0 && animation_id < _Animations.Used)
{
return &_Animations.Array[animation_id];
}
return NULL;
}
Font* Display_Objects_Font_From_ID(Font_ID font_id)
{
if (font_id >= 0 && font_id < _Fonts.Used)
{
return &_Fonts.Array[font_id];
}
return NULL;
}
void Display_Objects_Update_Coordinates_Offset_And_Dimension(Display_Object *object, Anchor_Point anchor_point, Coordinates_Type coordinates_type)
{
if (object == NULL) {
return;
}
///////////////////////////////////////
// Coordinated from Percent to Pixel //
///////////////////////////////////////
Coordinates Coordinates_In_Px = { .X = object->Coordinates.X, .Y = object->Coordinates.Y };
Display_Objects_Convert_Coordinates(coordinates_type, &Coordinates_In_Px);
if(object->Type == SHAPE && ((Object_Shape*)object->Data)->Type == LINE_XY) {
Object_Shape* Shape = (Object_Shape*)object->Data;
Coordinates Coordinates_Line_X2Y2 = { .X = Shape->Angle_Start, .Y = Shape->Angle_End };
Display_Objects_Convert_Coordinates(coordinates_type, &Coordinates_Line_X2Y2);
Shape->Angle_Start = Coordinates_Line_X2Y2.X;
Shape->Angle_End = Coordinates_Line_X2Y2.Y;
}
////////////////////////////////////////
// Get Coordinated of Top-Left corner //
////////////////////////////////////////
Dimension Content_Size = Display_Objects_Get_Content_Size(object);
Coordinates Coordinates_Content_Top_Left = Coordinates_In_Px;
// Horizontal
switch (anchor_point & 0x0F)
{
case CENTER:
Coordinates_Content_Top_Left.X = Coordinates_In_Px.X - (Content_Size.Width >> 1);
break;
case LEFT:
// Already assigned via default value
// Coordinates_Content_Top_Left.X = Coordinates_In_Px.X;
break;
case RIGHT:
Coordinates_Content_Top_Left.X = Coordinates_In_Px.X - Content_Size.Width;
break;
}
// Vertical
switch (anchor_point & 0xF0)
{
case MIDDLE:
Coordinates_Content_Top_Left.Y = Coordinates_In_Px.Y - (Content_Size.Height >> 1);
break;
case TOP:
// Already assigned via default value
// Coordinates_Content_Top_Left.Y = Coordinates_In_Px.Y;
break;
case BOTTOM:
Coordinates_Content_Top_Left.Y = Coordinates_In_Px.Y - Content_Size.Height;
break;
}
Coordinates Offset_Content_Style = { .X = 0, .Y = 0 };
Dimension Object_Dimension = Content_Size;
if(object->Style != NULL)
{
Style* Style = object->Style;
//////////////////////////////////////////////////////////
// !!! HEIGHT and WIDTH of Style not yet considered !!! //
//////////////////////////////////////////////////////////
Offset_Content_Style.X = Style->Border_Thickness + Style->Padding[PADDING_LEFT];
Offset_Content_Style.Y = Style->Border_Thickness + Style->Padding[PADDING_TOP];
Object_Dimension.Height += (Style->Border_Thickness << 1) + Style->Padding[PADDING_TOP] + Style->Padding[PADDING_BOTTOM];
Object_Dimension.Width += (Style->Border_Thickness << 1) + Style->Padding[PADDING_LEFT] + Style->Padding[PADDING_RIGHT];
if(Style->Width_Height_Ratio != STYLE_WIDTH_HEIGHT_RATIO_AUTO)
{
uint16_t Ratio_Height = Object_Dimension.Width * Style->Width_Height_Ratio;
int16_t Height_Difference = Ratio_Height - Object_Dimension.Height;
Object_Dimension.Height = Ratio_Height;
Offset_Content_Style.Y += (Height_Difference >> 1);
}
}
object->Content_Offset = Offset_Content_Style;
object->Coordinates.X = Coordinates_Content_Top_Left.X - Offset_Content_Style.X;
object->Coordinates.Y = Coordinates_Content_Top_Left.Y - Offset_Content_Style.Y;
object->Dimension = Object_Dimension;
}
void Display_Objects_Convert_Coordinates(Coordinates_Type coordinates_type, Coordinates* coordinates)
{
switch (coordinates_type)
{
case BOTH_IN_PIXEL:
break;
case X_IN_PIXEL_Y_IN_PERCENT:
coordinates->Y = (DISPLAY_HEIGHT * coordinates->Y) / 100;
break;
case X_IN_PERCENT_Y_IN_PIXEL:
coordinates->X = (DISPLAY_WIDTH * coordinates->X) / 100;
break;
case BOTH_IN_PERCENT:
coordinates->X = (DISPLAY_WIDTH * coordinates->X) / 100;
coordinates->Y = (DISPLAY_HEIGHT * coordinates->Y) / 100;
break;
default:
break;
}
}
Dimension Display_Objects_Get_Content_Size(Display_Object *object)
{
Dimension Dimension = { .Width = 0, .Height = 0 };
if (object == NULL)
{
return Dimension;
}
void *Data = object->Data;
char String[64];
uint String_Char_Count;
switch (object->Type)
{
case FLOAT:
Display_Font_Set_Font(((Object_Float *)Data)->Font->Font);
String_Char_Count = sprintf(String, ((Object_Float *)Data)->Format, *(((Object_Float *)Data)->Value));
Dimension.Height = Display_Font_Get_Font_Height();
Dimension.Width = Display_Font_Width_String(String, String_Char_Count, ((Object_Float *)Data)->Font->Character_Spacing);
break;
case INTEGER:
Display_Font_Set_Font(((Object_Integer *)Data)->Font->Font);
String_Char_Count = sprintf(String, ((Object_Integer *)Data)->Format, *(((Object_Integer *)Data)->Value));
Dimension.Height = Display_Font_Get_Font_Height();
Dimension.Width = Display_Font_Width_String(String, String_Char_Count, ((Object_Integer *)Data)->Font->Character_Spacing);
break;
case TEXT:
Display_Font_Set_Font(((Object_Text *)Data)->Font->Font);
Dimension.Height = Display_Font_Get_Font_Height();
Dimension.Width = Display_Font_Width_String((((Object_Text *)Data)->Text), ((Object_Text *)Data)->Length, ((Object_Text *)Data)->Font->Character_Spacing);
break;
case VALUE_BAR_RECT:
Dimension.Height = ((Object_Value_Bar_Rect *)Data)->Dimension.Height;
Dimension.Width = ((Object_Value_Bar_Rect *)Data)->Dimension.Width;
break;
case GRAPH:
Dimension.Height = ((Object_Graph *)Data)->Dimension.Height;
Dimension.Width = ((Object_Graph *)Data)->Dimension.Width;
break;
case BUTTON:
Dimension.Height = ((Object_Button *)Data)->Dimension.Height;
Dimension.Width = ((Object_Button *)Data)->Dimension.Width;
break;
case IMAGE:
Dimension.Height = Display_Image_Get_Height(((Object_Image_Color*)Data)->Image);
Dimension.Width = Display_Image_Get_Width(((Object_Image_Color*)Data)->Image);
break;
case BOOLEAN:
Display_Font_Set_Font(((Object_Bool *)Data)->Font->Font);
Dimension.Height = Display_Font_Get_Font_Height();
if(((Object_Bool *)Data)->Length_True >= ((Object_Bool *)Data)->Length_False)
{
Dimension.Width = Display_Font_Width_String((((Object_Bool *)Data)->Text_True), ((Object_Bool *)Data)->Length_True, ((Object_Bool *)Data)->Font->Character_Spacing);
}
else
{
Dimension.Width = Display_Font_Width_String((((Object_Bool *)Data)->Text_False), ((Object_Bool *)Data)->Length_False, ((Object_Bool *)Data)->Font->Character_Spacing);
}
break;
case SHAPE:
Dimension = Display_Objects_Get_Content_Size_From_Shape(object);
break;
case CANVAS:
Dimension.Height = ((Object_Canvas *)Data)->Dimension.Height;
Dimension.Width = ((Object_Canvas *)Data)->Dimension.Width;
break;
case MESSAGE_BOX:
Object_Message_Box* MB = (Object_Message_Box *)Data;
const Message_Box_Style* Style = MB->Style;
if(Style == NULL) {
return Dimension;
}
Display_Font_Set_Font(Style->Font);
Dimension.Height = Display_Font_Get_Font_Height() + 2 * Style->Border_Thickness + Style->Padding[PADDING_TOP] + Style->Padding[PADDING_BOTTOM];
Dimension.Width = Display_Font_Width_String(MB->Text, MB->Length, DISPLAY_DEFAULT_CHAR_SPACING) + 2 * Style->Border_Thickness + Style->Padding[PADDING_LEFT] + Style->Padding[PADDING_RIGHT];
if(MB->Icon != MESSAGE_BOX_ICON_NONE) {
Dimension.Width += (MESSAGE_BOX_TEXT_ICON_DISTANCE + Display_Message_Box_Icons_Get_Icon_Width(MB->Icon));
}
break;
case MENU_SELECT:
case MENU_ICON_ROW:
case MENU_RING:
case MENU_HIERARCHICAL:
case SELECT_YESNO:
case SELECT_LIST:
case SELECT_VALUE:
case SELECT_RGB:
break;
default:
break;
}
return Dimension;
}
Dimension Display_Objects_Get_Content_Size_From_Shape(Display_Object *object)
{
Dimension Dimension = { .Width = 0, .Height = 0 };
if(object->Type != SHAPE) {
return Dimension;
}
Object_Shape* Shape = (Object_Shape *)object->Data;
int16_t X1, X2, Y1, Y2;
switch(Shape->Type)
{
case RECTANGLE_FILLED:
case RECTANGLE_FRAME:
case ROUNDED_RECTANGLE_FILLED:
case ROUNDED_RECTANGLE_FRAME:
Dimension.Width = Shape->Dimension.Width;
Dimension.Height = Shape->Dimension.Height;
break;
case CIRCLE_FILLED:
case CIRCLE_FRAME:
Dimension.Width = Shape->Radius_Start * 2;
Dimension.Height = Shape->Radius_Start * 2;
break;
case ARC:
// This is still a ToDo
break;
case LINE_XY:
Dimension.Width = abs(object->Coordinates.X - Shape->Angle_Start); // Angle_Start contains x2
Dimension.Height = abs(object->Coordinates.Y - Shape->Angle_End); // Angle_End contains y2
break;
case LINE_RAD:
X1 = object->Coordinates.X + cos(Shape->Angle_Start * DEG2RAD) * Shape->Radius_Start;
Y1 = object->Coordinates.Y + sin(Shape->Angle_Start * DEG2RAD) * Shape->Radius_Start;
X2 = object->Coordinates.X + cos(Shape->Angle_Start * DEG2RAD) * Shape->Radius_End;
Y2 = object->Coordinates.Y + sin(Shape->Angle_Start * DEG2RAD) * Shape->Radius_End;
Dimension.Width = abs(X1 - X2);
Dimension.Height = abs(Y1 - Y2);
break;
default:
break;
}
return Dimension;
}