/* * 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 #include // ============================================================================================ // 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;iType == CANVAS) { Canvas_Count++; } } return Canvas_Count; } Object_ID Display_Objects_Get_ID_From_Canvas_Number(uint canvas_number) { for(uint i=0;iType == 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_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; 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;yData[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 ROUNDED_RECTANGLE_FILLED: Dimension.Width = Shape->Dimension.Width; Dimension.Height = Shape->Dimension.Height; break; case RECTANGLE_FRAME: case ROUNDED_RECTANGLE_FRAME: Dimension.Width = Shape->Dimension.Width + Shape->Thickness; Dimension.Height = Shape->Dimension.Height + Shape->Thickness; break; case CIRCLE: 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; }