Add text input function (broken, read description)

Note: using this function breaks the graphics rendering at the moment,
due to code inconsistencies (utilizing SDL renderers when the rest of
the program uses GL ones, mainly), working on fixes for it!
This commit is contained in:
Vinyl Darkscratch 2017-04-04 00:43:53 -07:00
parent 3913a3ef74
commit 6b5eff715b
5 changed files with 275 additions and 2 deletions

View file

@ -10,7 +10,6 @@
RB_METHOD(oneshotSetYesNo)
{
RB_UNUSED_PARAM;
const char *yes;
const char *no;
rb_get_args(argc, argv, "zz", &yes, &no RB_ARG_END);
@ -21,7 +20,6 @@ RB_METHOD(oneshotSetYesNo)
RB_METHOD(oneshotMsgBox)
{
RB_UNUSED_PARAM;
int type;
VALUE body;
VALUE title = Qnil;
@ -31,6 +29,19 @@ RB_METHOD(oneshotMsgBox)
return rb_bool_new(shState->oneshot().msgbox(type, bodyStr.c_str(), titleStr.c_str()));
}
RB_METHOD(oneshotTextInput)
{
// const char* prompt, int char_limit, const char* font
RB_UNUSED_PARAM;
VALUE prompt;
int char_limit = 100;
VALUE font = Qnil;
rb_get_args(argc, argv, "S|iS", &prompt, &char_limit, &font RB_ARG_END);
std::string promptStr = std::string(RSTRING_PTR(prompt), RSTRING_LEN(prompt));
std::string fontStr = (font == Qnil) ? "" : std::string(RSTRING_PTR(font), RSTRING_LEN(font));
return rb_str_new2(shState->oneshot().textinput(promptStr.c_str(), char_limit, fontStr.c_str()).c_str());
}
RB_METHOD(oneshotResetObscured)
{
RB_UNUSED_PARAM;
@ -108,6 +119,7 @@ void oneshotBindingInit()
//Functions
_rb_define_module_function(module, "set_yes_no", oneshotSetYesNo);
_rb_define_module_function(module, "msgbox", oneshotMsgBox);
_rb_define_module_function(module, "textinput", oneshotTextInput);
_rb_define_module_function(module, "reset_obscured", oneshotResetObscured);
_rb_define_module_function(module, "obscured_cleared?", oneshotObscuredCleared);
_rb_define_module_function(module, "allow_exit", oneshotAllowExit);

View file

@ -282,6 +282,10 @@ void EventThread::process(RGSSThreadData &rtData)
break;
case SDL_TEXTINPUT:
if (rtData.inputText.length() < rtData.inputTextLimit) rtData.inputText += event.text.text;
break;
case SDL_KEYDOWN :
if (event.key.keysym.scancode == SDL_SCANCODE_F1)
{
@ -339,6 +343,15 @@ void EventThread::process(RGSSThreadData &rtData)
break;
}
if (rtData.acceptingTextInput) {
if (event.key.keysym.sym == SDLK_BACKSPACE && rtData.inputText.length() > 0)
rtData.inputText.pop_back();
else if (event.key.keysym.sym == SDLK_RETURN)
rtData.acceptingTextInput.clear();
break;
}
keyStates[event.key.keysym.scancode] = true;
break;

View file

@ -238,6 +238,9 @@ struct RGSSThreadData
/* Set when attempting to exit and allowExit is false */
AtomicFlag triedExit;
/* True if accepting text input */
AtomicFlag acceptingTextInput;
EventThread *ethread;
UnidirMessage<Vec2i> windowSizeMsg;
UnidirMessage<BDescVec> bindingUpdateMsg;
@ -255,6 +258,8 @@ struct RGSSThreadData
Config config;
std::string rgssErrorMsg;
std::string inputText;
int inputTextLimit;
RGSSThreadData(EventThread *ethread,
const char *argv0,

View file

@ -8,6 +8,8 @@
#include "debugwriter.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
//OS-Specific code
#if defined _WIN32
@ -210,6 +212,9 @@
#error "Operating system not detected."
#endif
#define DEF_SCREEN_W 640
#define DEF_SCREEN_H 480
struct OneshotPrivate
{
//Main SDL window
@ -359,6 +364,130 @@ static WCHAR *w32_toWide(const char *str)
}
#endif
LTexture::LTexture() {
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture() {
//Deallocate
free();
}
bool LTexture::loadFromFile(std::string path, SDL_Renderer *gRenderer) {
//Get rid of preexisting texture
free();
//The final texture
SDL_Texture *newTexture = NULL;
//Load image at specified path
SDL_Surface *loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL) {
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
} else {
//Color key image
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF));
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface(gRenderer, loadedSurface);
if (newTexture == NULL) {
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
} else {
//Get image dimensions
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
//Return success
mTexture = newTexture;
return mTexture != NULL;
}
#ifdef _SDL_TTF_H
bool LTexture::loadFromRenderedText(std::string textureText, SDL_Color textColor, SDL_Renderer *gRenderer, TTF_Font *gFont) {
//Get rid of preexisting texture
free();
//Render text surface
SDL_Surface *textSurface = TTF_RenderText_Solid(gFont, textureText.c_str(), textColor);
if (textSurface != NULL) {
//Create texture from surface pixels
mTexture = SDL_CreateTextureFromSurface(gRenderer, textSurface);
if (mTexture == NULL) {
printf("Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError());
} else {
//Get image dimensions
mWidth = textSurface->w;
mHeight = textSurface->h;
}
//Get rid of old surface
SDL_FreeSurface(textSurface);
} else {
printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
}
//Return success
return mTexture != NULL;
}
#endif
void LTexture::free() {
//Free texture if it exists
if (mTexture != NULL) {
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::setColor(Uint8 red, Uint8 green, Uint8 blue) {
//Modulate texture rgb
SDL_SetTextureColorMod(mTexture, red, green, blue);
}
void LTexture::setBlendMode(SDL_BlendMode blending) {
//Set blending function
SDL_SetTextureBlendMode(mTexture, blending);
}
void LTexture::setAlpha(Uint8 alpha) {
//Modulate texture alpha
SDL_SetTextureAlphaMod(mTexture, alpha);
}
void LTexture::render(SDL_Renderer *gRenderer, int x, int y, SDL_Rect *clip, double angle, SDL_Point *center,
SDL_RendererFlip flip) {
//Set rendering space and render to screen
SDL_Rect renderQuad = {x, y, mWidth, mHeight };
//Set clip rendering dimensions
if (clip != NULL) {
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopyEx(gRenderer, mTexture, clip, &renderQuad, angle, center, flip);
}
int LTexture::getWidth() {
return mWidth;
}
int LTexture::getHeight() {
return mHeight;
}
Oneshot::Oneshot(RGSSThreadData &threadData) :
threadData(threadData)
{
@ -778,6 +907,69 @@ bool Oneshot::msgbox(int type, const char *body, const char *title)
#endif
}
std::string Oneshot::textinput(const char* prompt, int char_limit, const char* font) {
SDL_Color textColor = {0xFF, 0xFF, 0xFF, 0xFF}; //Set text color as black
SDL_Renderer *gRenderer = SDL_CreateRenderer(threadData.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
LTexture gPromptTextTexture;
LTexture gInputTextTexture;
//Open the font
TTF_Font *gFont = TTF_OpenFont("VL-Gothic-Regular.ttf", 18); // XXX Implement font changing
if (gFont == NULL) {
printf("Failed to load lazy font! SDL_ttf Error: %s\n", TTF_GetError());
// success = false;
} else {
//Render the prompt
if (!gPromptTextTexture.loadFromRenderedText(prompt, textColor, gRenderer, gFont)) {
printf("Failed to render prompt text!\n");
// success = false;
}
}
gInputTextTexture.loadFromRenderedText(threadData.inputText.c_str(), textColor, gRenderer, gFont);
SDL_StartTextInput();
threadData.acceptingTextInput.set();
threadData.inputTextLimit = char_limit;
threadData.inputText.clear();
//Main loop
while (threadData.acceptingTextInput) {
if (threadData.inputText.length() > 0) gInputTextTexture.loadFromRenderedText(threadData.inputText.c_str(), textColor, gRenderer, gFont);
else gInputTextTexture.loadFromRenderedText(" ", textColor, gRenderer, gFont);
//Clear screen
// SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
//Render text textures
gPromptTextTexture.render(gRenderer, (DEF_SCREEN_W - gPromptTextTexture.getWidth()) / 2,
(DEF_SCREEN_H / 2) - gPromptTextTexture.getHeight());
gInputTextTexture.render(gRenderer, (DEF_SCREEN_W - gInputTextTexture.getWidth()) / 2,
(DEF_SCREEN_H / 2));
//Update screen
SDL_RenderPresent(gRenderer);
}
//Disable text input
SDL_StopTextInput();
//Free loaded images
gPromptTextTexture.free();
gInputTextTexture.free();
//Free global font
TTF_CloseFont(gFont);
gFont = NULL;
//Destroy renderer
SDL_DestroyRenderer(gRenderer);
gRenderer = NULL;
return threadData.inputText;
}
void Oneshot::setWindowPos(int x, int y)
{
SDL_LockMutex(p->winMutex);

View file

@ -1,12 +1,62 @@
#ifndef ONESHOT_H
#define ONESHOT_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include "etc-internal.h"
#include <string>
struct OneshotPrivate;
struct RGSSThreadData;
//Texture wrapper class
class LTexture {
public:
//Initializes variables
LTexture();
//Deallocates memory
~LTexture();
//Loads image at specified path
bool loadFromFile(std::string path, SDL_Renderer *gRenderer);
#ifdef _SDL_TTF_H
//Creates image from font string
bool loadFromRenderedText(std::string textureText, SDL_Color textColor, SDL_Renderer *gRenderer, TTF_Font *gFont);
#endif
//Deallocates texture
void free();
//Set color modulation
void setColor(Uint8 red, Uint8 green, Uint8 blue);
//Set blending
void setBlendMode(SDL_BlendMode blending);
//Set alpha modulation
void setAlpha(Uint8 alpha);
//Renders texture at given point
void render(SDL_Renderer *gRenderer, int x, int y, SDL_Rect *clip = NULL, double angle = 0.0, SDL_Point *center = NULL,
SDL_RendererFlip flip = SDL_FLIP_NONE);
//Gets image dimensions
int getWidth();
int getHeight();
private:
//The actual hardware texture
SDL_Texture *mTexture;
//Image dimensions
int mWidth;
int mHeight;
};
class Oneshot
{
public:
@ -63,6 +113,7 @@ public:
//Functions
bool msgbox(int type, const char *body, const char *title);
std::string textinput(const char* prompt, int char_limit, const char* font);
//Dirty flag for obscured texture
bool obscuredDirty;