// ---------------------------------------------------------------------------
//  M88 - PC-8801 emulator
//	Copyright (C) cisc 1998, 1999.
// ---------------------------------------------------------------------------
//	User Interface for Win32
// ---------------------------------------------------------------------------
//	$Id: ui.h,v 1.33 2002/05/31 09:45:21 cisc Exp $

#pragma once

#include "types.h"
#include "wincore.h"
#include "WinDraw.h"
#include "WinKeyIF.h"
#include "88config.h"
#include "wincfg.h"
#include "wincrtcfg.h"
#include "newdisk.h"
#include "soundmon.h"
#include "memmon.h"
#include "codemon.h"
#include "basmon.h"
#include "regmon.h"
#include "loadmon.h"
#include "iomon.h"
#include "bpmon.h"
#include "watchmon.h"
#include "tracemon.h"
#include "dbgsettings.h"

// ---------------------------------------------------------------------------

class WinUI
{
public:
	WinUI(HINSTANCE hinst);
	~WinUI();
	
	bool InitWindow(int nwinmode);
	int  Main(const char* cmdline);
	uint GetMouseButton() { return mousebutton; }
	HWND GetHWnd() { return hwnd; }

private:
	struct DiskInfo
	{
		HMENU hmenu;
		int currentdisk;
		int idchgdisk;
		bool readonly;
		char filename[MAX_PATH];
	};
	struct ExtNode
	{
		ExtNode* next;
		IWinUIExtention* ext;
	};

private:
	bool InitM88(const char* cmdline);
	void CleanupM88();
	LRESULT WinProc(HWND, UINT, WPARAM, LPARAM);
	static LRESULT CALLBACK WinProcGate(HWND, UINT, WPARAM, LPARAM);
	void ReportError();
	void Reset();

	void ApplyConfig();
	void ApplyCRTParams();		// CRT パラメータを描画バックエンドへ反映する
	void ApplyCommandLine(const char* cmdline);

	void ToggleDisplayMode();
	void ChangeDisplayType();
	void ApplyWindowGeometry();				// 倍率/全画面に応じて窓とスタイルを設定
	void GetScaledSize(uint& w, uint& h);	// 現在の倍率での描画サイズ
	void SetScreenScale(int scale);			// メニューから呼ぶ
	void ComputeFullScreenRect(RECT& monitor);
	void SetCursorVisible(bool visible);		// ShowCursor をカウンタ安全に呼ぶ
	void SetWindowCornerRound(bool round);	// Win11 の角の丸め (全画面では切る)

	// フルスクリーン中はメニューを窓から外して hmenumain に退避しているため、
	// GetMenu(hwnd) は 0 を返す。メニュー項目を書き換える処理はこちらを使うこと
	HMENU GetMainMenu();

	void ShowFullScreenNotice();		// 全画面移行時の操作案内を表示する
	void HideFullScreenNotice();
	void ShowFullScreenMenu(int x, int y);	// 全画面時の右クリックメニュー

	void ChangeDiskImage(HWND hwnd, int drive);
	bool OpenDiskImage(int drive, const char* filename, bool readonly, int id, bool create);
	void OpenDiskImage(const char* filename);
	// ドライブ0のイメージが入れ替わったときに、ブレークポイント/ウォッチを
	// ディスクイメージ単位のサイドカーファイルへ保存/復元する。
	// oldkey/newkey はそれぞれ入れ替え前後の diskinfo[0].filename
	void SyncDebugSettings(const char* oldkey, const char* newkey);
	bool SelectDisk(uint drive, int id, bool menuonly);
	bool CreateDiskMenu(uint drive);

	void ChangeTapeImage();
	void OpenTapeImage(const char* filename);

	void ShowStatusWindow();
	void ShowPauseStatus();
	void ResizeWindow(uint width, uint height);
	void SetGUIFlag(bool);

	// ステップ実行の対象 CPU を決める (仕様書 §1.3)
	PC8801::Debugger::CpuTarget GetStepTarget();

	void SaveSnapshot(int n);
	void LoadSnapshot(int n);
	void GetSnapshotName(char*, int);
	bool MakeSnapshotMenu();

	void CaptureScreen();

	void SaveWindowPosition();
	void LoadWindowPosition();

	int AllocControlID();
	void FreeControlID(int);

	// ウインドウ関係
	HWND hwnd;
	HINSTANCE hinst;
	HACCEL accel;
	HMENU hmenudbg;
	HMENU hmenumain;			// 全画面時に外したメインメニューの退避先
	HWND hwndnotice;			// 全画面移行時の操作案内ポップアップ

	// 状態表示用
	UINT_PTR timerid;
	bool report;
	volatile bool active;

