Mercurial
comparison third_party/raylib/custom.c @ 163:058de208e640
[Config] Adding os ignore files.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Mon, 19 Jan 2026 04:52:02 -0800 |
| parents | 87d8d3eb3491 |
| children |
comparison
equal
deleted
inserted
replaced
| 162:8ceb5d3c6bdd | 163:058de208e640 |
|---|---|
| 1 #include "third_party/raylib/include/raylib.h" | 1 #include "third_party/raylib/include/raylib.h" |
| 2 #define RAYGUI_IMPLEMENTATION | 2 #define RAYGUI_IMPLEMENTATION |
| 3 #include "third_party/raylib/include/raygui.h" | 3 #include "third_party/raylib/include/raygui.h" |
| 4 #include "third_party/raylib/custom.h" | 4 #include "third_party/raylib/custom.h" |
| 5 | 5 #include <string.h> |
| 6 // -- forward declarations --// | 6 |
| 7 void DefaultBehaviours() | 7 // ============================================================================ |
| 8 { | 8 // COLOR SCHEME IMPLEMENTATION |
| 9 // Font sizes | 9 // ============================================================================ |
| 10 IncreaseFontSize(); | 10 |
| 11 DecreaseFontSize(); | 11 // Global color scheme instance |
| 12 } | 12 ColorScheme g_colors = {0}; |
| 13 | 13 |
| 14 void IncreaseFontSize() | 14 ColorScheme PostDog_DefaultColorScheme(void) |
| 15 { | 15 { |
| 16 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_EQUAL)) | 16 return (ColorScheme){ |
| 17 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) + 1); | 17 .primary = (Color){255, 140, 0, 255}, // Orange |
| 18 } | 18 .secondary = (Color){255, 248, 231, 255}, // Beige/Egg white |
| 19 | 19 .background = (Color){255, 255, 255, 255}, // White |
| 20 void DecreaseFontSize() | 20 .text = (Color){30, 30, 30, 255}, // Near black |
| 21 { | 21 .text_light = (Color){255, 255, 255, 255}, // White |
| 22 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_MINUS)) | 22 .border = (Color){200, 200, 200, 255}, // Light gray |
| 23 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) - 1); | 23 .highlight = (Color){255, 180, 100, 255}, // Light orange |
| 24 .success = (Color){76, 175, 80, 255}, // Green | |
| 25 .error = (Color){244, 67, 54, 255}, // Red | |
| 26 .muted = (Color){158, 158, 158, 255}, // Gray | |
| 27 }; | |
| 28 } | |
| 29 | |
| 30 ColorScheme PostDog_DarkColorScheme(void) | |
| 31 { | |
| 32 return (ColorScheme){ | |
| 33 .primary = (Color){255, 140, 0, 255}, // Orange | |
| 34 .secondary = (Color){45, 45, 48, 255}, // Dark gray | |
| 35 .background = (Color){30, 30, 30, 255}, // Near black | |
| 36 .text = (Color){240, 240, 240, 255}, // Near white | |
| 37 .text_light = (Color){255, 255, 255, 255}, // White | |
| 38 .border = (Color){70, 70, 70, 255}, // Dark gray | |
| 39 .highlight = (Color){255, 180, 100, 255}, // Light orange | |
| 40 .success = (Color){76, 175, 80, 255}, // Green | |
| 41 .error = (Color){244, 67, 54, 255}, // Red | |
| 42 .muted = (Color){100, 100, 100, 255}, // Gray | |
| 43 }; | |
| 44 } | |
| 45 | |
| 46 void PostDog_InitColorScheme(void) | |
| 47 { | |
| 48 g_colors = PostDog_DefaultColorScheme(); | |
| 49 } | |
| 50 | |
| 51 void PostDog_SetColorScheme(ColorScheme scheme) | |
| 52 { | |
| 53 g_colors = scheme; | |
| 54 } | |
| 55 | |
| 56 // ============================================================================ | |
| 57 // FUNCTIONALITY HELPERS | |
| 58 // ============================================================================ | |
| 59 | |
| 60 void DefaultBehaviours(void) | |
| 61 { | |
| 62 IncreaseFontSize(); | |
| 63 DecreaseFontSize(); | |
| 64 } | |
| 65 | |
| 66 void IncreaseFontSize(void) | |
| 67 { | |
| 68 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_EQUAL)) | |
| 69 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) + 1); | |
| 70 } | |
| 71 | |
| 72 void DecreaseFontSize(void) | |
| 73 { | |
| 74 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_MINUS)) | |
| 75 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) - 1); | |
| 24 } | 76 } |
| 25 | 77 |
| 26 // --- Layout helper --- // | 78 // --- Layout helper --- // |
| 27 Rectangle RightOf(Rectangle ref, float padding) | 79 Rectangle RightOf(Rectangle ref, float padding) |
| 28 { | 80 { |
| 72 .width = container.width * ratio, | 124 .width = container.width * ratio, |
| 73 .height = container.height | 125 .height = container.height |
| 74 }; | 126 }; |
| 75 } | 127 } |
| 76 | 128 |
| 129 | |
| 77 void DrawRectangleSelectiveRounded(Rectangle rec, float radius, int segments, Color color, | 130 void DrawRectangleSelectiveRounded(Rectangle rec, float radius, int segments, Color color, |
| 78 boolean roundTL, boolean roundTR, boolean roundBR, boolean roundBL) { | 131 boolean roundTL, boolean roundTR, boolean roundBR, boolean roundBL) { |
| 79 DrawRectangle(rec.x + radius, rec.y + radius, rec.width - 2*radius, rec.height - 2*radius, color); | 132 // Clamp radius to valid range |
| 80 // Top edge (excluding rounded corners) | 133 float maxR = fminf(rec.width, rec.height) * 0.5f; |
| 81 DrawRectangle(rec.x + (roundTL ? radius : 0), rec.y, rec.width - (roundTL ? radius : 0) - (roundTR ? radius : 0), radius, color); | 134 radius = fminf(fmaxf(radius, 0.0f), maxR); |
| 82 // Bottom edge | 135 |
| 83 DrawRectangle(rec.x + (roundBL ? radius : 0), rec.y + rec.height - radius, rec.width - (roundBL ? radius : 0) - (roundBR ? radius : 0), radius, color); | 136 // Fill center |
| 84 // Left edge | 137 DrawRectangleRec((Rectangle){ |
| 85 DrawRectangle(rec.x, rec.y + (roundTL ? radius : 0), radius, rec.height - (roundTL ? radius : 0) - (roundBL ? radius : 0), color); | 138 rec.x + radius, rec.y + radius, |
| 86 // Right edge | 139 rec.width - 2.0f * radius, rec.height - 2.0f * radius |
| 87 DrawRectangle(rec.x + rec.width - radius, rec.y + (roundTR ? radius : 0), radius, rec.height - (roundTR ? radius : 0) - (roundBR ? radius : 0), color); | 140 }, color); |
| 88 | 141 |
| 89 if (roundTL) | 142 // |
| 90 DrawCircleSector((Vector2){rec.x + radius, rec.y + radius}, radius, 180, 270, segments, color); | 143 // |--------| |
| 91 | 144 // | | |
| 92 if (roundTR) | 145 // | | |
| 93 DrawCircleSector((Vector2){rec.x + rec.width - radius, rec.y + radius}, radius, 270, 360, segments, color); | 146 // |--------| |
| 94 | 147 |
| 95 if (roundBR) | 148 // Top edge |
| 96 DrawCircleSector((Vector2){rec.x + rec.width - radius, rec.y + rec.height - radius}, radius, 0, 90, segments, color); | 149 float topStart = rec.x + (roundTL ? radius : 0.0f); |
| 97 | 150 float topWidth = rec.width - (roundTL ? radius : 0.0f) - (roundTR ? radius : 0.0f); |
| 98 if (roundBL) | 151 if (topWidth > 0.0f) |
| 99 DrawCircleSector((Vector2){rec.x + radius, rec.y + rec.height - radius}, radius, 90, 180, segments, color); | 152 DrawRectangleRec((Rectangle){ topStart, rec.y, topWidth, radius }, color); |
| 153 | |
| 154 // Bottom edge | |
| 155 float botStart = rec.x + (roundBL ? radius : 0.0f); | |
| 156 float botWidth = rec.width - (roundBL ? radius : 0.0f) - (roundBR ? radius : 0.0f); | |
| 157 if (botWidth > 0.0f) | |
| 158 DrawRectangleRec((Rectangle){ botStart, rec.y + rec.height - radius, botWidth, radius }, color); | |
| 159 | |
| 160 // Left edge | |
| 161 float leftStart = rec.y + (roundTL ? radius : 0.0f); | |
| 162 float leftHeight = rec.height - (roundTL ? radius : 0.0f) - (roundBL ? radius : 0.0f); | |
| 163 if (leftHeight > 0.0f) | |
| 164 DrawRectangleRec((Rectangle){ rec.x, leftStart, radius, leftHeight - radius}, color); | |
| 165 | |
| 166 // Right edge | |
| 167 float rightStart = rec.y + (roundTR ? radius : 0.0f); | |
| 168 float rightHeight = rec.height - (roundTR ? radius : 0.0f) - (roundBR ? radius : 0.0f); | |
| 169 if (rightHeight > 0.0f) | |
| 170 DrawRectangleRec((Rectangle){ rec.x + rec.width - radius, rightStart, radius, rightHeight - radius }, color); | |
| 171 | |
| 172 // Corners (arcs) | |
| 173 if (roundTL) { | |
| 174 DrawCircleSector((Vector2){ rec.x + radius, rec.y + radius }, radius, 180.0f, 270.0f, segments, color); | |
| 175 } | |
| 176 if (roundTR) { | |
| 177 DrawCircleSector((Vector2){ rec.x + rec.width - radius, rec.y + radius }, radius, 270.0f, 360.0f, segments, color); | |
| 178 } | |
| 179 if (roundBR) { | |
| 180 DrawCircleSector((Vector2){ rec.x + rec.width - radius, rec.y + rec.height - radius }, radius, 0.0f, 90.0f, segments, color); | |
| 181 } | |
| 182 if (roundBL) { | |
| 183 DrawCircleSector((Vector2){ rec.x + radius, rec.y + rec.height - radius }, radius, 90.0f, 180.0f, segments, color); | |
| 184 } | |
| 100 } | 185 } |
| 101 | 186 |
| 102 Rectangle AddPadding(Rectangle rect, float padding) | 187 Rectangle AddPadding(Rectangle rect, float padding) |
| 103 { | 188 { |
| 104 return (Rectangle){ | 189 return (Rectangle){ |
| 139 rect.width, | 224 rect.width, |
| 140 rect.height - (2 * padding) | 225 rect.height - (2 * padding) |
| 141 }; | 226 }; |
| 142 } | 227 } |
| 143 | 228 |
| 144 // // --- Components ---/ | 229 Rectangle VerticalSplit(Rectangle container, float ratio) |
| 145 // #define TEXT_SIZE_DEFAULT 10 | 230 { |
| 146 // #define TEXT_AREA_LINE_HEIGHT 20 | 231 return (Rectangle){ |
| 147 // #define TEXT_AREA_PADDING 8 | 232 .x = container.x, |
| 148 // #define TEXT_AREA_CURSOR_WIDTH 2 | 233 .y = container.y, |
| 149 // #define TEXT_AREA_MAX_UNDO_STATES 64 | 234 .width = container.width, |
| 150 // #define TEXT_AREA_MAX_INSTANCES 8 | 235 .height = container.height * ratio |
| 151 // | 236 }; |
| 152 // typedef struct { | 237 } |
| 153 // char *text; | 238 |
| 154 // int cursor_pos; | 239 // ============================================================================ |
| 155 // int selection_start; | 240 // DRAWING HELPERS - Additional |
| 156 // int selection_end; | 241 // ============================================================================ |
| 157 // } TextAreaUndoEntry; | 242 |
| 158 // | 243 void DrawRectangleSelectiveRoundedLines(Rectangle rec, float radius, int segments, Color color, |
| 159 // typedef struct { | 244 boolean roundTL, boolean roundTR, boolean roundBR, boolean roundBL) |
| 160 // int id; // Unique ID for this text area | 245 { |
| 161 // int cursor_pos; // Current cursor position in text | 246 // Top edge |
| 162 // int selection_start; // Selection start (-1 if no selection) | 247 DrawLine(rec.x + (roundTL ? radius : 0), rec.y, |
| 163 // int selection_end; // Selection end (-1 if no selection) | 248 rec.x + rec.width - (roundTR ? radius : 0), rec.y, color); |
| 164 // float scroll_offset_y; // Vertical scroll offset | 249 // Bottom edge |
| 165 // float scroll_offset_x; // Horizontal scroll offset (for non-wrap mode) | 250 DrawLine(rec.x + (roundBL ? radius : 0), rec.y + rec.height, |
| 166 // boolean is_selecting; // Currently dragging to select | 251 rec.x + rec.width - (roundBR ? radius : 0), rec.y + rec.height, color); |
| 167 // boolean is_initialized; // State has been initialized | 252 // Left edge |
| 168 // | 253 DrawLine(rec.x, rec.y + (roundTL ? radius : 0), |
| 169 // // Undo history | 254 rec.x, rec.y + rec.height - (roundBL ? radius : 0), color); |
| 170 // TextAreaUndoEntry *undo_stack; // Dowa array of undo entries | 255 // Right edge |
| 171 // int undo_index; // Current position in undo stack | 256 DrawLine(rec.x + rec.width, rec.y + (roundTR ? radius : 0), |
| 172 // | 257 rec.x + rec.width, rec.y + rec.height - (roundBR ? radius : 0), color); |
| 173 // // Internal tracking | 258 |
| 174 // double last_blink_time; | 259 // Corner arcs |
| 175 // boolean cursor_visible; | 260 if (roundTL) |
| 176 // } TextAreaState; | 261 DrawCircleSectorLines((Vector2){rec.x + radius, rec.y + radius}, radius, 180, 270, segments, color); |
| 177 // | 262 if (roundTR) |
| 178 // static TextAreaState g_text_area_states[TEXT_AREA_MAX_INSTANCES] = {0}; | 263 DrawCircleSectorLines((Vector2){rec.x + rec.width - radius, rec.y + radius}, radius, 270, 360, segments, color); |
| 179 // static int g_text_area_state_count = 0; | 264 if (roundBR) |
| 180 // static char *g_clipboard_text = NULL; | 265 DrawCircleSectorLines((Vector2){rec.x + rec.width - radius, rec.y + rec.height - radius}, radius, 0, 90, segments, color); |
| 181 // static Dowa_Arena *g_text_area_arena = NULL; | 266 if (roundBL) |
| 182 // | 267 DrawCircleSectorLines((Vector2){rec.x + radius, rec.y + rec.height - radius}, radius, 90, 180, segments, color); |
| 183 // // Helper functions | 268 } |
| 184 // static int TA_Min_Int(int a, int b) { return a < b ? a : b; } | 269 |
| 185 // static int TA_Max_Int(int a, int b) { return a > b ? a : b; } | 270 // ============================================================================ |
| 186 // static float TA_Min_Float(float a, float b) { return a < b ? a : b; } | 271 // CUSTOM TAB COMPONENT IMPLEMENTATION |
| 187 // static float TA_Max_Float(float a, float b) { return a > b ? a : b; } | 272 // ============================================================================ |
| 188 // | 273 |
| 189 // static TextAreaState* GetTextAreaState(int id) { | 274 boolean PostDog_TabBar(Rectangle bounds, TabConfig config) |
| 190 // for (int i = 0; i < g_text_area_state_count; i++) { | 275 { |
| 191 // if (g_text_area_states[i].id == id && g_text_area_states[i].is_initialized) { | 276 if (config.count <= 0 || config.labels == NULL || config.active_tab == NULL) |
| 192 // return &g_text_area_states[i]; | 277 return FALSE; |
| 193 // } | 278 |
| 194 // } | 279 boolean changed = FALSE; |
| 195 // return NULL; | 280 float tab_width = (bounds.width - config.padding * (config.count - 1)) / config.count; |
| 196 // } | 281 Vector2 mouse = GetMousePosition(); |
| 197 // | 282 |
| 198 // static TextAreaState* CreateTextAreaState(int id) { | 283 for (int i = 0; i < config.count; i++) |
| 199 // if (g_text_area_state_count >= TEXT_AREA_MAX_INSTANCES) | 284 { |
| 200 // return &g_text_area_states[0]; // Reuse first slot | 285 Rectangle tab_rect = { |
| 201 // | 286 .x = bounds.x + i * (tab_width + config.padding), |
| 202 // TextAreaState *state = &g_text_area_states[g_text_area_state_count++]; | 287 .y = bounds.y, |
| 203 // memset(state, 0, sizeof(TextAreaState)); | 288 .width = tab_width, |
| 204 // state->id = id; | 289 .height = bounds.height |
| 205 // state->selection_start = -1; | 290 }; |
| 206 // state->selection_end = -1; | 291 |
| 207 // state->undo_index = -1; | 292 boolean is_active = (i == *config.active_tab); |
| 208 // state->cursor_visible = TRUE; | 293 boolean is_hovered = CheckCollisionPointRec(mouse, tab_rect); |
| 209 // state->is_initialized = TRUE; | 294 Color bg_color = is_active ? config.active_color : config.inactive_color; |
| 210 // return state; | 295 Color txt_color = is_active ? config.active_text_color : config.text_color; |
| 211 // } | 296 |
| 212 // | 297 // Hover effect |
| 213 // static void GetLineAndColumn(const char *text, int pos, int *out_line, int *out_column) { | 298 if (is_hovered && !is_active) |
| 214 // int line = 0; | 299 bg_color = Fade(config.active_color, 0.5f); |
| 215 // int column = 0; | 300 |
| 216 // for (int i = 0; i < pos && text[i] != '\0'; i++) | 301 // Draw tab background with rounded top corners |
| 217 // { | 302 DrawRectangleSelectiveRounded(tab_rect, config.corner_radius, 8, bg_color, |
| 218 // if (text[i] == '\n') | 303 TRUE, TRUE, FALSE, FALSE); |
| 219 // { | 304 |
| 220 // line++; | 305 // Draw tab label |
| 221 // column = 0; | 306 int text_width = MeasureText(config.labels[i], GuiGetStyle(DEFAULT, TEXT_SIZE)); |
| 222 // } | 307 Vector2 text_pos = { |
| 223 // else | 308 tab_rect.x + (tab_rect.width - text_width) / 2, |
| 224 // column++; | 309 tab_rect.y + (tab_rect.height - GuiGetStyle(DEFAULT, TEXT_SIZE)) / 2 |
| 225 // } | 310 }; |
| 226 // *out_line = line; | 311 DrawText(config.labels[i], text_pos.x, text_pos.y, GuiGetStyle(DEFAULT, TEXT_SIZE), txt_color); |
| 227 // *out_column = column; | 312 |
| 228 // } | 313 // Handle click |
| 229 // | 314 if (is_hovered && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && !is_active) |
| 230 // static int GetPosFromLineColumn(const char *text, int line, int column) { | 315 { |
| 231 // int current_line = 0; | 316 *config.active_tab = i; |
| 232 // int current_col = 0; | 317 changed = TRUE; |
| 233 // int i = 0; | 318 } |
| 234 // | 319 } |
| 235 // while (text[i] != '\0') | 320 |
| 236 // { | 321 return changed; |
| 237 // if (current_line == line && current_col == column) | 322 } |
| 238 // return i; | 323 |
| 239 // | 324 boolean PostDog_TabBarSimple(Rectangle bounds, const char **labels, int count, int *active_tab) |
| 240 // if (text[i] == '\n') | 325 { |
| 241 // { | 326 TabConfig config = { |
| 242 // if (current_line == line) | 327 .labels = labels, |
| 243 // return i; | 328 .count = count, |
| 244 // current_line++; | 329 .active_tab = active_tab, |
| 245 // current_col = 0; | 330 .padding = 2, |
| 246 // } | 331 .corner_radius = 8, |
| 247 // else | 332 .active_color = g_colors.primary, |
| 248 // current_col++; | 333 .inactive_color = g_colors.secondary, |
| 249 // i++; | 334 .text_color = g_colors.text, |
| 250 // } | 335 .active_text_color = g_colors.text_light, |
| 251 // return i; | 336 }; |
| 252 // } | 337 return PostDog_TabBar(bounds, config); |
| 253 // | 338 } |
| 254 // static int GetLineStart(const char *text, int pos) { | 339 |
| 255 // int i = pos; | 340 // ============================================================================ |
| 256 // while (i > 0 && text[i - 1] != '\n') | 341 // SPLIT PANEL IMPLEMENTATION |
| 257 // i--; | 342 // ============================================================================ |
| 258 // return i; | 343 |
| 259 // } | 344 void PostDog_SplitPanel(Rectangle bounds, SplitPanelConfig config, |
| 260 // | 345 Rectangle *out_left, Rectangle *out_right) |
| 261 // static int GetLineEnd(const char *text, int pos) { | 346 { |
| 262 // int i = pos; | 347 float left_width = bounds.width * config.split_ratio - config.gap / 2; |
| 263 // int len = strlen(text); | 348 float right_width = bounds.width * (1.0f - config.split_ratio) - config.gap / 2; |
| 264 // while (i < len && text[i] != '\n') | 349 |
| 265 // i++; | 350 if (out_left) |
| 266 // return i; | 351 { |
| 267 // } | 352 *out_left = (Rectangle){ |
| 268 // | 353 .x = bounds.x, |
| 269 // static int CountLines(const char *text) { | 354 .y = bounds.y, |
| 270 // int count = 1; | 355 .width = left_width, |
| 271 // for (int i = 0; text[i] != '\0'; i++) | 356 .height = bounds.height |
| 272 // if (text[i] == '\n') count++; | 357 }; |
| 273 // return count; | 358 } |
| 274 // } | 359 |
| 275 // | 360 if (out_right) |
| 276 // static int MeasureTextRange(const char *text, int start, int end, int font_size) { | 361 { |
| 277 // if (start >= end) return 0; | 362 *out_right = (Rectangle){ |
| 278 // | 363 .x = bounds.x + left_width + config.gap, |
| 279 // char temp[1024]; | 364 .y = bounds.y, |
| 280 // int len = TA_Min_Int(end - start, 1023); | 365 .width = right_width, |
| 281 // strncpy(temp, text + start, len); | 366 .height = bounds.height |
| 282 // temp[len] = '\0'; | 367 }; |
| 283 // | 368 } |
| 284 // return MeasureTextEx(GuiGetFont(), temp, font_size, TEXT_SIZE_DEFAULT/GuiGetStyle(DEFAULT, TEXT_SIZE)).x; | 369 } |
| 285 // } | 370 |
| 286 // | 371 void PostDog_SplitPanelDraw(Rectangle bounds, SplitPanelConfig config) |
| 287 // static int GetCharIndexFromPos(const char *text, Rectangle bounds, Vector2 pos, | 372 { |
| 288 // boolean wrap, float scroll_y, int font_size, int line_height) { | 373 Rectangle left_rect, right_rect; |
| 289 // if (!text || strlen(text) == 0) return 0; | 374 PostDog_SplitPanel(bounds, config, &left_rect, &right_rect); |
| 290 // | 375 |
| 291 // float content_x = bounds.x + TEXT_AREA_PADDING; | 376 // Draw left panel with rounded left corners |
| 292 // float content_y = bounds.y + TEXT_AREA_PADDING - scroll_y; | 377 DrawRectangleSelectiveRounded(left_rect, config.corner_radius, 8, config.left_color, |
| 293 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | 378 TRUE, FALSE, FALSE, TRUE); |
| 294 // | 379 |
| 295 // int text_len = strlen(text); | 380 // Draw right panel with rounded right corners |
| 296 // | 381 DrawRectangleSelectiveRounded(right_rect, config.corner_radius, 8, config.right_color, |
| 297 // float click_line_y = (pos.y - content_y) / line_height; | 382 FALSE, TRUE, TRUE, FALSE); |
| 298 // int target_visual_line = (int)click_line_y; | 383 } |
| 299 // if (target_visual_line < 0) target_visual_line = 0; | 384 |
| 300 // | 385 // ============================================================================ |
| 301 // int current_visual_line = 0; | 386 // COMBINED INPUT COMPONENTS IMPLEMENTATION |
| 302 // int i = 0; | 387 // ============================================================================ |
| 303 // int line_char_start = 0; | 388 |
| 304 // | 389 // Helper: Parse semicolon-separated items and return item at index |
| 305 // while (i <= text_len) { | 390 static const char* GetDropdownItem(const char *items, int index, char *buffer, int buffer_size) |
| 306 // boolean is_newline = (i < text_len && text[i] == '\n'); | 391 { |
| 307 // | 392 int current_index = 0; |
| 308 // if (wrap && i > line_char_start) { | 393 int start = 0; |
| 309 // int line_width = MeasureTextRange(text, line_char_start, i, font_size); | 394 int len = strlen(items); |
| 310 // if (line_width > content_width && i > line_char_start + 1) { | 395 |
| 311 // int wrap_pos = i - 1; | 396 for (int i = 0; i <= len; i++) |
| 312 // for (int j = i - 1; j > line_char_start; j--) { | 397 { |
| 313 // if (text[j] == ' ') { | 398 if (items[i] == ';' || items[i] == '\0') |
| 314 // wrap_pos = j; | 399 { |
| 315 // break; | 400 if (current_index == index) |
| 316 // } | 401 { |
| 317 // } | 402 int item_len = i - start; |
| 318 // | 403 if (item_len >= buffer_size) item_len = buffer_size - 1; |
| 319 // if (current_visual_line == target_visual_line) { | 404 strncpy(buffer, items + start, item_len); |
| 320 // float click_x = pos.x - content_x; | 405 buffer[item_len] = '\0'; |
| 321 // int best_pos = line_char_start; | 406 return buffer; |
| 322 // float best_dist = 99999; | 407 } |
| 323 // | 408 current_index++; |
| 324 // for (int k = line_char_start; k <= wrap_pos; k++) { | 409 start = i + 1; |
| 325 // int char_x = MeasureTextRange(text, line_char_start, k, font_size); | 410 } |
| 326 // float dist = (float)(click_x - char_x); | 411 } |
| 327 // if (dist < 0) dist = -dist; | 412 buffer[0] = '\0'; |
| 328 // if (dist < best_dist) { | 413 return buffer; |
| 329 // best_dist = dist; | 414 } |
| 330 // best_pos = k; | 415 |
| 331 // } | 416 // Helper: Count items in semicolon-separated string |
| 332 // } | 417 static int CountDropdownItems(const char *items) |
| 333 // return best_pos; | 418 { |
| 334 // } | 419 if (!items || items[0] == '\0') return 0; |
| 335 // | 420 int count = 1; |
| 336 // current_visual_line++; | 421 for (int i = 0; items[i]; i++) |
| 337 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | 422 if (items[i] == ';') count++; |
| 338 // i = line_char_start; | 423 return count; |
| 339 // continue; | 424 } |
| 340 // } | 425 |
| 341 // } | 426 boolean PostDog_DropdownTextBox(Rectangle bounds, DropdownTextBoxConfig config) |
| 342 // | 427 { |
| 343 // if (is_newline || i == text_len) { | 428 boolean result = FALSE; |
| 344 // if (current_visual_line == target_visual_line || i == text_len) { | 429 |
| 345 // float click_x = pos.x - content_x; | 430 // Calculate dropdown width |
| 346 // int line_end = i; | 431 float dropdown_w = config.dropdown_width; |
| 347 // int best_pos = line_char_start; | 432 if (dropdown_w <= 1.0f) |
| 348 // float best_dist = 99999; | 433 dropdown_w = bounds.width * dropdown_w; |
| 349 // | 434 |
| 350 // for (int k = line_char_start; k <= line_end; k++) { | 435 // Calculate rectangles |
| 351 // int char_x = MeasureTextRange(text, line_char_start, k, font_size); | 436 Rectangle dropdown_rect = { |
| 352 // float dist = (float)(click_x - char_x); | 437 .x = bounds.x, |
| 353 // if (dist < 0) dist = -dist; | 438 .y = bounds.y, |
| 354 // if (dist < best_dist) { | 439 .width = dropdown_w, |
| 355 // best_dist = dist; | 440 .height = bounds.height |
| 356 // best_pos = k; | 441 }; |
| 357 // } | 442 |
| 358 // } | 443 Rectangle textbox_rect = { |
| 359 // return TA_Min_Int(best_pos, text_len); | 444 .x = bounds.x + dropdown_w, |
| 360 // } | 445 .y = bounds.y, |
| 361 // | 446 .width = bounds.width - dropdown_w, |
| 362 // current_visual_line++; | 447 .height = bounds.height |
| 363 // line_char_start = i + 1; | 448 }; |
| 364 // } | 449 |
| 365 // | 450 // Draw combined background |
| 366 // i++; | 451 DrawRectangleSelectiveRounded(dropdown_rect, config.corner_radius, 8, config.background_color, |
| 367 // } | 452 TRUE, FALSE, FALSE, TRUE); |
| 368 // | 453 DrawRectangleSelectiveRounded(textbox_rect, config.corner_radius, 8, config.background_color, |
| 369 // return text_len; | 454 FALSE, TRUE, TRUE, FALSE); |
| 370 // } | 455 |
| 371 // | 456 // Draw separator line |
| 372 // static Vector2 GetCursorScreenPos(const char *text, int cursor_pos, Rectangle bounds, | 457 DrawLine(dropdown_rect.x + dropdown_rect.width, dropdown_rect.y + 4, |
| 373 // boolean wrap, float scroll_y, int font_size, int line_height) { | 458 dropdown_rect.x + dropdown_rect.width, dropdown_rect.y + dropdown_rect.height - 4, |
| 374 // float content_x = bounds.x + TEXT_AREA_PADDING; | 459 config.border_color); |
| 375 // float content_y = bounds.y + TEXT_AREA_PADDING - scroll_y; | 460 |
| 376 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | 461 // Draw border |
| 377 // | 462 DrawRectangleSelectiveRoundedLines(bounds, config.corner_radius, 8, config.border_color, |
| 378 // if (!text || cursor_pos == 0) { | 463 TRUE, TRUE, TRUE, TRUE); |
| 379 // return (Vector2){content_x, content_y}; | 464 |
| 380 // } | 465 // Custom dropdown with per-item colors |
| 381 // | 466 Vector2 mouse_pos = GetMousePosition(); |
| 382 // int text_len = strlen(text); | 467 int item_count = config.item_count > 0 ? config.item_count : CountDropdownItems(config.dropdown_items); |
| 383 // cursor_pos = TA_Min_Int(cursor_pos, text_len); | 468 int font_size = GuiGetStyle(DEFAULT, TEXT_SIZE); |
| 384 // | 469 char item_buffer[64]; |
| 385 // int visual_line = 0; | 470 |
| 386 // int line_char_start = 0; | 471 // Get current selected item |
| 387 // | 472 GetDropdownItem(config.dropdown_items, *config.dropdown_active, item_buffer, sizeof(item_buffer)); |
| 388 // for (int i = 0; i <= cursor_pos; i++) { | 473 Color current_color = (config.item_colors && *config.dropdown_active < item_count) |
| 389 // if (i == cursor_pos) { | 474 ? config.item_colors[*config.dropdown_active] |
| 390 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | 475 : config.text_color; |
| 391 // float y = content_y + visual_line * line_height; | 476 |
| 392 // return (Vector2){x, y}; | 477 // Draw selected item in dropdown area |
| 393 // } | 478 Rectangle dropdown_inner = AddPadding(dropdown_rect, 6); |
| 394 // | 479 boolean dropdown_hovered = CheckCollisionPointRec(mouse_pos, dropdown_rect); |
| 395 // if (text[i] == '\n') { | 480 |
| 396 // visual_line++; | 481 // Highlight on hover |
| 397 // line_char_start = i + 1; | 482 if (dropdown_hovered && !(*config.dropdown_edit_mode)) |
| 398 // } else if (wrap) { | 483 { |
| 399 // int line_width = MeasureTextRange(text, line_char_start, i + 1, font_size); | 484 DrawRectangleSelectiveRounded(dropdown_rect, config.corner_radius, 8, |
| 400 // if (line_width > content_width && i > line_char_start) { | 485 Fade(current_color, 0.5f), TRUE, FALSE, FALSE, TRUE); |
| 401 // int wrap_pos = i; | 486 } |
| 402 // for (int j = i; j > line_char_start; j--) { | 487 |
| 403 // if (text[j] == ' ') { | 488 // Draw selected text with color |
| 404 // wrap_pos = j; | 489 int text_width = MeasureText(item_buffer, font_size); |
| 405 // break; | 490 DrawText(item_buffer, |
| 406 // } | 491 dropdown_inner.x + (dropdown_inner.width - text_width) / 2, |
| 407 // } | 492 dropdown_inner.y + (dropdown_inner.height - font_size) / 2, |
| 408 // | 493 font_size, current_color); |
| 409 // if (cursor_pos <= wrap_pos) { | 494 DrawRectangleSelectiveRounded(dropdown_rect, config.corner_radius, 8, |
| 410 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | 495 Fade(current_color, 0.3f), TRUE, FALSE, FALSE, TRUE); |
| 411 // float y = content_y + visual_line * line_height; | 496 |
| 412 // return (Vector2){x, y}; | 497 // Draw dropdown arrow |
| 413 // } | 498 float arrow_size = 6; |
| 414 // | 499 float arrow_x = dropdown_rect.x + dropdown_rect.width - 14; |
| 415 // visual_line++; | 500 float arrow_y = dropdown_rect.y + dropdown_rect.height / 2; |
| 416 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | 501 DrawTriangle( |
| 417 // } | 502 (Vector2){arrow_x, arrow_y - arrow_size/2}, |
| 418 // } | 503 (Vector2){arrow_x + arrow_size, arrow_y - arrow_size/2}, |
| 419 // } | 504 (Vector2){arrow_x + arrow_size/2, arrow_y + arrow_size/2}, |
| 420 // | 505 config.text_color); |
| 421 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | 506 |
| 422 // float y = content_y + visual_line * line_height; | 507 // Handle dropdown click |
| 423 // return (Vector2){x, y}; | 508 if (dropdown_hovered && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) |
| 424 // } | 509 { |
| 425 // | 510 *config.dropdown_edit_mode = !(*config.dropdown_edit_mode); |
| 426 // static float GetContentHeight(const char *text, Rectangle bounds, boolean wrap, | 511 } |
| 427 // int font_size, int line_height) { | 512 |
| 428 // if (!text || strlen(text) == 0) return line_height; | 513 // Draw dropdown list when open |
| 429 // | 514 if (*config.dropdown_edit_mode) |
| 430 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | 515 { |
| 431 // int visual_lines = 1; | 516 float item_height = bounds.height; |
| 432 // int line_char_start = 0; | 517 Rectangle list_rect = { |
| 433 // int text_len = strlen(text); | 518 .x = dropdown_rect.x, |
| 434 // | 519 .y = dropdown_rect.y + dropdown_rect.height + 2, |
| 435 // for (int i = 0; i <= text_len; i++) { | 520 .width = dropdown_rect.width, |
| 436 // if (i == text_len || text[i] == '\n') { | 521 .height = item_height * item_count |
| 437 // visual_lines++; | 522 }; |
| 438 // line_char_start = i + 1; | 523 |
| 439 // } else if (wrap) { | 524 // Background |
| 440 // int line_width = MeasureTextRange(text, line_char_start, i + 1, font_size); | 525 DrawRectangleRounded(list_rect, 0.1f, 8, config.background_color); |
| 441 // if (line_width > content_width && i > line_char_start) { | 526 DrawRectangleRoundedLines(list_rect, 0.1f, 8, config.border_color); |
| 442 // int wrap_pos = i; | 527 |
| 443 // for (int j = i; j > line_char_start; j--) { | 528 // Draw each item |
| 444 // if (text[j] == ' ') { | 529 for (int i = 0; i < item_count; i++) |
| 445 // wrap_pos = j; | 530 { |
| 446 // break; | 531 Rectangle item_rect = { |
| 447 // } | 532 .x = list_rect.x, |
| 448 // } | 533 .y = list_rect.y + i * item_height, |
| 449 // visual_lines++; | 534 .width = list_rect.width, |
| 450 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | 535 .height = item_height |
| 451 // } | 536 }; |
| 452 // } | 537 |
| 453 // } | 538 GetDropdownItem(config.dropdown_items, i, item_buffer, sizeof(item_buffer)); |
| 454 // | 539 Color item_color = (config.item_colors && i < item_count) |
| 455 // return visual_lines * line_height; | 540 ? config.item_colors[i] |
| 456 // } | 541 : config.text_color; |
| 457 // | 542 |
| 458 // static void PushUndoState(TextAreaState *state, const char *text, Dowa_Arena *arena) { | 543 boolean item_hovered = CheckCollisionPointRec(mouse_pos, item_rect); |
| 459 // TextAreaUndoEntry entry; | 544 |
| 460 // entry.text = Dowa_String_Copy_Arena((char*)text, arena); | 545 // Highlight hovered item |
| 461 // entry.cursor_pos = state->cursor_pos; | 546 if (item_hovered) |
| 462 // entry.selection_start = state->selection_start; | 547 DrawRectangleRec(item_rect, Fade(item_color, 0.15f)); |
| 463 // entry.selection_end = state->selection_end; | 548 |
| 464 // | 549 // Highlight selected item |
| 465 // if (state->undo_index < (int)Dowa_Array_Length(state->undo_stack) - 1) { | 550 DrawRectangleRec(item_rect, Fade(item_color, 0.2f)); |
| 466 // dowa__header(state->undo_stack)->length = state->undo_index + 1; | 551 |
| 467 // } | 552 // Draw item text |
| 468 // | 553 text_width = MeasureText(item_buffer, font_size); |
| 469 // Dowa_Array_Push_Arena(state->undo_stack, entry, arena); | 554 DrawText(item_buffer, |
| 470 // state->undo_index = Dowa_Array_Length(state->undo_stack) - 1; | 555 item_rect.x + (item_rect.width - text_width) / 2, |
| 471 // | 556 item_rect.y + (item_rect.height - font_size) / 2, |
| 472 // if (Dowa_Array_Length(state->undo_stack) > TEXT_AREA_MAX_UNDO_STATES) { | 557 font_size, item_color); |
| 473 // for (int i = 0; i < (int)Dowa_Array_Length(state->undo_stack) - 1; i++) { | 558 |
| 474 // state->undo_stack[i] = state->undo_stack[i + 1]; | 559 // Handle item click |
| 475 // } | 560 if (item_hovered && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) |
| 476 // dowa__header(state->undo_stack)->length--; | 561 { |
| 477 // state->undo_index--; | 562 *config.dropdown_active = i; |
| 478 // } | 563 *config.dropdown_edit_mode = FALSE; |
| 479 // } | 564 } |
| 480 // | 565 } |
| 481 // static boolean PerformUndo(TextAreaState *state, char *text, int text_size) { | 566 |
| 482 // if (state->undo_index <= 0) return FALSE; | 567 // Close dropdown if clicked outside |
| 483 // | 568 if (!CheckCollisionPointRec(mouse_pos, list_rect) && |
| 484 // state->undo_index--; | 569 !CheckCollisionPointRec(mouse_pos, dropdown_rect) && |
| 485 // TextAreaUndoEntry *entry = &state->undo_stack[state->undo_index]; | 570 IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) |
| 486 // | 571 { |
| 487 // strncpy(text, entry->text, text_size - 1); | 572 *config.dropdown_edit_mode = FALSE; |
| 488 // text[text_size - 1] = '\0'; | 573 } |
| 489 // state->cursor_pos = entry->cursor_pos; | 574 } |
| 490 // state->selection_start = entry->selection_start; | 575 |
| 491 // state->selection_end = entry->selection_end; | 576 // Draw text box (using raygui) |
| 492 // | 577 Rectangle textbox_inner = AddPadding(textbox_rect, 4); |
| 493 // return TRUE; | 578 boolean ctrl_pressed = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL) || IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_RIGHT_SUPER); |
| 494 // } | 579 if (*config.text_edit_mode && ctrl_pressed && IsKeyPressed(KEY_V)) |
| 495 // | 580 { |
| 496 // static boolean PerformRedo(TextAreaState *state, char *text, int text_size) { | 581 const char *clipboard = GetClipboardText(); |
| 497 // if (state->undo_index >= (int)Dowa_Array_Length(state->undo_stack) - 1) return FALSE; | 582 snprintf(config.text_buffer, config.text_buffer_size, "%s", clipboard); |
| 498 // | 583 } |
| 499 // state->undo_index++; | 584 if (GuiTextBox(textbox_inner, config.text_buffer, config.text_buffer_size, *config.text_edit_mode)) |
| 500 // TextAreaUndoEntry *entry = &state->undo_stack[state->undo_index]; | 585 { |
| 501 // | 586 *config.text_edit_mode = !(*config.text_edit_mode); |
| 502 // strncpy(text, entry->text, text_size - 1); | 587 result = TRUE; |
| 503 // text[text_size - 1] = '\0'; | 588 } |
| 504 // state->cursor_pos = entry->cursor_pos; | 589 |
| 505 // state->selection_start = entry->selection_start; | 590 return result; |
| 506 // state->selection_end = entry->selection_end; | 591 } |
| 507 // | |
| 508 // return TRUE; | |
| 509 // } | |
| 510 // | |
| 511 // static void InsertTextAtCursor(char *text, int text_size, int cursor_pos, | |
| 512 // const char *insert_text, int *new_cursor_pos) { | |
| 513 // int text_len = strlen(text); | |
| 514 // int insert_len = strlen(insert_text); | |
| 515 // | |
| 516 // if (text_len + insert_len >= text_size - 1) { | |
| 517 // insert_len = text_size - 1 - text_len; | |
| 518 // if (insert_len <= 0) return; | |
| 519 // } | |
| 520 // | |
| 521 // memmove(text + cursor_pos + insert_len, | |
| 522 // text + cursor_pos, | |
| 523 // text_len - cursor_pos + 1); | |
| 524 // | |
| 525 // memcpy(text + cursor_pos, insert_text, insert_len); | |
| 526 // | |
| 527 // *new_cursor_pos = cursor_pos + insert_len; | |
| 528 // } | |
| 529 // | |
| 530 // static void DeleteTextRange(char *text, int start, int end) { | |
| 531 // if (start >= end) return; | |
| 532 // int text_len = strlen(text); | |
| 533 // if (start < 0) start = 0; | |
| 534 // if (end > text_len) end = text_len; | |
| 535 // | |
| 536 // memmove(text + start, text + end, text_len - end + 1); | |
| 537 // } | |
| 538 // | |
| 539 // static char* GetSelectedText(const char *text, int sel_start, int sel_end, Dowa_Arena *arena) { | |
| 540 // if (sel_start < 0 || sel_end < 0 || sel_start >= sel_end) return NULL; | |
| 541 // | |
| 542 // int len = sel_end - sel_start; | |
| 543 // char *result = Dowa_Arena_Allocate(arena, len + 1); | |
| 544 // strncpy(result, text + sel_start, len); | |
| 545 // result[len] = '\0'; | |
| 546 // return result; | |
| 547 // } | |
| 548 // | |
| 549 // boolean GuiTextArea(int id, Rectangle bounds, char *text, int text_size, boolean is_edit_mode, | |
| 550 // boolean should_text_wrap, Dowa_Arena *arena) { | |
| 551 // boolean should_toggle_edit_mode = FALSE; | |
| 552 // | |
| 553 // // Get or create state for this text area | |
| 554 // TextAreaState *state = GetTextAreaState(id); | |
| 555 // if (!state) | |
| 556 // { | |
| 557 // state = CreateTextAreaState(id); | |
| 558 // state->cursor_pos = strlen(text); | |
| 559 // state->last_blink_time = GetTime(); | |
| 560 // PushUndoState(state, text, arena); | |
| 561 // } | |
| 562 // | |
| 563 // int text_len = strlen(text); | |
| 564 // Vector2 mouse_pos = GetMousePosition(); | |
| 565 // boolean mouse_in_bounds = CheckCollisionPointRec(mouse_pos, bounds); | |
| 566 // | |
| 567 // // Handle click to enter/exit edit mode | |
| 568 // if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { | |
| 569 // if (mouse_in_bounds && !is_edit_mode) { | |
| 570 // should_toggle_edit_mode = TRUE; | |
| 571 // } else if (!mouse_in_bounds && is_edit_mode) { | |
| 572 // should_toggle_edit_mode = TRUE; | |
| 573 // } | |
| 574 // } | |
| 575 // | |
| 576 // // Content area | |
| 577 // float content_height = GetContentHeight(text, bounds, should_text_wrap, | |
| 578 // GuiGetStyle(DEFAULT, TEXT_SIZE), TEXT_AREA_LINE_HEIGHT); | |
| 579 // float visible_height = bounds.height - TEXT_AREA_PADDING * 2; | |
| 580 // float max_scroll = TA_Max_Float(0, content_height - visible_height); | |
| 581 // | |
| 582 // // Handle scrolling | |
| 583 // float wheel = GetMouseWheelMove(); | |
| 584 // if (mouse_in_bounds && wheel != 0) { | |
| 585 // state->scroll_offset_y -= wheel * TEXT_AREA_LINE_HEIGHT * 3; | |
| 586 // state->scroll_offset_y = TA_Max_Float(0, TA_Min_Float(state->scroll_offset_y, max_scroll)); | |
| 587 // } | |
| 588 // | |
| 589 // if (is_edit_mode) { | |
| 590 // boolean ctrl_pressed = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL) || | |
| 591 // IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_RIGHT_SUPER); | |
| 592 // boolean shift_pressed = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); | |
| 593 // boolean text_changed = FALSE; | |
| 594 // | |
| 595 // double current_time = GetTime(); | |
| 596 // if (current_time - state->last_blink_time > 0.5) { | |
| 597 // state->cursor_visible = !state->cursor_visible; | |
| 598 // state->last_blink_time = current_time; | |
| 599 // } | |
| 600 // | |
| 601 // // Mouse Selection | |
| 602 // if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && mouse_in_bounds) { | |
| 603 // int click_pos = GetCharIndexFromPos(text, bounds, mouse_pos, should_text_wrap, | |
| 604 // state->scroll_offset_y, GuiGetStyle(DEFAULT, TEXT_SIZE), | |
| 605 // TEXT_AREA_LINE_HEIGHT); | |
| 606 // state->cursor_pos = click_pos; | |
| 607 // state->selection_start = -1; | |
| 608 // state->selection_end = -1; | |
| 609 // state->is_selecting = TRUE; | |
| 610 // state->cursor_visible = TRUE; | |
| 611 // state->last_blink_time = current_time; | |
| 612 // } | |
| 613 // | |
| 614 // if (state->is_selecting && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) { | |
| 615 // int drag_pos = GetCharIndexFromPos(text, bounds, mouse_pos, should_text_wrap, | |
| 616 // state->scroll_offset_y, GuiGetStyle(DEFAULT, TEXT_SIZE), | |
| 617 // TEXT_AREA_LINE_HEIGHT); | |
| 618 // if (drag_pos != state->cursor_pos) { | |
| 619 // if (state->selection_start < 0) { | |
| 620 // state->selection_start = state->cursor_pos; | |
| 621 // } | |
| 622 // state->selection_end = drag_pos; | |
| 623 // } | |
| 624 // } | |
| 625 // | |
| 626 // if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) { | |
| 627 // state->is_selecting = FALSE; | |
| 628 // if (state->selection_start >= 0 && state->selection_end >= 0) { | |
| 629 // if (state->selection_start > state->selection_end) { | |
| 630 // int temp = state->selection_start; | |
| 631 // state->selection_start = state->selection_end; | |
| 632 // state->selection_end = temp; | |
| 633 // } | |
| 634 // if (state->selection_start == state->selection_end) { | |
| 635 // state->selection_start = -1; | |
| 636 // state->selection_end = -1; | |
| 637 // } | |
| 638 // } | |
| 639 // } | |
| 640 // | |
| 641 // // Ctrl+A: Select All | |
| 642 // if (ctrl_pressed && IsKeyPressed(KEY_A)) { | |
| 643 // state->selection_start = 0; | |
| 644 // state->selection_end = text_len; | |
| 645 // state->cursor_pos = text_len; | |
| 646 // } | |
| 647 // | |
| 648 // // Ctrl+C: Copy | |
| 649 // if (ctrl_pressed && IsKeyPressed(KEY_C)) { | |
| 650 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 651 // state->selection_start != state->selection_end) { | |
| 652 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 653 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 654 // char *selected = GetSelectedText(text, sel_min, sel_max, arena); | |
| 655 // if (selected) { | |
| 656 // if (g_clipboard_text) free(g_clipboard_text); | |
| 657 // g_clipboard_text = strdup(selected); | |
| 658 // SetClipboardText(g_clipboard_text); | |
| 659 // } | |
| 660 // } | |
| 661 // } | |
| 662 // | |
| 663 // // Ctrl+X: Cut | |
| 664 // if (ctrl_pressed && IsKeyPressed(KEY_X)) { | |
| 665 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 666 // state->selection_start != state->selection_end) { | |
| 667 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 668 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 669 // char *selected = GetSelectedText(text, sel_min, sel_max, arena); | |
| 670 // if (selected) { | |
| 671 // if (g_clipboard_text) free(g_clipboard_text); | |
| 672 // g_clipboard_text = strdup(selected); | |
| 673 // SetClipboardText(g_clipboard_text); | |
| 674 // } | |
| 675 // | |
| 676 // PushUndoState(state, text, arena); | |
| 677 // DeleteTextRange(text, sel_min, sel_max); | |
| 678 // state->cursor_pos = sel_min; | |
| 679 // state->selection_start = -1; | |
| 680 // state->selection_end = -1; | |
| 681 // text_changed = TRUE; | |
| 682 // } | |
| 683 // } | |
| 684 // | |
| 685 // // Ctrl+V: Paste | |
| 686 // if (ctrl_pressed && IsKeyPressed(KEY_V)) { | |
| 687 // const char *clipboard = GetClipboardText(); | |
| 688 // if (clipboard && strlen(clipboard) > 0) { | |
| 689 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 690 // state->selection_start != state->selection_end) { | |
| 691 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 692 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 693 // PushUndoState(state, text, arena); | |
| 694 // DeleteTextRange(text, sel_min, sel_max); | |
| 695 // state->cursor_pos = sel_min; | |
| 696 // state->selection_start = -1; | |
| 697 // state->selection_end = -1; | |
| 698 // } else { | |
| 699 // PushUndoState(state, text, arena); | |
| 700 // } | |
| 701 // | |
| 702 // int new_cursor; | |
| 703 // InsertTextAtCursor(text, text_size, state->cursor_pos, clipboard, &new_cursor); | |
| 704 // state->cursor_pos = new_cursor; | |
| 705 // text_changed = TRUE; | |
| 706 // } | |
| 707 // } | |
| 708 // | |
| 709 // // Ctrl+Z: Undo / Ctrl+Shift+Z: Redo | |
| 710 // if (ctrl_pressed && IsKeyPressed(KEY_Z)) { | |
| 711 // if (shift_pressed) { | |
| 712 // PerformRedo(state, text, text_size); | |
| 713 // } else { | |
| 714 // PerformUndo(state, text, text_size); | |
| 715 // } | |
| 716 // } | |
| 717 // | |
| 718 // // Arrow Keys Navigation | |
| 719 // if (IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT)) { | |
| 720 // if (state->selection_start >= 0 && !shift_pressed) { | |
| 721 // state->cursor_pos = TA_Min_Int(state->selection_start, state->selection_end); | |
| 722 // state->selection_start = -1; | |
| 723 // state->selection_end = -1; | |
| 724 // } else if (state->cursor_pos > 0) { | |
| 725 // if (shift_pressed) { | |
| 726 // if (state->selection_start < 0) { | |
| 727 // state->selection_start = state->cursor_pos; | |
| 728 // state->selection_end = state->cursor_pos; | |
| 729 // } | |
| 730 // state->cursor_pos--; | |
| 731 // state->selection_end = state->cursor_pos; | |
| 732 // } else { | |
| 733 // state->cursor_pos--; | |
| 734 // } | |
| 735 // } | |
| 736 // state->cursor_visible = TRUE; | |
| 737 // state->last_blink_time = current_time; | |
| 738 // } | |
| 739 // | |
| 740 // if (IsKeyPressed(KEY_RIGHT) || IsKeyPressedRepeat(KEY_RIGHT)) { | |
| 741 // if (state->selection_start >= 0 && !shift_pressed) { | |
| 742 // state->cursor_pos = TA_Max_Int(state->selection_start, state->selection_end); | |
| 743 // state->selection_start = -1; | |
| 744 // state->selection_end = -1; | |
| 745 // } else if (state->cursor_pos < text_len) { | |
| 746 // if (shift_pressed) { | |
| 747 // if (state->selection_start < 0) { | |
| 748 // state->selection_start = state->cursor_pos; | |
| 749 // state->selection_end = state->cursor_pos; | |
| 750 // } | |
| 751 // state->cursor_pos++; | |
| 752 // state->selection_end = state->cursor_pos; | |
| 753 // } else { | |
| 754 // state->cursor_pos++; | |
| 755 // } | |
| 756 // } | |
| 757 // state->cursor_visible = TRUE; | |
| 758 // state->last_blink_time = current_time; | |
| 759 // } | |
| 760 // | |
| 761 // if (IsKeyPressed(KEY_UP) || IsKeyPressedRepeat(KEY_UP)) { | |
| 762 // int line, col; | |
| 763 // GetLineAndColumn(text, state->cursor_pos, &line, &col); | |
| 764 // if (line > 0) { | |
| 765 // int new_pos = GetPosFromLineColumn(text, line - 1, col); | |
| 766 // if (shift_pressed) { | |
| 767 // if (state->selection_start < 0) { | |
| 768 // state->selection_start = state->cursor_pos; | |
| 769 // state->selection_end = state->cursor_pos; | |
| 770 // } | |
| 771 // state->selection_end = new_pos; | |
| 772 // } else { | |
| 773 // state->selection_start = -1; | |
| 774 // state->selection_end = -1; | |
| 775 // } | |
| 776 // state->cursor_pos = new_pos; | |
| 777 // } | |
| 778 // state->cursor_visible = TRUE; | |
| 779 // state->last_blink_time = current_time; | |
| 780 // } | |
| 781 // | |
| 782 // if (IsKeyPressed(KEY_DOWN) || IsKeyPressedRepeat(KEY_DOWN)) | |
| 783 // { | |
| 784 // int line, col; | |
| 785 // GetLineAndColumn(text, state->cursor_pos, &line, &col); | |
| 786 // int total_lines = CountLines(text); | |
| 787 // if (line < total_lines - 1) { | |
| 788 // int new_pos = GetPosFromLineColumn(text, line + 1, col); | |
| 789 // if (shift_pressed) { | |
| 790 // if (state->selection_start < 0) { | |
| 791 // state->selection_start = state->cursor_pos; | |
| 792 // state->selection_end = state->cursor_pos; | |
| 793 // } | |
| 794 // state->selection_end = new_pos; | |
| 795 // } else { | |
| 796 // state->selection_start = -1; | |
| 797 // state->selection_end = -1; | |
| 798 // } | |
| 799 // state->cursor_pos = new_pos; | |
| 800 // } | |
| 801 // state->cursor_visible = TRUE; | |
| 802 // state->last_blink_time = current_time; | |
| 803 // } | |
| 804 // | |
| 805 // // Home/End keys | |
| 806 // if (IsKeyPressed(KEY_HOME)) { | |
| 807 // int line_start = GetLineStart(text, state->cursor_pos); | |
| 808 // if (shift_pressed) { | |
| 809 // if (state->selection_start < 0) { | |
| 810 // state->selection_start = state->cursor_pos; | |
| 811 // state->selection_end = state->cursor_pos; | |
| 812 // } | |
| 813 // state->selection_end = line_start; | |
| 814 // } else { | |
| 815 // state->selection_start = -1; | |
| 816 // state->selection_end = -1; | |
| 817 // } | |
| 818 // state->cursor_pos = line_start; | |
| 819 // } | |
| 820 // | |
| 821 // if (IsKeyPressed(KEY_END)) { | |
| 822 // int line_end = GetLineEnd(text, state->cursor_pos); | |
| 823 // if (shift_pressed) { | |
| 824 // if (state->selection_start < 0) { | |
| 825 // state->selection_start = state->cursor_pos; | |
| 826 // state->selection_end = state->cursor_pos; | |
| 827 // } | |
| 828 // state->selection_end = line_end; | |
| 829 // } else { | |
| 830 // state->selection_start = -1; | |
| 831 // state->selection_end = -1; | |
| 832 // } | |
| 833 // state->cursor_pos = line_end; | |
| 834 // } | |
| 835 // | |
| 836 // // Text Input | |
| 837 // if (!ctrl_pressed) { | |
| 838 // int key = GetCharPressed(); | |
| 839 // while (key > 0) { | |
| 840 // if (key >= 32 && key <= 126) { | |
| 841 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 842 // state->selection_start != state->selection_end) { | |
| 843 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 844 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 845 // PushUndoState(state, text, arena); | |
| 846 // DeleteTextRange(text, sel_min, sel_max); | |
| 847 // state->cursor_pos = sel_min; | |
| 848 // state->selection_start = -1; | |
| 849 // state->selection_end = -1; | |
| 850 // text_changed = TRUE; | |
| 851 // } else if (!text_changed) { | |
| 852 // PushUndoState(state, text, arena); | |
| 853 // } | |
| 854 // | |
| 855 // char insert_str[2] = {(char)key, '\0'}; | |
| 856 // int new_cursor; | |
| 857 // InsertTextAtCursor(text, text_size, state->cursor_pos, insert_str, &new_cursor); | |
| 858 // state->cursor_pos = new_cursor; | |
| 859 // text_changed = TRUE; | |
| 860 // } | |
| 861 // key = GetCharPressed(); | |
| 862 // } | |
| 863 // } | |
| 864 // | |
| 865 // // Enter key | |
| 866 // if (IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) { | |
| 867 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 868 // state->selection_start != state->selection_end) { | |
| 869 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 870 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 871 // PushUndoState(state, text, arena); | |
| 872 // DeleteTextRange(text, sel_min, sel_max); | |
| 873 // state->cursor_pos = sel_min; | |
| 874 // state->selection_start = -1; | |
| 875 // state->selection_end = -1; | |
| 876 // } else { | |
| 877 // PushUndoState(state, text, arena); | |
| 878 // } | |
| 879 // | |
| 880 // int new_cursor; | |
| 881 // InsertTextAtCursor(text, text_size, state->cursor_pos, "\n", &new_cursor); | |
| 882 // state->cursor_pos = new_cursor; | |
| 883 // text_changed = TRUE; | |
| 884 // } | |
| 885 // | |
| 886 // // Backspace | |
| 887 // if (IsKeyPressed(KEY_BACKSPACE) || IsKeyPressedRepeat(KEY_BACKSPACE)) { | |
| 888 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 889 // state->selection_start != state->selection_end) { | |
| 890 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 891 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 892 // PushUndoState(state, text, arena); | |
| 893 // DeleteTextRange(text, sel_min, sel_max); | |
| 894 // state->cursor_pos = sel_min; | |
| 895 // state->selection_start = -1; | |
| 896 // state->selection_end = -1; | |
| 897 // text_changed = TRUE; | |
| 898 // } else if (state->cursor_pos > 0) { | |
| 899 // PushUndoState(state, text, arena); | |
| 900 // DeleteTextRange(text, state->cursor_pos - 1, state->cursor_pos); | |
| 901 // state->cursor_pos--; | |
| 902 // text_changed = TRUE; | |
| 903 // } | |
| 904 // } | |
| 905 // | |
| 906 // // Delete key | |
| 907 // if (IsKeyPressed(KEY_DELETE) || IsKeyPressedRepeat(KEY_DELETE)) { | |
| 908 // text_len = strlen(text); | |
| 909 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 910 // state->selection_start != state->selection_end) { | |
| 911 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 912 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 913 // PushUndoState(state, text, arena); | |
| 914 // DeleteTextRange(text, sel_min, sel_max); | |
| 915 // state->cursor_pos = sel_min; | |
| 916 // state->selection_start = -1; | |
| 917 // state->selection_end = -1; | |
| 918 // text_changed = TRUE; | |
| 919 // } else if (state->cursor_pos < text_len) { | |
| 920 // PushUndoState(state, text, arena); | |
| 921 // DeleteTextRange(text, state->cursor_pos, state->cursor_pos + 1); | |
| 922 // text_changed = TRUE; | |
| 923 // } | |
| 924 // } | |
| 925 // | |
| 926 // // Tab key | |
| 927 // if (IsKeyPressed(KEY_TAB)) { | |
| 928 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 929 // state->selection_start != state->selection_end) { | |
| 930 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 931 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 932 // PushUndoState(state, text, arena); | |
| 933 // DeleteTextRange(text, sel_min, sel_max); | |
| 934 // state->cursor_pos = sel_min; | |
| 935 // state->selection_start = -1; | |
| 936 // state->selection_end = -1; | |
| 937 // } else { | |
| 938 // PushUndoState(state, text, arena); | |
| 939 // } | |
| 940 // | |
| 941 // int new_cursor; | |
| 942 // InsertTextAtCursor(text, text_size, state->cursor_pos, " ", &new_cursor); | |
| 943 // state->cursor_pos = new_cursor; | |
| 944 // text_changed = TRUE; | |
| 945 // } | |
| 946 // | |
| 947 // // Auto-scroll to keep cursor visible | |
| 948 // Vector2 cursor_screen = GetCursorScreenPos(text, state->cursor_pos, bounds, | |
| 949 // should_text_wrap, state->scroll_offset_y, | |
| 950 // GuiGetStyle(DEFAULT, TEXT_SIZE), TEXT_AREA_LINE_HEIGHT); | |
| 951 // | |
| 952 // float visible_top = bounds.y + TEXT_AREA_PADDING; | |
| 953 // float visible_bottom = bounds.y + bounds.height - TEXT_AREA_PADDING - TEXT_AREA_LINE_HEIGHT; | |
| 954 // | |
| 955 // if (cursor_screen.y < visible_top) { | |
| 956 // state->scroll_offset_y -= visible_top - cursor_screen.y; | |
| 957 // } else if (cursor_screen.y > visible_bottom) { | |
| 958 // state->scroll_offset_y += cursor_screen.y - visible_bottom; | |
| 959 // } | |
| 960 // | |
| 961 // state->scroll_offset_y = TA_Max_Float(0, TA_Min_Float(state->scroll_offset_y, max_scroll)); | |
| 962 // } | |
| 963 // | |
| 964 // // Drawing | |
| 965 // DrawRectangleRec(bounds, is_edit_mode ? DARKGRAY : (Color){40, 40, 40, 255}); | |
| 966 // DrawRectangleLinesEx(bounds, 1, is_edit_mode ? WHITE : GRAY); | |
| 967 // | |
| 968 // BeginScissorMode((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height); | |
| 969 // | |
| 970 // float content_x = bounds.x + TEXT_AREA_PADDING; | |
| 971 // float content_y = bounds.y + TEXT_AREA_PADDING - state->scroll_offset_y; | |
| 972 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | |
| 973 // | |
| 974 // text_len = strlen(text); | |
| 975 // | |
| 976 // // Draw selection highlight | |
| 977 // if (state->selection_start >= 0 && state->selection_end >= 0 && | |
| 978 // state->selection_start != state->selection_end) { | |
| 979 // int sel_min = TA_Min_Int(state->selection_start, state->selection_end); | |
| 980 // int sel_max = TA_Max_Int(state->selection_start, state->selection_end); | |
| 981 // | |
| 982 // int line_char_start = 0; | |
| 983 // int visual_line = 0; | |
| 984 // | |
| 985 // for (int i = 0; i <= text_len; i++) { | |
| 986 // boolean is_end = (i == text_len); | |
| 987 // boolean is_newline = (!is_end && text[i] == '\n'); | |
| 988 // boolean should_draw_line = is_end || is_newline; | |
| 989 // | |
| 990 // if (should_text_wrap && !is_end && !is_newline) { | |
| 991 // int line_width = MeasureTextRange(text, line_char_start, i + 1, GuiGetStyle(DEFAULT, TEXT_SIZE)); | |
| 992 // if (line_width > content_width && i > line_char_start) { | |
| 993 // should_draw_line = TRUE; | |
| 994 // } | |
| 995 // } | |
| 996 // | |
| 997 // if (should_draw_line) { | |
| 998 // int line_end = i; | |
| 999 // | |
| 1000 // if (sel_min < line_end && sel_max > line_char_start) { | |
| 1001 // int highlight_start = TA_Max_Int(sel_min, line_char_start); | |
| 1002 // int highlight_end = TA_Min_Int(sel_max, line_end); | |
| 1003 // | |
| 1004 // float x1 = content_x + MeasureTextRange(text, line_char_start, highlight_start, GuiGetStyle(DEFAULT, TEXT_SIZE)); | |
| 1005 // float x2 = content_x + MeasureTextRange(text, line_char_start, highlight_end, GuiGetStyle(DEFAULT, TEXT_SIZE)); | |
| 1006 // float y = content_y + visual_line * TEXT_AREA_LINE_HEIGHT; | |
| 1007 // | |
| 1008 // DrawRectangle((int)x1, (int)y, (int)(x2 - x1), TEXT_AREA_LINE_HEIGHT, | |
| 1009 // Fade(SKYBLUE, 0.5f)); | |
| 1010 // } | |
| 1011 // | |
| 1012 // visual_line++; | |
| 1013 // line_char_start = i + 1; | |
| 1014 // } | |
| 1015 // } | |
| 1016 // } | |
| 1017 // | |
| 1018 // // Draw text with wrapping support | |
| 1019 // if (should_text_wrap) { | |
| 1020 // int line_char_start = 0; | |
| 1021 // int visual_line = 0; | |
| 1022 // | |
| 1023 // for (int i = 0; i <= text_len; i++) { | |
| 1024 // boolean is_end = (i == text_len); | |
| 1025 // boolean is_newline = (!is_end && text[i] == '\n'); | |
| 1026 // boolean should_draw_line = is_end || is_newline; | |
| 1027 // | |
| 1028 // if (!is_end && !is_newline) { | |
| 1029 // int line_width = MeasureTextRange(text, line_char_start, i + 1, GuiGetStyle(DEFAULT, TEXT_SIZE)); | |
| 1030 // if (line_width > content_width && i > line_char_start) { | |
| 1031 // should_draw_line = TRUE; | |
| 1032 // } | |
| 1033 // } | |
| 1034 // | |
| 1035 // if (should_draw_line && i > line_char_start) { | |
| 1036 // char line_buffer[1024]; | |
| 1037 // int line_len = TA_Min_Int(i - line_char_start, 1023); | |
| 1038 // strncpy(line_buffer, text + line_char_start, line_len); | |
| 1039 // line_buffer[line_len] = '\0'; | |
| 1040 // | |
| 1041 // Vector2 draw_text_vector = { | |
| 1042 // .x = content_x, | |
| 1043 // .y = content_y + visual_line * TEXT_AREA_LINE_HEIGHT | |
| 1044 // }; | |
| 1045 // DrawTextEx(GuiGetFont(), line_buffer, draw_text_vector, | |
| 1046 // GuiGetStyle(DEFAULT, TEXT_SIZE), TEXT_SIZE_DEFAULT/GuiGetStyle(DEFAULT, TEXT_SIZE), WHITE); | |
| 1047 // | |
| 1048 // visual_line++; | |
| 1049 // line_char_start = is_newline ? i + 1 : i; | |
| 1050 // } else if (is_newline) { | |
| 1051 // visual_line++; | |
| 1052 // line_char_start = i + 1; | |
| 1053 // } | |
| 1054 // } | |
| 1055 // } else { | |
| 1056 // int line_start = 0; | |
| 1057 // int visual_line = 0; | |
| 1058 // | |
| 1059 // for (int i = 0; i <= text_len; i++) { | |
| 1060 // if (i == text_len || text[i] == '\n') { | |
| 1061 // if (i > line_start) { | |
| 1062 // char line_buffer[1024]; | |
| 1063 // int line_len = TA_Min_Int(i - line_start, 1023); | |
| 1064 // strncpy(line_buffer, text + line_start, line_len); | |
| 1065 // line_buffer[line_len] = '\0'; | |
| 1066 // | |
| 1067 // Vector2 draw_text_vector = { | |
| 1068 // .x = content_x, | |
| 1069 // .y = content_y + visual_line * TEXT_AREA_LINE_HEIGHT | |
| 1070 // }; | |
| 1071 // DrawTextEx(GuiGetFont(), line_buffer, draw_text_vector , | |
| 1072 // GuiGetStyle(DEFAULT, TEXT_SIZE), TEXT_SIZE_DEFAULT/GuiGetStyle(DEFAULT, TEXT_SIZE), WHITE); | |
| 1073 // } | |
| 1074 // visual_line++; | |
| 1075 // line_start = i + 1; | |
| 1076 // } | |
| 1077 // } | |
| 1078 // } | |
| 1079 // | |
| 1080 // // Draw cursor | |
| 1081 // if (is_edit_mode && state->cursor_visible) { | |
| 1082 // Vector2 cursor_pos = GetCursorScreenPos(text, state->cursor_pos, bounds, | |
| 1083 // should_text_wrap, state->scroll_offset_y, | |
| 1084 // GuiGetStyle(DEFAULT, TEXT_SIZE), TEXT_AREA_LINE_HEIGHT); | |
| 1085 // | |
| 1086 // DrawRectangle((int)cursor_pos.x, (int)cursor_pos.y, | |
| 1087 // TEXT_AREA_CURSOR_WIDTH, TEXT_AREA_LINE_HEIGHT, WHITE); | |
| 1088 // } | |
| 1089 // | |
| 1090 // EndScissorMode(); | |
| 1091 // | |
| 1092 // // Draw scrollbar if needed | |
| 1093 // if (max_scroll > 0) { | |
| 1094 // float scrollbar_height = (visible_height / content_height) * visible_height; | |
| 1095 // float scrollbar_y = bounds.y + TEXT_AREA_PADDING + | |
| 1096 // (state->scroll_offset_y / max_scroll) * (visible_height - scrollbar_height); | |
| 1097 // | |
| 1098 // DrawRectangle((int)(bounds.x + bounds.width - 8), (int)scrollbar_y, | |
| 1099 // 6, (int)scrollbar_height, Fade(WHITE, 0.3f)); | |
| 1100 // } | |
| 1101 // | |
| 1102 // return should_toggle_edit_mode; | |
| 1103 // } | |
| 1104 // | |
| 1105 // void GuiTextAreaResetState(int id) { | |
| 1106 // TextAreaState *state = GetTextAreaState(id); | |
| 1107 // if (state) { | |
| 1108 // if (state->undo_stack) { | |
| 1109 // Dowa_Array_Free(state->undo_stack); | |
| 1110 // state->undo_stack = NULL; | |
| 1111 // } | |
| 1112 // state->is_initialized = FALSE; | |
| 1113 // } | |
| 1114 // } | |
| 1115 // | |
| 1116 // void GuiTextAreaResetAllStates(void) { | |
| 1117 // for (int i = 0; i < g_text_area_state_count; i++) { | |
| 1118 // if (g_text_area_states[i].undo_stack) { | |
| 1119 // Dowa_Array_Free(g_text_area_states[i].undo_stack); | |
| 1120 // g_text_area_states[i].undo_stack = NULL; | |
| 1121 // } | |
| 1122 // g_text_area_states[i].is_initialized = FALSE; | |
| 1123 // } | |
| 1124 // g_text_area_state_count = 0; | |
| 1125 // } |