Skip to content

Commit 9ccda52

Browse files
docs: add Caffeine Studio IDE planning (M1-M4 milestones)
Added planning/ directory with detailed task documentation for the Caffeine Studio IDE — 4 milestones, 29 files total: planning/caffeine-studio-ide.md — master plan planning/m1-scene-editor-foundation/ — 7 tasks (1.1-1.7) planning/m2-visual-editing-assets/ — 7 tasks (2.1-2.7) planning/m3-scripting-runtime/ — 7 tasks (3.1-3.7) planning/m4-advanced-tools-polish/ — 8 tasks (4.1-4.8) Each task file includes: Visão Geral, Implementação (C++ API + diagrams), Decisões de Design, Critério de Aceitação, Dependências, Referências. Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 70848a6 commit 9ccda52

30 files changed

Lines changed: 4845 additions & 0 deletions

planning/caffeine-studio-ide.md

Lines changed: 614 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# 🔧 EditorContext & Undo/Redo
2+
3+
> **Milestone:** M1 — Scene Editor Foundation
4+
> **Namespace:** `Caffeine::Editor`
5+
> **Arquivos:** `src/editor/EditorContext.hpp`, `src/editor/EditorContext.cpp`
6+
> **Status:** 📅 Planeado
7+
> **RF:** RF6.1
8+
9+
---
10+
11+
## Visão Geral
12+
13+
O `EditorContext` funciona como o cérebro central do editor, mantendo o estado global da sessão atual. Ele armazena informações críticas como a entidade selecionada, o estado de modificação da cena (dirty flag) e o caminho do ficheiro aberto. Sem este contexto, os painéis individuais não teriam uma forma unificada de comunicar mudanças entre si.
14+
15+
O sistema de Undo/Redo é integrado diretamente neste contexto para permitir que o utilizador reverta ações destrutivas ou erros de edição. Ele utiliza um sistema de comandos baseado em estados (snapshots) para garantir que a cena possa regressar exatamente ao ponto anterior a qualquer modificação no ECS.
16+
17+
---
18+
19+
## Implementação
20+
21+
### Estrutura do Comando
22+
23+
Cada comando guarda o estado "antes" e "depois" da modificação para permitir a navegação bidirecional no histórico.
24+
25+
```cpp
26+
struct EditorCommand {
27+
enum Type {
28+
AddEntity,
29+
RemoveEntity,
30+
AddComponent,
31+
RemoveComponent,
32+
SetField,
33+
MoveEntity
34+
};
35+
36+
Type type;
37+
ECS::EntityID targetEntity;
38+
std::vector<u8> beforeState; // Serialização do componente/entidade antes
39+
std::vector<u8> afterState; // Serialização depois da mudança
40+
};
41+
```
42+
43+
### Gestor de Histórico (UndoStack)
44+
45+
Utiliza um buffer circular para evitar alocações constantes e limitar o uso de memória.
46+
47+
```cpp
48+
class UndoStack {
49+
static constexpr u32 MAX_UNDO = 256;
50+
EditorCommand m_commands[MAX_UNDO];
51+
u32 m_head = 0; // Onde o próximo comando será inserido
52+
u32 m_tail = 0; // O comando mais antigo disponível
53+
u32 m_current = 0; // Posição atual para undo/redo
54+
u32 m_count = 0;
55+
56+
public:
57+
void push(const EditorCommand& cmd) {
58+
m_commands[m_head] = cmd;
59+
m_head = (m_head + 1) % MAX_UNDO;
60+
61+
if (m_count < MAX_UNDO) {
62+
m_count++;
63+
} else {
64+
m_tail = (m_tail + 1) % MAX_UNDO;
65+
}
66+
m_current = m_head;
67+
}
68+
69+
bool undo(ECS::World& world) {
70+
if (m_current == m_tail) return false;
71+
m_current = (m_current - 1 + MAX_UNDO) % MAX_UNDO;
72+
applyState(world, m_commands[m_current].beforeState);
73+
return true;
74+
}
75+
76+
bool redo(ECS::World& world) {
77+
if (m_current == m_head) return false;
78+
applyState(world, m_commands[m_current].afterState);
79+
m_current = (m_current + 1) % MAX_UNDO;
80+
return true;
81+
}
82+
83+
void clear() {
84+
m_head = m_tail = m_current = m_count = 0;
85+
}
86+
87+
private:
88+
void applyState(ECS::World& world, const std::vector<u8>& data);
89+
};
90+
```
91+
92+
### EditorContext
93+
94+
O objeto singleton que orquestra a comunicação entre painéis.
95+
96+
```cpp
97+
class EditorContext {
98+
public:
99+
// Estado da Seleção
100+
ECS::EntityID selectedEntity = ECS::INVALID_ENTITY;
101+
ECS::EntityID hoveredEntity = ECS::INVALID_ENTITY;
102+
ECS::EntityID clipboardEntity = ECS::INVALID_ENTITY;
103+
104+
// Estado do Gizmo
105+
enum class GizmoMode { Translation, Rotation, Scale };
106+
GizmoMode currentGizmoMode = GizmoMode::Translation;
107+
108+
// Estado da Cena
109+
std::string currentScenePath = "";
110+
bool isDirty = false;
111+
112+
// Sistemas
113+
UndoStack undoStack;
114+
115+
void selectEntity(ECS::EntityID id) {
116+
selectedEntity = id;
117+
}
118+
119+
void markDirty() {
120+
isDirty = true;
121+
}
122+
};
123+
```
124+
125+
### Fluxo de Dados de Undo
126+
127+
```
128+
[Utilizador Altera Campo]
129+
-> Captura Estado Atual (beforeState)
130+
-> Aplica Mudança no ECS
131+
-> Captura Novo Estado (afterState)
132+
-> EditorContext::undoStack.push(comando)
133+
-> EditorContext::markDirty()
134+
```
135+
136+
---
137+
138+
## Decisões de Design
139+
140+
| Decisão | Justificativa |
141+
|---------|---------------|
142+
| Buffer Circular no UndoStack | Evita fragmentação de memória e garante um limite previsível de recursos. |
143+
| Snapshots de Estado | Mais simples de implementar para o ECS do que comandos delta complexos, aproveitando a serialização existente. |
144+
| Dirty Flag no Contexto | Centraliza a lógica de aviso de "Guardar Alterações" antes de fechar a aplicação ou mudar de cena. |
145+
146+
---
147+
148+
## Critério de Aceitação
149+
150+
- [ ] Undo/Redo funciona para a criação de entidades (AddEntity).
151+
- [ ] Undo/Redo funciona para a remoção de entidades (RemoveEntity).
152+
- [ ] A Dirty Flag é ativada após qualquer ação no histórico.
153+
- [ ] Selecionar uma entidade atualiza o `selectedEntity` globalmente.
154+
- [ ] O histórico é limpo ao carregar uma nova cena.
155+
156+
---
157+
158+
## Dependências
159+
160+
- **Upstream:** `docs/ecs/core.md`, `docs/ecs/scene.md`
161+
- **Downstream:** `1.2-hierarchy-panel.md`, `1.3-inspector-panel.md`, `1.6-scene-editor-orchestrator.md`
162+
163+
---
164+
165+
## 🔗 Tópicos Relacionados
166+
167+
| Tópico | Descrição |
168+
|--------|-----------|
169+
| Serialização ECS | Como transformar componentes em bytes para o UndoStack. |
170+
| Comandos de Editor | Padrão de desenho Command para isolar ações da UI. |
171+
172+
---
173+
174+
## Referências
175+
176+
- [`docs/ecs/core.md`](../docs/ecs/core.md) — Documentação base do sistema de entidades.
177+
- [Game Programming Patterns - Undo/Redo](https://gameprogrammingpatterns.com/undo-redo.html) — Referência teórica.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# 🔧 Hierarchy Panel
2+
3+
> **Milestone:** M1 — Scene Editor Foundation
4+
> **Namespace:** `Caffeine::Editor`
5+
> **Arquivos:** `src/editor/HierarchyPanel.hpp`, `src/editor/HierarchyPanel.cpp`
6+
> **Status:** 📅 Planeado
7+
> **RF:** RF6.2
8+
9+
---
10+
11+
## Visão Geral
12+
13+
O `HierarchyPanel` é a janela que apresenta a estrutura organizacional de todas as entidades presentes na cena atual. Ele exibe as entidades em formato de árvore, permitindo visualizar relações de parentesco (transform parenting). Este painel é essencial para a navegação rápida, seleção e organização lógica dos objetos de jogo.
14+
15+
Além da visualização, o painel oferece ferramentas para criação, destruição e reordenação de entidades através de interação direta (drag-and-drop) ou menus de contexto.
16+
17+
---
18+
19+
## Implementação
20+
21+
### Estrutura da Classe
22+
23+
O painel utiliza o `EditorContext` para sincronizar a seleção global.
24+
25+
```cpp
26+
class HierarchyPanel {
27+
EditorContext* m_context;
28+
char m_searchFilter[256] = "";
29+
30+
public:
31+
HierarchyPanel(EditorContext* context) : m_context(context) {}
32+
33+
void onImGuiRender() {
34+
ImGui::Begin("Hierarchy");
35+
36+
renderSearchBar();
37+
renderToolbar();
38+
39+
if (ImGui::BeginChild("EntityTree")) {
40+
auto view = m_world->view<ECS::NameComponent>();
41+
for (auto entity : view) {
42+
// Apenas renderiza raízes; filhos são processados recursivamente
43+
if (!m_world->has<ECS::ParentComponent>(entity)) {
44+
renderEntityNode(entity);
45+
}
46+
}
47+
}
48+
ImGui::EndChild();
49+
50+
renderContextMenu();
51+
52+
ImGui::End();
53+
}
54+
55+
private:
56+
void renderEntityNode(ECS::EntityID entity) {
57+
auto& name = m_world->get<ECS::NameComponent>(entity).name;
58+
59+
ImGuiTreeNodeFlags flags = ((m_context->selectedEntity == entity) ? ImGuiTreeNodeFlags_Selected : 0);
60+
flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
61+
62+
bool hasChildren = checkHasChildren(entity);
63+
if (!hasChildren) flags |= ImGuiTreeNodeFlags_Leaf;
64+
65+
bool opened = ImGui::TreeNodeEx((void*)(uintptr_t)entity, flags, "%s", name.c_str());
66+
67+
if (ImGui::IsItemClicked()) {
68+
m_context->selectEntity(entity);
69+
}
70+
71+
// Context Menu para a entidade específica
72+
if (ImGui::BeginPopupContextItem()) {
73+
if (ImGui::MenuItem("Delete")) { m_world->destroy(entity); }
74+
ImGui::EndPopup();
75+
}
76+
77+
// Drag and Drop Logic
78+
handleDragAndDrop(entity);
79+
80+
if (opened) {
81+
if (hasChildren) {
82+
renderChildren(entity);
83+
}
84+
ImGui::TreePop();
85+
}
86+
}
87+
88+
void handleDragAndDrop(ECS::EntityID entity);
89+
void renderContextMenu(); // Create empty, etc.
90+
};
91+
```
92+
93+
### Lógica de Hierarquia (Parenting)
94+
95+
A hierarquia é mantida através do `ParentComponent` e `ChildrenComponent` (ou uma lista de IDs). No M1, focaremos no `ParentComponent`.
96+
97+
```cpp
98+
struct ParentComponent {
99+
ECS::EntityID parentId;
100+
};
101+
```
102+
103+
### Diagrama de Fluxo de Seleção
104+
105+
```
106+
[HierarchyPanel] Click Node
107+
-> EditorContext::selectEntity(ID)
108+
-> [InspectorPanel] Observa mudança
109+
-> [InspectorPanel] Renderiza componentes de ID
110+
```
111+
112+
---
113+
114+
## Decisões de Design
115+
116+
| Decisão | Justificativa |
117+
|---------|---------------|
118+
| `ImGuiTreeNodeFlags_Leaf` para vazios | Fornece feedback visual imediato sobre quais entidades possuem filhos. |
119+
| Filtro de Pesquisa | Essencial para cenas com centenas de entidades onde a navegação manual é lenta. |
120+
| Drag-and-Drop Reparenting | Forma mais intuitiva de organizar objetos em 2D/3D. |
121+
122+
---
123+
124+
## Critério de Aceitação
125+
126+
- [ ] Apresenta todas as entidades da cena em formato de lista/árvore.
127+
- [ ] Clicar numa entidade seleciona-a no `EditorContext`.
128+
- [ ] Botão direito no vazio abre menu para "Create Empty Entity".
129+
- [ ] Tecla `Delete` com entidade selecionada remove-a da cena.
130+
- [ ] O filtro de pesquisa oculta entidades cujos nomes não coincidem com o texto.
131+
- [ ] Entidades com `ParentComponent` aparecem indentadas sob o pai.
132+
133+
---
134+
135+
## Dependências
136+
137+
- **Upstream:** `1.1-editor-context-undo-redo.md`, `docs/ecs/core.md`
138+
- **Downstream:** `1.3-inspector-panel.md`, `1.6-scene-editor-orchestrator.md`
139+
140+
---
141+
142+
## 🔗 Tópicos Relacionados
143+
144+
| Tópico | Descrição |
145+
|--------|-----------|
146+
| NameComponent | Armazena a string visível no painel. |
147+
| ECS Parenting | Sistema que sincroniza transformações entre pais e filhos. |
148+
149+
---
150+
151+
## Referências
152+
153+
- [`docs/ui/editor-ui.md`](../docs/ui/editor-ui.md) — Convenções de interface.
154+
- [ImGui Demo: Tree Nodes](https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp) — Referência de implementação.

0 commit comments

Comments
 (0)