Mercurial
comparison third_party/raylib/custom.c @ 161:87d8d3eb3491
[PostDog] WIP to make it more mordern looking
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 15 Jan 2026 08:29:26 -0800 |
| parents | 7bd795bac997 |
| children | 058de208e640 |
comparison
equal
deleted
inserted
replaced
| 160:948de3f54cea | 161:87d8d3eb3491 |
|---|---|
| 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 | 5 |
| 5 // -- forward declarations --// | 6 // -- forward declarations --// |
| 6 | |
| 7 // --- Default Behaviour that should be part of all raylib gui ---/ | |
| 8 void DefaultBehaviours(); | |
| 9 // --- Increase Font Sizes on key press --- // | |
| 10 void IncreaseFontSize(); | |
| 11 // --- Decrease Font Sizes on key press --- // | |
| 12 void DecreaseFontSize(); | |
| 13 | |
| 14 | |
| 15 void DefaultBehaviours() | 7 void DefaultBehaviours() |
| 16 { | 8 { |
| 17 // Font sizes | 9 // Font sizes |
| 18 IncreaseFontSize(); | 10 IncreaseFontSize(); |
| 19 DecreaseFontSize(); | 11 DecreaseFontSize(); |
| 28 void DecreaseFontSize() | 20 void DecreaseFontSize() |
| 29 { | 21 { |
| 30 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_MINUS)) | 22 if ((IsKeyDown(KEY_LEFT_SUPER) || IsKeyDown(KEY_LEFT_CONTROL)) && IsKeyDown(KEY_MINUS)) |
| 31 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) - 1); | 23 GuiSetStyle(DEFAULT, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE) - 1); |
| 32 } | 24 } |
| 33 | |
| 34 | 25 |
| 35 // --- Layout helper --- // | 26 // --- Layout helper --- // |
| 36 Rectangle RightOf(Rectangle ref, float padding) | 27 Rectangle RightOf(Rectangle ref, float padding) |
| 37 { | 28 { |
| 38 return (Rectangle){ | 29 return (Rectangle){ |
| 81 .width = container.width * ratio, | 72 .width = container.width * ratio, |
| 82 .height = container.height | 73 .height = container.height |
| 83 }; | 74 }; |
| 84 } | 75 } |
| 85 | 76 |
| 86 | 77 void DrawRectangleSelectiveRounded(Rectangle rec, float radius, int segments, Color color, |
| 78 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); | |
| 80 // Top edge (excluding rounded corners) | |
| 81 DrawRectangle(rec.x + (roundTL ? radius : 0), rec.y, rec.width - (roundTL ? radius : 0) - (roundTR ? radius : 0), radius, color); | |
| 82 // Bottom edge | |
| 83 DrawRectangle(rec.x + (roundBL ? radius : 0), rec.y + rec.height - radius, rec.width - (roundBL ? radius : 0) - (roundBR ? radius : 0), radius, color); | |
| 84 // Left edge | |
| 85 DrawRectangle(rec.x, rec.y + (roundTL ? radius : 0), radius, rec.height - (roundTL ? radius : 0) - (roundBL ? radius : 0), color); | |
| 86 // Right edge | |
| 87 DrawRectangle(rec.x + rec.width - radius, rec.y + (roundTR ? radius : 0), radius, rec.height - (roundTR ? radius : 0) - (roundBR ? radius : 0), color); | |
| 88 | |
| 89 if (roundTL) | |
| 90 DrawCircleSector((Vector2){rec.x + radius, rec.y + radius}, radius, 180, 270, segments, color); | |
| 91 | |
| 92 if (roundTR) | |
| 93 DrawCircleSector((Vector2){rec.x + rec.width - radius, rec.y + radius}, radius, 270, 360, segments, color); | |
| 94 | |
| 95 if (roundBR) | |
| 96 DrawCircleSector((Vector2){rec.x + rec.width - radius, rec.y + rec.height - radius}, radius, 0, 90, segments, color); | |
| 97 | |
| 98 if (roundBL) | |
| 99 DrawCircleSector((Vector2){rec.x + radius, rec.y + rec.height - radius}, radius, 90, 180, segments, color); | |
| 100 } | |
| 101 | |
| 102 Rectangle AddPadding(Rectangle rect, float padding) | |
| 103 { | |
| 104 return (Rectangle){ | |
| 105 rect.x + padding, | |
| 106 rect.y + padding, | |
| 107 rect.width - (2 * padding), | |
| 108 rect.height - (2 * padding) | |
| 109 }; | |
| 110 } | |
| 111 | |
| 112 Rectangle AddPaddingAll(Rectangle rect, float top, float right,float down, float left) | |
| 113 { | |
| 114 return (Rectangle){ | |
| 115 rect.x + left, | |
| 116 rect.y + top, | |
| 117 rect.width - (right + left), | |
| 118 rect.height - (top + down), | |
| 119 }; | |
| 120 } | |
| 121 | |
| 122 | |
| 123 | |
| 124 Rectangle AddPaddingHorizontal(Rectangle rect, float padding) | |
| 125 { | |
| 126 return (Rectangle){ | |
| 127 rect.x + padding, | |
| 128 rect.y, | |
| 129 rect.width - (2 * padding), | |
| 130 rect.height | |
| 131 }; | |
| 132 } | |
| 133 | |
| 134 Rectangle AddPaddingVertical(Rectangle rect, float padding) | |
| 135 { | |
| 136 return (Rectangle){ | |
| 137 rect.x, | |
| 138 rect.y + padding, | |
| 139 rect.width, | |
| 140 rect.height - (2 * padding) | |
| 141 }; | |
| 142 } | |
| 143 | |
| 144 // // --- Components ---/ | |
| 145 // #define TEXT_SIZE_DEFAULT 10 | |
| 146 // #define TEXT_AREA_LINE_HEIGHT 20 | |
| 147 // #define TEXT_AREA_PADDING 8 | |
| 148 // #define TEXT_AREA_CURSOR_WIDTH 2 | |
| 149 // #define TEXT_AREA_MAX_UNDO_STATES 64 | |
| 150 // #define TEXT_AREA_MAX_INSTANCES 8 | |
| 151 // | |
| 152 // typedef struct { | |
| 153 // char *text; | |
| 154 // int cursor_pos; | |
| 155 // int selection_start; | |
| 156 // int selection_end; | |
| 157 // } TextAreaUndoEntry; | |
| 158 // | |
| 159 // typedef struct { | |
| 160 // int id; // Unique ID for this text area | |
| 161 // int cursor_pos; // Current cursor position in text | |
| 162 // int selection_start; // Selection start (-1 if no selection) | |
| 163 // int selection_end; // Selection end (-1 if no selection) | |
| 164 // float scroll_offset_y; // Vertical scroll offset | |
| 165 // float scroll_offset_x; // Horizontal scroll offset (for non-wrap mode) | |
| 166 // boolean is_selecting; // Currently dragging to select | |
| 167 // boolean is_initialized; // State has been initialized | |
| 168 // | |
| 169 // // Undo history | |
| 170 // TextAreaUndoEntry *undo_stack; // Dowa array of undo entries | |
| 171 // int undo_index; // Current position in undo stack | |
| 172 // | |
| 173 // // Internal tracking | |
| 174 // double last_blink_time; | |
| 175 // boolean cursor_visible; | |
| 176 // } TextAreaState; | |
| 177 // | |
| 178 // static TextAreaState g_text_area_states[TEXT_AREA_MAX_INSTANCES] = {0}; | |
| 179 // static int g_text_area_state_count = 0; | |
| 180 // static char *g_clipboard_text = NULL; | |
| 181 // static Dowa_Arena *g_text_area_arena = NULL; | |
| 182 // | |
| 183 // // Helper functions | |
| 184 // static int TA_Min_Int(int a, int b) { return a < b ? a : b; } | |
| 185 // static int TA_Max_Int(int a, int b) { return a > b ? a : b; } | |
| 186 // static float TA_Min_Float(float a, float b) { return a < b ? a : b; } | |
| 187 // static float TA_Max_Float(float a, float b) { return a > b ? a : b; } | |
| 188 // | |
| 189 // static TextAreaState* GetTextAreaState(int id) { | |
| 190 // for (int i = 0; i < g_text_area_state_count; i++) { | |
| 191 // if (g_text_area_states[i].id == id && g_text_area_states[i].is_initialized) { | |
| 192 // return &g_text_area_states[i]; | |
| 193 // } | |
| 194 // } | |
| 195 // return NULL; | |
| 196 // } | |
| 197 // | |
| 198 // static TextAreaState* CreateTextAreaState(int id) { | |
| 199 // if (g_text_area_state_count >= TEXT_AREA_MAX_INSTANCES) | |
| 200 // return &g_text_area_states[0]; // Reuse first slot | |
| 201 // | |
| 202 // TextAreaState *state = &g_text_area_states[g_text_area_state_count++]; | |
| 203 // memset(state, 0, sizeof(TextAreaState)); | |
| 204 // state->id = id; | |
| 205 // state->selection_start = -1; | |
| 206 // state->selection_end = -1; | |
| 207 // state->undo_index = -1; | |
| 208 // state->cursor_visible = TRUE; | |
| 209 // state->is_initialized = TRUE; | |
| 210 // return state; | |
| 211 // } | |
| 212 // | |
| 213 // static void GetLineAndColumn(const char *text, int pos, int *out_line, int *out_column) { | |
| 214 // int line = 0; | |
| 215 // int column = 0; | |
| 216 // for (int i = 0; i < pos && text[i] != '\0'; i++) | |
| 217 // { | |
| 218 // if (text[i] == '\n') | |
| 219 // { | |
| 220 // line++; | |
| 221 // column = 0; | |
| 222 // } | |
| 223 // else | |
| 224 // column++; | |
| 225 // } | |
| 226 // *out_line = line; | |
| 227 // *out_column = column; | |
| 228 // } | |
| 229 // | |
| 230 // static int GetPosFromLineColumn(const char *text, int line, int column) { | |
| 231 // int current_line = 0; | |
| 232 // int current_col = 0; | |
| 233 // int i = 0; | |
| 234 // | |
| 235 // while (text[i] != '\0') | |
| 236 // { | |
| 237 // if (current_line == line && current_col == column) | |
| 238 // return i; | |
| 239 // | |
| 240 // if (text[i] == '\n') | |
| 241 // { | |
| 242 // if (current_line == line) | |
| 243 // return i; | |
| 244 // current_line++; | |
| 245 // current_col = 0; | |
| 246 // } | |
| 247 // else | |
| 248 // current_col++; | |
| 249 // i++; | |
| 250 // } | |
| 251 // return i; | |
| 252 // } | |
| 253 // | |
| 254 // static int GetLineStart(const char *text, int pos) { | |
| 255 // int i = pos; | |
| 256 // while (i > 0 && text[i - 1] != '\n') | |
| 257 // i--; | |
| 258 // return i; | |
| 259 // } | |
| 260 // | |
| 261 // static int GetLineEnd(const char *text, int pos) { | |
| 262 // int i = pos; | |
| 263 // int len = strlen(text); | |
| 264 // while (i < len && text[i] != '\n') | |
| 265 // i++; | |
| 266 // return i; | |
| 267 // } | |
| 268 // | |
| 269 // static int CountLines(const char *text) { | |
| 270 // int count = 1; | |
| 271 // for (int i = 0; text[i] != '\0'; i++) | |
| 272 // if (text[i] == '\n') count++; | |
| 273 // return count; | |
| 274 // } | |
| 275 // | |
| 276 // static int MeasureTextRange(const char *text, int start, int end, int font_size) { | |
| 277 // if (start >= end) return 0; | |
| 278 // | |
| 279 // char temp[1024]; | |
| 280 // int len = TA_Min_Int(end - start, 1023); | |
| 281 // strncpy(temp, text + start, len); | |
| 282 // temp[len] = '\0'; | |
| 283 // | |
| 284 // return MeasureTextEx(GuiGetFont(), temp, font_size, TEXT_SIZE_DEFAULT/GuiGetStyle(DEFAULT, TEXT_SIZE)).x; | |
| 285 // } | |
| 286 // | |
| 287 // static int GetCharIndexFromPos(const char *text, Rectangle bounds, Vector2 pos, | |
| 288 // boolean wrap, float scroll_y, int font_size, int line_height) { | |
| 289 // if (!text || strlen(text) == 0) return 0; | |
| 290 // | |
| 291 // float content_x = bounds.x + TEXT_AREA_PADDING; | |
| 292 // float content_y = bounds.y + TEXT_AREA_PADDING - scroll_y; | |
| 293 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | |
| 294 // | |
| 295 // int text_len = strlen(text); | |
| 296 // | |
| 297 // float click_line_y = (pos.y - content_y) / line_height; | |
| 298 // int target_visual_line = (int)click_line_y; | |
| 299 // if (target_visual_line < 0) target_visual_line = 0; | |
| 300 // | |
| 301 // int current_visual_line = 0; | |
| 302 // int i = 0; | |
| 303 // int line_char_start = 0; | |
| 304 // | |
| 305 // while (i <= text_len) { | |
| 306 // boolean is_newline = (i < text_len && text[i] == '\n'); | |
| 307 // | |
| 308 // if (wrap && i > line_char_start) { | |
| 309 // int line_width = MeasureTextRange(text, line_char_start, i, font_size); | |
| 310 // if (line_width > content_width && i > line_char_start + 1) { | |
| 311 // int wrap_pos = i - 1; | |
| 312 // for (int j = i - 1; j > line_char_start; j--) { | |
| 313 // if (text[j] == ' ') { | |
| 314 // wrap_pos = j; | |
| 315 // break; | |
| 316 // } | |
| 317 // } | |
| 318 // | |
| 319 // if (current_visual_line == target_visual_line) { | |
| 320 // float click_x = pos.x - content_x; | |
| 321 // int best_pos = line_char_start; | |
| 322 // float best_dist = 99999; | |
| 323 // | |
| 324 // for (int k = line_char_start; k <= wrap_pos; k++) { | |
| 325 // int char_x = MeasureTextRange(text, line_char_start, k, font_size); | |
| 326 // float dist = (float)(click_x - char_x); | |
| 327 // if (dist < 0) dist = -dist; | |
| 328 // if (dist < best_dist) { | |
| 329 // best_dist = dist; | |
| 330 // best_pos = k; | |
| 331 // } | |
| 332 // } | |
| 333 // return best_pos; | |
| 334 // } | |
| 335 // | |
| 336 // current_visual_line++; | |
| 337 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | |
| 338 // i = line_char_start; | |
| 339 // continue; | |
| 340 // } | |
| 341 // } | |
| 342 // | |
| 343 // if (is_newline || i == text_len) { | |
| 344 // if (current_visual_line == target_visual_line || i == text_len) { | |
| 345 // float click_x = pos.x - content_x; | |
| 346 // int line_end = i; | |
| 347 // int best_pos = line_char_start; | |
| 348 // float best_dist = 99999; | |
| 349 // | |
| 350 // for (int k = line_char_start; k <= line_end; k++) { | |
| 351 // int char_x = MeasureTextRange(text, line_char_start, k, font_size); | |
| 352 // float dist = (float)(click_x - char_x); | |
| 353 // if (dist < 0) dist = -dist; | |
| 354 // if (dist < best_dist) { | |
| 355 // best_dist = dist; | |
| 356 // best_pos = k; | |
| 357 // } | |
| 358 // } | |
| 359 // return TA_Min_Int(best_pos, text_len); | |
| 360 // } | |
| 361 // | |
| 362 // current_visual_line++; | |
| 363 // line_char_start = i + 1; | |
| 364 // } | |
| 365 // | |
| 366 // i++; | |
| 367 // } | |
| 368 // | |
| 369 // return text_len; | |
| 370 // } | |
| 371 // | |
| 372 // static Vector2 GetCursorScreenPos(const char *text, int cursor_pos, Rectangle bounds, | |
| 373 // boolean wrap, float scroll_y, int font_size, int line_height) { | |
| 374 // float content_x = bounds.x + TEXT_AREA_PADDING; | |
| 375 // float content_y = bounds.y + TEXT_AREA_PADDING - scroll_y; | |
| 376 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | |
| 377 // | |
| 378 // if (!text || cursor_pos == 0) { | |
| 379 // return (Vector2){content_x, content_y}; | |
| 380 // } | |
| 381 // | |
| 382 // int text_len = strlen(text); | |
| 383 // cursor_pos = TA_Min_Int(cursor_pos, text_len); | |
| 384 // | |
| 385 // int visual_line = 0; | |
| 386 // int line_char_start = 0; | |
| 387 // | |
| 388 // for (int i = 0; i <= cursor_pos; i++) { | |
| 389 // if (i == cursor_pos) { | |
| 390 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | |
| 391 // float y = content_y + visual_line * line_height; | |
| 392 // return (Vector2){x, y}; | |
| 393 // } | |
| 394 // | |
| 395 // if (text[i] == '\n') { | |
| 396 // visual_line++; | |
| 397 // line_char_start = i + 1; | |
| 398 // } else if (wrap) { | |
| 399 // int line_width = MeasureTextRange(text, line_char_start, i + 1, font_size); | |
| 400 // if (line_width > content_width && i > line_char_start) { | |
| 401 // int wrap_pos = i; | |
| 402 // for (int j = i; j > line_char_start; j--) { | |
| 403 // if (text[j] == ' ') { | |
| 404 // wrap_pos = j; | |
| 405 // break; | |
| 406 // } | |
| 407 // } | |
| 408 // | |
| 409 // if (cursor_pos <= wrap_pos) { | |
| 410 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | |
| 411 // float y = content_y + visual_line * line_height; | |
| 412 // return (Vector2){x, y}; | |
| 413 // } | |
| 414 // | |
| 415 // visual_line++; | |
| 416 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | |
| 417 // } | |
| 418 // } | |
| 419 // } | |
| 420 // | |
| 421 // float x = content_x + MeasureTextRange(text, line_char_start, cursor_pos, font_size); | |
| 422 // float y = content_y + visual_line * line_height; | |
| 423 // return (Vector2){x, y}; | |
| 424 // } | |
| 425 // | |
| 426 // static float GetContentHeight(const char *text, Rectangle bounds, boolean wrap, | |
| 427 // int font_size, int line_height) { | |
| 428 // if (!text || strlen(text) == 0) return line_height; | |
| 429 // | |
| 430 // float content_width = bounds.width - TEXT_AREA_PADDING * 2; | |
| 431 // int visual_lines = 1; | |
| 432 // int line_char_start = 0; | |
| 433 // int text_len = strlen(text); | |
| 434 // | |
| 435 // for (int i = 0; i <= text_len; i++) { | |
| 436 // if (i == text_len || text[i] == '\n') { | |
| 437 // visual_lines++; | |
| 438 // line_char_start = i + 1; | |
| 439 // } else if (wrap) { | |
| 440 // int line_width = MeasureTextRange(text, line_char_start, i + 1, font_size); | |
| 441 // if (line_width > content_width && i > line_char_start) { | |
| 442 // int wrap_pos = i; | |
| 443 // for (int j = i; j > line_char_start; j--) { | |
| 444 // if (text[j] == ' ') { | |
| 445 // wrap_pos = j; | |
| 446 // break; | |
| 447 // } | |
| 448 // } | |
| 449 // visual_lines++; | |
| 450 // line_char_start = (text[wrap_pos] == ' ') ? wrap_pos + 1 : wrap_pos; | |
| 451 // } | |
| 452 // } | |
| 453 // } | |
| 454 // | |
| 455 // return visual_lines * line_height; | |
| 456 // } | |
| 457 // | |
| 458 // static void PushUndoState(TextAreaState *state, const char *text, Dowa_Arena *arena) { | |
| 459 // TextAreaUndoEntry entry; | |
| 460 // entry.text = Dowa_String_Copy_Arena((char*)text, arena); | |
| 461 // entry.cursor_pos = state->cursor_pos; | |
| 462 // entry.selection_start = state->selection_start; | |
| 463 // entry.selection_end = state->selection_end; | |
| 464 // | |
| 465 // if (state->undo_index < (int)Dowa_Array_Length(state->undo_stack) - 1) { | |
| 466 // dowa__header(state->undo_stack)->length = state->undo_index + 1; | |
| 467 // } | |
| 468 // | |
| 469 // Dowa_Array_Push_Arena(state->undo_stack, entry, arena); | |
| 470 // state->undo_index = Dowa_Array_Length(state->undo_stack) - 1; | |
| 471 // | |
| 472 // if (Dowa_Array_Length(state->undo_stack) > TEXT_AREA_MAX_UNDO_STATES) { | |
| 473 // for (int i = 0; i < (int)Dowa_Array_Length(state->undo_stack) - 1; i++) { | |
| 474 // state->undo_stack[i] = state->undo_stack[i + 1]; | |
| 475 // } | |
| 476 // dowa__header(state->undo_stack)->length--; | |
| 477 // state->undo_index--; | |
| 478 // } | |
| 479 // } | |
| 480 // | |
| 481 // static boolean PerformUndo(TextAreaState *state, char *text, int text_size) { | |
| 482 // if (state->undo_index <= 0) return FALSE; | |
| 483 // | |
| 484 // state->undo_index--; | |
| 485 // TextAreaUndoEntry *entry = &state->undo_stack[state->undo_index]; | |
| 486 // | |
| 487 // strncpy(text, entry->text, text_size - 1); | |
| 488 // text[text_size - 1] = '\0'; | |
| 489 // state->cursor_pos = entry->cursor_pos; | |
| 490 // state->selection_start = entry->selection_start; | |
| 491 // state->selection_end = entry->selection_end; | |
| 492 // | |
| 493 // return TRUE; | |
| 494 // } | |
| 495 // | |
| 496 // static boolean PerformRedo(TextAreaState *state, char *text, int text_size) { | |
| 497 // if (state->undo_index >= (int)Dowa_Array_Length(state->undo_stack) - 1) return FALSE; | |
| 498 // | |
| 499 // state->undo_index++; | |
| 500 // TextAreaUndoEntry *entry = &state->undo_stack[state->undo_index]; | |
| 501 // | |
| 502 // strncpy(text, entry->text, text_size - 1); | |
| 503 // text[text_size - 1] = '\0'; | |
| 504 // state->cursor_pos = entry->cursor_pos; | |
| 505 // state->selection_start = entry->selection_start; | |
| 506 // state->selection_end = entry->selection_end; | |
| 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 // } |