// // Created by bruno on 5.2.2025. // Modified to use dynamic limits. // #include "texteditor.h" #include "font.h" #include "../cpu/core.h" // Initialize the text editor with dynamic sizes. void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer, int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly) { editor->max_line_width = max_line_width; editor->maxLines = max_lines_asm; editor->displayLineCount = max_lines_display; editor->line_count = 0; editor->cursor_line = 0; editor->cursor_line_offset = 0; editor->cursor_pos = 0; editor->readOnly = readOnly; editor->font = font; editor->outRect = malloc(sizeof(SDL_Rect)); editor->cursorRect = malloc(sizeof(SDL_Rect)); editor->rect = malloc(sizeof(SDL_Rect)); editor->highlightedLineRect = malloc(sizeof(SDL_Rect)); memset(editor->outRect, 0, sizeof(SDL_Rect)); memset(editor->cursorRect, 0, sizeof(SDL_Rect)); memset(editor->rect, 0, sizeof(SDL_Rect)); memset(editor->highlightedLineRect, 0, sizeof(SDL_Rect)); // Allocate dynamic array for lines. editor->lines = (Line *) malloc(sizeof(Line) * editor->maxLines); if (!editor->lines) { fprintf(stderr, "Failed to allocate memory for lines.\n"); exit(EXIT_FAILURE); } // For each line, allocate memory for the text (including space for '\0') for (int i = 0; i < editor->maxLines; i++) { editor->lines[i].text = (char *) malloc(sizeof(char) * (editor->max_line_width + 1)); if (!editor->lines[i].text) { fprintf(stderr, "Failed to allocate memory for line %d.\n", i); exit(EXIT_FAILURE); } editor->lines[i].text[0] = '\0'; editor->lines[i].active = 0; } // Allocate output and display strings. editor->outputString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->maxLines + 1)); editor->displayString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->displayLineCount + 1)); if (!editor->outputString || !editor->displayString) { fprintf(stderr, "Failed to allocate memory for output/display strings.\n"); exit(EXIT_FAILURE); } editor->outputString[0] = '\0'; editor->displayString[0] = '\0'; // Initialize with two active lines (like the original code). editor->lines[0].active = 1; editor->lines[1].active = 1; editor->line_count = 2; // Set up the editor rectangle based on font size and dynamic max_line_width and displayLineCount. editor->rect->x = 2; editor->rect->y = 2; editor->rect->w = editor->max_line_width * (font->size + 1) + ((font->size + 1) / 2); editor->rect->h = editor->displayLineCount * (font->size + 1) + 2; editor->outRect->w = editor->rect->w; editor->outRect->h = editor->rect->h; editor->outRect->x = x; editor->outRect->y = y; editor->highlightedLineRect->x = 2; editor->highlightedLineRect->y = 2; editor->highlightedLineRect->w = editor->outRect->w - (2 * editor->highlightedLineRect->x); editor->highlightedLineRect->h = editor->font->size; editor->cursorRect->x = 3 + editor->cursor_pos * font->size + editor->outRect->x; editor->cursorRect->y = 2 + (editor->cursor_line - editor->cursor_line_offset) * (font->size + 1) + editor->outRect->y; editor->cursorRect->w = editor->font->size; editor->cursorRect->h = editor->font->size; // Create texture for rendering. editor->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, editor->rect->w, editor->rect->h); if (!editor->texture) { fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError()); exit(EXIT_FAILURE); } } void insert_line(TextEditor *editor, int position, const char *text, SDL_Renderer *renderer) { if (editor->line_count >= editor->maxLines || position < 0 || position > editor->line_count) { printf("Invalid position or max lines reached!\n"); return; } // Shift lines down. for (int i = editor->line_count; i > position; i--) { strcpy(editor->lines[i].text, editor->lines[i - 1].text); editor->lines[i].active = editor->lines[i - 1].active; } // Copy the text into the new line, ensuring it does not exceed max_line_width. strncpy(editor->lines[position].text, text, editor->max_line_width); editor->lines[position].text[editor->max_line_width] = '\0'; editor->lines[position].active = 1; editor->line_count++; move_cursor(editor, editor->cursor_line + 1, 0, false, renderer); generate_string_display(editor, renderer); } void insert_line_rel(TextEditor *editor, SDL_Renderer *renderer) { int line = editor->cursor_line; int pos = editor->cursor_pos; char *current_text = editor->lines[line].text; // Split the current line at the cursor position char new_line_text[editor->max_line_width + 1]; strcpy(new_line_text, ¤t_text[pos]); // Copy the text after cursor to the new line current_text[pos] = '\0'; // Truncate the current line at cursor position insert_line(editor, line + 1, new_line_text, renderer); editor->cursor_pos = 0; } void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer) { if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) { printf("Invalid cursor position!\n"); return; } Line *line = &editor->lines[editor->cursor_line]; int len = strlen(line->text); if (len >= editor->max_line_width || editor->cursor_pos > len) { printf("Position out of bounds or line is full!\n"); return; } // Shift characters to the right. for (int i = len; i >= editor->cursor_pos; i--) { line->text[i + 1] = line->text[i]; } line->text[editor->cursor_pos] = ch; editor->cursor_pos++; generate_string_display(editor, renderer); } void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer) { if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) { printf("Invalid cursor position!\n"); return; } Line *line = &editor->lines[editor->cursor_line]; int len = strlen(line->text); if (isDelete) { // Delete character after cursor if (editor->cursor_pos < len) { for (int i = editor->cursor_pos; i < len; i++) { line->text[i] = line->text[i + 1]; } } else if (editor->cursor_pos == len && editor->cursor_line < editor->line_count - 1) { // Merge next line with the current line when pressing delete at the end strcat(line->text, editor->lines[editor->cursor_line + 1].text); // Shift remaining lines up for (int i = editor->cursor_line + 1; i < editor->line_count - 1; i++) { strcpy(editor->lines[i].text, editor->lines[i + 1].text); editor->lines[i].active = editor->lines[i + 1].active; } editor->lines[editor->line_count - 1].text[0] = '\0'; editor->lines[editor->line_count - 1].active = 0; editor->line_count--; } } else { // Backspace behavior (delete character before cursor) if (editor->cursor_pos == 0 && editor->cursor_line > 0) { // Append current line to previous line int prev_len = strlen(editor->lines[editor->cursor_line - 1].text); strcat(editor->lines[editor->cursor_line - 1].text, line->text); // Shift lines up for (int i = editor->cursor_line; i < editor->line_count - 1; i++) { strcpy(editor->lines[i].text, editor->lines[i + 1].text); editor->lines[i].active = editor->lines[i + 1].active; } editor->lines[editor->line_count - 1].text[0] = '\0'; editor->lines[editor->line_count - 1].active = 0; editor->line_count--; // Move cursor to the end of the previous line editor->cursor_line--; editor->cursor_pos = prev_len; } else if (editor->cursor_pos > 0) { for (int i = editor->cursor_pos - 1; i < len; i++) { line->text[i] = line->text[i + 1]; } editor->cursor_pos--; } } generate_string_display(editor, renderer); } void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset, bool keepPos, SDL_Renderer *renderer) { int new_line = editor->cursor_line + line_offset; int new_pos = editor->cursor_pos + pos_offset; move_cursor(editor, new_line, new_pos, keepPos, renderer); } void move_cursor(TextEditor *editor, int new_line, int new_pos, bool keepPos, SDL_Renderer *renderer) { if (new_line < 0) new_line = 0; int trgt = editor->line_count - editor->displayLineCount; if (trgt < 0) { trgt = 0; } if (new_line >= trgt && new_line >= editor->line_count) { new_line = editor->line_count - 1; } if (keepPos) { editor->cursor_line_offset = new_line; } if (new_line < editor->cursor_line_offset) { editor->cursor_line_offset = new_line; } if (new_line >= editor->cursor_line_offset + editor->displayLineCount) { editor->cursor_line_offset = new_line - editor->displayLineCount + 1; } if (editor->cursor_line_offset >= editor->line_count - editor->displayLineCount) { editor->cursor_line_offset = editor->line_count - editor->displayLineCount; } if (editor->cursor_line_offset < 0) { editor->cursor_line_offset = 0; } int line_length = strlen(editor->lines[new_line].text); if (new_pos < 0) new_pos = 0; if (new_pos > line_length) new_pos = line_length; editor->cursor_line = new_line; editor->cursor_pos = new_pos; generate_string_display(editor, renderer); } void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) { if (editor->cursor_line_offset < 0 || editor->cursor_line_offset >= editor->line_count) { printf("Invalid start line!\n"); return; } int end_line = editor->cursor_line_offset + editor->displayLineCount; if (end_line > editor->line_count) end_line = editor->line_count; // Clear the display string. editor->displayString[0] = '\0'; SDL_SetRenderTarget(renderer, editor->texture); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); SDL_Rect charDstRect; charDstRect.x = 4; charDstRect.y = 3; charDstRect.w = editor->font->size; charDstRect.h = editor->font->size; SDL_Rect charRect; charRect.x = 0; charRect.y = 0; charRect.w = editor->font->size; charRect.h = editor->font->size; editor->cursorRect->x = 3 + editor->cursor_pos * (charDstRect.w + 1) + editor->outRect->x; editor->cursorRect->y = 2 + (editor->cursor_line - editor->cursor_line_offset) * (charDstRect.h + 1) + editor->outRect->y; for (int line = editor->cursor_line_offset; line < end_line; line++) { if (editor->lines[line].active) { strcat(editor->displayString, editor->lines[line].text); char *linePTR = editor->lines[line].text; while (*linePTR) { SDL_RenderCopy(renderer, editor->font->texture[(unsigned char) *linePTR], &charRect, &charDstRect); charDstRect.x += charDstRect.w + 1; linePTR++; } strcat(editor->displayString, "\n"); charDstRect.x = 4; charDstRect.y += charDstRect.h + 1; } } SDL_SetRenderTarget(renderer, NULL); } void editor_render(TextEditor *editor, SDL_Renderer *renderer, CPU *cpu, uint8_t editorIndex, bool isActive, bool cursorBlink) { if (isActive) { SDL_Rect bgRect; bgRect = *editor->outRect; bgRect.x -= 6; bgRect.y -= 6; bgRect.w += 12; bgRect.h += 12; SDL_SetRenderDrawColor(renderer, editor->readOnly ? 128 : 0, editor->readOnly ? 0 : 128, 64, 255); SDL_RenderFillRect(renderer, &bgRect); } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderFillRect(renderer, editor->outRect); uint32_t targetLine = 0; const uint32_t instrLine = cpu->pc / CPU_INSTRUCTION_SIZE; if (editorIndex == 0) { targetLine = cpu->addrToLineMapper[instrLine] - editor->cursor_line_offset; editor->highlightedLineRect->w = editor->rect->w - 1; editor->highlightedLineRect->x = 2; } if (editorIndex == 1) { targetLine = (instrLine / 2) - editor->cursor_line_offset; editor->highlightedLineRect->w = (editor->rect->w / 5 * 2) - 2; editor->highlightedLineRect->x = 2 + (11 * editor->font->size) + (instrLine % 2 ? (28 * editor->font->size) : 0); } editor->highlightedLineRect->y = 2 + ((editor->font->size + 1) * targetLine); SDL_Rect highlightedLineAbs = *editor->highlightedLineRect; highlightedLineAbs.x += editor->outRect->x; highlightedLineAbs.y += editor->outRect->y; SDL_SetRenderDrawColor(renderer, 0, 72, 64, 255); if (targetLine >= editor->cursor_line_offset && targetLine < editor->cursor_line_offset + editor->displayLineCount) { SDL_RenderFillRect(renderer, &highlightedLineAbs); } SDL_SetTextureBlendMode(editor ->texture, SDL_BLENDMODE_BLEND); SDL_RenderCopy(renderer, editor ->texture, editor->rect, editor->outRect); if (isActive && cursorBlink) { SDL_SetRenderDrawColor(renderer, 0, 255, 255, 128); SDL_RenderFillRect(renderer, editor ->cursorRect); } } void generate_string(TextEditor *editor) { editor->outputString[0] = '\0'; for (int i = 0; i < editor->maxLines; i++) { if (editor->lines[i].active) { if (strlen(editor->lines[i].text)) { strcat(editor->outputString, editor->lines[i].text); strcat(editor->outputString, "\n"); } } } } void fill_editor_from_string(TextEditor *editor, const char *content, int lineStart, bool isComplete, SDL_Renderer *renderer) { if (!editor || !content) { printf("Invalid editor or content pointer!\n"); return; } char *str = content; int numLines = 0; while (*str) if (*str++ == '\n') ++numLines; // Clear the current editor content for (int i = lineStart; i < editor->maxLines && i < lineStart + numLines + 1; i++) { editor->lines[i].text[0] = '\0'; editor->lines[i].active = 0; } if (isComplete) { editor->line_count = numLines; if (editor->line_count >= editor->maxLines) { editor->line_count = editor->maxLines - 1; } } // Parse the content and fill the editor lines const char *ptr = content; int line_index = lineStart; while (*ptr && line_index < editor->maxLines && line_index < numLines + lineStart) { int char_count = 0; // Ensure the text buffer does not overflow while (*ptr && *ptr != '\n' && char_count < editor->max_line_width) { editor->lines[line_index].text[char_count++] = *ptr++; } editor->lines[line_index].text[char_count] = '\0'; // Null-terminate editor->lines[line_index].active = 1; line_index++; // Move past the newline character if present if (*ptr == '\n') ptr++; } editor->lines[line_index].active = 1; // Update the total number of lines in use //editor->line_count = line_index + (line_index < editor->maxLines - 1 ? 1 : 0); //if (editor->line_count >= editor-> maxLines) // Generate the visual representation generate_string_display(editor, renderer); } // Free all dynamically allocated memory. void destroy_editor(TextEditor *editor) { if (editor->lines) { for (int i = 0; i < editor->maxLines; i++) { free(editor->lines[i].text); } free(editor->lines); } //free(editor->outputString); //free(editor->displayString); free(editor->outRect); free(editor->rect); free(editor->cursorRect); if (editor->texture) { SDL_DestroyTexture(editor->texture); } }