1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
/* SPDX-License-Identifier: MIT */
/*
* kontextbox.h
*
* Copyright (c) 2026 KonAki
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef KONTEXTBOX_H
#define KONTEXTBOX_H
#include "konsofren.h"
#include "konfont.h"
#include "kon2d.h"
/*** panels ***/
typedef enum kon_panelMode {
KON_PANEL_STRETCH, /* the image is stretched over the whole panel */
KON_PANEL_SLICE /* nine patch: the corners stay as they are, the edges and the middle stretch */
} kon_panelMode_t;
/* what a box, a name plate or a menu is drawn on. every part is optional: colours with alpha 0 and a NULL image draw nothing.
the fill is drawn first, then the image over it, then the border */
typedef struct kon_panel {
uint32_t fill; /* 0xAARRGGBB, a low alpha lets what is behind show through */
uint32_t border;
int borderWidth;
const kon_image *image;
kon_rect_t src; /* w == 0 is the whole image */
kon_panelMode_t mode;
int slice; /* with KON_PANEL_SLICE: the size of the corners in image pixels */
} kon_panel_t;
/* alpha from 0 to 1 fades the whole panel */
void kon_drawPanel(kon_framebuffer_t *fb, const kon_panel_t *panel, int x, int y, int width, int height, float alpha);
/*** text box ***/
#define KON_TEXTBOX_TEXT 1024 /* bytes of text kept, a longer text is cut */
#define KON_TEXTBOX_NAME 64
#define KON_TEXTBOX_LINES 64 /* lines kept after wrapping */
#define KON_TEXTBOX_CHOICES 8
#define KON_TEXTBOX_LABEL 64
typedef enum kon_textboxState {
KON_TEXTBOX_EMPTY,
KON_TEXTBOX_TYPING, /* the letters are still coming in */
KON_TEXTBOX_WAITING, /* the page is all there, waiting for kon_textboxAdvance */
KON_TEXTBOX_CHOOSING /* a menu is up, see kon_textboxConfirm */
} kon_textboxState_t;
typedef enum kon_side {
KON_SIDE_LEFT,
KON_SIDE_RIGHT
} kon_side_t;
typedef enum kon_align {
KON_ALIGN_LEFT,
KON_ALIGN_CENTER,
KON_ALIGN_RIGHT
} kon_align_t;
typedef enum kon_choiceMode {
KON_CHOICES_LIST, /* the rows of a menu inside the box's panel */
KON_CHOICES_BUTTONS /* every choice is a panel of its own, the box's panel is not drawn. the usual look in a visual novel */
} kon_choiceMode_t;
typedef enum kon_portraitMode {
KON_PORTRAIT_INSIDE, /* in the middle of the box's height, inside its padding */
KON_PORTRAIT_HANG /* standing on the bottom of the box, a tall picture reaches above the top edge */
} kon_portraitMode_t;
/* one box for a message in an RPG, a visual novel or a plain popup, and with kon_textboxChoices it is the menu too.
fill in the public fields after kon_textboxInit, the rest is private. the box does not read input, the game calls kon_textboxAdvance
and kon_textboxSelect when it wants to. sprites in a visual novel belong to the stage, the box only holds the face that sits inside it */
typedef struct kon_textbox {
kon_font_t *font;
int width, height;
kon_tween_t x, y, alpha; /* where it is and how solid, see kon_textboxMove and kon_textboxFade */
kon_panel_t panel, plate;
int padding;
int marginLeft, marginRight; /* extra room kept clear of text on each side, for a sprite that stands over the box */
int showEmpty; /* draw the panel while there is nothing to say, for a box that stays on screen. otherwise an empty box is not drawn */
int platePadding;
int plateOffsetX, plateOffsetY; /* the name plate sits on the top left of the box, moved by this */
uint32_t textColor, nameColor, choiceColor, selectColor, selectFill;
kon_align_t align; /* of the lines of a message */
kon_align_t choiceAlign; /* of the text of a choice */
kon_choiceMode_t choiceMode;
kon_panel_t button, buttonSelected; /* for KON_CHOICES_BUTTONS, a button is as wide as the box and as tall as a line plus the padding */
int buttonGap;
float speed; /* letters a second, 0 shows each page at once */
int lineSpacing; /* extra pixels between lines */
const kon_image *portrait;
kon_rect_t portraitSrc; /* w == 0 is the whole image */
kon_side_t portraitSide;
kon_portraitMode_t portraitMode;
/* private */
kon_textboxState_t state;
char text[KON_TEXTBOX_TEXT];
char name[KON_TEXTBOX_NAME];
int length;
int lineStart[KON_TEXTBOX_LINES], lineLength[KON_TEXTBOX_LINES];
int lineCount, linesPerPage, page, pageCount;
int pageChars;
float shown;
char labels[KON_TEXTBOX_CHOICES][KON_TEXTBOX_LABEL];
int choiceCount, selected;
} kon_textbox_t;
/* x, y is the top left. the font has to stay alive as long as the box is used. the defaults are the pastel on dark palette */
void kon_textboxInit(kon_textbox_t *box, kon_font_t *font, int x, int y, int width, int height);
/* shows text, wrapped to the box and split into pages that fit. name may be NULL. replaces what was there, menu included.
the text is copied. new lines in it start a new line in the box */
void kon_textboxSay(kon_textbox_t *box, const char *name, const char *text);
/* a face from a sheet of equally sized faces, counted left to right then top to bottom, 144 by 144 and 4 across in RPG Maker.
an index off the sheet takes the face out */
void kon_textboxFace(kon_textbox_t *box, const kon_image *sheet, int frameWidth, int frameHeight, int index, kon_side_t side);
/* the face inside the box, NULL takes it out. src NULL is the whole image. the text is wrapped again to fit beside it */
void kon_textboxPortrait(kon_textbox_t *box, const kon_image *image, const kon_rect_t *src, kon_side_t side, kon_portraitMode_t mode);
/* the action key. finishes the letters coming in, or turns to the next page, or ends the message. returns 1 when the last
page was dismissed, the box is empty again */
int kon_textboxAdvance(kon_textbox_t *box);
/* 1 when the page is complete, and 1 if there is a page after it, for a "more" mark you draw yourself */
int kon_textboxWaiting(const kon_textbox_t *box);
int kon_textboxMore(const kon_textbox_t *box);
/* shows a menu in place of a message, the labels are copied. at most KON_TEXTBOX_CHOICES, the rest are dropped.
kon_textboxFitChoices makes the box just big enough for them, at least minWidth wide */
void kon_textboxChoices(kon_textbox_t *box, const char *const *labels, int count);
void kon_textboxFitChoices(kon_textbox_t *box, int minWidth);
/* moves the selection by delta, wrapping round */
void kon_textboxSelect(kon_textbox_t *box, int delta);
void kon_textboxHighlight(kon_textbox_t *box, int index);
/* the choice under a point (in the pixels you draw at), or -1 */
int kon_textboxChoiceAt(const kon_textbox_t *box, int x, int y);
/* returns the selected choice and closes the menu, -1 if there is none */
int kon_textboxConfirm(kon_textbox_t *box);
void kon_textboxClear(kon_textbox_t *box);
/* puts the box against the left, in the middle or against the right of a view, margin pixels from the edge, at once.
RPG Maker's choice position. a menu with no panel at all (fill and border 0 on panel, button and buttonSelected) is its transparent window */
void kon_textboxPlaceX(kon_textbox_t *box, int viewWidth, kon_align_t align, int margin);
/* puts the box in the middle of a view of that size, along the axes you ask for, at once */
void kon_textboxCenter(kon_textbox_t *box, int viewWidth, int viewHeight, int horizontal, int vertical);
void kon_textboxMove(kon_textbox_t *box, float x, float y, float seconds, kon_ease_t ease);
void kon_textboxFade(kon_textbox_t *box, float alpha, float seconds, kon_ease_t ease);
/* returns 1 on the frame the page finished appearing */
int kon_textboxUpdate(kon_textbox_t *box, float dt);
void kon_textboxDraw(kon_textbox_t *box, kon_framebuffer_t *fb);
#endif
|