stockpiles: implement GUI controls

develop
Casey Link 2014-12-02 20:00:16 +01:00
parent 2e43ea8b38
commit 1cde8cffa4
3 changed files with 319 additions and 8 deletions

@ -0,0 +1,84 @@
local _ENV = mkmodule('plugins.stockpiles')
--[[
Native functions:
* stockpiles_list_settings(dir_path), list files in directory
* stockpiles_load(file), with full path
* stockpiles_save(file), with full path
--]]
local gui = require 'gui'
local script = require 'gui.script'
local persist = require 'persist-table'
if persist.GlobalTable.stockpiles == nil then
persist.GlobalTable.stockpiles = {}
persist.GlobalTable.stockpiles['settings_path'] = './stocksettings'
end
function tablify(iterableObject)
t={}
for k,v in ipairs(iterableObject) do
t[k] = v~=nil and v or 'nil'
end
return t
end
function load_settings()
script.start(function()
local path = persist.GlobalTable.stockpiles['settings_path']
local list = stockpiles_list_settings(path)
local tok,i = script.showListPrompt('Stockpile Settings','Load which stockpile?',COLOR_WHITE,tablify(list))
if tok then
local filename = list[i];
stockpiles_load(path..'/'..filename);
end
end)
end
function save_settings(stockpile)
script.start(function()
--local sp = dfhack.gui.geSelectedBuilding(true)
local suggested = stockpile.name
if #suggested == 0 then
suggested = 'Stock1'
end
local path = persist.GlobalTable.stockpiles['settings_path']
local sok,filename = script.showInputPrompt('Stockpile Settings', 'Enter stockpile name', COLOR_WHITE, suggested)
if sok then
stockpiles_save(path..'/'..filename);
end
end)
end
function manage_settings(sp)
if not guard() then return false end
script.start(function()
local list = {'Load', 'Save'}
local tok,i = script.showListPrompt('Stockpile Settings','Load or Save Settings?',COLOR_WHITE,tablify(list))
if tok then
if i == 1 then
load_settings()
else
save_settings(sp)
end
end
end)
end
function guard()
if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/QueryBuilding/Some/Stockpile') then
qerror("This script requires a stockpile selected in the 'q' mode")
return false
end
return true
end
function set_path(path)
persist.GlobalTable.stockpiles['settings_path'] = path
end
return _ENV

@ -2,15 +2,15 @@ PROJECT(stockpiles)
# add *our* headers here. # add *our* headers here.
SET(PROJECT_HDRS SET(PROJECT_HDRS
StockpileUtils.h StockpileUtils.h
OrganicMatLookup.h OrganicMatLookup.h
StockpileSerializer.h StockpileSerializer.h
) )
SET(PROJECT_SRCS SET(PROJECT_SRCS
OrganicMatLookup.cpp OrganicMatLookup.cpp
StockpileSerializer.cpp StockpileSerializer.cpp
stockpiles.cpp stockpiles.cpp
) )
SET(PROJECT_PROTOS SET(PROJECT_PROTOS
@ -38,7 +38,7 @@ DEPENDS protoc-bin ${PROJECT_PROTOS}
) )
IF(WIN32) IF(WIN32)
DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite) DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite lua)
ELSE() ELSE()
DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite) DFHACK_PLUGIN(stockpiles ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite lua)
ENDIF() ENDIF()

