mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-26 08:28:04 +03:00
347 lines
8.9 KiB
C
347 lines
8.9 KiB
C
/*
|
|
* sprite_sel.c: 選択肢処理
|
|
*
|
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
/* $Id: sprite_sel.c,v 1.1 2003/04/22 16:29:52 chikama Exp $ */
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <SDL.h>
|
|
|
|
#include "portab.h"
|
|
#include "nact.h"
|
|
#include "variable.h"
|
|
#include "ags.h"
|
|
#include "input.h"
|
|
#include "sact.h"
|
|
#include "sprite.h"
|
|
#include "drawtext.h"
|
|
|
|
// 選択された要素(1~) キャンセルの場合は0、初期状態は -1
|
|
static int selected_item;
|
|
static int selected_item_cur;
|
|
|
|
// 前のカーソルの状態
|
|
static bool oldstate; // spriteの中か外か
|
|
static int oldindex; // 何番目の要素か(0~)
|
|
|
|
|
|
static bool sp_is_insprite2(sprite_t *sp, int x, int y, int margin);
|
|
static void cb_select_move(agsevent_t *e);
|
|
static void cb_select_release(agsevent_t *e);
|
|
static void setup_selwindow();
|
|
static void remove_selwindow();
|
|
static int sel_main();
|
|
|
|
|
|
|
|
|
|
/**
|
|
* 内側にマージンを含む sprite内領域チェック
|
|
* マージン内はsprite内部とは判断しない
|
|
*/
|
|
static bool sp_is_insprite2(sprite_t *sp, int x, int y, int margin) {
|
|
SDL_Point p = {x, y};
|
|
SDL_Rect r = {
|
|
sp->cur.x + margin,
|
|
sp->cur.y + margin,
|
|
sp->curcg->sf->w - 2 * margin,
|
|
sp->curcg->sf->h - 2 * margin
|
|
};
|
|
return SDL_PointInRect(&p, &r);
|
|
}
|
|
|
|
// マウスが移動したときの callback
|
|
static void cb_select_move(agsevent_t *e) {
|
|
int x = e->mousex, y = e->mousey;
|
|
sprite_t *sp = sact.sp[sact.sel.spno];
|
|
bool newstate;
|
|
int newindex;
|
|
|
|
// sprite内か?
|
|
newstate = sp_is_insprite2(sp, x, y, sact.sel.frame_dot);
|
|
newindex = (y - (sp->cur.y + sact.sel.frame_dot)) / (sact.sel.font_size + sact.sel.linespace);
|
|
|
|
if (newstate == oldstate) {
|
|
if (!newstate || newindex == oldindex) {
|
|
// 前と状態が同じでかつ、新しい状態がspriteの外か、
|
|
// indexが変わらない場合はなにもしない。
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (newstate) {
|
|
// spriteの内部
|
|
// fprintf(stderr, "in region %d\n", newindex);
|
|
//update_selwindow(newindex + 1);
|
|
selected_item_cur = newindex + 1;
|
|
} else {
|
|
// spriteの外部
|
|
//update_selwindow(0);
|
|
selected_item_cur = 0;
|
|
}
|
|
|
|
oldstate = newstate;
|
|
oldindex = newindex;
|
|
|
|
// 再描画
|
|
sp_updateme(sp);
|
|
sp_update_clipped();
|
|
}
|
|
|
|
// ボタンがリリースされたときの callback
|
|
static void cb_select_release(agsevent_t *e) {
|
|
int x = e->mousex, y = e->mousey;
|
|
sprite_t *sp = sact.sp[sact.sel.spno];
|
|
bool st;
|
|
int iy;
|
|
|
|
switch (e->code) {
|
|
case AGSEVENT_BUTTON_LEFT:
|
|
st = sp_is_insprite2(sp, x, y, sact.sel.frame_dot);
|
|
iy = (y - (sp->cur.y + sact.sel.frame_dot)) / (sact.sel.font_size + sact.sel.linespace);
|
|
|
|
// カーソルが sprite の外の場合は無視
|
|
if (!st) {
|
|
return;
|
|
}
|
|
|
|
// 選択要素が空の場合も無視
|
|
if (sact.sel.elem[iy + 1] == NULL) return;
|
|
|
|
selected_item = iy + 1;
|
|
break;
|
|
|
|
case AGSEVENT_BUTTON_RIGHT:
|
|
// キャンセル
|
|
selected_item = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void draw_box(SDL_Surface *dst, int x, int y, int w, int h) {
|
|
SDL_FillRect(dst, &(SDL_Rect){x, y, w, h}, SDL_MapRGB(dst->format, 0, 0, 0));
|
|
SDL_Rect border_rects[4] = {
|
|
{x, y, w, 1},
|
|
{x, y + h - 1, w, 1},
|
|
{x, y, 1, h},
|
|
{x + w - 1, y, 1, h}
|
|
};
|
|
SDL_FillRects(dst, border_rects, 4, SDL_MapRGB(dst->format, 255, 255, 255));
|
|
}
|
|
|
|
// 選択ウィンドを更新するときの callback
|
|
static void update_selwindow(sprite_t *sp) {
|
|
int selno = selected_item_cur;
|
|
int x0, y0;
|
|
|
|
x0 = sp->cur.x;
|
|
y0 = sp->cur.y;
|
|
// 背景 CG
|
|
sp_draw(sp);
|
|
|
|
// 選択されている要素
|
|
if (selno && sact.sel.elem[selno] != NULL) {
|
|
int w = sact.sel.charcanvas->w - 2 * sact.sel.frame_dot;
|
|
int h = sact.sel.font_size + sact.sel.linespace;
|
|
int x = x0 + sact.sel.frame_dot;
|
|
int y = y0 + sact.sel.frame_dot + (selno -1) * h;
|
|
draw_box(main_surface, x, y, w, h);
|
|
}
|
|
|
|
// 選択肢文字列
|
|
SDL_BlitSurface(sact.sel.charcanvas, NULL, main_surface,
|
|
&(SDL_Rect){x0, y0, sact.sel.charcanvas->w, sact.sel.charcanvas->h});
|
|
}
|
|
|
|
// 選択ウィンドの準備
|
|
static void setup_selwindow() {
|
|
sprite_t *sp = sact.sp[sact.sel.spno];
|
|
int i;
|
|
|
|
// 選択肢文字用 canvas
|
|
sact.sel.charcanvas = SDL_CreateRGBSurfaceWithFormat(0, sp->cg1->sf->w, sp->cg1->sf->h, 32, SDL_PIXELFORMAT_ARGB8888);
|
|
SDL_SetSurfaceBlendMode(sact.sel.charcanvas, SDL_BLENDMODE_BLEND);
|
|
|
|
dt_setfont(sact.sel.font_type, sact.sel.font_size);
|
|
|
|
// 指定のスプライトに文字(選択肢を書く)
|
|
for (i = 1; i < SEL_ELEMENT_MAX; i++) {
|
|
int x, y;
|
|
if (sact.sel.elem[i] == NULL) continue;
|
|
// 文字の場所計算
|
|
x = 0; // 行そろえは無し
|
|
y = (i - 1) * (sact.sel.font_size + sact.sel.linespace);
|
|
dt_drawtext_col(sact.sel.charcanvas,
|
|
x + sact.sel.frame_dot, y + sact.sel.frame_dot,
|
|
sact.sel.elem[i], 255, 255, 255);
|
|
}
|
|
|
|
// デフォルトで選択される選択肢がある場合、そこへカーソルを移動
|
|
if (sact.sel.movecursor) {
|
|
int x = sp->cur.x + sact.sel.frame_dot + 2;
|
|
int y = sp->cur.y + sact.sel.frame_dot + 2 +
|
|
(sact.sel.font_size + sact.sel.linespace) * (sact.sel.movecursor - 1);
|
|
ags_setCursorLocation(x, y, true, true);
|
|
selected_item = (sact.sel.movecursor -1);
|
|
oldstate = true;
|
|
oldindex = selected_item -1;
|
|
}
|
|
|
|
// その他初期化
|
|
selected_item_cur = 0;
|
|
|
|
// スプライト再描画 callback の登録
|
|
sp->update = update_selwindow;
|
|
}
|
|
|
|
// 選択ウィンドの削除
|
|
static void remove_selwindow() {
|
|
sprite_t *sp = sact.sp[sact.sel.spno];
|
|
|
|
// スプライト再描画 callback を元にもどす
|
|
sp->update = sp_draw;
|
|
|
|
// スプライトを再描画して(おそらく消す)
|
|
sp_updateme(sp);
|
|
sp_update_clipped();
|
|
|
|
// 作業用 surface の削除
|
|
if (sact.sel.charcanvas)
|
|
SDL_FreeSurface(sact.sel.charcanvas);
|
|
sact.sel.charcanvas = NULL;
|
|
}
|
|
|
|
|
|
// 選択メインループ
|
|
static int sel_main() {
|
|
sact.waittype = KEYWAIT_SELECT;
|
|
sact.waitkey = -1;
|
|
|
|
selected_item = -1;
|
|
|
|
while(selected_item == -1) {
|
|
sys_keywait(25, KEYWAIT_CANCELABLE);
|
|
if (nact->is_quit)
|
|
selected_item = 0;
|
|
}
|
|
|
|
sact.waittype = KEYWAIT_NONE;
|
|
|
|
return selected_item;
|
|
}
|
|
|
|
/*
|
|
選択肢関連の初期化
|
|
*/
|
|
void ssel_init() {
|
|
// callbackの設定
|
|
sact.sel.cbmove = cb_select_move;
|
|
sact.sel.cbrelease = cb_select_release;
|
|
|
|
// デフォルトフォント
|
|
sact.sel.font_type = FONT_GOTHIC;
|
|
}
|
|
|
|
void ssel_reset(void) {
|
|
ssel_clear();
|
|
if (sact.sel.charcanvas) {
|
|
SDL_FreeSurface(sact.sel.charcanvas);
|
|
sact.sel.charcanvas = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
内部の選択肢情報をクリア
|
|
*/
|
|
void ssel_clear() {
|
|
int i;
|
|
|
|
for (i = 0; i < SEL_ELEMENT_MAX; i++) {
|
|
free(sact.sel.elem[i]);
|
|
sact.sel.elem[i] = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
登録文字列を内部選択肢情報に追加
|
|
@param nString: 登録文字列変数
|
|
@param wI : 登録位置
|
|
*/
|
|
void ssel_add(int nString, int wI) {
|
|
if ((wI >= SEL_ELEMENT_MAX -1) || (wI <= 0)) {
|
|
//error
|
|
return;
|
|
}
|
|
if (sact.sel.elem[wI] != NULL) {
|
|
free(sact.sel.elem[wI]);
|
|
}
|
|
|
|
sact.sel.elem[wI] = strdup(svar_get(nString));
|
|
}
|
|
|
|
/*
|
|
選択ウィンドを開いて選択
|
|
|
|
@param wNum: 枠,背景とするスプライト番号
|
|
@param wChoiceSize: 選択肢文字サイズ
|
|
@param wMenuOutSpc: 枠スプライトの外側からのピクセル数
|
|
@param wChoiceLineSpace: 選択肢の行間
|
|
@param wChoiceAutoMoveCursor: オープン時に自動的に移動する選択肢の番号
|
|
@param nAlign: 行そろえ (0:左, 1:中央, 2: 右)
|
|
*/
|
|
int ssel_select(int wNum, int wChoiceSize, int wMenuOutSpc, int wChoiceLineSpace, int wChoiceAutoMoveCursor, int nAlign) {
|
|
int ret = 0;
|
|
bool saveflag;
|
|
|
|
// check sprite number is sane
|
|
if (wNum >= (SPRITEMAX-1) || wNum <= 0) return ret;
|
|
|
|
// check sprite is set
|
|
if (sact.sp[wNum] == NULL) return ret;
|
|
|
|
// must be normal sprite
|
|
if (sact.sp[wNum]->type != SPRITE_NORMAL) return ret;
|
|
|
|
sact.sel.spno = wNum;
|
|
sact.sel.font_size = wChoiceSize;
|
|
sact.sel.frame_dot = wMenuOutSpc;
|
|
sact.sel.linespace = wChoiceLineSpace;
|
|
sact.sel.movecursor = wChoiceAutoMoveCursor;
|
|
sact.sel.align = nAlign;
|
|
|
|
// 古い sprite の表示フラグを保存
|
|
saveflag = sact.sp[wNum]->show;
|
|
sact.sp[wNum]->show = true;
|
|
setup_selwindow();
|
|
|
|
ret = sel_main();
|
|
|
|
// 表示フラグを元に戻す
|
|
sact.sp[wNum]->show = saveflag;
|
|
|
|
remove_selwindow();
|
|
|
|
return ret;
|
|
}
|