343 lines
14 KiB
C#
343 lines
14 KiB
C#
using System.ComponentModel;
|
|
|
|
namespace AccompanyingAssistant {
|
|
public partial class MainForm : Form {
|
|
bool haveHandle = true; //用于SetBits
|
|
bool bFormDragging = false; // 用于窗体移动
|
|
Point oPointClicked; // 用于窗体移动
|
|
|
|
int dragFrame = 0; //拖拽帧数计数
|
|
int blinkFrame = 0; //眨眼帧数计数
|
|
int hatNum = -1;
|
|
int clothesNum = -1;
|
|
private enum PetStates { General = 0, Drag = 1 };
|
|
|
|
Bitmap[] pet = new Bitmap[30];
|
|
Bitmap[] petDrag = new Bitmap[3];
|
|
Bitmap[] petBlink = new Bitmap[2];
|
|
|
|
Bitmap[,] petHat = new Bitmap[10, 2];
|
|
Bitmap[,] petClothes = new Bitmap[5, 4];
|
|
|
|
Bitmap[] petWithClothes = new Bitmap[30];
|
|
Bitmap[] petDragWithClothes = new Bitmap[3];
|
|
Bitmap[] petBlinkWithClothes = new Bitmap[3];
|
|
|
|
private Queue<string> messageQueue = new Queue<string>();
|
|
private bool isBubbleVisible = false;
|
|
private int bubbleShowTime = 5000; // 显示时间(毫秒)
|
|
private DateTime bubbleStartTime;
|
|
private BubbleForm bubbleForm;
|
|
|
|
public MainForm() {
|
|
InitializeComponent();
|
|
}
|
|
#region 重载
|
|
|
|
protected override void OnClosing(CancelEventArgs e) {
|
|
e.Cancel = true;
|
|
base.OnClosing(e);
|
|
haveHandle = false;
|
|
}
|
|
|
|
protected override void OnHandleCreated(EventArgs e) {
|
|
InitializeStyles();
|
|
base.OnHandleCreated(e);
|
|
haveHandle = true;
|
|
}
|
|
|
|
private void InitializeStyles() {
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
SetStyle(ControlStyles.UserPaint, true);
|
|
UpdateStyles();
|
|
}
|
|
|
|
protected override CreateParams CreateParams {
|
|
get {
|
|
CreateParams cParms = base.CreateParams;
|
|
cParms.ExStyle |= 0x00080000; // WS_EX_LAYERED
|
|
return cParms;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void SetBits(Bitmap bitmap) {
|
|
if (!haveHandle) return;
|
|
|
|
if (!Bitmap.IsCanonicalPixelFormat(bitmap.PixelFormat) || !Bitmap.IsAlphaPixelFormat(bitmap.PixelFormat))
|
|
MessageBox.Show("Error Bitmap");
|
|
|
|
IntPtr oldBits = IntPtr.Zero;
|
|
IntPtr screenDC = Win32.GetDC(IntPtr.Zero);
|
|
IntPtr hBitmap = IntPtr.Zero;
|
|
IntPtr memDc = Win32.CreateCompatibleDC(screenDC);
|
|
|
|
try {
|
|
Win32.Point topLoc = new Win32.Point(Left, Top);
|
|
Win32.Size bitMapSize = new Win32.Size(bitmap.Width, bitmap.Height);
|
|
Win32.BLENDFUNCTION blendFunc = new Win32.BLENDFUNCTION();
|
|
Win32.Point srcLoc = new Win32.Point(0, 0);
|
|
|
|
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
|
|
oldBits = Win32.SelectObject(memDc, hBitmap);
|
|
|
|
blendFunc.BlendOp = Win32.AC_SRC_OVER;
|
|
blendFunc.SourceConstantAlpha = 255;
|
|
blendFunc.AlphaFormat = Win32.AC_SRC_ALPHA;
|
|
blendFunc.BlendFlags = 0;
|
|
|
|
Win32.UpdateLayeredWindow(Handle, screenDC, ref topLoc, ref bitMapSize, memDc, ref srcLoc, 0, ref blendFunc, Win32.ULW_ALPHA);
|
|
} finally {
|
|
if (hBitmap != IntPtr.Zero) {
|
|
Win32.SelectObject(memDc, oldBits);
|
|
Win32.DeleteObject(hBitmap);
|
|
}
|
|
Win32.ReleaseDC(IntPtr.Zero, screenDC);
|
|
Win32.DeleteDC(memDc);
|
|
}
|
|
}
|
|
|
|
private Bitmap CombinedPic(Bitmap bottom, Bitmap top, int x, int y) {
|
|
Bitmap bitmap = new Bitmap(bottom.Width, bottom.Height);
|
|
Graphics g = Graphics.FromImage(bitmap);
|
|
g.DrawImage(bottom, new Rectangle(0, 0, bottom.Width, bottom.Height), new Rectangle(0, 0, bottom.Width, bottom.Height), GraphicsUnit.Pixel);
|
|
g.DrawImage(top, new Rectangle(x, y, top.Width, top.Height), new Rectangle(0, 0, top.Width, top.Height), GraphicsUnit.Pixel);
|
|
return bitmap;
|
|
}
|
|
|
|
private Bitmap Dress(Bitmap img, int state) {
|
|
Bitmap bitmap = new Bitmap(img.Width, img.Height);
|
|
bitmap = img;
|
|
if (clothesNum != -1) {
|
|
bitmap = CombinedPic(bitmap, petClothes[clothesNum, state], 0, 0);
|
|
}
|
|
if (hatNum != -1) {
|
|
bitmap = CombinedPic(bitmap, petHat[hatNum, state], 0, 0);
|
|
}
|
|
return bitmap;
|
|
}
|
|
protected override void OnLocationChanged(EventArgs e) {
|
|
base.OnLocationChanged(e);
|
|
if (isBubbleVisible) {
|
|
bubbleForm.Location = CalculateBubblePosition();
|
|
}
|
|
}
|
|
|
|
private void Form1_Load(object sender, EventArgs e) {
|
|
pet[0] = new Bitmap(Application.StartupPath + "\\shell\\surface0000.png");
|
|
pet[1] = new Bitmap(Application.StartupPath + "\\shell\\surface0001.png");
|
|
pet[2] = new Bitmap(Application.StartupPath + "\\shell\\surface0002.png");
|
|
pet[3] = new Bitmap(Application.StartupPath + "\\shell\\surface0003.png");
|
|
pet[4] = new Bitmap(Application.StartupPath + "\\shell\\surface0004.png");
|
|
pet[5] = new Bitmap(Application.StartupPath + "\\shell\\surface0005.png");
|
|
pet[6] = new Bitmap(Application.StartupPath + "\\shell\\surface0006.png");
|
|
pet[7] = new Bitmap(Application.StartupPath + "\\shell\\surface0007.png");
|
|
pet[8] = new Bitmap(Application.StartupPath + "\\shell\\surface0008.png");
|
|
pet[9] = new Bitmap(Application.StartupPath + "\\shell\\surface0009.png");
|
|
petDrag[0] = new Bitmap(Application.StartupPath + "\\shell\\surface0091.png");
|
|
petDrag[1] = new Bitmap(Application.StartupPath + "\\shell\\surface0092.png");
|
|
petDrag[2] = new Bitmap(Application.StartupPath + "\\shell\\surface0093.png");
|
|
petBlink[0] = new Bitmap(Application.StartupPath + "\\shell\\surface1003.png");
|
|
petBlink[1] = new Bitmap(Application.StartupPath + "\\shell\\surface1004.png");
|
|
petHat[0, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3000.png");
|
|
petHat[0, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3001.png");
|
|
petHat[1, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3002.png");
|
|
petHat[1, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3003.png");
|
|
petHat[2, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3004.png");
|
|
petHat[2, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3005.png");
|
|
petHat[3, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3006.png");
|
|
petHat[3, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3007.png");
|
|
petClothes[0, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3100.png");
|
|
petClothes[0, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3101.png");
|
|
petClothes[0, 2] = new Bitmap(Application.StartupPath + "\\shell\\surface3102.png");
|
|
petClothes[0, 3] = new Bitmap(Application.StartupPath + "\\shell\\surface3103.png");
|
|
petClothes[1, 0] = new Bitmap(Application.StartupPath + "\\shell\\surface3200.png");
|
|
petClothes[1, 1] = new Bitmap(Application.StartupPath + "\\shell\\surface3201.png");
|
|
petClothes[1, 2] = new Bitmap(Application.StartupPath + "\\shell\\surface3202.png");
|
|
petClothes[1, 3] = new Bitmap(Application.StartupPath + "\\shell\\surface3203.png");
|
|
|
|
DressAll();
|
|
SetBits(petWithClothes[0]);
|
|
// 初始化气泡窗体
|
|
InitializeBubbleForm();
|
|
|
|
}
|
|
// 初始化气泡窗体
|
|
private void InitializeBubbleForm() {
|
|
bubbleForm = new BubbleForm();
|
|
bubbleForm.Visible = false;
|
|
bubbleForm.Owner = this;
|
|
bubbleForm.Location = CalculateBubblePosition();
|
|
}
|
|
|
|
// 计算气泡位置(在宠物上方)
|
|
private Point CalculateBubblePosition() {
|
|
// 获取宠物窗体的中心点
|
|
Point petCenter = new Point(
|
|
this.Left + (this.Width / 2),
|
|
this.Top
|
|
);
|
|
|
|
// 计算气泡位置(居中于宠物上方)
|
|
return new Point(
|
|
petCenter.X - (bubbleForm.Width / 2),
|
|
petCenter.Y - bubbleForm.Height - 10
|
|
);
|
|
}
|
|
|
|
// 新增方法:显示消息气泡
|
|
public void ShowMessage(string message) {
|
|
if (isBubbleVisible) {
|
|
messageQueue.Enqueue(message);
|
|
return;
|
|
}
|
|
|
|
bubbleForm.Message = message;
|
|
|
|
// 先确保气泡大小已更新
|
|
bubbleForm.UpdateSize();
|
|
|
|
// 计算正确位置
|
|
Point bubblePos = CalculateBubblePosition();
|
|
bubbleForm.Location = bubblePos;
|
|
|
|
bubbleForm.Show();
|
|
bubbleForm.BringToFront();
|
|
isBubbleVisible = true;
|
|
bubbleStartTime = DateTime.Now;
|
|
|
|
tmrBubble.Interval = 100;
|
|
tmrBubble.Enabled = true;
|
|
}
|
|
|
|
// 新增方法:关闭当前气泡
|
|
public void CloseBubble() {
|
|
bubbleForm.Hide();
|
|
isBubbleVisible = false;
|
|
|
|
// 检查队列中是否有待显示消息
|
|
if (messageQueue.Count > 0) {
|
|
ShowMessage(messageQueue.Dequeue());
|
|
}
|
|
}
|
|
|
|
// 新增气泡计时器Tick事件
|
|
private void tmrBubble_Tick(object sender, EventArgs e) {
|
|
// 检查是否达到显示时间
|
|
if ((DateTime.Now - bubbleStartTime).TotalMilliseconds >= bubbleShowTime) {
|
|
CloseBubble();
|
|
}
|
|
}
|
|
|
|
|
|
#region 拖拽
|
|
|
|
private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Left) {
|
|
bFormDragging = true;
|
|
oPointClicked = new Point(e.X, e.Y);
|
|
tmrDrag.Interval = 110;
|
|
tmrDrag.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Left) {
|
|
bFormDragging = false;
|
|
tmrDrag.Enabled = false;
|
|
SetBits(petWithClothes[0]);
|
|
}
|
|
}
|
|
|
|
private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
|
|
if (bFormDragging) {
|
|
Point oMoveToPoint = default(Point);
|
|
//以当前鼠标位置为基础,找出目标位置
|
|
oMoveToPoint = PointToScreen(new Point(e.X, e.Y));
|
|
oMoveToPoint.Offset(oPointClicked.X * -1, (oPointClicked.Y + SystemInformation.CaptionHeight + SystemInformation.BorderSize.Height) * -1 + 24);
|
|
Location = oMoveToPoint;
|
|
}
|
|
}
|
|
|
|
private void tmrDrag_Tick(object sender, EventArgs e) {
|
|
if (dragFrame < 2) {
|
|
SetBits(petDragWithClothes[dragFrame]);
|
|
dragFrame += 1;
|
|
} else {
|
|
SetBits(petDragWithClothes[dragFrame]);
|
|
dragFrame = 0;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e) {
|
|
Application.Exit();
|
|
}
|
|
|
|
private void 眨眼ToolStripMenuItem_Click(object sender, EventArgs e) {
|
|
tmrBlink.Interval = 40;
|
|
tmrBlink.Start();
|
|
}
|
|
|
|
private void tmrBlink_Tick(object sender, EventArgs e) {
|
|
if (blinkFrame < 2) {
|
|
SetBits(petBlinkWithClothes[blinkFrame]);
|
|
blinkFrame += 1;
|
|
} else {
|
|
SetBits(petWithClothes[0]);
|
|
blinkFrame = 0;
|
|
tmrBlink.Stop();
|
|
}
|
|
}
|
|
|
|
private void 帽子ToolStripMenuItem_Click(object sender, EventArgs e) {
|
|
bool itemChecked = (sender as ToolStripMenuItem).Checked;
|
|
if (itemChecked) {
|
|
hatNum = -1;
|
|
} else {
|
|
hatNum = this.衣柜ToolStripMenuItem.DropDownItems.IndexOf(sender as ToolStripMenuItem);
|
|
}
|
|
this.圣诞帽子ToolStripMenuItem.Checked = false;
|
|
this.樱花帽子ToolStripMenuItem.Checked = false;
|
|
this.水手帽ToolStripMenuItem.Checked = false;
|
|
this.风车帽子ToolStripMenuItem.Checked = false;
|
|
(sender as ToolStripMenuItem).Checked = !itemChecked;
|
|
DressAll();
|
|
SetBits(petWithClothes[0]);
|
|
}
|
|
|
|
private void 衣服ToolStripMenuItem_Click(object sender, EventArgs e) {
|
|
bool itemChecked = (sender as ToolStripMenuItem).Checked;
|
|
if (itemChecked) {
|
|
clothesNum = -1;
|
|
} else {
|
|
clothesNum = this.衣柜ToolStripMenuItem.DropDownItems.IndexOf(sender as ToolStripMenuItem) - 4;
|
|
}
|
|
this.圣诞衣服ToolStripMenuItem.Checked = false;
|
|
this.和服ToolStripMenuItem.Checked = false;
|
|
(sender as ToolStripMenuItem).Checked = !itemChecked;
|
|
DressAll();
|
|
SetBits(petWithClothes[0]);
|
|
}
|
|
|
|
private void DressAll() {
|
|
int i;
|
|
for (i = 0; i < 10; i++) {
|
|
petWithClothes[i] = Dress(pet[i], (int)PetStates.General);
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
petDragWithClothes[i] = Dress(petDrag[i], (int)PetStates.Drag);
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
petBlinkWithClothes[i] = Dress(petBlink[i], (int)PetStates.General);
|
|
}
|
|
}
|
|
|
|
private void 消息测试ToolStripMenuItem_Click(object sender, EventArgs e) {
|
|
ShowMessage("这是一个测试消息气泡!\n它会在5秒后自动消失。\n你可以点击右键查看更多选项。");
|
|
}
|
|
}
|
|
}
|