/*
 * 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 <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_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 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;
	
	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, Font_ID font, Object_Message_Box_Icon icon, Display_Color color, Style_ID style_id)
{
	Object_Message_Box *Message_Box = malloc(sizeof(Object_Message_Box));
	Message_Box->Length 			= sprintf(Message_Box->Text, "%s", text);
	Message_Box->Font 				= Display_Objects_Font_From_ID(font);
	Message_Box->Color 				= color;
	Message_Box->Icon				= icon;
	Message_Box->Show_Ticks_Left 	= 0;
	
	return Display_Objects_Add(MESSAGE_BOX, anchor_point, coordinates_type, x, y, NOT_SELECTABLE, (void *)Message_Box, style_id, 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, 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_Select_YesNo(char* title, uint32_t title_length, bool* value, 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, 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->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, 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(RGB_Color* color_value, uint8_t* current_component, 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, 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;

		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) {
		return;
	}

	if(Object->Type != IMAGE) {
		return;
	}

	Object_Image_Color* IM = (Object_Image_Color*)(Object->Data);

	IM->Alpha = new_alpha;
}

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 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:
		Display_Font_Set_Font(((Object_Message_Box *)Data)->Font->Font);
		Dimension.Height 	= Display_Font_Get_Font_Height() + MESSAGE_BOX_TEXT_BAR_DISTANCE + MESSAGE_BOX_BAR_HEIGHT;
		Dimension.Width 	= Display_Font_Width_String((((Object_Message_Box *)Data)->Text), ((Object_Message_Box *)Data)->Length, ((Object_Message_Box *)Data)->Font->Character_Spacing);
		
		if((((Object_Message_Box *)Data)->Icon) != MESSAGE_BOX_ICON_NONE) {
			Dimension.Width += MESSAGE_BOX_TEXT_ICON_DISTANCE + Display_Message_Box_Icons_Get_Icon_Width(((Object_Message_Box *)Data)->Icon);

			if(Display_Message_Box_Icons_Get_Icon_Height(((Object_Message_Box *)Data)->Icon) > Display_Font_Get_Font_Height()) {
				Dimension.Height = Display_Message_Box_Icons_Get_Icon_Height(((Object_Message_Box *)Data)->Icon) + MESSAGE_BOX_TEXT_BAR_DISTANCE + MESSAGE_BOX_BAR_HEIGHT;
			}
		}
		break;

		case MENU_SELECT:
		case MENU_ICON_ROW:
		case SELECT_YESNO:
		case SELECT_LIST:
		case SELECT_VALUE:
		case SELECT_RGB:
			Dimension.Height = 0;
			Dimension.Width = 0;
			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;
}