#ifndef YAZE_GUI_CANVAS_H #define YAZE_GUI_CANVAS_H #include "gfx/tilemap.h" #define IMGUI_DEFINE_MATH_OPERATORS #include #include #include "app/gfx/bitmap.h" #include "app/rom.h" #include "imgui/imgui.h" namespace yaze { /** * @namespace yaze::gui * @brief Graphical User Interface (GUI) components for the application. */ namespace gui { using gfx::Bitmap; using gfx::BitmapTable; enum class CanvasType { kTile, kBlock, kMap }; enum class CanvasMode { kPaint, kSelect }; enum class CanvasGridSize { k8x8, k16x16, k32x32, k64x64 }; /** * @class Canvas * @brief Represents a canvas for drawing and manipulating graphics. * * The Canvas class provides various functions for updating and drawing graphics * on a canvas. It supports features such as bitmap drawing, context menu * handling, tile painting, custom grid, and more. */ class Canvas { public: Canvas() = default; explicit Canvas(const std::string &id) : canvas_id_(id) { context_id_ = id + "Context"; } explicit Canvas(const std::string &id, ImVec2 canvas_size) : custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) { context_id_ = id + "Context"; } explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size) : custom_canvas_size_(true), canvas_sz_(canvas_size), canvas_id_(id) { context_id_ = id + "Context"; SetCanvasGridSize(grid_size); } explicit Canvas(const std::string &id, ImVec2 canvas_size, CanvasGridSize grid_size, float global_scale) : custom_canvas_size_(true), global_scale_(global_scale), canvas_sz_(canvas_size), canvas_id_(id) { context_id_ = id + "Context"; SetCanvasGridSize(grid_size); } void SetCanvasGridSize(CanvasGridSize grid_size) { switch (grid_size) { case CanvasGridSize::k8x8: custom_step_ = 8.0f; break; case CanvasGridSize::k16x16: custom_step_ = 16.0f; break; case CanvasGridSize::k32x32: custom_step_ = 32.0f; break; case CanvasGridSize::k64x64: custom_step_ = 64.0f; break; } } void UpdateColorPainter(gfx::Bitmap &bitmap, const ImVec4 &color, const std::function &event, int tile_size, float scale = 1.0f); void UpdateInfoGrid(ImVec2 bg_size, float grid_size = 64.0f, int label_id = 0); // Background for the Canvas represents region without any content drawn to // it, but can be controlled by the user. void DrawBackground(ImVec2 canvas_size = ImVec2(0, 0)); // Context Menu refers to what happens when the right mouse button is pressed // This routine also handles the scrolling for the canvas. void DrawContextMenu(); // Context menu system for consumers to add their own menu elements struct ContextMenuItem { std::string label; std::string shortcut; std::function callback; std::function enabled_condition = []() { return true; }; std::vector subitems; }; void AddContextMenuItem(const ContextMenuItem& item); void ClearContextMenuItems(); void SetContextMenuEnabled(bool enabled) { context_menu_enabled_ = enabled; } // Enhanced view and edit operations void ShowBitmapProperties(const gfx::Bitmap& bitmap); void ShowPaletteEditor(gfx::SnesPalette& palette); void SetZoomToFit(const gfx::Bitmap& bitmap); void ResetView(); private: void DrawContextMenuItem(const ContextMenuItem& item); // Tile painter shows a preview of the currently selected tile // and allows the user to left click to paint the tile or right // click to select a new tile to paint with. // (Moved to public section) // Draws a tile on the canvas at the specified position // (Moved to public section) // These methods are now public - see public section above public: // Tile painter methods bool DrawTilePainter(const Bitmap &bitmap, int size, float scale = 1.0f); bool DrawSolidTilePainter(const ImVec4 &color, int size); void DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, ImVec4 color); void DrawOutline(int x, int y, int w, int h); void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color); void DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color); void DrawRect(int x, int y, int w, int h, ImVec4 color); void DrawText(std::string text, int x, int y); void DrawGridLines(float grid_step); void DrawInfoGrid(float grid_step = 64.0f, int tile_id_offset = 8, int label_id = 0); void DrawLayeredElements(); int GetTileIdFromMousePos() { float x = mouse_pos_in_canvas_.x; float y = mouse_pos_in_canvas_.y; int num_columns = (canvas_sz_.x / global_scale_) / custom_step_; int num_rows = (canvas_sz_.y / global_scale_) / custom_step_; int tile_id = (x / custom_step_) + (y / custom_step_) * num_columns; tile_id = tile_id / global_scale_; if (tile_id >= num_columns * num_rows) { tile_id = -1; // Invalid tile ID } return tile_id; } void DrawCustomHighlight(float grid_step); bool IsMouseHovering() const { return is_hovered_; } void ZoomIn() { global_scale_ += 0.25f; } void ZoomOut() { global_scale_ -= 0.25f; } auto points() const { return points_; } auto mutable_points() { return &points_; } auto push_back(ImVec2 pos) { points_.push_back(pos); } auto draw_list() const { return draw_list_; } auto zero_point() const { return canvas_p0_; } auto scrolling() const { return scrolling_; } void set_scrolling(ImVec2 scroll) { scrolling_ = scroll; } auto drawn_tile_position() const { return drawn_tile_pos_; } auto canvas_size() const { return canvas_sz_; } void set_global_scale(float scale) { global_scale_ = scale; } void set_draggable(bool draggable) { draggable_ = draggable; } // Public accessors for commonly used private members auto select_rect_active() const { return select_rect_active_; } auto selected_tiles() const { return selected_tiles_; } auto selected_tile_pos() const { return selected_tile_pos_; } void set_selected_tile_pos(ImVec2 pos) { selected_tile_pos_ = pos; } // Public methods for commonly used private methods void SetCanvasSize(ImVec2 canvas_size) { canvas_sz_ = canvas_size; custom_canvas_size_ = true; } auto global_scale() const { return global_scale_; } auto custom_labels_enabled() { return &enable_custom_labels_; } auto custom_step() const { return custom_step_; } auto width() const { return canvas_sz_.x; } auto height() const { return canvas_sz_.y; } // Public accessors for methods that need to be accessed externally auto canvas_id() const { return canvas_id_; } // Public methods for drawing operations void DrawBitmap(Bitmap &bitmap, int border_offset, float scale); void DrawBitmap(Bitmap &bitmap, int x_offset, int y_offset, float scale = 1.0f, int alpha = 255); void DrawBitmap(Bitmap &bitmap, ImVec2 dest_pos, ImVec2 dest_size, ImVec2 src_pos, ImVec2 src_size); void DrawBitmapTable(const BitmapTable &gfx_bin); void DrawBitmapGroup(std::vector &group, gfx::Tilemap &tilemap, int tile_size, float scale = 1.0f); bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile); void DrawSelectRect(int current_map, int tile_size = 0x10, float scale = 1.0f); bool DrawTileSelector(int size, int size_y = 0); void DrawGrid(float grid_step = 64.0f, int tile_id_offset = 8); void DrawOverlay(); auto labels(int i) { if (i >= labels_.size()) { labels_.push_back(ImVector()); } return labels_[i]; } auto mutable_labels(int i) { if (i >= labels_.size()) { int x = i; while (x >= labels_.size()) { labels_.push_back(ImVector()); x--; } labels_.push_back(ImVector()); } return &labels_[i]; } auto set_current_labels(int i) { current_labels_ = i; } auto set_highlight_tile_id(int i) { highlight_tile_id = i; } auto mutable_selected_tiles() { return &selected_tiles_; } auto selected_points() const { return selected_points_; } auto hover_mouse_pos() const { return mouse_pos_in_canvas_; } void set_rom(Rom *rom) { rom_ = rom; } Rom *rom() const { return rom_; } private: bool draggable_ = false; bool is_hovered_ = false; bool enable_grid_ = true; bool enable_hex_tile_labels_ = false; bool enable_custom_labels_ = false; bool enable_context_menu_ = true; bool custom_canvas_size_ = false; bool select_rect_active_ = false; bool refresh_graphics_ = false; // Context menu system std::vector context_menu_items_; bool context_menu_enabled_ = true; float custom_step_ = 0.0f; float global_scale_ = 1.0f; int current_labels_ = 0; int highlight_tile_id = -1; uint16_t edit_palette_index_ = 0; uint64_t edit_palette_group_name_index_ = 0; uint64_t edit_palette_sub_index_ = 0; Bitmap *bitmap_ = nullptr; Rom *rom_ = nullptr; ImDrawList *draw_list_ = nullptr; ImVec2 scrolling_; ImVec2 canvas_sz_; ImVec2 canvas_p0_; ImVec2 canvas_p1_; ImVec2 drawn_tile_pos_; ImVec2 mouse_pos_in_canvas_; ImVec2 selected_tile_pos_ = ImVec2(-1, -1); ImVector points_; ImVector selected_points_; ImVector> labels_; std::string canvas_id_ = "Canvas"; std::string context_id_ = "CanvasContext"; std::vector selected_tiles_; }; void BeginCanvas(Canvas &canvas, ImVec2 child_size = ImVec2(0, 0)); void EndCanvas(Canvas &canvas); void GraphicsBinCanvasPipeline(int width, int height, int tile_size, int num_sheets_to_load, int canvas_id, bool is_loaded, BitmapTable &graphics_bin); void BitmapCanvasPipeline(gui::Canvas &canvas, gfx::Bitmap &bitmap, int width, int height, int tile_size, bool is_loaded, bool scrollbar, int canvas_id); } // namespace gui } // namespace yaze #endif