2020-02-10 23:57:51 +01:00
/*******************************************************************************************
*
* raygui - Controls test
*
* TEST CONTROLS :
* - GuiTextEditor ( )
*
* DEPENDENCIES :
* raylib 3.0 - Windowing / input management and drawing .
* raygui 2.7 - Immediate - mode GUI controls .
*
* COMPILATION ( Windows - MinGW ) :
* gcc - o $ ( NAME_PART ) . exe $ ( FILE_NAME ) - I . . / . . / src - lraylib - lopengl32 - lgdi32 - std = c99
*
* LICENSE : zlib / libpng
*
* Copyright ( c ) 2020 Ramon Santamaria ( @ raysan5 )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "raylib.h"
# define RAYGUI_IMPLEMENTATION
# define RAYGUI_SUPPORT_ICONS
# include "../../src/raygui.h"
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static char text01 [ 128 ] = " Lorem ipsum dolor sit amet, \xE7 \x8C \xBF \xE3 \x82 \x82 \xE6 \x9C \xA8 \xE3 \x81 \x8B \xE3 \x82 \x89 \xE8 \x90 \xBD \xE3 \x81 \xA1 \xE3 \x82 \x8B consectetur adipiscing elit... \0 " ; // including some hiragana/kanji
static char text02 [ 128 ] = " Here's another, much bigger textbox extended. \xf4 \xa1 \xa1 \xff TIP: try COPY/PASTE ;) \0 " ; // Including some invalid UTF8
bool GuiTextEditor ( Rectangle bounds , char * text , int textLen , bool editMode ) ;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main ( int argc , char * * argv )
{
// Initialization
//---------------------------------------------------------------------------------------
const int screenWidth = 800 ;
const int screenHeight = 450 ;
InitWindow ( screenWidth , screenHeight , " raygui - gui text editor test " ) ;
Font font = { 0 } ;
bool textEditor01EditMode = false ;
bool textEditor02EditMode = false ;
SetTargetFPS ( 60 ) ;
//---------------------------------------------------------------------------------------
// Main game loop
while ( ! WindowShouldClose ( ) ) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
Vector2 mouse = GetMousePosition ( ) ;
// Fonts drag & drop logic
if ( IsFileDropped ( ) )
{
int count = 0 ;
char * * files = GetDroppedFiles ( & count ) ;
if ( IsFileExtension ( files [ 0 ] , " .ttf " ) | |
IsFileExtension ( files [ 0 ] , " .otf " ) | |
IsFileExtension ( files [ 0 ] , " .fnt " ) )
{
Font fnt = LoadFont ( files [ 0 ] ) ;
if ( fnt . texture . id ! = 0 )
{
// Font was loaded, only change font on success
GuiSetFont ( fnt ) ;
// Remove old font
if ( font . texture . id ! = 0 ) UnloadFont ( font ) ;
font = fnt ;
}
}
ClearDroppedFiles ( ) ;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing ( ) ;
ClearBackground ( RAYWHITE ) ;
// Draw textboxes extended
//---------------------------------------------------------------------------------------
if ( GuiTextEditor ( ( Rectangle ) { 20 , 20 , 380 , 410 } , text01 , strlen ( text01 ) , textEditor01EditMode ) ) textEditor01EditMode = ! textEditor01EditMode ;
if ( GuiTextEditor ( ( Rectangle ) { 420 , 20 , 360 , 410 } , text02 , strlen ( text02 ) , textEditor02EditMode ) ) textEditor02EditMode = ! textEditor02EditMode ;
//---------------------------------------------------------------------------------------
EndDrawing ( ) ;
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow ( ) ; // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0 ;
}
// Text editor control (Advanced text box)
bool GuiTextEditor ( Rectangle bounds , char * text , int textSize , bool editMode )
{
static Rectangle cursor = { 0 } ; // Cursor position and size
static int framesCounter = 0 ; // Blinking cursor frames counter
static int cursorCodepoint = - 1 ;
static int selectStartCp = - 1 ;
static int selectLengthCp = 0 ;
GuiControlState state = guiState ;
bool pressed = false ;
bool textWrap = true ; // TODO: Word-Wrap vs Char-Wrap -> textWrapMode { NO_WRAP_LOCK, NO_WRAP_OVERFLOW, CHAR_WRAP, WORD_WRAP }
// WARNING: First string full traversal
int codepointCount = GetCodepointsCount ( text ) ;
int textLen = strlen ( text ) ; // Text length in bytes
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
if ( editMode )
{
state = GUI_STATE_PRESSED ;
framesCounter + + ;
// TODO: Cursor position logic (mouse and keys)
// Characters selection logic
if ( selectStartCp ! = - 1 )
{
if ( IsKeyDown ( KEY_LEFT_SHIFT ) & & IsKeyPressed ( KEY_RIGHT ) )
{
selectLengthCp + + ;
if ( selectLengthCp > = ( codepointCount - selectStartCp ) ) selectLengthCp = codepointCount - selectStartCp ;
}
if ( IsKeyDown ( KEY_LEFT_SHIFT ) & & IsKeyPressed ( KEY_LEFT ) )
{
selectLengthCp - - ;
if ( selectLengthCp < 0 ) selectLengthCp = 0 ;
}
}
2020-12-18 19:50:57 +01:00
int key = GetCharPressed ( ) ;
2020-02-10 23:57:51 +01:00
// TODO: On key pressed, place new character in cursor position
// Exit edit mode logic
if ( IsKeyPressed ( KEY_ENTER ) | | ( ! CheckCollisionPointRec ( mousePoint , bounds ) & & IsMouseButtonPressed ( 0 ) ) ) pressed = true ;
}
else
{
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
if ( IsMouseButtonPressed ( 0 ) ) pressed = true ;
}
}
if ( pressed )
{
// Exiting edit mode, reset temp variables
framesCounter = 0 ;
cursor = ( Rectangle ) { 0 } ;
cursorCodepoint = - 1 ;
selectStartCp = - 1 ;
selectLengthCp = 0 ;
}
}
//--------------------------------------------------------------------
// Draw control
//--------------------------------------------------------------------
DrawRectangleLinesEx ( bounds , GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) ) ;
if ( state = = GUI_STATE_PRESSED ) DrawRectangle ( bounds . x + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . y + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . width - 2 * GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . height - 2 * GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
else if ( state = = GUI_STATE_DISABLED ) DrawRectangle ( bounds . x + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . y + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . width - 2 * GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , bounds . height - 2 * GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
Font font = GetFontDefault ( ) ;
int textOffsetY = 0 ; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f ; // Offset X to next character to draw
float scaleFactor = GuiGetStyle ( DEFAULT , TEXT_SIZE ) * 2 / font . baseSize ; // Character quad scaling factor
for ( int i = 0 , cp = 0 ; i < textLen ; i + + )
{
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0 ;
int codepoint = GetNextCodepoint ( & text [ i ] , & codepointByteCount ) ;
int index = GetGlyphIndex ( font , codepoint ) ;
Rectangle rec = { bounds . x + textOffsetX + font . chars [ index ] . offsetX * scaleFactor ,
bounds . y + textOffsetY + font . chars [ index ] . offsetY * scaleFactor ,
font . recs [ index ] . width * scaleFactor , font . recs [ index ] . height * scaleFactor } ;
// Automatic line break to wrap text inside box
if ( textWrap & & ( ( rec . x + rec . width ) > = ( bounds . x + bounds . width ) ) )
{
textOffsetY + = ( int ) ( ( font . baseSize + font . baseSize / 2 ) * scaleFactor ) ;
textOffsetX = 0.0f ;
// Recalculate drawing rectangle position
rec = ( Rectangle ) { bounds . x + textOffsetX + font . chars [ index ] . offsetX * scaleFactor ,
bounds . y + textOffsetY + font . chars [ index ] . offsetY * scaleFactor ,
font . recs [ index ] . width * scaleFactor , font . recs [ index ] . height * scaleFactor } ;
}
// Check selected codepoint
if ( editMode )
{
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) & & CheckCollisionPointRec ( GetMousePosition ( ) , rec ) )
{
cursor = rec ;
cursorCodepoint = cp ;
selectStartCp = cursorCodepoint ;
selectLengthCp = 0 ;
// TODO: Place cursor at the end if pressed out of text
}
// On mouse left button down allow text selection
if ( ( selectStartCp ! = - 1 ) & & IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) & & CheckCollisionPointRec ( GetMousePosition ( ) , rec ) )
{
if ( cp > = selectStartCp ) selectLengthCp = cp - selectStartCp ;
else if ( cp < selectStartCp )
{
//int temp = selectStartCp;
//selectStartCp = cp;
//selectLengthCp = temp - selectStartCp;
}
}
}
if ( codepoint = = ' \n ' ) // Line break character
{
// NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user
textOffsetY + = ( int ) ( ( font . baseSize + font . baseSize / 2 ) * scaleFactor ) ;
textOffsetX = 0.0f ;
}
else
{
// Draw codepoint glyph
if ( ( codepoint ! = ' ' ) & & ( codepoint ! = ' \t ' ) & & ( ( rec . x + rec . width ) < ( bounds . x + bounds . width ) ) )
{
DrawTexturePro ( font . texture , font . recs [ index ] , rec , ( Vector2 ) { 0 , 0 } , 0.0f , GetColor ( GuiGetStyle ( DEFAULT , TEXT_COLOR_NORMAL ) ) ) ;
}
// TODO: On text overflow do something... move text to the left?
}
// Draw codepoints selection from selectStartCp to selectLengthCp
// TODO: Consider spacing when drawing selected characters background
if ( editMode & & ( selectStartCp ! = - 1 ) & & ( ( cp > = selectStartCp ) & & ( cp < = ( selectStartCp + selectLengthCp ) ) ) ) DrawRectangleRec ( rec , MAROON ) ;
if ( font . chars [ index ] . advanceX = = 0 ) textOffsetX + = ( ( float ) font . recs [ index ] . width * scaleFactor + GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
else textOffsetX + = ( ( float ) font . chars [ index ] . advanceX * scaleFactor + GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
i + = ( codepointByteCount - 1 ) ; // Move text bytes counter to next codepoint
cp + + ;
}
// Draw blinking cursor
if ( editMode & & ( ( framesCounter / 20 ) % 2 = = 0 ) ) DrawRectangleRec ( cursor , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER_COLOR_PRESSED ) ) , guiAlpha ) ) ;
//GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
//--------------------------------------------------------------------
return pressed ;
}