From 83b49f402ed8a8ed5d39d8d85d5c56aafb6759ce Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Mon, 23 Jun 2025 18:58:58 -0500 Subject: [PATCH] import terrain icons to custom sheets --- rsrc/dialogs/graphic-sheets.xml | 4 + src/scenedit/scen.core.cpp | 211 ++++++++++++++++++++------------ 2 files changed, 138 insertions(+), 77 deletions(-) diff --git a/rsrc/dialogs/graphic-sheets.xml b/rsrc/dialogs/graphic-sheets.xml index cc905a8f..9b69a37a 100644 --- a/rsrc/dialogs/graphic-sheets.xml +++ b/rsrc/dialogs/graphic-sheets.xml @@ -22,6 +22,10 @@ - 0 + + + + diff --git a/src/scenedit/scen.core.cpp b/src/scenedit/scen.core.cpp index 85ef359e..ec987323 100644 --- a/src/scenedit/scen.core.cpp +++ b/src/scenedit/scen.core.cpp @@ -3712,13 +3712,35 @@ void edit_custom_pics_types() { pic_dlg.run(); } +extern fs::path tempDir; +extern std::string scenario_temp_dir_name; + +// Keep a single RenderTexture for splicing together custom graphics +bool canvas_created = false; +static sf::RenderTexture& canvas() { + static sf::RenderTexture instance; + if(!canvas_created){ + instance.create(280, 360); + canvas_created = true; + } + return instance; +} + static void set_dlg_custom_sheet(cDialog& me, size_t sheet) { me["num"].setTextToNum(sheet); dynamic_cast(me["sheet"]).setPict(sheet, PIC_FULL); } -extern fs::path tempDir; -extern std::string scenario_temp_dir_name; +static void set_up_canvas(size_t sheet){ + fs::path pic_dir = tempDir/scenario_temp_dir_name/"graphics"; + fs::path fromPath = pic_dir/("sheet" + std::to_string(sheet) + ".png"); + + sf::Texture texture; + texture.loadFromFile(fromPath.string()); + sf::Sprite s(texture); + canvas().clear(sf::Color(0,0,0,0)); + canvas().draw(s); +} void edit_custom_sheets() { // Everything you do in this dialog can be undone when you hit cancel, leaving no trace in the main history. @@ -3781,79 +3803,7 @@ void edit_custom_sheets() { sheets[i] = spec_scen_g.sheets[i]->copyToImage(); } - using namespace std::placeholders; - cDialog pic_dlg(*ResMgr::dialogs.get("graphic-sheets")); - pic_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, _1, false)); - pic_dlg["okay"].attachClickHandler(std::bind(&cDialog::toast, _1, true)); - pic_dlg["copy"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir](cDialog&, std::string, eKeyMod) -> bool { - if(cur >= spec_scen_g.numSheets) { - fs::path fromPath = pic_dir/("sheet" + std::to_string(all_pics[cur]) + ".png"); - sf::Image img; - img.loadFromFile(fromPath.string().c_str()); - set_clipboard_img(img); - return true; - } - set_clipboard_img(sheets[cur]); - return true; - }); - pic_dlg["paste"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir,&deferred_actions](cDialog& me, std::string, eKeyMod) -> bool { - auto img = get_clipboard_img(); - if(img == nullptr) { - beep(); - return true; - } - sf::Image new_image = *img; - if(cur >= spec_scen_g.numSheets) { - std::string resName = "sheet" + std::to_string(all_pics[cur]); - fs::path toPath = pic_dir/(resName + ".png"); - - sf::Image image_for_undo; - image_for_undo.loadFromFile(toPath.string()); - deferred_actions.push_back(action_ptr(new aReplaceGraphicsSheet("Paste Graphics Sheet", all_pics[cur], image_for_undo, new_image))); - - img->saveToFile(toPath.string().c_str()); - ResMgr::graphics.free(resName); - set_dlg_custom_sheet(me, all_pics[cur]); - return true; - } - deferred_actions.push_back(action_ptr(new aReplaceGraphicsSheet("Paste Graphics Sheet", cur, sheets[cur], new_image))); - - sheets[cur] = *img; - spec_scen_g.replace_sheet(cur, *img); - set_dlg_custom_sheet(me, all_pics[cur]); - return true; - }); - pic_dlg["edit"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir](cDialog&, std::string, eKeyMod) -> bool { - fs::path image_editor = get_string_pref("ImageEditor"); - if(image_editor.empty()){ - showWarning("Choose an external image editor in the preferences window first."); - return true; - } - #ifdef SFML_SYSTEM_MACOS - // Find actual binary inside the .app bundle: - - image_editor = image_editor / "Contents" / "MacOS" / image_editor.stem(); - - #endif - - std::string resName = "sheet" + std::to_string(all_pics[cur]); - fs::path toPath = pic_dir/(resName + ".png"); - - std::vector args = {toPath.string()}; - try{ - bp::child ch(image_editor, args, bp::std_out > stdout); - ch.detach(); - } - catch(std::exception& x) { - showError(std::string{"Error running your image editor: "} + x.what()); - } catch(std::string& x) { - showError("Error running your image editor: " + x); - } catch(...) { - showError("An unknown error occurred running your image editor!"); - } - return true; - }); auto replace_from_file = [&pic_dlg,&sheets,&cur,&all_pics,&pic_dir,&deferred_actions](std::string action_name, fs::path fpath) -> bool { sf::Image img; @@ -3886,12 +3836,86 @@ void edit_custom_sheets() { set_dlg_custom_sheet(pic_dlg, all_pics[cur]); return true; }; + + auto replace_from_image = [&cur, &all_pics, pic_dir, &deferred_actions, &sheets, &pic_dlg](std::string action_name, sf::Image& image) -> bool { + if(cur >= spec_scen_g.numSheets) { + std::string resName = "sheet" + std::to_string(all_pics[cur]); + fs::path toPath = pic_dir/(resName + ".png"); + + sf::Image image_for_undo; + image_for_undo.loadFromFile(toPath.string()); + deferred_actions.push_back(action_ptr(new aReplaceGraphicsSheet(action_name, all_pics[cur], image_for_undo, image))); + + image.saveToFile(toPath.string().c_str()); + ResMgr::graphics.free(resName); + set_dlg_custom_sheet(pic_dlg, all_pics[cur]); + return true; + } + deferred_actions.push_back(action_ptr(new aReplaceGraphicsSheet(action_name, cur, sheets[cur], image))); + + sheets[cur] = image; + spec_scen_g.replace_sheet(cur, image); + set_dlg_custom_sheet(pic_dlg, all_pics[cur]); + return true; + }; + + using namespace std::placeholders; + pic_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, _1, false)); + pic_dlg["okay"].attachClickHandler(std::bind(&cDialog::toast, _1, true)); + pic_dlg["copy"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir](cDialog&, std::string, eKeyMod) -> bool { + if(cur >= spec_scen_g.numSheets) { + fs::path fromPath = pic_dir/("sheet" + std::to_string(all_pics[cur]) + ".png"); + sf::Image img; + img.loadFromFile(fromPath.string().c_str()); + set_clipboard_img(img); + return true; + } + set_clipboard_img(sheets[cur]); + return true; + }); + pic_dlg["paste"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir,&deferred_actions,replace_from_image](cDialog& me, std::string, eKeyMod) -> bool { + auto img = get_clipboard_img(); + if(img == nullptr) { + beep(); + return true; + } + return replace_from_image("Paste Graphics Sheet", *img); + }); + pic_dlg["edit"].attachClickHandler([&sheets,&cur,&all_pics,&pic_dir](cDialog&, std::string, eKeyMod) -> bool { + fs::path image_editor = get_string_pref("ImageEditor"); + if(image_editor.empty()){ + showWarning("Choose an external image editor in the preferences window first."); + return true; + } + #ifdef SFML_SYSTEM_MACOS + // Find actual binary inside the .app bundle: + + image_editor = image_editor / "Contents" / "MacOS" / image_editor.stem(); + + #endif + + std::string resName = "sheet" + std::to_string(all_pics[cur]); + fs::path toPath = pic_dir/(resName + ".png"); + + std::vector args = {toPath.string()}; + try{ + bp::child ch(image_editor, args, bp::std_out > stdout); + ch.detach(); + } + catch(std::exception& x) { + showError(std::string{"Error running your image editor: "} + x.what()); + } catch(std::string& x) { + showError("Error running your image editor: " + x); + } catch(...) { + showError("An unknown error occurred running your image editor!"); + } + return true; + }); pic_dlg["reload"].attachClickHandler([replace_from_file, &all_pics, &cur, &pic_dir](cDialog&, std::string, eKeyMod) -> bool { std::string resName = "sheet" + std::to_string(all_pics[cur]); fs::path sheetPath = pic_dir/(resName + ".png"); - replace_from_file("Reload Graphics Sheet", sheetPath); - return true; + return replace_from_file("Reload Graphics Sheet", sheetPath); }); pic_dlg["open"].attachClickHandler([replace_from_file](cDialog& me, std::string, eKeyMod) -> bool { fs::path fpath = nav_get_rsrc({"png", "bmp", "jpg", "jpeg", "gif", "psd"}); @@ -4012,12 +4036,22 @@ void edit_custom_sheets() { int icon_end = 0; int icon_min = 0; int icon_max = 0; - auto show_icon_selection = [&icon_min, &icon_max, &pic_dlg]() { + + std::vector icon_buttons = {"icon-terr", "strip-terr", "add-terr"}; + auto show_icon_selection = [&icon_min, &icon_max, &pic_dlg, icon_buttons]() { pic_dlg["icon-min"].setTextToNum(icon_min); pic_dlg["icon-max"].setTextToNum(icon_max); // TODO highlight the selected icons visually + for(auto name : icon_buttons){ + if(icon_min != 0){ + pic_dlg[name].show(); + }else{ + pic_dlg[name].hide(); + } + } }; + show_icon_selection(); pic_dlg.attachClickHandlers([&sheets,&cur,&all_pics,show_icon_selection,&icon_start,&icon_end,&icon_min,&icon_max](cDialog& me, std::string dir, eKeyMod) -> bool { size_t old_cur = cur; if(dir == "left") { @@ -4066,6 +4100,29 @@ void edit_custom_sheets() { return true; }); + pic_dlg.attachClickHandlers([&icon_max, &icon_min, &all_pics, &cur, replace_from_image](cDialog& me, std::string item_hit, eKeyMod) -> bool { + if(item_hit == "icon-terr"){ + pic_num_t icon = choose_graphic(0, PIC_TER, &me); + set_up_canvas(all_pics[cur]); + int sheet_start = 1000 + 100 * all_pics[cur]; + for(int i = 0; i < (icon_max - icon_min) + 1; ++i){ + int sheet_icon = icon_min + i - sheet_start; + int x = sheet_icon % 10; + int y = sheet_icon / 10; + rectangle dest {y * 36, x * 28, y * 36 + 36, x * 28 + 28}; + cPict::drawAt(mainPtr(),canvas(),dest,icon+i,PIC_TER,false); + } + canvas().display(); + sf::Image img = canvas().getTexture().copyToImage(); + return replace_from_image("Import Terrain Icon", img); + }else if(item_hit == "strip-terr"){ + + }else if(item_hit == "add-terr"){ + + } + return true; + },icon_buttons); + shut_down_menus(5); // So that cmd+O, cmd+N, cmd+S can work pic_dlg.run();