From 7ff9d73a4cafa6fdd63dc208cbd988240fafa04a Mon Sep 17 00:00:00 2001 From: John Cosker Date: Thu, 30 Mar 2023 15:17:08 -0400 Subject: [PATCH 1/6] Technically drawing works --- plugins/CMakeLists.txt | 1 + plugins/design.cpp | 452 +++++++++++++++++++++++++++++++++++++++++ plugins/lua/design.lua | 9 + 3 files changed, 462 insertions(+) create mode 100644 plugins/design.cpp create mode 100644 plugins/lua/design.lua diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 477e83436..c880a89ff 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -77,6 +77,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) #dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) +dfhack_plugin(design design.cpp LINK_LIBRARIES lua) dfhack_plugin(autoclothing autoclothing.cpp) dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autofarm autofarm.cpp) diff --git a/plugins/design.cpp b/plugins/design.cpp new file mode 100644 index 000000000..25f876d3e --- /dev/null +++ b/plugins/design.cpp @@ -0,0 +1,452 @@ +#include +#include +#include +#include +#include +#include + +#include "ColorText.h" +#include "Debug.h" +#include "LuaTools.h" +#include "PluginManager.h" +#include "df/graphic_viewportst.h" +#include "df/world.h" +#include "modules/Persistence.h" +#include "modules/Screen.h" +#include "modules/World.h" + +DFHACK_PLUGIN("design"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); +using DFHack::color_value; + +REQUIRE_GLOBAL(window_x); +REQUIRE_GLOBAL(window_y); +REQUIRE_GLOBAL(world); +REQUIRE_GLOBAL(plotinfo); +using namespace DFHack; +using namespace df::enums; + +enum ConfigValues { + CONFIG_IS_ENABLED = 0, +}; +namespace DFHack { +// // for configuration-related logging +DBG_DECLARE(design, status, DebugCategory::LDEBUG); +// for logging during the periodic scan +DBG_DECLARE(design, cycle, DebugCategory::LDEBUG); +} // namespace DFHack +static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; +static PersistentDataItem config; +static const int32_t CYCLE_TICKS = 1200; +static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle + +static command_result do_command(color_ostream &out, + std::vector ¶meters); +static int32_t do_cycle(color_ostream &out, bool force_designate = false); + +DFhackCExport command_result plugin_init(color_ostream &out, + std::vector &commands) { + DEBUG(status, out).print("initializing %s\n", plugin_name); + + // provide a configuration interface for the plugin + commands.push_back( + PluginCommand(plugin_name, "Designs stuff TBD", do_command)); + + return CR_OK; +} + +static int get_config_val(PersistentDataItem &c, int index) { + if (!c.isValid()) return -1; + return c.ival(index); +} + +static bool get_config_bool(PersistentDataItem &c, int index) { + return get_config_val(c, index) == 1; +} + +static void set_config_val(PersistentDataItem &c, int index, int value) { + if (c.isValid()) c.ival(index) = value; +} + +static void set_config_bool(PersistentDataItem &c, int index, bool value) { + set_config_val(c, index, value ? 1 : 0); +} + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); + + return CR_FAILURE; + } + + if (enable != is_enabled) { + is_enabled = enable; + DEBUG(status, out) + .print("%s from the API; persisting\n", + is_enabled ? "enabled" : "disabled"); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + if (enable) do_cycle(out, true); + } else { + DEBUG(status, out) + .print("%s from the API, but already %s; no action\n", + is_enabled ? "enabled" : "disabled", + is_enabled ? "enabled" : "disabled"); + } + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown(color_ostream &out) { + DEBUG(status, out).print("shutting down %s\n", plugin_name); + + return CR_OK; +} + +DFhackCExport command_result plugin_load_data(color_ostream &out) { + cycle_timestamp = 0; + config = World::GetPersistentData(CONFIG_KEY); + + if (!config.isValid()) { + DEBUG(status, out).print("no config found in this save; initializing\n"); + config = World::AddPersistentData(CONFIG_KEY); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + } + + // we have to copy our enabled flag into the global plugin variable, but + // all the other state we can directly read/modify from the persistent + // data structure. + is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); + DEBUG(status, out) + .print("loading persisted enabled state: %s\n", + is_enabled ? "true" : "false"); + + return CR_OK; +} + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, + state_change_event event) { + if (event == DFHack::SC_WORLD_UNLOADED) { + if (is_enabled) { + DEBUG(status, out).print("world unloaded; disabling %s\n", plugin_name); + is_enabled = false; + } + } + + return CR_OK; +} + +DFhackCExport command_result plugin_onupdate(color_ostream &out) { + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) { + int32_t ret = do_cycle(out); + } + + return CR_OK; +} +int selected_tile_texpos = 0; +const static bool hi = + Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); + +static command_result do_command(color_ostream &out, + std::vector ¶meters) { + return CR_OK; +} + +static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } + +// Assuming the existence of a class named Point, similar to the one in Lua +class Point { + public: + int x; + int y; + + Point(int x, int y) : x(x), y(y) {} + + bool operator==(const Point &other) const { + return x == other.x && y == other.y; + } +}; + +// Assuming the existence of a class named Color, similar to the one in Lua +class Color { + public: + // Define your color values here +}; + +// Assuming the existence of a class named Pen, similar to the one in Lua +class Pen { + public: + std::string ch; + int tile; + color_value fg; + // Define your pen properties and methods here +}; + +class Design { + public: + std::map PENS; + + enum PEN_MASK { + NORTH = 0, + SOUTH, + EAST, + WEST, + DRAG_POINT, + MOUSEOVER, + INSHAPE, + EXTRA_POINT, + NUM_FLAGS + }; + + // Define the function similar to the Lua version + + uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_corner, + bool is_mouse_over, bool inshape, bool extra_point) { + std::bitset ret; + ret[NORTH] = n; + ret[SOUTH] = s; + ret[EAST] = e; + ret[WEST] = w; + ret[DRAG_POINT] = is_corner; + ret[MOUSEOVER] = is_mouse_over; + ret[INSHAPE] = inshape; + ret[EXTRA_POINT] = extra_point; + + return static_cast(ret.to_ulong()); + } + + Pen Design::get_pen(int x, int y, + const std::map> &arr); + // Define the function similar to the Lua version +}; + +Design design; + +// Add other methods and member variables needed for the class + +static int design_getPen(lua_State *L) { + std::map> arr; + if (lua_istable(L, -1)) { + // Iterate over the outer table + lua_pushnil(L); // First key + while (lua_next(L, -2) != 0) { + int x = lua_tointeger(L, -2); // Convert key to an integer + + if (lua_istable(L, -1)) { + // Iterate over the inner table + lua_pushnil(L); // First key + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); // Convert key to an integer + bool value = lua_toboolean(L, -1); + + if (value) { + if (arr.count(x) == 0) arr[x] = {}; + arr[x][y] = value; + } + lua_pop(L, 1); // Remove value, keep the key for the next iteration + } + } + lua_pop(L, 1); // Remove inner table, keep the key for the next iteration + } + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + // cur_tile.tile = selected_tile_texpos; + Pen pen = design.get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, + true); + } + } + return 0; +} +enum class CURSORS { + INSIDE, + NORTH, + N_NUB, + S_NUB, + W_NUB, + E_NUB, + NE, + NW, + WEST, + EAST, + SW, + SOUTH, + SE, + VERT_NS, + VERT_EW, + POINT +}; + +std::map> CURSORS_MAP = { + {CURSORS::INSIDE, {1, 2}}, {CURSORS::NORTH, {1, 1}}, + {CURSORS::N_NUB, {3, 2}}, {CURSORS::S_NUB, {4, 2}}, + {CURSORS::W_NUB, {3, 1}}, {CURSORS::E_NUB, {5, 1}}, + {CURSORS::NE, {2, 1}}, {CURSORS::NW, {0, 1}}, + {CURSORS::WEST, {0, 2}}, {CURSORS::EAST, {2, 2}}, + {CURSORS::SW, {0, 3}}, {CURSORS::SOUTH, {1, 3}}, + {CURSORS::SE, {2, 3}}, {CURSORS::VERT_NS, {3, 3}}, + {CURSORS::VERT_EW, {4, 1}}, {CURSORS::POINT, {4, 3}}, +}; +Pen make_pen(const std::pair &direction, bool is_corner, + bool is_mouse_over, bool inshape, bool extra_point) { + color_value color = COLOR_GREEN; + int ycursor_mod = 0; + + if (!extra_point) { + if (is_corner) { + color = COLOR_CYAN; + ycursor_mod += 6; + if (is_mouse_over) { + color = COLOR_MAGENTA; + ycursor_mod += 3; + } + } + } else { + ycursor_mod += 15; + color = COLOR_LIGHTRED; + + if (is_mouse_over) { + color = COLOR_RED; + ycursor_mod += 3; + } + } + + Pen pen; + pen.ch = inshape ? "X" : "o"; + pen.fg = color; + int selected_tile_texpos = 0; + Screen::findGraphicsTile("CURSORS", direction.first, direction.second, &selected_tile_texpos); + pen.tile = selected_tile_texpos; + + // Assuming dfhack.screen.findGraphicsTile is replaced with a custom function + // findGraphicsTile pen.tile = findGraphicsTile("CURSORS", direction.first, + // direction.second + ycursor_mod); + + return pen; +} +Pen Design::get_pen(int x, int y, + const std::map> &arr) { + auto has_point = [&arr](int _x, int _y) { + return arr.count(_x) != 0 && arr.at(_x).count(_y) != 0 && arr.at(_x).at(_y); + }; + bool get_point = has_point(x, y); + + // Basic shapes are bounded by rectangles and therefore can have corner drag + // points even if they're not real points in the shape if (marks.size() >= + // shape.min_points && shape.basic_shape) { + // Point shape_top_left, shape_bot_right; + // shape.get_point_dims(shape_top_left, shape_bot_right); + + // if (x == shape_top_left.x && y == shape_top_left.y && + // shape.drag_corners.nw) { + // drag_point = true; + // } else if (x == shape_bot_right.x && y == shape_top_left.y && + // shape.drag_corners.ne) { + // drag_point = true; + // } else if (x == shape_top_left.x && y == shape_bot_right.y && + // shape.drag_corners.sw) { + // drag_point = true; + // } else if (x == shape_bot_right.x && y == shape_bot_right.y && + // shape.drag_corners.se) { + // drag_point = true; + // } + // } + + // for (const auto& mark : marks) { + // if (mark == Point(x, y)) { + // drag_point = true; + // } + // } + + // if (mirror_point && *mirror_point == Point(x, y)) { + // drag_point = true; + // } + + // // Check for an extra point + // bool extra_point = false; + // for (const auto& point : extra_points) { + // if (x == point.x && y == point.y) { + // extra_point = true; + // break; + // } + // } + + // // Show center point if both marks are set + // if ((shape.basic_shape && marks.size() == shape.max_points) || + // (!shape.basic_shape && !placing_mark.active && !marks.empty())) { + // int center_x, center_y; + // shape.get_center(center_x, center_y); + + // if (x == center_x && y == center_y) { + // extra_point = true; + // } + // } + + bool n = false, w = false, e = false, s = false; + if (get_point) { + if (y == 0 || !has_point(x, y - 1)) n = true; + if (x == 0 || !has_point(x - 1, y)) w = true; + if (!has_point(x + 1, y)) e = true; + if (!has_point(x, y + 1)) s = true; + } + // DEBUG(status).print("jcosker %d %d %d %d\n", n, s, e, w); + + // Get the bit field to use as a key for the PENS map + uint32_t pen_key = gen_pen_key(n, s, e, w, false, false, get_point, false); + // DEBUG(status).print("jcosker %zu\n", pen_key); + + if (PENS.find(pen_key) == PENS.end()) { + std::pair cursor{-1, -1}; + // int cursor = -1; // Assuming -1 is an invalid cursor value + + // Determine the cursor to use based on the input parameters + // The CURSORS enum or equivalent should be defined in your code + if (get_point && !n && !w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::INSIDE); + else if (get_point && n && w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::NW); + else if (get_point && n && !w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::NORTH); + else if (get_point && n && e && !w && !s) + cursor = CURSORS_MAP.at(CURSORS::NE); + else if (get_point && !n && w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::WEST); + else if (get_point && !n && !w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::EAST); + else if (get_point && !n && w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::SW); + else if (get_point && !n && !w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::SOUTH); + else if (get_point && !n && !w && e && s) + cursor = CURSORS_MAP.at(CURSORS::SE); + else if (get_point && n && w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::N_NUB); + else if (get_point && n && !w && e && s) + cursor = CURSORS_MAP.at(CURSORS::E_NUB); + else if (get_point && n && w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::W_NUB); + else if (get_point && !n && w && e && s) + cursor = CURSORS_MAP.at(CURSORS::S_NUB); + else if (get_point && !n && w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::VERT_NS); + else if (get_point && n && !w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::VERT_EW); + else if (get_point && n && w && e && s) + cursor = CURSORS_MAP.at(CURSORS::POINT); + // else if (drag_point && !get_point) cursor = CURSORS::INSIDE; + // else if (extra_point) cursor = CURSORS::INSIDE; + // Create the pen if the cursor is set + + DEBUG(status).print("jcosker %d, %d\n", cursor.first, cursor.second); + if (cursor.first != -1) { + PENS[pen_key] = make_pen(cursor, false, false, get_point, false); + } + } + + // Return the pen for the caller + return PENS.at(pen_key); +} + +DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_getPen), DFHACK_LUA_END}; diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua new file mode 100644 index 000000000..fe916aa41 --- /dev/null +++ b/plugins/lua/design.lua @@ -0,0 +1,9 @@ +local _ENV = mkmodule('plugins.design') + +view2 = {design_window = { name = "hello"}} + +function getPen(hi) + design_getPen(hi) +end + +return _ENV From 6b7c90b676ec51001a59da1388e3fa8e35ca52bf Mon Sep 17 00:00:00 2001 From: John Cosker Date: Thu, 27 Apr 2023 22:37:56 -0400 Subject: [PATCH 2/6] Working C++ and refactors --- plugins/design.cpp | 423 +++++++++++++++++------------------------ plugins/lua/design.lua | 12 +- 2 files changed, 186 insertions(+), 249 deletions(-) diff --git a/plugins/design.cpp b/plugins/design.cpp index 25f876d3e..88d40a630 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -11,6 +11,7 @@ #include "PluginManager.h" #include "df/graphic_viewportst.h" #include "df/world.h" +#include "modules/Gui.h" #include "modules/Persistence.h" #include "modules/Screen.h" #include "modules/World.h" @@ -49,8 +50,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, DEBUG(status, out).print("initializing %s\n", plugin_name); // provide a configuration interface for the plugin - commands.push_back( - PluginCommand(plugin_name, "Designs stuff TBD", do_command)); + commands.push_back(PluginCommand( + plugin_name, + "Plugin to handle performance sensitive functions of gui/design", + do_command)); return CR_OK; } @@ -152,150 +155,77 @@ static command_result do_command(color_ostream &out, static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } -// Assuming the existence of a class named Point, similar to the one in Lua -class Point { - public: - int x; - int y; +std::map PENS; - Point(int x, int y) : x(x), y(y) {} +struct DrawingPoint { + uint32_t penKey = 0; + std::pair cursor_coords; - bool operator==(const Point &other) const { - return x == other.x && y == other.y; - } + DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} }; -// Assuming the existence of a class named Color, similar to the one in Lua -class Color { - public: - // Define your color values here -}; +typedef std::map> ShapeMap; +ShapeMap arr; -// Assuming the existence of a class named Pen, similar to the one in Lua -class Pen { - public: - std::string ch; - int tile; - color_value fg; - // Define your pen properties and methods here +bool has_point(int x, int y) { + return arr.count(x) != 0 && arr.at(x).count(y) != 0; }; -class Design { - public: - std::map PENS; - - enum PEN_MASK { - NORTH = 0, - SOUTH, - EAST, - WEST, - DRAG_POINT, - MOUSEOVER, - INSHAPE, - EXTRA_POINT, - NUM_FLAGS - }; - - // Define the function similar to the Lua version - - uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_corner, - bool is_mouse_over, bool inshape, bool extra_point) { - std::bitset ret; - ret[NORTH] = n; - ret[SOUTH] = s; - ret[EAST] = e; - ret[WEST] = w; - ret[DRAG_POINT] = is_corner; - ret[MOUSEOVER] = is_mouse_over; - ret[INSHAPE] = inshape; - ret[EXTRA_POINT] = extra_point; - - return static_cast(ret.to_ulong()); - } - - Pen Design::get_pen(int x, int y, - const std::map> &arr); - // Define the function similar to the Lua version +// Key tuple is N, W, E, S +typedef std::tuple DirectionKey; +std::map> CURSORS_MAP = { + {{false, false, false, false}, {1, 2}}, // INSIDE + {{true, true, false, false}, {0, 1}}, // NW + {{true, false, false, false}, {1, 1}}, // NORTH + {{true, false, true, false}, {2, 1}}, // NE + {{false, true, false, false}, {0, 2}}, // WEST + {{false, false, true, false}, {2, 2}}, // EAST + {{false, true, false, true}, {0, 3}}, // SW + {{false, false, false, true}, {1, 3}}, // SOUTH + {{false, false, true, true}, {2, 3}}, // SE + {{true, true, true, false}, {3, 2}}, // N_NUB + {{true, false, true, true}, {5, 1}}, // E_NUB + {{true, true, false, true}, {3, 1}}, // W_NUB + {{false, true, true, true}, {4, 2}}, // S_NUB + {{false, true, true, false}, {3, 3}}, // VERT_NS + {{true, false, false, true}, {4, 1}}, // VERT_EW + {{true, true, true, true}, {4, 3}}, // POINT }; -Design design; - -// Add other methods and member variables needed for the class - -static int design_getPen(lua_State *L) { - std::map> arr; - if (lua_istable(L, -1)) { - // Iterate over the outer table - lua_pushnil(L); // First key - while (lua_next(L, -2) != 0) { - int x = lua_tointeger(L, -2); // Convert key to an integer - - if (lua_istable(L, -1)) { - // Iterate over the inner table - lua_pushnil(L); // First key - while (lua_next(L, -2) != 0) { - int y = lua_tointeger(L, -2); // Convert key to an integer - bool value = lua_toboolean(L, -1); - - if (value) { - if (arr.count(x) == 0) arr[x] = {}; - arr[x][y] = value; - } - lua_pop(L, 1); // Remove value, keep the key for the next iteration - } - } - lua_pop(L, 1); // Remove inner table, keep the key for the next iteration - } - } +enum PenMask { + North = 0, + South, + East, + West, + DragPoint, + MouseOver, + InShape, + ExtraPoint, + NumFlags +}; - for (auto x : arr) { - for (auto y : x.second) { - Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); - // cur_tile.tile = selected_tile_texpos; - Pen pen = design.get_pen(x.first, y.first, arr); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, - true); - } - } - return 0; +uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_drag_point, + bool is_mouse_over, bool inshape, bool extra_point) { + std::bitset(PenMask::NumFlags)> ret; + ret[PenMask::North] = n; + ret[PenMask::South] = s; + ret[PenMask::East] = e; + ret[PenMask::West] = w; + ret[PenMask::DragPoint] = is_drag_point; + ret[PenMask::MouseOver] = is_mouse_over; + ret[PenMask::InShape] = inshape; + ret[PenMask::ExtraPoint] = extra_point; + + return ret.to_ulong(); } -enum class CURSORS { - INSIDE, - NORTH, - N_NUB, - S_NUB, - W_NUB, - E_NUB, - NE, - NW, - WEST, - EAST, - SW, - SOUTH, - SE, - VERT_NS, - VERT_EW, - POINT -}; -std::map> CURSORS_MAP = { - {CURSORS::INSIDE, {1, 2}}, {CURSORS::NORTH, {1, 1}}, - {CURSORS::N_NUB, {3, 2}}, {CURSORS::S_NUB, {4, 2}}, - {CURSORS::W_NUB, {3, 1}}, {CURSORS::E_NUB, {5, 1}}, - {CURSORS::NE, {2, 1}}, {CURSORS::NW, {0, 1}}, - {CURSORS::WEST, {0, 2}}, {CURSORS::EAST, {2, 2}}, - {CURSORS::SW, {0, 3}}, {CURSORS::SOUTH, {1, 3}}, - {CURSORS::SE, {2, 3}}, {CURSORS::VERT_NS, {3, 3}}, - {CURSORS::VERT_EW, {4, 1}}, {CURSORS::POINT, {4, 3}}, -}; -Pen make_pen(const std::pair &direction, bool is_corner, - bool is_mouse_over, bool inshape, bool extra_point) { +Screen::Pen make_pen(const std::pair &direction, bool is_drag_point, + bool is_mouse_over, bool inshape, bool extra_point) { color_value color = COLOR_GREEN; int ycursor_mod = 0; if (!extra_point) { - if (is_corner) { + if (is_drag_point) { color = COLOR_CYAN; ycursor_mod += 6; if (is_mouse_over) { @@ -313,140 +243,141 @@ Pen make_pen(const std::pair &direction, bool is_corner, } } - Pen pen; - pen.ch = inshape ? "X" : "o"; + Screen::Pen pen; + pen.ch = inshape ? 'X' : 'o'; pen.fg = color; int selected_tile_texpos = 0; - Screen::findGraphicsTile("CURSORS", direction.first, direction.second, &selected_tile_texpos); + Screen::findGraphicsTile("CURSORS", direction.first, + direction.second + ycursor_mod, + &selected_tile_texpos); pen.tile = selected_tile_texpos; - // Assuming dfhack.screen.findGraphicsTile is replaced with a custom function - // findGraphicsTile pen.tile = findGraphicsTile("CURSORS", direction.first, - // direction.second + ycursor_mod); - return pen; } -Pen Design::get_pen(int x, int y, - const std::map> &arr) { - auto has_point = [&arr](int _x, int _y) { - return arr.count(_x) != 0 && arr.at(_x).count(_y) != 0 && arr.at(_x).at(_y); - }; - bool get_point = has_point(x, y); - - // Basic shapes are bounded by rectangles and therefore can have corner drag - // points even if they're not real points in the shape if (marks.size() >= - // shape.min_points && shape.basic_shape) { - // Point shape_top_left, shape_bot_right; - // shape.get_point_dims(shape_top_left, shape_bot_right); - - // if (x == shape_top_left.x && y == shape_top_left.y && - // shape.drag_corners.nw) { - // drag_point = true; - // } else if (x == shape_bot_right.x && y == shape_top_left.y && - // shape.drag_corners.ne) { - // drag_point = true; - // } else if (x == shape_top_left.x && y == shape_bot_right.y && - // shape.drag_corners.sw) { - // drag_point = true; - // } else if (x == shape_bot_right.x && y == shape_bot_right.y && - // shape.drag_corners.se) { - // drag_point = true; - // } - // } - - // for (const auto& mark : marks) { - // if (mark == Point(x, y)) { - // drag_point = true; - // } - // } - - // if (mirror_point && *mirror_point == Point(x, y)) { - // drag_point = true; - // } - - // // Check for an extra point - // bool extra_point = false; - // for (const auto& point : extra_points) { - // if (x == point.x && y == point.y) { - // extra_point = true; - // break; - // } - // } - - // // Show center point if both marks are set - // if ((shape.basic_shape && marks.size() == shape.max_points) || - // (!shape.basic_shape && !placing_mark.active && !marks.empty())) { - // int center_x, center_y; - // shape.get_center(center_x, center_y); - - // if (x == center_x && y == center_y) { - // extra_point = true; - // } - // } +Screen::Pen get_pen(int x, int y, ShapeMap &arr, const std::string &type = "") { bool n = false, w = false, e = false, s = false; - if (get_point) { + if (has_point(x, y)) { if (y == 0 || !has_point(x, y - 1)) n = true; if (x == 0 || !has_point(x - 1, y)) w = true; - if (!has_point(x + 1, y)) e = true; - if (!has_point(x, y + 1)) s = true; + if (!has_point(x + 1, y)) e = true; // TODO check map size + if (!has_point(x, y + 1)) s = true; // TODO check map size } - // DEBUG(status).print("jcosker %d %d %d %d\n", n, s, e, w); - // Get the bit field to use as a key for the PENS map - uint32_t pen_key = gen_pen_key(n, s, e, w, false, false, get_point, false); - // DEBUG(status).print("jcosker %zu\n", pen_key); + bool is_drag_point = type == "drag_point"; + bool is_extra = type == "extra_point"; + bool is_in_shape = has_point(x, y); + auto mouse_pos = Gui::getMousePos(); + bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; + + uint32_t pen_key = + gen_pen_key(n, s, e, w, is_drag_point, mouse_over, is_in_shape, is_extra); + + if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x,y)) { + arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); + } if (PENS.find(pen_key) == PENS.end()) { std::pair cursor{-1, -1}; - // int cursor = -1; // Assuming -1 is an invalid cursor value - - // Determine the cursor to use based on the input parameters - // The CURSORS enum or equivalent should be defined in your code - if (get_point && !n && !w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::INSIDE); - else if (get_point && n && w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::NW); - else if (get_point && n && !w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::NORTH); - else if (get_point && n && e && !w && !s) - cursor = CURSORS_MAP.at(CURSORS::NE); - else if (get_point && !n && w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::WEST); - else if (get_point && !n && !w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::EAST); - else if (get_point && !n && w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::SW); - else if (get_point && !n && !w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::SOUTH); - else if (get_point && !n && !w && e && s) - cursor = CURSORS_MAP.at(CURSORS::SE); - else if (get_point && n && w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::N_NUB); - else if (get_point && n && !w && e && s) - cursor = CURSORS_MAP.at(CURSORS::E_NUB); - else if (get_point && n && w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::W_NUB); - else if (get_point && !n && w && e && s) - cursor = CURSORS_MAP.at(CURSORS::S_NUB); - else if (get_point && !n && w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::VERT_NS); - else if (get_point && n && !w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::VERT_EW); - else if (get_point && n && w && e && s) - cursor = CURSORS_MAP.at(CURSORS::POINT); - // else if (drag_point && !get_point) cursor = CURSORS::INSIDE; - // else if (extra_point) cursor = CURSORS::INSIDE; - // Create the pen if the cursor is set - - DEBUG(status).print("jcosker %d, %d\n", cursor.first, cursor.second); - if (cursor.first != -1) { - PENS[pen_key] = make_pen(cursor, false, false, get_point, false); + + if (type != "") { + return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, mouse_over, + is_in_shape, is_extra); + } + + if (CURSORS_MAP.count({n, w, e, s}) > 0) { + PENS.emplace(pen_key, + make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra)); + if (type == "" && has_point(x,y)) { + arr[x][y].penKey = pen_key; + } } } - // Return the pen for the caller + // DEBUG(status).print("not cached lmao\n"); return PENS.at(pen_key); } -DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_getPen), DFHACK_LUA_END}; +static int design_load_shape(lua_State *L) { + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int x = lua_tointeger(L, -2); + + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); + bool value = lua_toboolean(L, -1); + + if (value) { + arr[x][y] = DrawingPoint(); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + } + + return 0; +} + +static int design_clear_shape(lua_State *L) { + arr.clear(); + + return 0; +} + +static int design_draw_shape(lua_State *L) { + if (arr.size() == 0) { + design_load_shape(L); + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + Screen::Pen pen = get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, + true); + } + } + + return 0; +} + +static int design_draw_points(lua_State *L) { + if (lua_istable(L, -1)) { + const char *str; + lua_rawgeti(L, -1, 2); + str = lua_tostring(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, -1, 1); + int n = luaL_len(L, -1); + for (int i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + int x, y; + lua_getfield(L, -1, "y"); + y = lua_tointeger(L, -1); + lua_getfield(L, -2, "x"); + x = lua_tointeger(L, -1); + lua_pop(L, 3); + + Screen::Pen cur_tile = Screen::readTile(x, y, true); + Screen::Pen pen = get_pen(x, y, arr, str); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + } + lua_pop(L, 1); + } + + return 0; +} + +DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_draw_shape), + DFHACK_LUA_COMMAND(design_draw_points), + DFHACK_LUA_COMMAND(design_clear_shape), + DFHACK_LUA_END}; diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua index fe916aa41..eb9dd3d9a 100644 --- a/plugins/lua/design.lua +++ b/plugins/lua/design.lua @@ -1,9 +1,15 @@ local _ENV = mkmodule('plugins.design') -view2 = {design_window = { name = "hello"}} +function draw_shape(arr) + design_draw_shape(arr) +end + +function draw_points(points_obj) + design_draw_points(points_obj) +end -function getPen(hi) - design_getPen(hi) +function clear_shape(arr) + design_clear_shape(arr) end return _ENV From 528dc466e2d2f6e8114282c7d23eb2e0090a66e1 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Mon, 1 May 2023 14:20:53 -0400 Subject: [PATCH 3/6] address review comments --- plugins/CMakeLists.txt | 2 +- plugins/design.cpp | 122 ++--------------------------------------- plugins/lua/design.lua | 12 ---- 3 files changed, 6 insertions(+), 130 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c880a89ff..943bc311c 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -77,8 +77,8 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) #dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) +dfhack_plugin(autoclothing autoclothing.cpp LINK_LIBRARIES lua) dfhack_plugin(design design.cpp LINK_LIBRARIES lua) -dfhack_plugin(autoclothing autoclothing.cpp) dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autofarm autofarm.cpp) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) diff --git a/plugins/design.cpp b/plugins/design.cpp index 88d40a630..1abd61842 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -30,131 +30,19 @@ using namespace df::enums; enum ConfigValues { CONFIG_IS_ENABLED = 0, }; -namespace DFHack { -// // for configuration-related logging -DBG_DECLARE(design, status, DebugCategory::LDEBUG); -// for logging during the periodic scan -DBG_DECLARE(design, cycle, DebugCategory::LDEBUG); -} // namespace DFHack -static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; -static PersistentDataItem config; -static const int32_t CYCLE_TICKS = 1200; -static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle - -static command_result do_command(color_ostream &out, - std::vector ¶meters); -static int32_t do_cycle(color_ostream &out, bool force_designate = false); - -DFhackCExport command_result plugin_init(color_ostream &out, - std::vector &commands) { - DEBUG(status, out).print("initializing %s\n", plugin_name); - - // provide a configuration interface for the plugin - commands.push_back(PluginCommand( - plugin_name, - "Plugin to handle performance sensitive functions of gui/design", - do_command)); - - return CR_OK; -} -static int get_config_val(PersistentDataItem &c, int index) { - if (!c.isValid()) return -1; - return c.ival(index); -} - -static bool get_config_bool(PersistentDataItem &c, int index) { - return get_config_val(c, index) == 1; -} - -static void set_config_val(PersistentDataItem &c, int index, int value) { - if (c.isValid()) c.ival(index) = value; +namespace DFHack { + DBG_DECLARE(pathable, log, DebugCategory::LINFO); } -static void set_config_bool(PersistentDataItem &c, int index, bool value) { - set_config_val(c, index, value ? 1 : 0); -} - -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { - if (!Core::getInstance().isWorldLoaded()) { - out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); - - return CR_FAILURE; - } - - if (enable != is_enabled) { - is_enabled = enable; - DEBUG(status, out) - .print("%s from the API; persisting\n", - is_enabled ? "enabled" : "disabled"); - set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - if (enable) do_cycle(out, true); - } else { - DEBUG(status, out) - .print("%s from the API, but already %s; no action\n", - is_enabled ? "enabled" : "disabled", - is_enabled ? "enabled" : "disabled"); - } - return CR_OK; +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + return CR_OK; } DFhackCExport command_result plugin_shutdown(color_ostream &out) { - DEBUG(status, out).print("shutting down %s\n", plugin_name); - - return CR_OK; + return CR_OK; } -DFhackCExport command_result plugin_load_data(color_ostream &out) { - cycle_timestamp = 0; - config = World::GetPersistentData(CONFIG_KEY); - - if (!config.isValid()) { - DEBUG(status, out).print("no config found in this save; initializing\n"); - config = World::AddPersistentData(CONFIG_KEY); - set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - } - - // we have to copy our enabled flag into the global plugin variable, but - // all the other state we can directly read/modify from the persistent - // data structure. - is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); - DEBUG(status, out) - .print("loading persisted enabled state: %s\n", - is_enabled ? "true" : "false"); - - return CR_OK; -} - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, - state_change_event event) { - if (event == DFHack::SC_WORLD_UNLOADED) { - if (is_enabled) { - DEBUG(status, out).print("world unloaded; disabling %s\n", plugin_name); - is_enabled = false; - } - } - - return CR_OK; -} - -DFhackCExport command_result plugin_onupdate(color_ostream &out) { - if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) { - int32_t ret = do_cycle(out); - } - - return CR_OK; -} -int selected_tile_texpos = 0; -const static bool hi = - Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); - -static command_result do_command(color_ostream &out, - std::vector ¶meters) { - return CR_OK; -} - -static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } - std::map PENS; struct DrawingPoint { diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua index eb9dd3d9a..ec3b4c79b 100644 --- a/plugins/lua/design.lua +++ b/plugins/lua/design.lua @@ -1,15 +1,3 @@ local _ENV = mkmodule('plugins.design') -function draw_shape(arr) - design_draw_shape(arr) -end - -function draw_points(points_obj) - design_draw_points(points_obj) -end - -function clear_shape(arr) - design_clear_shape(arr) -end - return _ENV From 0eb04f1b73d61752245a4113d89183840c55cfa2 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Mon, 1 May 2023 14:32:09 -0400 Subject: [PATCH 4/6] changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 66904aa6d..e1e45f799 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -50,6 +50,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `gui/control-panel`: add preference option for hiding "armok" tools in command lists - ``Dwarf Therapist``: add a warning to the Labors screen when Dwarf Therapist is active so players know that changes they make to that screen will have no effect. If you're starting a new embark and nobody seems to be doing anything, check your Labors tab for this warning to see if Dwarf Therapist thinks it is in control (even if it's not running). - `overlay`: add the DFHack version string to the DF title screen +- `gui/design`: Improved performance for drawing shapes ## Documentation From 58e11b01cba07e3721ea1dc795b3f9258354bfc0 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Wed, 3 May 2023 19:37:44 -0400 Subject: [PATCH 5/6] Comments --- docs/changelog.txt | 1 + plugins/design.cpp | 313 ++++++++++++++++++++++----------------------- 2 files changed, 157 insertions(+), 157 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a7ce7c25f..0a37bb3b9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -41,6 +41,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup +- `gui/design`: Improved performance for drawing shapes ## Documentation diff --git a/plugins/design.cpp b/plugins/design.cpp index 1abd61842..37ee32cbd 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -17,7 +17,6 @@ #include "modules/World.h" DFHACK_PLUGIN("design"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); using DFHack::color_value; REQUIRE_GLOBAL(window_x); @@ -27,36 +26,37 @@ REQUIRE_GLOBAL(plotinfo); using namespace DFHack; using namespace df::enums; -enum ConfigValues { - CONFIG_IS_ENABLED = 0, -}; - namespace DFHack { - DBG_DECLARE(pathable, log, DebugCategory::LINFO); +DBG_DECLARE(design, log, DebugCategory::LINFO); } -DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { +DFhackCExport command_result plugin_init(color_ostream &out, + std::vector &commands) { return CR_OK; } -DFhackCExport command_result plugin_shutdown(color_ostream &out) { +std::map PENS; + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { + if (event == DFHack::SC_WORLD_UNLOADED) { + DEBUG(log,out).print("clearing PENS\n"); + PENS.clear(); + } return CR_OK; } -std::map PENS; - struct DrawingPoint { - uint32_t penKey = 0; - std::pair cursor_coords; + uint32_t penKey = 0; + std::pair cursor_coords; - DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} + DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} }; typedef std::map> ShapeMap; ShapeMap arr; bool has_point(int x, int y) { - return arr.count(x) != 0 && arr.at(x).count(y) != 0; + return arr.count(x) != 0 && arr.at(x).count(y) != 0; }; // Key tuple is N, W, E, S @@ -81,188 +81,187 @@ std::map> CURSORS_MAP = { }; enum PenMask { - North = 0, - South, - East, - West, - DragPoint, - MouseOver, - InShape, - ExtraPoint, - NumFlags + North = 0, + South, + East, + West, + DragPoint, + MouseOver, + InShape, + ExtraPoint, + NumFlags }; uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_drag_point, bool is_mouse_over, bool inshape, bool extra_point) { - std::bitset(PenMask::NumFlags)> ret; - ret[PenMask::North] = n; - ret[PenMask::South] = s; - ret[PenMask::East] = e; - ret[PenMask::West] = w; - ret[PenMask::DragPoint] = is_drag_point; - ret[PenMask::MouseOver] = is_mouse_over; - ret[PenMask::InShape] = inshape; - ret[PenMask::ExtraPoint] = extra_point; - - return ret.to_ulong(); + std::bitset(PenMask::NumFlags)> ret; + ret[PenMask::North] = n; + ret[PenMask::South] = s; + ret[PenMask::East] = e; + ret[PenMask::West] = w; + ret[PenMask::DragPoint] = is_drag_point; + ret[PenMask::MouseOver] = is_mouse_over; + ret[PenMask::InShape] = inshape; + ret[PenMask::ExtraPoint] = extra_point; + + return ret.to_ulong(); } Screen::Pen make_pen(const std::pair &direction, bool is_drag_point, bool is_mouse_over, bool inshape, bool extra_point) { - color_value color = COLOR_GREEN; - int ycursor_mod = 0; - - if (!extra_point) { - if (is_drag_point) { - color = COLOR_CYAN; - ycursor_mod += 6; - if (is_mouse_over) { - color = COLOR_MAGENTA; - ycursor_mod += 3; - } - } - } else { - ycursor_mod += 15; - color = COLOR_LIGHTRED; + color_value color = COLOR_GREEN; + int ycursor_mod = 0; + + if (!extra_point) { + if (is_drag_point) { + color = COLOR_CYAN; + ycursor_mod += 6; + if (is_mouse_over) { + color = COLOR_MAGENTA; + ycursor_mod += 3; + } + } + } else { + ycursor_mod += 15; + color = COLOR_LIGHTRED; - if (is_mouse_over) { - color = COLOR_RED; - ycursor_mod += 3; + if (is_mouse_over) { + color = COLOR_RED; + ycursor_mod += 3; + } } - } - - Screen::Pen pen; - pen.ch = inshape ? 'X' : 'o'; - pen.fg = color; - int selected_tile_texpos = 0; - Screen::findGraphicsTile("CURSORS", direction.first, - direction.second + ycursor_mod, - &selected_tile_texpos); - pen.tile = selected_tile_texpos; - - return pen; + + Screen::Pen pen; + pen.ch = inshape ? 'X' : 'o'; + pen.fg = color; + int selected_tile_texpos = 0; + Screen::findGraphicsTile("CURSORS", direction.first, + direction.second + ycursor_mod, + &selected_tile_texpos); + pen.tile = selected_tile_texpos; + + return pen; } Screen::Pen get_pen(int x, int y, ShapeMap &arr, const std::string &type = "") { - bool n = false, w = false, e = false, s = false; - if (has_point(x, y)) { - if (y == 0 || !has_point(x, y - 1)) n = true; - if (x == 0 || !has_point(x - 1, y)) w = true; - if (!has_point(x + 1, y)) e = true; // TODO check map size - if (!has_point(x, y + 1)) s = true; // TODO check map size - } - - bool is_drag_point = type == "drag_point"; - bool is_extra = type == "extra_point"; - bool is_in_shape = has_point(x, y); - auto mouse_pos = Gui::getMousePos(); - bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; - - uint32_t pen_key = - gen_pen_key(n, s, e, w, is_drag_point, mouse_over, is_in_shape, is_extra); - - if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x,y)) { - arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); - } - - if (PENS.find(pen_key) == PENS.end()) { - std::pair cursor{-1, -1}; - - if (type != "") { - return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, mouse_over, - is_in_shape, is_extra); + bool n = false, w = false, e = false, s = false; + if (has_point(x, y)) { + if (y == 0 || !has_point(x, y - 1)) n = true; + if (x == 0 || !has_point(x - 1, y)) w = true; + if (!has_point(x + 1, y)) e = true; // TODO check map size + if (!has_point(x, y + 1)) s = true; // TODO check map size + } + + bool is_drag_point = type == "drag_point"; + bool is_extra = type == "extra_point"; + bool is_in_shape = has_point(x, y); + auto mouse_pos = Gui::getMousePos(); + bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; + + uint32_t pen_key = gen_pen_key(n, s, e, w, is_drag_point, mouse_over, + is_in_shape, is_extra); + + if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x, y)) { + arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); } - if (CURSORS_MAP.count({n, w, e, s}) > 0) { - PENS.emplace(pen_key, - make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, - mouse_over, is_in_shape, is_extra)); - if (type == "" && has_point(x,y)) { - arr[x][y].penKey = pen_key; - } + if (PENS.find(pen_key) == PENS.end()) { + std::pair cursor{-1, -1}; + + if (type != "") { + return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra); + } + + if (CURSORS_MAP.count({n, w, e, s}) > 0) { + PENS.emplace(pen_key, + make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra)); + if (type == "" && has_point(x, y)) { + arr[x][y].penKey = pen_key; + } + } } - } - // DEBUG(status).print("not cached lmao\n"); - return PENS.at(pen_key); + return PENS.at(pen_key); } static int design_load_shape(lua_State *L) { - if (lua_istable(L, -1)) { - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - int x = lua_tointeger(L, -2); - - if (lua_istable(L, -1)) { + if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { - int y = lua_tointeger(L, -2); - bool value = lua_toboolean(L, -1); - - if (value) { - arr[x][y] = DrawingPoint(); - } - lua_pop(L, 1); + int x = lua_tointeger(L, -2); + + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); + bool value = lua_toboolean(L, -1); + + if (value) { + arr[x][y] = DrawingPoint(); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); } - } - lua_pop(L, 1); } - } - return 0; + return 0; } static int design_clear_shape(lua_State *L) { - arr.clear(); + arr.clear(); - return 0; + return 0; } static int design_draw_shape(lua_State *L) { - if (arr.size() == 0) { - design_load_shape(L); - } - - for (auto x : arr) { - for (auto y : x.second) { - Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); - Screen::Pen pen = get_pen(x.first, y.first, arr); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, - true); + if (arr.size() == 0) { + design_load_shape(L); + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + Screen::Pen pen = get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, + y.first - *window_y, true); + } } - } - return 0; + return 0; } static int design_draw_points(lua_State *L) { - if (lua_istable(L, -1)) { - const char *str; - lua_rawgeti(L, -1, 2); - str = lua_tostring(L, -1); - lua_pop(L, 1); - - lua_rawgeti(L, -1, 1); - int n = luaL_len(L, -1); - for (int i = 1; i <= n; i++) { - lua_rawgeti(L, -1, i); - int x, y; - lua_getfield(L, -1, "y"); - y = lua_tointeger(L, -1); - lua_getfield(L, -2, "x"); - x = lua_tointeger(L, -1); - lua_pop(L, 3); - - Screen::Pen cur_tile = Screen::readTile(x, y, true); - Screen::Pen pen = get_pen(x, y, arr, str); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + if (lua_istable(L, -1)) { + const char *str; + lua_rawgeti(L, -1, 2); + str = lua_tostring(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, -1, 1); + int n = luaL_len(L, -1); + for (int i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + int x, y; + lua_getfield(L, -1, "y"); + y = lua_tointeger(L, -1); + lua_getfield(L, -2, "x"); + x = lua_tointeger(L, -1); + lua_pop(L, 3); + + Screen::Pen cur_tile = Screen::readTile(x, y, true); + Screen::Pen pen = get_pen(x, y, arr, str); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + } + lua_pop(L, 1); } - lua_pop(L, 1); - } - return 0; + return 0; } DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_draw_shape), From aa0721edee40396c3aa11ec933f3beacdb85bc3d Mon Sep 17 00:00:00 2001 From: John Cosker Date: Wed, 3 May 2023 20:01:17 -0400 Subject: [PATCH 6/6] Changelog --- docs/changelog.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0a37bb3b9..f6524dc58 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -68,7 +68,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `gui/control-panel`: add preference option for hiding "armok" tools in command lists - ``Dwarf Therapist``: add a warning to the Labors screen when Dwarf Therapist is active so players know that changes they make to that screen will have no effect. If you're starting a new embark and nobody seems to be doing anything, check your Labors tab for this warning to see if Dwarf Therapist thinks it is in control (even if it's not running). - `overlay`: add the DFHack version string to the DF title screen -- `gui/design`: Improved performance for drawing shapes ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget