// ============================================================================ // block_workspace.c - 工作区管理实现 // ============================================================================ #include "block_workspace.h" #include #include #include BlockWorkspace* workspace_create(void) { BlockWorkspace* ws = (BlockWorkspace*)calloc(1, sizeof(BlockWorkspace)); if (!ws) return NULL; ws->zoom = 1.0f; ws->next_block_id = 1; return ws; } void workspace_destroy(BlockWorkspace* ws) { if (!ws) return; workspace_clear(ws); free(ws); } int workspace_add_block(BlockWorkspace* ws, Block* block) { if (ws->block_count >= MAX_WORKSPACE_BLOCKS) return -1; if (!block) return -1; if (block->id <= 0) block->id = ws->next_block_id++; else if (block->id >= ws->next_block_id) ws->next_block_id = block->id + 1; block->workspace = ws; ws->blocks[ws->block_count++] = block; return block->id; } void workspace_remove_block(BlockWorkspace* ws, int block_id) { // 先移除所有相关连接 for (int i = ws->connection_count - 1; i >= 0; i--) { BlockSlot* from = ws->connections[i].from; BlockSlot* to = ws->connections[i].to; if (from && from->owner && from->owner->id == block_id) { workspace_remove_connection(ws, from); } else if (to && to->owner && to->owner->id == block_id) { workspace_remove_connection(ws, to); } } // 移除积木 for (int i = 0; i < ws->block_count; i++) { if (ws->blocks[i]->id == block_id) { block_destroy(ws->blocks[i]); ws->blocks[i] = ws->blocks[ws->block_count - 1]; ws->block_count--; return; } } } bool workspace_add_connection(BlockWorkspace* ws, BlockSlot* from, BlockSlot* to) { if (ws->connection_count >= MAX_WORKSPACE_CONNECTIONS) return false; if (!from || !to) return false; // 检查是否已连接 for (int i = 0; i < ws->connection_count; i++) { if (ws->connections[i].from == from || ws->connections[i].to == to) { return false; // 已有连接 } } // 建立连接 block_connect(from, to); BlockConnection* conn = &ws->connections[ws->connection_count++]; conn->from = from; conn->to = to; return true; } void workspace_remove_connection(BlockWorkspace* ws, BlockSlot* slot) { for (int i = ws->connection_count - 1; i >= 0; i--) { if (ws->connections[i].from == slot || ws->connections[i].to == slot) { block_disconnect(ws->connections[i].from); ws->connections[i] = ws->connections[ws->connection_count - 1]; ws->connection_count--; } } } void workspace_remove_all_connections(BlockWorkspace* ws, Block* block) { if (!block) return; for (int i = ws->connection_count - 1; i >= 0; i--) { BlockSlot* from = ws->connections[i].from; BlockSlot* to = ws->connections[i].to; if ((from && from->owner == block) || (to && to->owner == block)) { block_disconnect(from); ws->connections[i] = ws->connections[ws->connection_count - 1]; ws->connection_count--; } } } Block* workspace_find_block(BlockWorkspace* ws, int block_id) { for (int i = 0; i < ws->block_count; i++) { if (ws->blocks[i]->id == block_id) return ws->blocks[i]; } return NULL; } Block* workspace_find_block_at(BlockWorkspace* ws, float x, float y) { // 从后往前找 (最后添加的在最上面) for (int i = ws->block_count - 1; i >= 0; i--) { if (block_contains_point(ws->blocks[i], x, y)) { return ws->blocks[i]; } } return NULL; } BlockSlot* workspace_find_slot_at(BlockWorkspace* ws, float x, float y) { float threshold = 10.0f; for (int i = ws->block_count - 1; i >= 0; i--) { Block* block = ws->blocks[i]; // 检查输出槽位 for (int j = 0; j < block->output_count; j++) { BlockSlot* slot = &block->outputs[j]; float sx, sy; block_slot_world_pos(slot, &sx, &sy); float dx = x - sx; float dy = y - sy; if (dx * dx + dy * dy < threshold * threshold) { return slot; } } // 检查输入槽位 for (int j = 0; j < block->input_count; j++) { BlockSlot* slot = &block->inputs[j]; float sx, sy; block_slot_world_pos(slot, &sx, &sy); float dx = x - sx; float dy = y - sy; if (dx * dx + dy * dy < threshold * threshold) { return slot; } } } return NULL; } void workspace_screen_to_world(BlockWorkspace* ws, float sx, float sy, float* wx, float* wy) { *wx = (sx / ws->zoom) + ws->view_x; *wy = (sy / ws->zoom) + ws->view_y; } void workspace_world_to_screen(BlockWorkspace* ws, float wx, float wy, float* sx, float* sy) { *sx = (wx - ws->view_x) * ws->zoom; *sy = (wy - ws->view_y) * ws->zoom; } void workspace_clear(BlockWorkspace* ws) { for (int i = 0; i < ws->block_count; i++) { block_destroy(ws->blocks[i]); } ws->block_count = 0; ws->connection_count = 0; ws->selected_block = NULL; }