fix some stuff that used RAD types and so were totally broken, add a compile test/sample

pull/1/head
Sean Barrett 2014-05-27 22:56:57 -07:00
parent 1d2770394a
commit e63b3e0702
3 changed files with 127 additions and 41 deletions

View File

@ -1,4 +1,4 @@
// stb_textedit.h - v1.1 - public domain - Sean Barrett
// stb_textedit.h - v1.2 - public domain - Sean Barrett
// Development of this library was sponsored by RAD Game Tools
//
// This C header file implements the guts of a multi-line text-editing
@ -30,6 +30,7 @@
//
// VERSION HISTORY
//
// 1.2 (2013-05-27) fix some RAD types that had crept into the new code
// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE )
// 1.0 (2012-07-26) improve documentation, initial public release
// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode
@ -419,7 +420,7 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
state->cursor = stb_text_locate_coord(str, x, y);
state->select_start = state->cursor;
state->select_end = state->cursor;
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
@ -529,7 +530,7 @@ static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *sta
{
stb_text_makeundo_delete(str, state, where, len);
STB_TEXTEDIT_DELETECHARS(str, where, len);
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
// delete the section
@ -544,7 +545,7 @@ static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_Textedit
stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
state->select_start = state->cursor = state->select_end;
}
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
}
@ -565,7 +566,7 @@ static void stb_textedit_move_to_first(STB_TexteditState *state)
stb_textedit_sortselection(state);
state->cursor = state->select_start;
state->select_end = state->select_start;
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
}
@ -577,16 +578,14 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
stb_textedit_clamp(str, state);
state->cursor = state->select_end;
state->select_start = state->select_end;
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
}
#ifdef STB_TEXTEDIT_IS_SPACE
static rrbool is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx )
static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx )
{
RR_ASSERT( _idx < STB_TEXTEDIT_STRINGLEN(_str) );
return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : true;
return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1;
}
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state )
@ -629,15 +628,16 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
{
if (STB_TEXT_HAS_SELECTION(state)) {
stb_textedit_delete_selection(str,state); // implicity clamps
state->has_preferred_x = false;
state->has_preferred_x = 0;
return 1;
}
return 0;
}
// API paste: replace existing selection with passed-in text
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
{
STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext;
// if there's a selection, the paste should delete it
stb_textedit_clamp(str, state);
stb_textedit_delete_selection(str,state);
@ -645,7 +645,7 @@ static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
stb_text_makeundo_insert(str, state, state->cursor, len);
state->cursor += len;
state->has_preferred_x = false;
state->has_preferred_x = 0;
return 1;
}
// remove the undo since we didn't actually insert the characters
@ -673,14 +673,14 @@ retry:
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
++state->cursor;
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
} else {
stb_textedit_delete_selection(str,state); // implicity clamps
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
stb_text_makeundo_insert(str, state, state->cursor, 1);
++state->cursor;
state->has_preferred_x = false;
state->has_preferred_x = 0;
}
}
}
@ -695,12 +695,12 @@ retry:
case STB_TEXTEDIT_K_UNDO:
stb_text_undo(str, state);
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_REDO:
stb_text_redo(str, state);
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_LEFT:
@ -710,7 +710,7 @@ retry:
else
if (state->cursor > 0)
--state->cursor;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_RIGHT:
@ -720,7 +720,7 @@ retry:
else
++state->cursor;
stb_textedit_clamp(str, state);
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
@ -730,7 +730,7 @@ retry:
if (state->select_end > 0)
--state->select_end;
state->cursor = state->select_end;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
#ifdef STB_TEXTEDIT_IS_SPACE
@ -779,7 +779,7 @@ retry:
++state->select_end;
stb_textedit_clamp(str, state);
state->cursor = state->select_end;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_DOWN:
@ -805,14 +805,14 @@ retry:
// now find character position down a row
if (find.length) {
F32 goal_x = state->has_preferred_x ? state->preferred_x : find.x;
F32 x;
S32 start = find.first_char + find.length;
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
int start = find.first_char + find.length;
state->cursor = start;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
F32 dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@ -824,7 +824,7 @@ retry:
}
stb_textedit_clamp(str, state);
state->has_preferred_x = true;
state->has_preferred_x = 1;
state->preferred_x = goal_x;
if (sel)
@ -857,13 +857,13 @@ retry:
// can only go up if there's a previous row
if (find.prev_first != find.first_char) {
// now find character position up a row
F32 goal_x = state->has_preferred_x ? state->preferred_x : find.x;
F32 x;
float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
float x;
state->cursor = find.prev_first;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
x = row.x0;
for (i=0; i < row.num_chars; ++i) {
F32 dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@ -875,7 +875,7 @@ retry:
}
stb_textedit_clamp(str, state);
state->has_preferred_x = true;
state->has_preferred_x = 1;
state->preferred_x = goal_x;
if (sel)
@ -893,7 +893,7 @@ retry:
if (state->cursor < n)
stb_textedit_delete(str, state, state->cursor, 1);
}
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_BACKSPACE:
@ -907,30 +907,30 @@ retry:
--state->cursor;
}
}
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_TEXTSTART:
state->cursor = state->select_start = state->select_end = 0;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_TEXTEND:
state->cursor = STB_TEXTEDIT_STRINGLEN(str);
state->select_start = state->select_end = 0;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
stb_textedit_prep_selection_at_cursor(state);
state->cursor = state->select_end = 0;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
stb_textedit_prep_selection_at_cursor(state);
state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
@ -940,7 +940,7 @@ retry:
stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = find.first_char;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
}
@ -950,7 +950,7 @@ retry:
stb_textedit_move_to_first(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->cursor = find.first_char + find.length;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
}
@ -960,7 +960,7 @@ retry:
stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->select_end = find.first_char;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
}
@ -970,7 +970,7 @@ retry:
stb_textedit_prep_selection_at_cursor(state);
stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
state->select_end = find.first_char + find.length;
state->has_preferred_x = false;
state->has_preferred_x = 0;
break;
}