@ -3,11 +3,21 @@
#include "Export.h" #include "Export.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "DataFuncs.h"
#include "LuaTools.h"
#include "../uicommon.h"
#include "StockpileSerializer.h" #include "StockpileSerializer.h"
#include "modules/Gui.h"
#include "modules/Filesystem.h"
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "DataDefs.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/building_stockpilest.h" #include "df/building_stockpilest.h"
#include "df/stockpile_settings.h" #include "df/stockpile_settings.h"
@ -89,6 +99,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
} }
std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui ) std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui )
<< " b_stock: " << sizeof ( building_stockpilest ) << endl; << " b_stock: " << sizeof ( building_stockpilest ) << endl;
// ViewscreenStocks::reset();
return CR_OK; return CR_OK;
} }
@ -97,6 +110,20 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event event )
{
switch ( event )
{
case SC_MAP_LOADED:
// ViewscreenStocks::reset();
break;
default:
break;
}
return CR_OK;
}
static bool copystock_guard ( df::viewscreen *top ) static bool copystock_guard ( df::viewscreen *top )
{ {
using namespace ui_sidebar_mode; using namespace ui_sidebar_mode;
@ -297,7 +324,207 @@ static command_result loadstock ( color_ostream &out, vector <string> & paramete
return CR_OK; return CR_OK;
} }
bool manage_settings ( building_stockpilest *sp )
{
// Find strings representing the job to order, and the trigger condition.
// There might be a memory leak here; C++ is odd like that.
auto L = Lua::Core::State;
color_ostream_proxy out ( Core::getInstance().getConsole() );
CoreSuspendClaimer suspend;
Lua::StackUnwinder top ( L );
if ( !lua_checkstack ( L, 2 ) )
return false;
if ( !Lua::PushModulePublic ( out, L, "plugins.stockpiles", "manage_settings" ) )
return false;
Lua::Push ( L, sp );
if ( !Lua::SafeCall ( out, L, 1, 2 ) )
return false;
return true;
}
struct stockpiles_import_hook : public df::viewscreen_dwarfmodest
{
typedef df::viewscreen_dwarfmodest interpose_base;
bool handleInput ( set<df::interface_key> *input )
{
df::building_stockpilest *sp = get_selected_stockpile();
if ( !sp )
return false;
if ( input->count ( interface_key::CUSTOM_L ) )
{
manage_settings ( sp );
return true;
}
return false;
}
DEFINE_VMETHOD_INTERPOSE ( void, feed, ( set<df::interface_key> *input ) )
{
if ( !handleInput ( input ) )
INTERPOSE_NEXT ( feed ) ( input );
}
DEFINE_VMETHOD_INTERPOSE ( void, render, () )
{
INTERPOSE_NEXT ( render ) ();
df::building_stockpilest *sp = get_selected_stockpile();
if ( !sp )
return;
auto dims = Gui::getDwarfmodeViewDims();
int left_margin = dims.menu_x1 + 1;
int x = left_margin;
int y = dims.y2 - 7;
int y2 = dims.y2 - 8;
int links = 0;
links += sp->links.give_to_pile.size();
links += sp->links.take_from_pile.size();
links += sp->links.give_to_workshop.size();
links += sp->links.take_from_workshop.size();
if ( links + 12 >= y )
{
y += 1;
y2 += 1;
}
OutputHotkeyString ( x, y, "Load/Save Settings", "l", true, left_margin, COLOR_WHITE, COLOR_LIGHTRED );
}
};
IMPLEMENT_VMETHOD_INTERPOSE ( stockpiles_import_hook, feed );
IMPLEMENT_VMETHOD_INTERPOSE ( stockpiles_import_hook, render );
DFHACK_PLUGIN_IS_ENABLED ( is_enabled );
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable )
{
if ( !gps )
return CR_FAILURE;
if ( enable != is_enabled )
{
if (
!INTERPOSE_HOOK ( stockpiles_import_hook, feed ).apply ( enable ) ||
!INTERPOSE_HOOK ( stockpiles_import_hook, render ).apply ( enable )
)
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
static std::vector<std::string> list_dir ( const std::string &path, bool recursive = false )
{
color_ostream_proxy out ( Core::getInstance().getConsole() );
std::vector<std::string> files;
std::stack<std::string> dirs;
dirs.push(path);
out << "list_dir start" << endl;
while (!dirs.empty() ) {
const std::string current = dirs.top();
out << "\t walking " << current << endl;
dirs.pop();
std::vector<std::string> entries;
const int res = DFHack::getdir(current, entries);
if ( res != 0 )
continue;
for ( std::vector<std::string>::iterator it = entries.begin() ; it != entries.end(); ++it )
{
if ( (*it).empty() || (*it)[0] == '.' ) continue;
// shitty cross platform c++ we've got to construct the actual path manually
std::ostringstream child_path_s;
child_path_s << current << "/" << *it;
const std::string child = child_path_s.str();
if ( recursive && Filesystem::isdir ( child ) )
{
out << "\t\tgot child dir: " << child << endl;
dirs.push ( child );
}
else if ( Filesystem::isfile ( child ) )
{
const std::string rel_path ( child.substr ( std::string ( "./"+path).length()-1 ) );
out << "\t\t adding file: " << child << " as " << rel_path << endl;
files.push_back ( rel_path );
}
}
}
out << "listdir_stop" << endl;
return files;
}
static std::vector<std::string> clean_dfstock_list ( const std::string &path )
{
std::vector<std::string> files ( list_dir ( path, true) );
files.erase ( std::remove_if ( files.begin(), files.end(), [] ( const std::string &f )
{
return !is_dfstockfile ( f );
} ), files.end() );
std::transform ( files.begin(), files.end(), files.begin(), [] ( const std::string &f )
{
return f.substr ( 0, f.find_last_of ( "." ) );
} );
return files;
}
static int stockpiles_list_settings ( lua_State *L )
{
auto path = luaL_checkstring ( L, 1 );
color_ostream &out = *Lua::GetOutput ( L );
if ( !Filesystem::isdir(path) )
{
lua_pushfstring ( L, "invalid directory: %s", path );
lua_error ( L );
return 0;
}
std::vector<std::string> files = clean_dfstock_list ( path );
Lua::PushVector ( L, files, true );
return 1;
}
static void stockpiles_load ( color_ostream &out, std::string filename )
{
out << "stockpiles_load " << filename << " ";
std::vector<std::string> params;
params.push_back ( filename );
command_result r = loadstock ( out, params );
out << " result = "<< r << endl;
}
static void stockpiles_save ( color_ostream &out, std::string filename )
{
out << "stockpiles_save " << filename << " ";
std::vector<std::string> params;
params.push_back ( filename );
command_result r = savestock ( out, params );
out << " result = "<< r << endl;
}
DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION(stockpiles_load),
DFHACK_LUA_FUNCTION(stockpiles_save),
DFHACK_LUA_END
};
DFHACK_PLUGIN_LUA_COMMANDS
{
DFHACK_LUA_COMMAND ( stockpiles_list_settings ),
DFHACK_LUA_END
};