311 lines
9.0 KiB
D
311 lines
9.0 KiB
D
module otya.smilebasic.dialog;
|
|
import otya.smilebasic.petitcomputer;
|
|
import otya.smilebasic.project;
|
|
import otya.smilebasic.error;
|
|
import derelict.sdl2.sdl;
|
|
import derelict.sdl2.image;
|
|
import derelict.sdl2.ttf;
|
|
import derelict.opengl3.gl;
|
|
import derelict.opengl3.gl3;
|
|
|
|
class DialogBase
|
|
{
|
|
abstract void render();
|
|
}
|
|
|
|
enum SelectionType
|
|
{
|
|
ok,
|
|
noYes,
|
|
backNext,
|
|
cancelConfirm,
|
|
cancelExecute,
|
|
next,
|
|
}
|
|
|
|
enum ButtonResult
|
|
{
|
|
a = 128,
|
|
b = 129,
|
|
x = 130,
|
|
y = 131,
|
|
up = 132,
|
|
down = 133,
|
|
left = 134,
|
|
right = 135,
|
|
l = 136,
|
|
r = 137,
|
|
touch = 140,
|
|
}
|
|
|
|
class DialogButton
|
|
{
|
|
int x, y, width, height;
|
|
SDL_Rect foregroundRect;
|
|
GraphicPage background;
|
|
GraphicPage foreground;
|
|
DialogResult result;
|
|
bool isPressed;
|
|
this(GraphicPage background, GraphicPage foreground, int x, int y, DialogResult result, int fx, int fy)
|
|
{
|
|
this.background = background;
|
|
this.foreground = foreground;
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = background.surface.w;
|
|
this.height = background.surface.h;
|
|
this.result = result;
|
|
foregroundRect.x = fx;
|
|
foregroundRect.y = fy;
|
|
foregroundRect.w = foreground.surface.w;
|
|
foregroundRect.h = foreground.surface.h;
|
|
}
|
|
bool colDetect(int x, int y)
|
|
{
|
|
return x >= this.x && y >= this.y && this.x + this.width > x && this.y + this.height > y;
|
|
}
|
|
}
|
|
|
|
class DialogResources
|
|
{
|
|
public GraphicPage button1;
|
|
public GraphicPage button2;
|
|
public TTF_Font* font;
|
|
wstring[][] buttonCaptions;
|
|
public this(SDL_Renderer* renderer, GLenum textureScaleMode)
|
|
{
|
|
button1 = new GraphicPage("dialogresource/yes.png");
|
|
button1.createTexture(renderer, textureScaleMode);
|
|
button2 = new GraphicPage("dialogresource/no.png");
|
|
button2.createTexture(renderer, textureScaleMode);
|
|
font = TTF_OpenFont("dialogresource/mplus-1c-regular.ttf", 14);
|
|
buttonCaptions = [["了解"], ["はい", "いいえ"], ["次へ", "戻る"], ["中止", "決定"], ["中止", "実行"]];
|
|
}
|
|
}
|
|
|
|
struct Text
|
|
{
|
|
GraphicPage texture;
|
|
this(PetitComputer petitcom, wstring text, SDL_Color color)
|
|
{
|
|
text ~= '\0';
|
|
auto surface = petitcom.dialogResource.font.TTF_RenderUNICODE_Blended((cast(ushort[])text).ptr, color);
|
|
texture = new GraphicPage(surface);
|
|
texture.createTexture(petitcom.renderer, petitcom.textureScaleMode);
|
|
}
|
|
this(PetitComputer petitcom, wchar* text, SDL_Color color, uint width)
|
|
{
|
|
auto surface = petitcom.dialogResource.font.TTF_RenderUNICODE_Blended_Wrapped((cast(ushort*)text), color, width);
|
|
texture = new GraphicPage(surface);
|
|
texture.createTexture(petitcom.renderer, petitcom.textureScaleMode);
|
|
}
|
|
~this()
|
|
{
|
|
if (texture)
|
|
{
|
|
texture.deleteGL();
|
|
texture.deleteSDL();
|
|
}
|
|
}
|
|
}
|
|
|
|
class Dialog : DialogBase
|
|
{
|
|
private PetitComputer petitcom;
|
|
this(PetitComputer petitcom)
|
|
{
|
|
this.petitcom = petitcom;
|
|
}
|
|
private int result;
|
|
private SDL_Rect area;
|
|
DialogButton[] buttons;
|
|
|
|
void renderBackground()
|
|
{
|
|
int w = 16, h = 16;
|
|
glDepthMask(GL_FALSE);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glColor3ub(248, 248, 248);
|
|
glBegin(GL_QUADS);
|
|
glVertex2i(0, 0);
|
|
glVertex2i(area.w, 0);
|
|
glVertex2i(area.w, area.h);
|
|
glVertex2i(0, area.h);
|
|
glEnd();
|
|
glColor3ub(192, 192, 192);
|
|
glBegin(GL_LINES);
|
|
for (int y = 0; y < area.h; y += h)
|
|
{
|
|
glVertex2i(0, y);
|
|
glVertex2i(area.w, y);
|
|
}
|
|
for (int x = 0; x < area.w; x += w)
|
|
{
|
|
glVertex2i(x, 0);
|
|
glVertex2i(x, area.h);
|
|
}
|
|
glEnd();
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
void renderQuad(SDL_Rect rect)
|
|
{
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2i(0, 0);
|
|
glVertex2i(rect.x, rect.y);
|
|
glTexCoord2i(1, 0);
|
|
glVertex2i(rect.x + rect.w, rect.y);
|
|
glTexCoord2i(1, 1);
|
|
glVertex2i(rect.x + rect.w, rect.y + rect.h);
|
|
glTexCoord2i(0, 1);
|
|
glVertex2i(rect.x, rect.y + rect.h);
|
|
glEnd();
|
|
}
|
|
void renderButton(DialogButton button)
|
|
{
|
|
int mx, my;
|
|
if (button.isPressed)
|
|
{
|
|
mx += 2;
|
|
my += 2;
|
|
}
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glColor3ub(255, 255, 255);
|
|
glBindTexture(GL_TEXTURE_2D, button.background.glTexture);
|
|
renderQuad(SDL_Rect(button.x + mx, button.y + my, button.width, button.height));
|
|
if (button.foreground)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, button.foreground.glTexture);
|
|
renderQuad(SDL_Rect(button.x + button.foregroundRect.x + mx, button.y + button.foregroundRect.y + my, button.foregroundRect.w, button.foregroundRect.h));
|
|
}
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
void renderContent()
|
|
{
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glColor3ub(255, 255, 255);
|
|
glBindTexture(GL_TEXTURE_2D, message.glTexture);
|
|
renderQuad(SDL_Rect(12, 24, message.surface.w, message.surface.h));
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
override void render()
|
|
{
|
|
petitcom.chScreen2(area.x, area.y, area.w, area.h);
|
|
renderBackground();
|
|
foreach (b; buttons)
|
|
{
|
|
renderButton(b);
|
|
}
|
|
renderContent();
|
|
}
|
|
|
|
GraphicPage message;
|
|
|
|
int show(wstring text, SelectionType selType = SelectionType.ok, wstring caption = "■DIALOG", int timeout = 0)
|
|
{
|
|
area = petitcom.showTouchScreen();
|
|
scope (exit)
|
|
petitcom.hideTouchScreen();
|
|
wchar[257] buffer;
|
|
if (text.length > 256)
|
|
{
|
|
buffer[0..256] = text[0..256];
|
|
buffer[256] = '\0';
|
|
}
|
|
else
|
|
{
|
|
buffer[0..text.length] = text[];
|
|
buffer[text.length] = '\0';
|
|
}
|
|
Text messageText = Text(petitcom, buffer.ptr, SDL_Color(0, 0, 0, 255), area.w - 24);
|
|
message = messageText.texture;
|
|
int buttonMarginWidth = 12;
|
|
int buttonMarginHeight = 12;
|
|
|
|
int buttonCount;
|
|
auto cs = petitcom.dialogResource.buttonCaptions[cast(size_t)selType];
|
|
|
|
auto button1text = Text(petitcom, cs[0], SDL_Color(0, 0, 0, 255));
|
|
auto button1 =
|
|
new DialogButton(
|
|
petitcom.dialogResource.button1,
|
|
button1text.texture,
|
|
area.w - buttonMarginWidth - petitcom.dialogResource.button1.surface.w,
|
|
area.h - buttonMarginHeight - petitcom.dialogResource.button1.surface.h,
|
|
DialogResult.SUCCESS,
|
|
22,
|
|
1
|
|
);
|
|
Text button2text;
|
|
DialogButton button2;
|
|
if (cs.length > 1)
|
|
{
|
|
ubyte sr, sg, sb, sa;
|
|
SDL_GetRGBA((cast(uint*)petitcom.dialogResource.button2.surface.pixels)[0], petitcom.dialogResource.button2.surface.format, &sr, &sg, &sb, &sa);
|
|
button2text = Text(petitcom, cs[1], SDL_Color(sr, sg, sb, 255));
|
|
button2 =
|
|
new DialogButton(
|
|
petitcom.dialogResource.button2,
|
|
button2text.texture,
|
|
buttonMarginWidth,
|
|
area.h - buttonMarginHeight - petitcom.dialogResource.button1.surface.h,
|
|
DialogResult.CANCEL,
|
|
22,
|
|
1
|
|
);
|
|
buttons = [button1, button2];
|
|
}
|
|
else
|
|
{
|
|
buttons = [button1];
|
|
}
|
|
petitcom.dialog = this;
|
|
scope (exit)
|
|
petitcom.dialog = null;
|
|
bool isPressed;
|
|
int timeoutframe;
|
|
if (timeout > 0)
|
|
{
|
|
timeoutframe = timeout * 60;
|
|
}
|
|
else if (timeout < 0)
|
|
{
|
|
timeoutframe = -timeout;
|
|
}
|
|
auto startmaincnt = petitcom.maincnt;
|
|
while (!isPressed)
|
|
{
|
|
petitcom.maincnt++;
|
|
if (petitcom.maincnt - startmaincnt == timeoutframe)
|
|
{
|
|
break;
|
|
}
|
|
auto to = petitcom.touchPosition();
|
|
auto x = to.display1X;
|
|
auto y = to.display1Y;
|
|
foreach (b; buttons)
|
|
{
|
|
if (to.tm == 1 && b.colDetect(x, y))
|
|
{
|
|
b.isPressed = true;
|
|
}
|
|
else if (b.isPressed && to.tm < 1)
|
|
{
|
|
result = b.result;
|
|
isPressed = true;
|
|
}
|
|
}
|
|
SDL_Delay(16);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|