Blame src/worldui.c

a20939
a20939
#include <sdl.h></sdl.h>
a20939
a20939
#include "private.h"
a20939
534343
#include "drawing.h"
534343
#include "font.h"
a20939
#include "world.h"
a20939
a20939
534343
static int utf8charlen(const char *c) {
534343
	if (!*c) return 0;
534343
	if ( (c[0] & 0x80) == 0x00 )
534343
		return 1;
534343
	if ( (c[0] & 0xE0) == 0xC0
534343
	  && (c[1] & 0xC0) == 0x80 )
534343
		return 2;
534343
	if ( (c[0] & 0xF0) == 0xE0
534343
	  && (c[1] & 0xC0) == 0x80
534343
	  && (c[2] & 0xC0) == 0x80 )
534343
		return 3;
534343
	if ( (c[0] & 0xF8) == 0xF0
534343
	  && (c[1] & 0xC0) == 0x80
534343
	  && (c[2] & 0xC0) == 0x80
534343
	  && (c[3] & 0xC0) == 0x80 )
534343
		return 4;
534343
	return -1;
a20939
}
a20939
a20939
534343
static int utf8shift(const char *s, int pos, int offset) {
534343
	int len = strlen(s);
534343
	if (pos > len) { offset += pos - len; pos = len; }
534343
	if (pos < 0) { offset += pos; pos = 0; }
534343
	
534343
	while(offset > 0 && pos < len) {
534343
		int l = utf8charlen(s + pos);
534343
		if (l > 0) {
534343
			pos += l;
534343
		} else {
534343
			while(pos < len && utf8charlen(s + pos) <= 0) ++pos;
534343
		}
534343
		--offset;
534343
	}
534343
	
534343
	while(offset < 0 && pos > 0) {
534343
		do --pos; while(pos > 0 && utf8charlen(s + pos) <= 0);
534343
		++offset;
534343
	}
534343
	
534343
	return pos;
534343
}
534343
534343
534343
static void fixPos(HeliDialog *dialog) {
534343
	int answerLen = strlen(dialog->answer);
534343
	if (dialog->pos < 0) dialog->pos = 0;
534343
	if (dialog->pos > answerLen) dialog->pos = answerLen;
534343
	if (dialog->selPos < 0) dialog->selPos = 0;
534343
	if (dialog->selPos > answerLen) dialog->selPos = answerLen;
534343
}
534343
534343
534343
static void insert(HeliDialog *dialog, const char *text) {
534343
	int answerLen = strlen(dialog->answer);
534343
	fixPos(dialog);
534343
	
534343
	int pos0 = dialog->pos < dialog->selPos ? dialog->pos : dialog->selPos;
534343
	int pos1 = dialog->pos < dialog->selPos ? dialog->selPos : dialog->pos;
534343
	int selLen = pos1 - pos0;
534343
	
534343
	int textLen = strlen(text);
534343
	int dl = answerLen - selLen + textLen - dialog->maxAnswerSize;
534343
	if (dl > 0) textLen -= dl;
534343
	if (textLen < 0) textLen = 0;
534343
	
534343
	int tailPos = pos0 + selLen;
534343
	int offset = textLen - selLen;
534343
	int tailLen = answerLen - tailPos;
534343
	if (offset && tailLen > 0)
534343
		memmove(
534343
			dialog->answer + tailPos + offset,
534343
			dialog->answer + tailPos,
534343
			tailLen);
534343
	tailPos += offset;
534343
	dialog->answer[tailPos + tailLen] = 0;
534343
	
534343
	if (textLen > 0)
534343
		memcpy(dialog->answer + pos0, text, textLen);
534343
	
534343
	dialog->pos = dialog->selPos = tailPos;
534343
}
534343
534343
534343
static void copy(HeliDialog *dialog) {
534343
	if (dialog->pos != dialog->selPos) {
534343
		int pos0 = dialog->pos < dialog->selPos ? dialog->pos : dialog->selPos;
534343
		int pos1 = dialog->pos < dialog->selPos ? dialog->selPos : dialog->pos;
534343
		char c = dialog->answer[pos1];
534343
		dialog->answer[pos1] = 0;
534343
		SDL_SetClipboardText(dialog->answer + pos0);
534343
		dialog->answer[pos1] = c;
534343
	}
534343
}
534343
534343
534343
static void paste(HeliDialog *dialog) {
534343
	const char *text = SDL_GetClipboardText();
534343
	if (text && text[0]) insert(dialog, text);
534343
}
534343
534343
534343
static void draw(HeliDialog *dialog) {
534343
	pushDrawingState();
534343
	
da4619
	const double time = SDL_GetTicks()*1e-3;
da4619
	
534343
	const double w = worldGetWidth();
534343
	const double h = worldGetHeight();
534343
	const double border = 16;
534343
	const double scroll = 16;
534343
	const double title = 64;
534343
	const double buttons = 32;
534343
	const double l = border;
534343
	const double t = border + title;
534343
	const double r = w - border - scroll;
534343
	const double b = h - border - scroll - buttons;
534343
	
534343
	const double bt = h - buttons - border + 8;
534343
	const double bb = h - border;
534343
	const double bh = bb - bt;
534343
	double bw = (w - 2*border)/4;
534343
	if (bw < bh) bw = bh;
534343
	const double bl0 = border - 2;
534343
	const double br0 = bl0 + bw;
534343
	const double br1 = w - border + 2;
534343
	const double bl1 = br1 - bw;
534343
	
534343
	const char *strokeColor = "white";
534343
	const char *fillColor = "0.3 0.3 0.3";
da4619
	const char *selTextColor = "black";
da4619
	const char *selFillColor = "white";
534343
	strokeWeight(1);
534343
	textFontDefault();
534343
	textSize(16);
534343
	
534343
	noStroke();
534343
	fill(fillColor);
534343
	rect(0, 0, w, h);
534343
	
534343
	noFill();
534343
	stroke(strokeColor);
534343
	textAlign(HALIGN_LEFT, VALIGN_TOP);
da4619
	TextLayout layout = createTextLayout(dialog->answer);
da4619
	double tx = l + dialog->scrollX;
da4619
	double ty = t + dialog->scrollY;
da4619
	double cx = textLayoutCursorGetX(layout, dialog->pos) + tx;
da4619
	double cy = textLayoutCursorGetY(layout, dialog->pos) + ty;
da4619
	double ch = textLayoutCursorGetHeight(layout, dialog->pos);
da4619
	cliprect(l-1, t-1, r-l+2, b-t+2);
da4619
	if (dialog->pos == dialog->selPos) {
da4619
		textLayoutDraw(layout, tx, ty);
da4619
	} else {
da4619
		int p0 = dialog->pos < dialog->selPos ? dialog->pos : dialog->selPos;
da4619
		int p1 = dialog->pos < dialog->selPos ? dialog->selPos : dialog->pos;
da4619
		fill(selFillColor);
da4619
		stroke(selTextColor);
da4619
		textLayoutDrawSubstr(layout, tx, ty, p0, p1 - p0);
da4619
		noFill();
da4619
		stroke(strokeColor);
da4619
		textLayoutDrawSubstr(layout, tx, ty, 0, p0);
da4619
		textLayoutDrawFrom(layout, tx, ty, p1);
da4619
	}
da4619
	stroke(rgba(1, 1, 1, 0.5 + 0.5*sin(time/0.5*2*PI)));
da4619
	line(cx, cy, cx, cy - ch);
da4619
	int shift = keyDown("left shift") || keyDown("right shift");
da4619
	if (keyWentDown("up")) {
da4619
		dialog->pos = textLayoutCursorUp(layout, dialog->pos);
da4619
		if (!shift) dialog->selPos = dialog->pos;
da4619
	}
da4619
	if (keyWentDown("down")) {
da4619
		dialog->pos = textLayoutCursorDown(layout, dialog->pos);
da4619
		if (!shift) dialog->selPos = dialog->pos;
da4619
	}
da4619
	textLayoutDestroy(layout);
8bc1f1
	noClip();
534343
	
534343
	noFill();
534343
	stroke(strokeColor);
534343
	rect(l - 2, t - 2, r - l + 4, b - t + 4);
534343
	
534343
	textAlign(HALIGN_CENTER, VALIGN_CENTER);
534343
	text(dialog->question, w/2, title/2);
534343
	
534343
	rect(bl0, bt, bw, bh);
534343
	rect(bl1, bt, bw, bh);
534343
	text("<<", (bl0 + br0)/2, (bt + bb)/2);
534343
	text("\u23CE", (bl1 + br1)/2, (bt + bb)/2);
534343
	
534343
	if (mouseWentDown("left")) {
534343
		double x = mouseX();
534343
		double y = mouseY();
534343
		if (y >= bt && y <= bb) {
534343
			if (x >= bl0 && x <= br0) dialog->shown = FALSE;
534343
			if (x >= bl1 && x <= br1) { dialog->success = TRUE; dialog->shown = FALSE; }
534343
		}
534343
	}
534343
	
534343
	popDrawingState();
534343
}
534343
534343
534343
void heliDialogDraw(HeliDialog *dialog) {
534343
	if (dialog->newText[0]) insert(dialog, dialog->newText);
534343
	
534343
	int shift = keyDown("left shift") || keyDown("right shift");
534343
	int ctrl = keyDown("left ctrl") || keyDown("right ctrl");
534343
	
534343
	if (keyWentDown("backspace")) {
534343
		if (dialog->pos == dialog->selPos) {
534343
			dialog->selPos = dialog->pos;
534343
			dialog->pos = utf8shift(dialog->answer, dialog->pos, -1);
534343
		}
534343
		insert(dialog, "");
534343
	}
534343
	
534343
	if (keyWentDown("delete")) {
534343
		if (dialog->pos == dialog->selPos) {
534343
			dialog->selPos = dialog->pos;
534343
			dialog->pos = utf8shift(dialog->answer, dialog->pos, 1);
534343
		} else
534343
		if (shift) {
534343
			copy(dialog);
534343
		}
534343
		insert(dialog, "");
534343
	}
534343
	
534343
	if (keyWentDown("left")) {
534343
		dialog->pos = utf8shift(dialog->answer, dialog->pos, -1);
534343
		if (!shift) dialog->selPos = dialog->pos;
534343
	}
534343
	
534343
	if (keyWentDown("right")) {
534343
		dialog->pos = utf8shift(dialog->answer, dialog->pos, 1);
534343
		if (!shift) dialog->selPos = dialog->pos;
534343
	}
534343
	
da4619
	if (keyWentDown("home")) {
da4619
		if (ctrl) {
da4619
			dialog->pos = 0;
da4619
		} else {
da4619
			while( dialog->pos > 0
da4619
			    && dialog->answer[dialog->pos-1] != '\r'
da4619
			    && dialog->answer[dialog->pos-1] != '\n' ) --dialog->pos;
da4619
		}
534343
		if (!shift) dialog->selPos = dialog->pos;
534343
	}
534343
	
da4619
	if (keyWentDown("end")) {
da4619
		if (ctrl) {
da4619
			dialog->pos = strlen(dialog->answer);
da4619
		} else {
da4619
			while( dialog->answer[dialog->pos] != 0
da4619
			    && dialog->answer[dialog->pos] != '\r'
da4619
			    && dialog->answer[dialog->pos] != '\n' ) ++dialog->pos;
da4619
		}
534343
		if (!shift) dialog->selPos = dialog->pos;
534343
	}
534343
	
534343
	if (keyWentDown("return")) {
534343
		if (!dialog->multiline || ctrl) {
534343
			dialog->success = TRUE;
534343
			dialog->shown = FALSE;
534343
		} else {
534343
			insert(dialog, "\n");
534343
		}
534343
	}
534343
	
da4619
	if (ctrl && keyWentDown("a"))
da4619
		{ dialog->selPos = 0; dialog->pos = strlen(dialog->answer); }
534343
	if (ctrl && keyWentDown("c"))
534343
		copy(dialog);
534343
	if (ctrl && keyWentDown("insert"))
534343
		copy(dialog);
534343
	if (ctrl && keyWentDown("v"))
534343
		paste(dialog);
534343
	if (shift && keyWentDown("insert"))
534343
		paste(dialog);
534343
	if (ctrl && keyWentDown("x"))
534343
		{ copy(dialog); insert(dialog, ""); }
534343
	
534343
	if (keyWentDown("escape")) dialog->shown = FALSE;
534343
	
534343
	if (!dialog->multiline) {
534343
		char *c = strpbrk(dialog->answer, "\n\r");
534343
		if (c) *c = 0;
534343
		fixPos(dialog);
534343
	}
534343
	
534343
	draw(dialog);
534343
}