[C++] 纯文本查看 复制代码
#include <graphics.h>
#include <vector>
#include <string>
#include <cmath>
#include <conio.h>
#include <windows.h>
using namespace std;
// ===================== 尺寸 =====================
const int TOOLBAR_WIDTH = 160;
const int WINDOW_WIDTH = 1000;
const int WINDOW_HEIGHT = 700;
const int BLOCK_WIDTH = 42;
const int BLOCK_HEIGHT = 72;
const int PORT_RADIUS = 5;
// 效果器类型
enum EffectType {
COMPRESSOR, EQ, DISTORTION, REVERB, DELAY,
GATE, OVERDRIVE, FUZZ, NOISE_GATE, DI
};
string getEffectName(EffectType type) {
switch (type) {
case COMPRESSOR: return "压缩";
case EQ: return "均衡";
case DISTORTION: return "失真";
case REVERB: return "混响";
case DELAY: return "延迟";
case GATE: return "门限";
case OVERDRIVE: return "过载";
case FUZZ: return "法兹";
case NOISE_GATE: return "清音";
case DI: return "降噪";
default: return "效果器";
}
}
COLORREF getEffectColor(EffectType type) {
switch (type) {
case COMPRESSOR: return RGB(40, 160, 255);
case EQ: return RGB(255, 120, 40);
case DISTORTION: return RGB(255, 60, 60);
case REVERB: return RGB(60, 255, 100);
case DELAY: return RGB(200, 60, 255);
case GATE: return RGB(50, 200, 200);
case OVERDRIVE: return RGB(255, 140, 0);
case FUZZ: return RGB(180, 0, 0);
case NOISE_GATE: return RGB(80, 80, 220);
case DI: return RGB(120, 120, 120);
default: return RGB(150, 150, 150);
}
}
// ===================== 效果器模块 =====================
struct EffectBlock {
EffectType type;
int x, y;
EffectBlock(EffectType t, int x_, int y_) : type(t), x(x_), y(y_) {}
// 统一扁平风格(左右完全一样)
void drawWithoutPorts() const {
setfillcolor(getEffectColor(type));
solidrectangle(x, y, x + BLOCK_WIDTH, y + BLOCK_HEIGHT);
settextcolor(WHITE);
setbkmode(TRANSPARENT);
settextstyle(16, 0, "微软雅黑"); // 统一小字体
outtextxy(x + 6, y + 26, getEffectName(type).c_str());
setfillcolor(BLACK);
solidcircle(x + 9, y + 12, 5);
solidcircle(x + 21, y + 12, 5);
solidcircle(x + 33, y + 12, 5);
setlinestyle(PS_SOLID, 1);
setlinecolor(BLACK);
line(x+5,y+25,x+37,y+25);
setfillcolor(WHITE);
solidcircle(x + 21, y + 60, 5);
}
// 统一扁平风格 + 端口
void drawWithPorts() const {
setfillcolor(getEffectColor(type));
solidrectangle(x, y, x + BLOCK_WIDTH, y + BLOCK_HEIGHT);
settextcolor(WHITE);
setbkmode(TRANSPARENT);
settextstyle(16, 0, "微软雅黑"); // 统一小字体,不超出
outtextxy(x + 6, y + 26, getEffectName(type).c_str());
setfillcolor(BLACK);
solidcircle(x + 9, y + 12, 5);
solidcircle(x + 21, y + 12, 5);
solidcircle(x + 33, y + 12, 5);
setlinestyle(PS_SOLID, 1);
setlinecolor(BLACK);
line(x+5,y+25,x+37,y+25);
setfillcolor(WHITE);
solidcircle(x + 21, y + 60, 5);
setfillcolor(WHITE);
solidcircle(getInPortX(), getInPortY(), PORT_RADIUS);
setfillcolor(YELLOW);
solidcircle(getOutPortX(), getOutPortY(), PORT_RADIUS);
}
int getInPortX() const { return x; }
int getInPortY() const { return y + BLOCK_HEIGHT / 2; }
int getOutPortX() const { return x + BLOCK_WIDTH; }
int getOutPortY() const { return y + BLOCK_HEIGHT / 2; }
bool isPointIn(int mx, int my) const {
return mx >= x && mx <= x + BLOCK_WIDTH && my >= y && my <= y + BLOCK_HEIGHT;
}
bool isClickInPort(int mx, int my) const {
return hypot(mx - getInPortX(), my - getInPortY()) <= PORT_RADIUS + 4;
}
bool isClickOutPort(int mx, int my) const {
return hypot(mx - getOutPortX(), my - getOutPortY()) <= PORT_RADIUS + 4;
}
};
// ===================== 连线结构 =====================
struct Connection {
bool fromMainInput = false;
int fromBlock = -1;
bool toMainOutput = false;
int toBlock = -1;
};
// ===================== 全局变量 =====================
vector<EffectBlock> blocks;
vector<Connection> connections;
// 左侧工具栏:两列布局
vector<EffectBlock> toolbarBlocks = {
EffectBlock(COMPRESSOR, 20, 50),
EffectBlock(EQ, 20, 140),
EffectBlock(DISTORTION, 20, 230),
EffectBlock(REVERB, 20, 320),
EffectBlock(DELAY, 20, 410),
EffectBlock(GATE, 90, 50),
EffectBlock(OVERDRIVE, 90, 140),
EffectBlock(FUZZ, 90, 230),
EffectBlock(NOISE_GATE, 90, 320),
EffectBlock(DI, 90, 410),
};
bool draggingBlock = false;
int dragIndex = -1;
bool drawingLine = false;
int lineFromIndex = -1;
int lineStartX, lineStartY;
bool lineFromInput = false;
bool needRedraw = true;
const int MAIN_IN_X = TOOLBAR_WIDTH + 40;
const int MAIN_IN_Y = 40;
const int MAIN_OUT_X = WINDOW_WIDTH - 40;
const int MAIN_OUT_Y = WINDOW_HEIGHT - 40;
// ===================== 函数声明 =====================
void drawAll();
void onMouse();
void drawMainIO();
// ===================== 主函数 =====================
int main() {
initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
BeginBatchDraw();
DWORD lastFrame = GetTickCount();
const int FPS = 60;
const int frameDelay = 1000 / FPS;
while (true) {
onMouse();
DWORD now = GetTickCount();
if (now - lastFrame >= frameDelay) {
if (needRedraw) {
drawAll();
needRedraw = false;
}
lastFrame = now;
}
Sleep(1);
}
closegraph();
return 0;
}
void drawMainIO() {
// 总输入(扁平)
setfillcolor(RGB(220, 60, 60));
solidrectangle(MAIN_IN_X - 35, MAIN_IN_Y - 22, MAIN_IN_X + 35, MAIN_IN_Y + 22);
settextcolor(WHITE);
settextstyle(22, 0, "微软雅黑");
outtextxy(MAIN_IN_X - 20, MAIN_IN_Y - 12, "IN");
setfillcolor(YELLOW);
solidcircle(MAIN_IN_X + 35, MAIN_IN_Y, 7);
// 总输出(扁平)
setfillcolor(RGB(60, 200, 80));
solidrectangle(MAIN_OUT_X - 35, MAIN_OUT_Y - 22, MAIN_OUT_X + 35, MAIN_OUT_Y + 22);
settextcolor(WHITE);
settextstyle(22, 0, "微软雅黑");
outtextxy(MAIN_OUT_X - 22, MAIN_OUT_Y - 12, "OUT");
setfillcolor(WHITE);
solidcircle(MAIN_OUT_X - 35, MAIN_OUT_Y, 7);
}
void drawAll() {
cleardevice();
// 工具栏背景
setfillcolor(RGB(40, 40, 40));
solidrectangle(0, 0, TOOLBAR_WIDTH, WINDOW_HEIGHT);
settextcolor(WHITE);
settextstyle(24, 0, "微软雅黑");
outtextxy(25, 12, "效果器栏");
settextstyle(16, 0, "微软雅黑");
outtextxy(12, 600, "白色 = 输入端口");
outtextxy(12, 625, "黄色 = 输出端口");
outtextxy(12, 650, "输出→输入 连线");
outtextxy(12, 675, "右键删除模块");
for (auto& b : toolbarBlocks)
b.drawWithoutPorts();
// 画布
setfillcolor(RGB(30, 30, 50));
solidrectangle(TOOLBAR_WIDTH, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
drawMainIO();
// 连线
setlinecolor(YELLOW);
setlinestyle(PS_SOLID, 2);
for (const auto& conn : connections) {
if (conn.fromMainInput && conn.toBlock >= 0 && conn.toBlock < (int)blocks.size()) {
const auto& t = blocks[conn.toBlock];
line(MAIN_IN_X + 35, MAIN_IN_Y, t.getInPortX(), t.getInPortY());
} else if (conn.toMainOutput && conn.fromBlock >= 0 && conn.fromBlock < (int)blocks.size()) {
const auto& f = blocks[conn.fromBlock];
line(f.getOutPortX(), f.getOutPortY(), MAIN_OUT_X - 35, MAIN_OUT_Y);
} else if (conn.fromBlock >= 0 && conn.toBlock >= 0 &&
conn.fromBlock < (int)blocks.size() && conn.toBlock < (int)blocks.size()) {
const auto& f = blocks[conn.fromBlock];
const auto& t = blocks[conn.toBlock];
line(f.getOutPortX(), f.getOutPortY(), t.getInPortX(), t.getInPortY());
}
}
// 效果器
for (auto& b : blocks)
b.drawWithPorts();
// 临时连线
if (drawingLine) {
POINT p;
GetCursorPos(&p);
ScreenToClient(GetHWnd(), &p);
setlinecolor(YELLOW);
setlinestyle(PS_DASH, 2);
line(lineStartX, lineStartY, p.x, p.y);
setlinestyle(PS_SOLID, 1);
}
FlushBatchDraw();
}
void onMouse() {
if (!MouseHit()) return;
MOUSEMSG m = GetMouseMsg();
needRedraw = true;
if (m.uMsg == WM_LBUTTONDOWN) {
if (hypot(m.x - (MAIN_IN_X + 35), m.y - MAIN_IN_Y) < 10) {
drawingLine = true;
lineFromInput = true;
lineStartX = MAIN_IN_X + 35;
lineStartY = MAIN_IN_Y;
return;
}
for (int i = 0; i < (int)blocks.size(); i++) {
if (blocks[i].isClickOutPort(m.x, m.y)) {
drawingLine = true;
lineFromInput = false;
lineFromIndex = i;
lineStartX = blocks[i].getOutPortX();
lineStartY = blocks[i].getOutPortY();
return;
}
}
for (int i = 0; i < (int)toolbarBlocks.size(); i++) {
if (toolbarBlocks[i].isPointIn(m.x, m.y)) {
blocks.emplace_back(toolbarBlocks[i].type, m.x - BLOCK_WIDTH / 2, m.y - BLOCK_HEIGHT / 2);
dragIndex = (int)blocks.size() - 1;
draggingBlock = true;
return;
}
}
for (int i = 0; i < (int)blocks.size(); i++) {
if (blocks[i].isPointIn(m.x, m.y)) {
dragIndex = i;
draggingBlock = true;
return;
}
}
}
if (m.uMsg == WM_LBUTTONUP) {
if (drawingLine) {
bool connected = false;
for (int i = 0; i < (int)blocks.size(); i++) {
if (blocks[i].isClickInPort(m.x, m.y)) {
Connection c;
if (lineFromInput)
c.fromMainInput = true;
else
c.fromBlock = lineFromIndex;
c.toBlock = i;
connections.push_back(c);
connected = true;
break;
}
}
if (!connected && !lineFromInput) {
if (hypot(m.x - (MAIN_OUT_X - 35), m.y - MAIN_OUT_Y) < 10) {
Connection c;
c.fromBlock = lineFromIndex;
c.toMainOutput = true;
connections.push_back(c);
}
}
drawingLine = false;
}
draggingBlock = false;
dragIndex = -1;
}
if (m.uMsg == WM_MOUSEMOVE && draggingBlock && dragIndex != -1) {
if (m.x > TOOLBAR_WIDTH) {
blocks[dragIndex].x = m.x - BLOCK_WIDTH / 2;
blocks[dragIndex].y = m.y - BLOCK_HEIGHT / 2;
}
}
if (m.uMsg == WM_RBUTTONDOWN) {
for (int i = 0; i < (int)blocks.size(); i++) {
if (blocks[i].isPointIn(m.x, m.y)) {
blocks.erase(blocks.begin() + i);
vector<Connection> temp;
for (const auto& c : connections) {
if (c.fromBlock == i || c.toBlock == i) continue;
Connection nc = c;
if (nc.fromBlock > i) nc.fromBlock--;
if (nc.toBlock > i) nc.toBlock--;
temp.push_back(nc);
}
connections.swap(temp);
break;
}
}
}
if (kbhit()) {
if (getch() == 32) {
blocks.clear();
connections.clear();
needRedraw = true;
}
}
}