extern I64 Saphir(Bool enable = TRUE); U0 saphir_debug_info(SaphirRect* rect) { DCFill; gr.dc->color = LTPURPLE; GrRect(gr.dc, 0, 0, 640, 8); gr.dc->color = WHITE; GrPrint(gr.dc, 0, 0, "node: 0x%08x, index: %d", saphir.current_node, saphir.current_node->index); gr.dc->color = CYAN; GrLine(gr.dc, 8 * rect->x1, 8 * rect->y1, 8 * rect->x2, 8 * rect->y2); GrLine(gr.dc, 8 * rect->x1, 8 * rect->y2, 8 * rect->x2, 8 * rect->y1); } Bool saphir_node_validate(SaphirNode* node) { if (!node) { return FALSE; } return node->sig == SAPHIR_NODE_SIG; } Bool saphir_task_is_windowed(CTask* task) { if (!task || task == ac.task || task == adam_task) { return FALSE; } if ((task->display_flags & 1 << DISPLAYf_SHOW) && ((task->display_flags & 1 << DISPLAYf_NOT_RAW))) return TRUE; return FALSE; } I64 saphir_reflow_step(SaphirNode* node) { switch (node->mode) { case 0: return ((node->rect.y2 - node->rect.y1) / node->count); case 1: return ((node->rect.x2 - node->rect.x1) / node->count); default: return 0; } } U0 saphir_reflow_win(CTask* task, SaphirRect* rect) { if (!task || !rect) { return; } task->win_top = rect->y1; task->win_left = rect->x1; task->win_bottom = rect->y2; task->win_right = rect->x2; WinZBufUpdate; } U0 saphir_remove_child(SaphirNode* node, I64 i) { I64 j; for (j = i; j < 16; j++) { node->child[j] = node->child[j + 1]; } --node->count; if (node->index == i) { --node->index; node->index = MaxI64(0, node->index); } } U0 saphir_destroy_node(SaphirNode* node) { if (!node) { return; } // FIXME: do this cleanly if (node->child) { Free(node->child); } Free(node); } Bool saphir_reflow(SaphirNode* node = NULL) { if (!node) { node = saphir.root_node; } SaphirNode* tmp_node; SaphirRect rect; SaphirRect debug_rect; MemCpy(&rect, &node->rect, sizeof(SaphirRect)); // orig_x1, orig_y1 debug_rect.x1 = rect.x1; debug_rect.y1 = rect.y1; I64 i; I64 step = saphir_reflow_step(node); for (i = 0; i < node->count; i++) { switch (node->mode) { case 0: rect.y2 = rect.y1 + step; break; case 1: rect.x2 = rect.x1 + step; break; default: PopUpOk("error1 : node->mode invalid"); "mode: %d\n", node->mode; Break; } if (saphir_node_validate(node->child[i])) { tmp_node = node->child[i]; if (tmp_node->count < 2) { node->child[i] = tmp_node->child[0]; saphir_destroy_node(tmp_node); if (saphir.current_node == tmp_node) { saphir.current_node = node; node->index = i; } return FALSE; } MemCpy(&node->child[i](SaphirNode*)->rect, &rect, sizeof(SaphirRect)); if (saphir.current_node == node && saphir.current_node->index == i) { saphir.current_node = node->child[i]; } if (!saphir_reflow(node->child[i])) { return FALSE; } } else { if (TaskValidate(node->child[i])) { saphir_reflow_win(node->child[i], &rect); if (saphir.current_node == node && saphir.current_node->index == i) { WinFocus(node->child[i]); } WinZBufUpdate; } else { saphir_remove_child(node, i); return FALSE; } } switch (node->mode) { case 0: rect.y1 = rect.y2 + 2; break; case 1: rect.x1 = rect.x2 + 2; break; default: PopUpOk("error2 : node->mode invalid"); Break; } } if (node == saphir.current_node && saphir.debug) { debug_rect.x2 = rect.x2; debug_rect.y2 = rect.y2; saphir_debug_info(&debug_rect); } return TRUE; } U0 saphir_reflow_task_end() { if (saphir.current_node == saphir.root_node && saphir.current_node->count == 1) { Saphir(0); return; } while (!saphir_reflow) ; } U0 saphir_reflow_task_end_cb() { Spawn(&saphir_reflow_task_end); Exit; } U0 saphir_rect_set_defaults(SaphirRect* rect) { rect->x1 = 1; rect->x2 = TEXT_COLS - 2; rect->y1 = 2; rect->y2 = TEXT_ROWS - 3; } SaphirNode* saphir_node_alloc(I64 mode = 0) { SaphirNode* node = CAlloc(sizeof(SaphirNode)); node->child = CAlloc(sizeof(U64*) * 16); node->mode = mode; node->sig = SAPHIR_NODE_SIG; return node; } U0 saphir_node_append_task(SaphirNode* node, CTask* task) { if (!node || !task) { return; } if (node->count && !(node->count % 16)) { PopUpOk("FIXME: realloc node->child"); Break; } node->child[node->count++] = task; task->task_end_cb = &saphir_reflow_task_end_cb; } U0 saphir_node_init_root() { saphir.root_node = saphir_node_alloc(1); saphir_rect_set_defaults(&saphir.root_node->rect); SaphirNode* node = saphir.root_node; CTask* task1 = adam_task->next_task; while (task1 != adam_task) { if (saphir_task_is_windowed(task1)) { saphir_node_append_task(node, task1); } task1 = task1->next_task; } } U0 saphir_split_pane(I64 dir) { SaphirNode* node = saphir_node_alloc(dir); CTask* new_task = User; saphir_node_append_task(node, saphir.current_node->child[saphir.current_node->index]); saphir_node_append_task(node, new_task); node->parent_node = saphir.current_node; saphir.current_node->child[saphir.current_node->index] = node; saphir.current_node = node; saphir.current_node->index = 1; // 1= focus the new User task created by splitting while (!saphir_reflow) ; } U0 saphir_split_row() { saphir_split_pane(0); } U0 saphir_split_col() { saphir_split_pane(1); } U0 saphir_win_select_up() { SaphirNode* node = saphir.current_node; if (!node->mode && node->index) { --node->index; return; } node = node->parent_node; while (node && node->mode) { node = node->parent_node; } if (node && node->index) { --node->index; } if (node) { saphir.current_node = node; } } U0 saphir_win_select_down() { SaphirNode* node = saphir.current_node; if (!node->mode && node->index < node->count - 1) { ++node->index; return; } node = node->parent_node; while (node && node->mode) { node = node->parent_node; } if (node && node->index < node->count - 1) { ++node->index; } if (node) { saphir.current_node = node; } } U0 saphir_win_select_left() { SaphirNode* node = saphir.current_node; if (node->mode && node->index) { --node->index; return; } node = node->parent_node; while (node && !node->mode) { node = node->parent_node; } if (node && node->index) { --node->index; } if (node) { saphir.current_node = node; } } U0 saphir_win_select_right() { SaphirNode* node = saphir.current_node; if (node->mode && node->index < node->count - 1) { ++node->index; return; } node = node->parent_node; while (node && !node->mode) { node = node->parent_node; } if (node && node->index < node->count - 1) { ++node->index; } if (node) { saphir.current_node = node; } } U0 saphir_win_select(I64 dir) { switch (dir) { case SC_CURSOR_UP: saphir_win_select_up; break; case SC_CURSOR_DOWN: saphir_win_select_down; break; case SC_CURSOR_LEFT: saphir_win_select_left; break; case SC_CURSOR_RIGHT: saphir_win_select_right; break; default: break; } while (!saphir_reflow) ; } U0 saphir_enable() { saphir_node_init_root; saphir.current_node = saphir.root_node; saphir.current_node->index = 0; while (!saphir_reflow) ; }