View File

@ -66,7 +66,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zd /Od /I "..\.." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "MAIN_TEST" /FR /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /GX /Zd /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "MAIN_TEST" /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@ -104,5 +104,9 @@ SOURCE=..\stb_vorbis.c
SOURCE=.\test_truetype.c
# End Source File
# Begin Source File
SOURCE=.\textedit_sample.c
# End Source File
# End Target
# End Project

82
tests/textedit_sample.c Normal file
View File

@ -0,0 +1,82 @@
// I haven't actually tested this yet, this is just to make sure it compiles
#include <stdlib.h>
#include <string.h> // memmove
#include <ctype.h> // isspace
#define STB_TEXTEDIT_CHARTYPE char
#define STB_TEXTEDIT_STRING text_control
// get the base type
#include "stb_textedit.h"
// define our editor structure
typedef struct
{
char *string;
int stringlen;
STB_TexteditState state;
} text_control;
// define the functions we need
void layout_func(StbTexteditRow *row, STB_TEXTEDIT_STRING *str, int start_i)
{
int remaining_chars = str->stringlen - start_i;
row->num_chars = remaining_chars > 20 ? 20 : remaining_chars; // should do real word wrap here
row->x0 = 0;
row->x1 = 20; // need to account for actual size of characters
row->baseline_y_delta = 1.25;
row->ymin = -1;
row->ymax = 0;
}
int delete_chars(STB_TEXTEDIT_STRING *str, int pos, int num)
{
memmove(&str->string[pos], &str->string[pos+num], str->stringlen - (pos-num));
str->stringlen -= num;
return 1; // always succeeds
}
int insert_chars(STB_TEXTEDIT_STRING *str, int pos, STB_TEXTEDIT_CHARTYPE *newtext, int num)
{
str->string = realloc(str, str->stringlen + num);
memmove(&str->string[pos+num], &str->string[pos], str->stringlen - pos);
memcpy(&str->string[pos], newtext, num);
return 1; // always succeeds
}
// define all the #defines needed
#define KEYDOWN_BIT 0x80000000
#define STB_TEXTEDIT_STRINGLEN(tc) ((tc)->stringlen)
#define STB_TEXTEDIT_LAYOUTROW layout_func
#define STB_TEXTEDIT_GETWIDTH(tc,n,i) (1) // quick hack for monospaced
#define STB_TEXTEDIT_KEYTOTEXT(key) (((key) & KEYDOWN_BIT) ? 0 : (key))
#define STB_TEXTEDIT_GETCHAR(tc,i) ((tc)->string[i])
#define STB_TEXTEDIT_NEWLINE '\n'
#define STB_TEXTEDIT_IS_SPACE(ch) isspace(ch)
#define STB_TEXTEDIT_DELETECHARS delete_chars
#define STB_TEXTEDIT_INSERTCHARS insert_chars
#define STB_TEXTEDIT_K_SHIFT 0x40000000
#define STB_TEXTEDIT_K_CONTROL 0x20000000
#define STB_TEXTEDIT_K_LEFT (KEYDOWN_BIT | 1) // actually use VK_LEFT, SDLK_LEFT, etc
#define STB_TEXTEDIT_K_RIGHT (KEYDOWN_BIT | 2) // VK_RIGHT
#define STB_TEXTEDIT_K_UP (KEYDOWN_BIT | 3) // VK_UP
#define STB_TEXTEDIT_K_DOWN (KEYDOWN_BIT | 4) // VK_DOWN
#define STB_TEXTEDIT_K_LINESTART (KEYDOWN_BIT | 5) // VK_HOME
#define STB_TEXTEDIT_K_LINEEND (KEYDOWN_BIT | 6) // VK_END
#define STB_TEXTEDIT_K_TEXTSTART (STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_CONTROL)
#define STB_TEXTEDIT_K_TEXTEND (STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_CONTROL)
#define STB_TEXTEDIT_K_DELETE (KEYDOWN_BIT | 7) // VK_DELETE
#define STB_TEXTEDIT_K_BACKSPACE (KEYDOWN_BIT | 8) // VK_BACKSPACE
#define STB_TEXTEDIT_K_UNDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'z')
#define STB_TEXTEDIT_K_REDO (KEYDOWN_BIT | STB_TEXTEDIT_K_CONTROL | 'y')
#define STB_TEXTEDIT_K_INSERT (KEYDOWN_BIT | 9) // VK_INSERT
#define STB_TEXTEDIT_K_WORDLEFT (STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_CONTROL)
#define STB_TEXTEDIT_K_WORDRIGHT (STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_CONTROL)
#define STB_TEXTEDIT_K_PGUP (KEYDOWN_BIT | 10) // VK_PGUP -- not implemented
#define STB_TEXTEDIT_K_PGDOWN (KEYDOWN_BIT | 11) // VK_PGDOWN -- not implemented
#define STB_TEXTEDIT_IMPLEMENTATION
#include "stb_textedit.h"