Files
Gobang-Game/src/gui_menu.c
T
Serendipity 0baab8bec6 feat(gui): 添加主菜单和游戏模式选择界面
- 新增 GUI 主菜单,支持玩家对战、人机对战、复盘模式和设置选项
- 新增游戏设置对话框,可配置棋盘大小、禁手、计时器和 AI 难度
- 重构 GUI 游戏窗口,集成悔棋、保存和返回菜单功能
- 更新 Makefile 以支持 PowerShell 并添加新源文件编译
- 调整窗口尺寸为 1000x800 以提供更好的游戏体验
2026-03-17 15:41:48 +08:00

264 lines
8.1 KiB
C

#include <iup.h>
#include <stdlib.h>
#include <stdio.h>
#include "gui_menu.h"
#include "gui.h"
#include "globals.h"
#include "config.h"
static Ihandle *menu_dlg = NULL;
static int btn_pvp_cb(Ihandle *ih)
{
(void)ih;
hide_main_menu();
start_pvp_game_gui();
return IUP_DEFAULT;
}
static int btn_pve_cb(Ihandle *ih)
{
(void)ih;
hide_main_menu();
start_pve_game_gui();
return IUP_DEFAULT;
}
static int btn_replay_cb(Ihandle *ih)
{
(void)ih;
hide_main_menu();
start_replay_gui();
return IUP_DEFAULT;
}
static int btn_save_settings_cb(Ihandle *ih)
{
Ihandle *dlg = IupGetDialog(ih);
// Get values
Ihandle *txt_board_size = IupGetDialogChild(dlg, "BOARD_SIZE");
Ihandle *tgl_forbidden = IupGetDialogChild(dlg, "FORBIDDEN");
Ihandle *tgl_timer = IupGetDialogChild(dlg, "TIMER");
Ihandle *txt_time_limit = IupGetDialogChild(dlg, "TIME_LIMIT");
Ihandle *lst_ai = IupGetDialogChild(dlg, "AI_DIFFICULTY");
// Update globals
int new_size = IupGetInt(txt_board_size, "VALUE");
if (new_size < MIN_BOARD_SIZE) new_size = MIN_BOARD_SIZE;
if (new_size > MAX_BOARD_SIZE) new_size = MAX_BOARD_SIZE;
BOARD_SIZE = new_size;
use_forbidden_moves = IupGetInt(tgl_forbidden, "VALUE");
use_timer = IupGetInt(tgl_timer, "VALUE");
if (use_timer) {
int minutes = IupGetInt(txt_time_limit, "VALUE");
if (minutes < 1) minutes = 1;
time_limit = minutes * 60;
}
int ai_level = IupGetInt(lst_ai, "VALUE");
if (ai_level < 1) ai_level = 1;
if (ai_level > 5) ai_level = 5;
ai_difficulty = ai_level;
defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT + (ai_difficulty - 1) * 0.1;
// Save config
save_game_config();
IupHide(dlg);
return IUP_DEFAULT;
}
static int btn_cancel_settings_cb(Ihandle *ih)
{
Ihandle *dlg = IupGetDialog(ih);
IupHide(dlg);
return IUP_DEFAULT;
}
static int tgl_timer_cb(Ihandle *ih, int state)
{
Ihandle *dlg = IupGetDialog(ih);
Ihandle *txt_time_limit = IupGetDialogChild(dlg, "TIME_LIMIT");
IupSetAttribute(txt_time_limit, "ACTIVE", state ? "YES" : "NO");
return IUP_DEFAULT;
}
static int btn_settings_cb(Ihandle *ih)
{
(void)ih;
// 1. Board Size
Ihandle *lbl_board_size = IupLabel("棋盘大小 (5-25):");
Ihandle *txt_board_size = IupText(NULL);
IupSetAttribute(txt_board_size, "NAME", "BOARD_SIZE");
IupSetAttribute(txt_board_size, "SPIN", "YES");
IupSetAttribute(txt_board_size, "SPINMIN", "5");
IupSetAttribute(txt_board_size, "SPINMAX", "25");
IupSetInt(txt_board_size, "VALUE", BOARD_SIZE);
IupSetAttribute(txt_board_size, "SIZE", "50x");
// 2. Forbidden Moves
Ihandle *tgl_forbidden = IupToggle("启用禁手规则", NULL);
IupSetAttribute(tgl_forbidden, "NAME", "FORBIDDEN");
IupSetInt(tgl_forbidden, "VALUE", use_forbidden_moves);
// 3. Timer
Ihandle *tgl_timer = IupToggle("启用计时器", NULL);
IupSetAttribute(tgl_timer, "NAME", "TIMER");
IupSetInt(tgl_timer, "VALUE", use_timer);
IupSetCallback(tgl_timer, "ACTION", (Icallback)tgl_timer_cb);
// 4. Time Limit
Ihandle *lbl_time_limit = IupLabel("时间限制 (分钟):");
Ihandle *txt_time_limit = IupText(NULL);
IupSetAttribute(txt_time_limit, "NAME", "TIME_LIMIT");
IupSetAttribute(txt_time_limit, "SPIN", "YES");
IupSetAttribute(txt_time_limit, "SPINMIN", "1");
IupSetAttribute(txt_time_limit, "SPINMAX", "60");
IupSetInt(txt_time_limit, "VALUE", time_limit / 60);
IupSetAttribute(txt_time_limit, "ACTIVE", use_timer ? "YES" : "NO");
IupSetAttribute(txt_time_limit, "SIZE", "50x");
// 5. AI Difficulty
Ihandle *lbl_ai = IupLabel("AI 难度 (1-5):");
Ihandle *lst_ai = IupList(NULL);
IupSetAttribute(lst_ai, "NAME", "AI_DIFFICULTY");
IupSetAttribute(lst_ai, "DROPDOWN", "YES");
IupSetAttribute(lst_ai, "1", "1 (简单)");
IupSetAttribute(lst_ai, "2", "2 (普通)");
IupSetAttribute(lst_ai, "3", "3 (中等)");
IupSetAttribute(lst_ai, "4", "4 (困难)");
IupSetAttribute(lst_ai, "5", "5 (专家)");
IupSetInt(lst_ai, "VALUE", ai_difficulty);
IupSetAttribute(lst_ai, "SIZE", "80x");
// Buttons
Ihandle *btn_save = IupButton("保存", NULL);
IupSetCallback(btn_save, "ACTION", (Icallback)btn_save_settings_cb);
IupSetAttribute(btn_save, "SIZE", "60x");
Ihandle *btn_cancel = IupButton("取消", NULL);
IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_cancel_settings_cb);
IupSetAttribute(btn_cancel, "SIZE", "60x");
// Layout
Ihandle *hbox_board = IupHbox(lbl_board_size, txt_board_size, NULL);
IupSetAttribute(hbox_board, "ALIGNMENT", "ACENTER");
IupSetAttribute(hbox_board, "GAP", "10");
Ihandle *hbox_time = IupHbox(lbl_time_limit, txt_time_limit, NULL);
IupSetAttribute(hbox_time, "ALIGNMENT", "ACENTER");
IupSetAttribute(hbox_time, "GAP", "10");
Ihandle *hbox_ai = IupHbox(lbl_ai, lst_ai, NULL);
IupSetAttribute(hbox_ai, "ALIGNMENT", "ACENTER");
IupSetAttribute(hbox_ai, "GAP", "10");
Ihandle *hbox_btns = IupHbox(btn_save, btn_cancel, NULL);
IupSetAttribute(hbox_btns, "GAP", "20");
IupSetAttribute(hbox_btns, "MARGIN", "10x0");
IupSetAttribute(hbox_btns, "ALIGNMENT", "ACENTER");
Ihandle *vbox = IupVbox(
hbox_board,
tgl_forbidden,
tgl_timer,
hbox_time,
hbox_ai,
IupLabel(NULL), // Spacer
hbox_btns,
NULL);
IupSetAttribute(vbox, "GAP", "15");
IupSetAttribute(vbox, "MARGIN", "30x30");
Ihandle *dlg = IupDialog(vbox);
IupSetAttribute(dlg, "TITLE", "游戏设置");
IupSetAttribute(dlg, "RESIZE", "NO");
IupSetAttribute(dlg, "MINBOX", "NO");
IupSetAttribute(dlg, "MAXBOX", "NO");
IupPopup(dlg, IUP_CENTER, IUP_CENTER);
IupDestroy(dlg);
return IUP_DEFAULT;
}
static int btn_exit_cb(Ihandle *ih)
{
(void)ih;
cleanup_gui(); // 清理GUI资源
exit(0);
return IUP_DEFAULT;
}
void create_main_menu()
{
if (menu_dlg) return;
Ihandle *lbl_title = IupLabel("五子棋 (Gobang)");
IupSetAttribute(lbl_title, "FONT", "SimHei, 24");
IupSetAttribute(lbl_title, "ALIGNMENT", "ACENTER");
Ihandle *btn_pvp = IupButton("玩家对战 (PvP)", NULL);
IupSetCallback(btn_pvp, "ACTION", (Icallback)btn_pvp_cb);
IupSetAttribute(btn_pvp, "SIZE", "120x30");
IupSetAttribute(btn_pvp, "FONT", "SimHei, 12");
Ihandle *btn_pve = IupButton("人机对战 (PvE)", NULL);
IupSetCallback(btn_pve, "ACTION", (Icallback)btn_pve_cb);
IupSetAttribute(btn_pve, "SIZE", "120x30");
IupSetAttribute(btn_pve, "FONT", "SimHei, 12");
Ihandle *btn_replay = IupButton("复盘模式", NULL);
IupSetCallback(btn_replay, "ACTION", (Icallback)btn_replay_cb);
IupSetAttribute(btn_replay, "SIZE", "120x30");
IupSetAttribute(btn_replay, "FONT", "SimHei, 12");
Ihandle *btn_settings = IupButton("设置", NULL);
IupSetCallback(btn_settings, "ACTION", (Icallback)btn_settings_cb);
IupSetAttribute(btn_settings, "SIZE", "120x30");
IupSetAttribute(btn_settings, "FONT", "SimHei, 12");
Ihandle *btn_exit = IupButton("退出", NULL);
IupSetCallback(btn_exit, "ACTION", (Icallback)btn_exit_cb);
IupSetAttribute(btn_exit, "SIZE", "120x30");
IupSetAttribute(btn_exit, "FONT", "SimHei, 12");
Ihandle *vbox = IupVbox(
lbl_title,
btn_pvp,
btn_pve,
btn_replay,
btn_settings,
btn_exit,
NULL);
IupSetAttribute(vbox, "ALIGNMENT", "ACENTER");
IupSetAttribute(vbox, "GAP", "15");
IupSetAttribute(vbox, "MARGIN", "40x40");
menu_dlg = IupDialog(vbox);
IupSetAttribute(menu_dlg, "TITLE", "五子棋 - 主菜单");
IupSetAttribute(menu_dlg, "RESIZE", "NO");
IupSetAttribute(menu_dlg, "MINBOX", "NO");
IupSetAttribute(menu_dlg, "MAXBOX", "NO");
// 设置对话框关闭回调 (点X关闭程序)
IupSetCallback(menu_dlg, "CLOSE_CB", (Icallback)btn_exit_cb);
}
void show_main_menu()
{
if (!menu_dlg)
create_main_menu();
IupShowXY(menu_dlg, IUP_CENTER, IUP_CENTER);
}
void hide_main_menu()
{
if (menu_dlg)
IupHide(menu_dlg);
}