diff --git a/NEWS b/NEWS index 9cb7ab18e..cd18cffb2 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ DFHack future New commands: - move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands - 'plant create' - spawn a new shrub under the cursor + - command-prompt: a dfhack command prompt in df. Misc improvements: - digfort: improved csv parsing, add start() comment handling diff --git a/Readme.rst b/Readme.rst index 6207b916f..cd17ff383 100644 --- a/Readme.rst +++ b/Readme.rst @@ -329,6 +329,12 @@ Options: The building must be one of stockpile, workshop, furnace, trap, siege engine or an activity zone. +command-prompt +-------------- +A one line command prompt in df. Same as entering command into dfhack console. Best +used as a keybinding. Can be called with optional "entry" that will start prompt with +that pre-filled. + Adventure mode ============== diff --git a/dfhack.init-example b/dfhack.init-example index 62d6c1125..3470bf36b 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -31,6 +31,9 @@ keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave keybinding add Ctrl-Shift-N gui/rename keybinding add Ctrl-Shift-T "gui/rename unit-profession" +# a dfhack prompt in df. Sublime text like. +keybinding add Ctrl-Shift-P command-prompt + ############################## # Generic adv mode bindings # ############################## diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 29acba8a1..6e1425b9c 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -163,6 +163,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(cleanconst cleanconst.cpp) DFHACK_PLUGIN(3dveins 3dveins.cpp) DFHACK_PLUGIN(strangemood strangemood.cpp) + DFHACK_PLUGIN(command-prompt command-prompt.cpp) endif() # this is the skeleton plugin. If you want to make your own, make a copy and then change it diff --git a/plugins/command-prompt.cpp b/plugins/command-prompt.cpp new file mode 100644 index 000000000..842daad7b --- /dev/null +++ b/plugins/command-prompt.cpp @@ -0,0 +1,187 @@ +//command-prompt a one line command entry at the top of the screen for quick commands + +#include "Core.h" +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "df/interface_key.h" +#include "df/ui.h" +#include "df/graphic.h" +#include "df/enabler.h" +using namespace DFHack; +using namespace df::enums; + +using df::global::ui; +using df::global::gps; +using df::global::enabler; + +class viewscreen_commandpromptst; +class prompt_ostream:public buffered_color_ostream +{ + viewscreen_commandpromptst *parent_; + protected: + void flush_proxy(); + public: + prompt_ostream(viewscreen_commandpromptst* parent):parent_(parent){} + bool empty(){return buffer.empty();} +}; +class viewscreen_commandpromptst : public dfhack_viewscreen { +public: + void feed(std::set *events); + + void logic() { + dfhack_viewscreen::logic(); + } + + void render(); + void help() { } + + std::string getFocusString() { return "commandprompt"; } + viewscreen_commandpromptst(std::string entry):is_response(false),entry(entry) + { + show_fps=df::global::gps->display_frames; + df::global::gps->display_frames=0; + } + ~viewscreen_commandpromptst() + { + df::global::gps->display_frames=show_fps; + } + + void add_response(color_value v,std::string s) + { + responses.push_back(std::make_pair(v,s)); + } +protected: + std::list > responses; + bool is_response; + bool show_fps; + void submit(); + std::string entry; +}; +void prompt_ostream::flush_proxy() +{ + if (buffer.empty()) + return; + for(auto it=buffer.begin();it!=buffer.end();it++) + parent_->add_response(it->first,it->second); + buffer.clear(); +} +void viewscreen_commandpromptst::render() +{ + if (Screen::isDismissed(this)) + return; + + dfhack_viewscreen::render(); + + auto dim = Screen::getWindowSize(); + parent->render(); + if(is_response) + { + auto it=responses.begin(); + for(int i=0;isecond; + Screen::paintString(Screen::Pen(' ',it->first,0),0,i,cur_line.substr(0,cur_line.size()-1)); + } + } + else + { + Screen::fillRect(Screen::Pen(' ', 7, 0),0,0,dim.x,0); + Screen::paintString(Screen::Pen(' ', 7, 0), 0, 0,"[DFHack]#"); + if(entry.size()', 7, 0), 9, 0); + Screen::paintString(Screen::Pen(' ', 7, 0), 10, 0, entry.substr(entry.size()-dim.x)); + } + } +} +void viewscreen_commandpromptst::submit() +{ + CoreSuspendClaimer suspend; + if(is_response) + { + Screen::dismiss(this); + return; + } + //color_ostream_proxy out(Core::getInstance().getConsole()); + prompt_ostream out(this); + Core::getInstance().runCommand(out, entry); + if(out.empty() && responses.empty()) + Screen::dismiss(this); + else + { + is_response=true; + } +} +void viewscreen_commandpromptst::feed(std::set *events) +{ + + bool leave_all = events->count(interface_key::LEAVESCREEN_ALL); + if (leave_all || events->count(interface_key::LEAVESCREEN)) + { + events->clear(); + Screen::dismiss(this); + if (leave_all) + { + events->insert(interface_key::LEAVESCREEN); + parent->feed(events); + events->clear(); + } + return; + } + if(events->count(interface_key::SELECT)) + { + submit(); + return; + } + if(is_response) + return; + for (auto it = events->begin(); it != events->end(); ++it) + { + auto key = *it; + if (key==interface_key::STRING_A000) //delete? + { + if(entry.size()) + entry.pop_back(); + continue; + } + if (key >= interface_key::STRING_A000 && + key <= interface_key::STRING_A255) + { + entry.push_back(char(key - interface_key::STRING_A000)); + } + } +} +DFHACK_PLUGIN("command-prompt"); +command_result show_prompt(color_ostream &out, std::vector & parameters) +{ + std::string params; + for(size_t i=0;i &commands) +{ + commands.push_back(PluginCommand( + "command-prompt","Shows a command prompt on window.",show_prompt,false, + "command-prompt [entry] - shows a cmd prompt in df window. Entry is used for default prefix (e.g. ':lua')" + )); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown ( color_ostream &out ) +{ + return CR_OK; +} \ No newline at end of file