#include <SDL.h>
#include "private.h"
#include "drawing.h"
#include "font.h"
#include "world.h"
static int utf8charlen(const char *c) {
if (!*c) return 0;
if ( (c[0] & 0x80) == 0x00 )
return 1;
if ( (c[0] & 0xE0) == 0xC0
&& (c[1] & 0xC0) == 0x80 )
return 2;
if ( (c[0] & 0xF0) == 0xE0
&& (c[1] & 0xC0) == 0x80
&& (c[2] & 0xC0) == 0x80 )
return 3;
if ( (c[0] & 0xF8) == 0xF0
&& (c[1] & 0xC0) == 0x80
&& (c[2] & 0xC0) == 0x80
&& (c[3] & 0xC0) == 0x80 )
return 4;
return -1;
}
static int utf8shift(const char *s, int pos, int offset) {
int len = strlen(s);
if (pos > len) { offset += pos - len; pos = len; }
if (pos < 0) { offset += pos; pos = 0; }
while(offset > 0 && pos < len) {
int l = utf8charlen(s + pos);
if (l > 0) {
pos += l;
} else {
while(pos < len && utf8charlen(s + pos) <= 0) ++pos;
}
--offset;
}
while(offset < 0 && pos > 0) {
do --pos; while(pos > 0 && utf8charlen(s + pos) <= 0);
++offset;
}
return pos;
}
static void fixPos(HeliDialog *dialog) {
int answerLen = strlen(dialog->answer);
if (dialog->pos < 0) dialog->pos = 0;
if (dialog->pos > answerLen) dialog->pos = answerLen;
if (dialog->selPos < 0) dialog->selPos = 0;
if (dialog->selPos > answerLen) dialog->selPos = answerLen;
}
static void insert(HeliDialog *dialog, const char *text) {
int answerLen = strlen(dialog->answer);
fixPos(dialog);
int pos0 = dialog->pos < dialog->selPos ? dialog->pos : dialog->selPos;
int pos1 = dialog->pos < dialog->selPos ? dialog->selPos : dialog->pos;
int selLen = pos1 - pos0;
int textLen = strlen(text);
int dl = answerLen - selLen + textLen - dialog->maxAnswerSize;
if (dl > 0) textLen -= dl;
if (textLen < 0) textLen = 0;
int tailPos = pos0 + selLen;
int offset = textLen - selLen;
int tailLen = answerLen - tailPos;
if (offset && tailLen > 0)
memmove(
dialog->answer + tailPos + offset,
dialog->answer + tailPos,
tailLen);
tailPos += offset;
dialog->answer[tailPos + tailLen] = 0;
if (textLen > 0)
memcpy(dialog->answer + pos0, text, textLen);
dialog->pos = dialog->selPos = tailPos;
}
static void copy(HeliDialog *dialog) {
if (dialog->pos != dialog->selPos) {
int pos0 = dialog->pos < dialog->selPos ? dialog->pos : dialog->selPos;
int pos1 = dialog->pos < dialog->selPos ? dialog->selPos : dialog->pos;
char c = dialog->answer[pos1];
dialog->answer[pos1] = 0;
SDL_SetClipboardText(dialog->answer + pos0);
dialog->answer[pos1] = c;
}
}
static void paste(HeliDialog *dialog) {
const char *text = SDL_GetClipboardText();
if (text && text[0]) insert(dialog, text);
}
static void draw(HeliDialog *dialog) {
pushDrawingState();
const double w = worldGetWidth();
const double h = worldGetHeight();
const double border = 16;
const double scroll = 16;
const double title = 64;
const double buttons = 32;
const double l = border;
const double t = border + title;
const double r = w - border - scroll;
const double b = h - border - scroll - buttons;
const double bt = h - buttons - border + 8;
const double bb = h - border;
const double bh = bb - bt;
double bw = (w - 2*border)/4;
if (bw < bh) bw = bh;
const double bl0 = border - 2;
const double br0 = bl0 + bw;
const double br1 = w - border + 2;
const double bl1 = br1 - bw;
const char *strokeColor = "white";
const char *fillColor = "0.3 0.3 0.3";
strokeWeight(1);
textFontDefault();
textSize(16);
noStroke();
fill(fillColor);
rect(0, 0, w, h);
noFill();
stroke(strokeColor);
cliprect(l, t, r - l, b - t);
textAlign(HALIGN_LEFT, VALIGN_TOP);
text(dialog->answer, l + dialog->scrollX, t + dialog->scrollY);
noClip();
noFill();
stroke(strokeColor);
rect(l - 2, t - 2, r - l + 4, b - t + 4);
textAlign(HALIGN_CENTER, VALIGN_CENTER);
text(dialog->question, w/2, title/2);
rect(bl0, bt, bw, bh);
rect(bl1, bt, bw, bh);
text("<<", (bl0 + br0)/2, (bt + bb)/2);
text("\u23CE", (bl1 + br1)/2, (bt + bb)/2);
if (mouseWentDown("left")) {
double x = mouseX();
double y = mouseY();
if (y >= bt && y <= bb) {
if (x >= bl0 && x <= br0) dialog->shown = FALSE;
if (x >= bl1 && x <= br1) { dialog->success = TRUE; dialog->shown = FALSE; }
}
}
popDrawingState();
}
void heliDialogDraw(HeliDialog *dialog) {
if (dialog->newText[0]) insert(dialog, dialog->newText);
int shift = keyDown("left shift") || keyDown("right shift");
int ctrl = keyDown("left ctrl") || keyDown("right ctrl");
if (keyWentDown("backspace")) {
if (dialog->pos == dialog->selPos) {
dialog->selPos = dialog->pos;
dialog->pos = utf8shift(dialog->answer, dialog->pos, -1);
}
insert(dialog, "");
}
if (keyWentDown("delete")) {
if (dialog->pos == dialog->selPos) {
dialog->selPos = dialog->pos;
dialog->pos = utf8shift(dialog->answer, dialog->pos, 1);
} else
if (shift) {
copy(dialog);
}
insert(dialog, "");
}
if (keyWentDown("left")) {
dialog->pos = utf8shift(dialog->answer, dialog->pos, -1);
if (!shift) dialog->selPos = dialog->pos;
}
if (keyWentDown("right")) {
dialog->pos = utf8shift(dialog->answer, dialog->pos, 1);
if (!shift) dialog->selPos = dialog->pos;
}
if (ctrl && keyWentDown("home")) {
dialog->pos = 0;
if (!shift) dialog->selPos = dialog->pos;
}
if (ctrl && keyWentDown("end")) {
dialog->pos = strlen(dialog->answer);
if (!shift) dialog->selPos = dialog->pos;
}
if (keyWentDown("return")) {
if (!dialog->multiline || ctrl) {
dialog->success = TRUE;
dialog->shown = FALSE;
} else {
insert(dialog, "\n");
}
}
if (ctrl && keyWentDown("c"))
copy(dialog);
if (ctrl && keyWentDown("insert"))
copy(dialog);
if (ctrl && keyWentDown("v"))
paste(dialog);
if (shift && keyWentDown("insert"))
paste(dialog);
if (ctrl && keyWentDown("x"))
{ copy(dialog); insert(dialog, ""); }
if (keyWentDown("escape")) dialog->shown = FALSE;
if (!dialog->multiline) {
char *c = strpbrk(dialog->answer, "\n\r");
if (c) *c = 0;
fixPos(dialog);
}
draw(dialog);
}