Files
kichikuou_xsystem35-sdl2/src/editor.c
T
kichikuou c7c0f69ec4 Split sdl_core.h to event.h and editor.h
And rename sdl_event.c to event.c, sdl_input.c to editor.c.
2025-06-11 10:12:25 +09:00

174 lines
4.2 KiB
C

/*
* Copyright (C) 2020 <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "config.h"
#include <string.h>
#include <SDL.h>
#include "editor.h"
#include "event.h"
#include "gfx.h"
#include "menu.h"
#include "nact.h"
#include "system.h"
#define XMARGIN 3
#define YMARGIN 2
struct EditorState {
INPUTSTRING_PARAM *params;
SDL_Rect rect;
char *text;
char composingText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
int cursor;
bool done;
};
static struct EditorState *input;
static void redraw() {
const int bgcolor = nact->msg.WinBackgroundColor;
const int fgcolor = nact->msg.MsgFontColor;
ags_fillRectangle(input->rect.x, input->rect.y, input->rect.w, input->rect.h, bgcolor);
SDL_Rect r = {
.x = input->rect.x + XMARGIN,
.y = input->rect.y + YMARGIN,
.w = input->rect.w - XMARGIN * 2,
.h = input->rect.h - YMARGIN * 2,
};
if (*input->text) {
int w = gfx_drawString(r.x, r.y, input->text, fgcolor).w;
r.x += w;
r.w -= w;
}
if (*input->composingText) {
int w = gfx_drawString(r.x, r.y, input->composingText, fgcolor).w;
ags_fillRectangle(r.x, r.y + r.h, w, 2, fgcolor); // underline
}
// FIXME: This doesn't work with propotional fonts!
int cursor_x = r.x + r.h * input->cursor;
ags_fillRectangle(cursor_x, r.y, 2, r.h, fgcolor); // cursor
// Dib geometry -> window geometry
r.x -= nact->ags.view_area.x;
r.y -= nact->ags.view_area.y;
SDL_SetTextInputRect(&r);
ags_updateArea(input->rect.x, input->rect.y, input->rect.w, input->rect.h);
}
static bool handle_event(const SDL_Event *e) {
switch (e->type) {
case SDL_KEYDOWN:
if (*input->composingText)
break; // Let the IME handle this event.
switch (e->key.keysym.sym) {
case SDLK_RETURN:
input->params->newstring = input->text;
input->done = true;
return true;
case SDLK_ESCAPE:
input->params->newstring = NULL;
input->done = true;
return true;
case SDLK_BACKSPACE:
{
char *p = input->text + strlen(input->text) - 1;
while (p >= input->text && UTF8_TRAIL_BYTE(*p))
p--;
if (p >= input->text)
*p = '\0';
redraw();
}
return true;
}
break;
case SDL_TEXTINPUT:
{
int chars = input->params->max;
for (const char *p = input->text; *p; p = advance_char(p, UTF8))
chars--;
const char *end = e->text.text;
while (chars > 0 && *end) {
end = advance_char(end, UTF8);
chars--;
}
strncat(input->text, e->text.text, end - e->text.text);
input->composingText[0] = '\0';
input->cursor = 0;
redraw();
}
return true;
case SDL_TEXTEDITING:
strncpy(input->composingText, e->edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
input->cursor = e->edit.start;
redraw();
return true;
}
return false;
}
bool edit_string(INPUTSTRING_PARAM *p) {
static char *buf;
free(buf);
buf = malloc(p->max * MAX_UTF8_BYTES_PAR_CHAR + 1);
struct EditorState s = {
.params = p,
.rect = {
.x = p->x + nact->ags.view_area.x, // window geometry -> dib geometry
.y = p->y + nact->ags.view_area.y,
.w = p->h * p->max + XMARGIN * 2,
.h = p->h + YMARGIN * 2
},
.text = buf,
};
strcpy(s.text, p->oldstring);
input = &s;
SDL_StartTextInput();
void *saved_region = ags_saveRegion(s.rect.x, s.rect.y, s.rect.w, s.rect.h);
ags_setFont(FONT_GOTHIC, p->h);
redraw();
event_custom_handler = handle_event;
while (!input->done) {
event_get_key(); // message pump
nact->callback();
sys_wait_vsync();
}
SDL_StopTextInput();
event_custom_handler = NULL;
ags_restoreRegion(saved_region, s.rect.x, s.rect.y);
ags_updateArea(s.rect.x, s.rect.y, s.rect.w, s.rect.h);
input = NULL;
return true;
}