	// F5/F10/F11 の WM_(SYS)KEYDOWN を処理する直前、TranslateAccelerator を
	// 呼ぶ前の時点でのデバッガ状態を保持する。Wm(Sys)KeyDown 側で
	// core.IsPaused()/IsStepping() を再取得すると、既に同じキーで実行された
	// デバッガコマンド(StepIn等)の結果を見てしまい判定がずれるため
	bool debugkeysuppress;

	// ウインドウの状態
	bool background;
	bool fullscreen;
	uint displaychangedtime;
	uint resetwindowsize;
	DWORD wstyle;
	POINT point;
	int clipmode;
	bool guimodebymouse;
	bool cursorvisible;			// ShowCursor のカウンタ管理用
	
	// disk
	DiskInfo diskinfo[2];
	char tapetitle[MAX_PATH];
	
	// snapshot 関係
	HMENU hmenuss[2];
	int currentsnapshot;
	bool snapshotchanged;

	// PC88
	bool capturemouse;
	uint mousebutton;
	
	WinCore core;
	WinDraw draw;
	PC8801::WinKeyIF keyif;
	PC8801::Config config;
	PC8801::WinConfig winconfig;
	PC8801::WinCRTConfig wincrtcfg;
	WinNewDisk newdisk;
	OPNMonitor opnmon;
	PC8801::MemoryMonitor memmon;
	PC8801::CodeMonitor codemon;
	PC8801::BasicMonitor basmon;
	PC8801::IOMonitor iomon;
	PC8801::BreakMonitor bpmon;
	PC8801::WatchMonitor watchmon;
	PC8801::TraceMonitor tracemon;
	bool debugnodiskwarned;		// 「ディスク未挿入のため保存されません」を一度だけ出す
	Z80RegMonitor regmon;
	LoadMonitor loadmon;
	DiskManager* diskmgr;
	TapeManager* tapemgr;

private:
	// メッセージ関数
	LRESULT M88ChangeDisplay(HWND, WPARAM, LPARAM);
	LRESULT M88ChangeVolume(HWND, WPARAM, LPARAM);
	LRESULT M88ApplyConfig(HWND, WPARAM, LPARAM);
	LRESULT M88ApplyCRTParam(HWND, WPARAM, LPARAM);
	LRESULT M88SendKeyState(HWND, WPARAM, LPARAM);
	LRESULT M88ClipCursor(HWND, WPARAM, LPARAM);
	LRESULT M88DebugBreak(HWND, WPARAM, LPARAM);
	LRESULT WmDropFiles(HWND, WPARAM, LPARAM);
	LRESULT WmDisplayChange(HWND, WPARAM, LPARAM);
	LRESULT WmKeyDown(HWND, WPARAM, LPARAM);
	LRESULT WmKeyUp(HWND, WPARAM, LPARAM);
	LRESULT WmSysKeyDown(HWND, WPARAM, LPARAM);
	LRESULT WmSysKeyUp(HWND, WPARAM, LPARAM);
	LRESULT WmInitMenu(HWND, WPARAM, LPARAM);
	LRESULT WmQueryNewPalette(HWND, WPARAM, LPARAM);
	LRESULT WmPaletteChanged(HWND, WPARAM, LPARAM);
	LRESULT WmActivate(HWND, WPARAM, LPARAM);
	LRESULT WmTimer(HWND, WPARAM, LPARAM);
	LRESULT WmClose(HWND, WPARAM, LPARAM);
	LRESULT WmCreate(HWND, WPARAM, LPARAM);
	LRESULT WmDestroy(HWND, WPARAM, LPARAM);
	LRESULT WmPaint(HWND, WPARAM, LPARAM);
	LRESULT WmCommand(HWND, WPARAM, LPARAM);
	LRESULT WmSize(HWND, WPARAM, LPARAM);
	LRESULT WmDrawItem(HWND, WPARAM, LPARAM);
	LRESULT WmEnterMenuLoop(HWND, WPARAM, LPARAM);
	LRESULT WmExitMenuLoop(HWND, WPARAM, LPARAM);
	LRESULT WmLButtonDown(HWND, WPARAM, LPARAM);
	LRESULT WmLButtonUp(HWND, WPARAM, LPARAM);
	LRESULT WmRButtonDown(HWND, WPARAM, LPARAM);
	LRESULT WmRButtonUp(HWND, WPARAM, LPARAM);
	LRESULT WmEnterSizeMove(HWND, WPARAM, LPARAM);
	LRESULT WmExitSizeMove(HWND, WPARAM, LPARAM);
	LRESULT WmMove(HWND, WPARAM, LPARAM);
	LRESULT WmMouseMove(HWND, WPARAM, LPARAM);
	LRESULT WmSetCursor(HWND, WPARAM, LPARAM);
	LRESULT WmEraseBkgnd(HWND, WPARAM, LPARAM);
};

