#include #include #include #include namespace raleigh { window::window(widget &root, _pixel_t bg_color, bool (*on_close)(window_tag_t), window_tag_t tag) : root(root), handle(0), pixbuf(0), size(root.size), focussed(&root), drag_reciever(0), bg_color(bg_color), on_close(on_close), tag(tag) { root.w = this; root.window_offset = coord(0, 0); root.notify_window_change(); if (size.x && size.y) { pixbuf = new _pixel_t[size.x * size.y]; if (!pixbuf) show_error_and_quitf("Failed to create %d byte pixel buffer\nfor requested %dx%d pixel window.", size.x * size.y * sizeof(_pixel_t), size.x, size.y); } paint_full(); root.on_focus(); needs_repaint = false; } void window::consume_actions() { struct window_action wa; while (1) { _get_win_action(handle, &wa); if (!wa.action_type) { if (needs_repaint) { needs_repaint = false; _paint_window(handle); } return; } if ((wa.action_type == wa.KEY_DOWN) && (wa.as_key.modifiers & wa.as_key.ALTS) && (wa.as_key.key_id == wa.as_key.KEY_F4)) { if (!on_close || on_close(tag)) { to_be_deleted.add_back(*this); return; } } else if (wa.action_type == wa.MOUSE_DOWN) root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, false); else if (wa.action_type == wa.MOUSE_UP) { if (drag_reciever && (wa.as_mouse.which == drag_until)) drag_reciever = 0; root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, true); } else if (wa.action_type == wa.KEY_DOWN) { void (*const f)(window_tag_t) = keybinds.transform(wa.as_key); if (f) f(tag); else focussed->handle_key(wa.as_key); } else if (wa.action_type == wa.FOCUS_ENTER) focussed->on_focus(); else if (wa.action_type == wa.FOCUS_LEAVE) focussed->on_unfocus(); else if (drag_reciever && (wa.action_type == wa.MOUSE_MOVE)) drag_reciever->on_mouse_move(coord(wa.moved_to.x, wa.moved_to.y)); } } void window::notify_needs_paint(widget &head) { if (head.closest_opaque) head.closest_opaque->paint(pixbuf, size.x); else paint_full(); needs_repaint = true; } void window::paint_full() { for (uint32_t i = 0; i < size.x * size.y; ++i) pixbuf[i] = bg_color; root.next_paint_full = true; root.paint(pixbuf, size.x); } void window::show() { if (handle) return; handle = _new_window(size.x, size.y, pixbuf); _wants_mouse_moves(handle); if (!handle) show_error_and_quitf("Failed to get window handle for requested window."); open_windows.add_front(*this); } void window::focus(widget &w) { if (focussed != &w) { focussed->on_unfocus(); focussed = &w; focussed->on_focus(); } } void window::notify_widget_size_change(widget &from, coord old_size) { if (from.parent) from.parent->notify_child_size_change(from, old_size); else { size = root.size; if (pixbuf) delete[] pixbuf; pixbuf = new _pixel_t[size.x * size.y]; if (!pixbuf) show_error_and_quitf("Failed to allocate %u byte buffer while\nresizing window to %ux%u pixels.", size.x * size.y, size.x, size.y); paint_full(); _resize_window(handle, size.x, size.y, pixbuf); } } void window::add_keybind(struct key_packet kp, void (*handler)(window_tag_t)) { keybinds.add_pair(kp, handler); } void window::notify_wants_movements(widget &from, enum mouse_packet::mouse_button while_down) { drag_reciever = &from; drag_until = while_down; } }