diff options
Diffstat (limited to 'kon/kontextbox.h')
| -rw-r--r-- | kon/kontextbox.h | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/kon/kontextbox.h b/kon/kontextbox.h new file mode 100644 index 0000000..25c60b0 --- /dev/null +++ b/kon/kontextbox.h @@ -0,0 +1,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 |
