diff options
| author | Alexander Gavrilov | 2012-09-05 19:45:45 +0400 |
|---|---|---|
| committer | Alexander Gavrilov | 2012-09-05 19:45:45 +0400 |
| commit | 57086ac56eb489abd0c7759aed084020edc71148 (patch) | |
| tree | 06b3e64f5f9114ae762ca1d2a99d08382a63ce23 | |
| parent | 27f169e298e658f3957aa2db1f76fe8aa20caef7 (diff) | |
| download | dfhack-57086ac56eb489abd0c7759aed084020edc71148.tar.gz dfhack-57086ac56eb489abd0c7759aed084020edc71148.tar.bz2 dfhack-57086ac56eb489abd0c7759aed084020edc71148.tar.xz | |
Add stock MessageBox and InputBox dialog screens for lua scripts.
| -rw-r--r-- | LUA_API.rst | 8 | ||||
| -rw-r--r-- | Lua API.html | 6 | ||||
| -rw-r--r-- | library/LuaApi.cpp | 2 | ||||
| -rw-r--r-- | library/LuaTools.cpp | 3 | ||||
| -rw-r--r-- | library/Process-darwin.cpp | 8 | ||||
| -rw-r--r-- | library/Process-linux.cpp | 8 | ||||
| -rw-r--r-- | library/Process-windows.cpp | 5 | ||||
| -rw-r--r-- | library/include/MemAccess.h | 3 | ||||
| -rw-r--r-- | library/lua/gui.lua | 12 | ||||
| -rw-r--r-- | library/lua/gui/dialogs.lua | 175 | ||||
| -rw-r--r-- | library/lua/utils.lua | 13 |
11 files changed, 241 insertions, 2 deletions
diff --git a/LUA_API.rst b/LUA_API.rst index 22130efd..799f623e 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -553,6 +553,10 @@ Exception handling Miscellaneous ------------- +* ``dfhack.VERSION`` + + DFHack version string constant. + * ``dfhack.curry(func,args...)``, or ``curry(func,args...)`` Returns a closure that invokes the function with args combined @@ -719,6 +723,10 @@ can be omitted. Returns the dfhack directory path, i.e. ``".../df/hack/"``. +* ``dfhack.getTickCount()`` + + Returns the tick count in ms, exactly as DF ui uses. + * ``dfhack.isWorldLoaded()`` Checks if the world is loaded. diff --git a/Lua API.html b/Lua API.html index f6f2d42b..f05ee551 100644 --- a/Lua API.html +++ b/Lua API.html @@ -846,6 +846,9 @@ following properties:</p> <div class="section" id="miscellaneous"> <h3><a class="toc-backref" href="#id14">Miscellaneous</a></h3> <ul> +<li><p class="first"><tt class="docutils literal">dfhack.VERSION</tt></p> +<p>DFHack version string constant.</p> +</li> <li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.curry(func,args...)</span></tt>, or <tt class="docutils literal"><span class="pre">curry(func,args...)</span></tt></p> <p>Returns a closure that invokes the function with args combined both from the curry call and the closure call itself. I.e. @@ -985,6 +988,9 @@ can be omitted.</p> <li><p class="first"><tt class="docutils literal">dfhack.getHackPath()</tt></p> <p>Returns the dfhack directory path, i.e. <tt class="docutils literal"><span class="pre">".../df/hack/"</span></tt>.</p> </li> +<li><p class="first"><tt class="docutils literal">dfhack.getTickCount()</tt></p> +<p>Returns the tick count in ms, exactly as DF ui uses.</p> +</li> <li><p class="first"><tt class="docutils literal">dfhack.isWorldLoaded()</tt></p> <p>Checks if the world is loaded.</p> </li> diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 4e57b113..1dcb001f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -728,6 +728,7 @@ static std::string getOSType() } static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } +static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } static std::string getDFPath() { return Core::getInstance().p->getPath(); } static std::string getHackPath() { return Core::getInstance().getHackPath(); } @@ -739,6 +740,7 @@ static const LuaWrapper::FunctionReg dfhack_module[] = { WRAP(getOSType), WRAP(getDFVersion), WRAP(getDFPath), + WRAP(getTickCount), WRAP(getHackPath), WRAP(isWorldLoaded), WRAP(isMapLoaded), diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 9f047753..a283d215 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -1580,6 +1580,9 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state) lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_BASE_G_TOKEN); lua_setfield(state, -2, "BASE_G"); + lua_pushstring(state, DFHACK_VERSION); + lua_setfield(state, -2, "VERSION"); + lua_pushboolean(state, IsCoreContext(state)); lua_setfield(state, -2, "is_core_context"); diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index 5a97d9e0..3893cfc5 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -27,6 +27,7 @@ distribution. #include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/time.h> #include <mach-o/dyld.h> @@ -262,6 +263,13 @@ bool Process::getThreadIDs(vector<uint32_t> & threads ) return true; } +uint32_t Process::getTickCount() +{ + struct timeval tp; + gettimeofday(&tp, NULL); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); +} + string Process::getPath() { char path[1024]; diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index fe864784..4a66470f 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -27,6 +27,7 @@ distribution. #include <errno.h> #include <unistd.h> #include <sys/mman.h> +#include <sys/time.h> #include <string> #include <vector> @@ -192,6 +193,13 @@ bool Process::getThreadIDs(vector<uint32_t> & threads ) return true; } +uint32_t Process::getTickCount() +{ + struct timeval tp; + gettimeofday(&tp, NULL); + return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); +} + string Process::getPath() { const char * cwd_name = "/proc/self/cwd"; diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index 7eb6ff5f..db58c4d3 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -410,6 +410,11 @@ string Process::doReadClassName (void * vptr) return raw; } +uint32_t Process::getTickCount() +{ + return GetTickCount(); +} + string Process::getPath() { HMODULE hmod; diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h index 0e5f618e..a226018a 100644 --- a/library/include/MemAccess.h +++ b/library/include/MemAccess.h @@ -281,6 +281,9 @@ namespace DFHack /// get the DF Process FilePath std::string getPath(); + /// millisecond tick count, exactly as DF uses + uint32_t getTickCount(); + /// modify permisions of memory range bool setPermisions(const t_memrange & range,const t_memrange &trgrange); diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 9e189ea1..23904c14 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -94,6 +94,9 @@ function Painter:isValidPos() end function Painter:viewport(x,y,w,h) + if type(x) == 'table' then + x,y,w,h = x.x1, x.y1, x.width, x.height + end local x1,y1 = self.x1+x, self.y1+y local x2,y2 = x1+w-1, y1+h-1 local vp = { @@ -353,11 +356,16 @@ local function hint_coord(gap,hint) end end +function FramedScreen:getWantedFrameSize() + return self.frame_width, self.frame_height +end + function FramedScreen:updateFrameSize() local sw, sh = dscreen.getWindowSize() local iw, ih = sw-2, sh-2 - local width = math.min(self.frame_width or iw, iw) - local height = math.min(self.frame_height or ih, ih) + local fw, fh = self:getWantedFrameSize() + local width = math.min(fw or iw, iw) + local height = math.min(fh or ih, ih) local gw, gh = iw-width, ih-height local x1, y1 = hint_coord(gw,self.frame_xhint), hint_coord(gh,self.frame_yhint) self.frame_rect = mkdims_wh(x1+1,y1+1,width,height) diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua new file mode 100644 index 00000000..e6d30c97 --- /dev/null +++ b/library/lua/gui/dialogs.lua @@ -0,0 +1,175 @@ +-- Some simple dialog screens + +local _ENV = mkmodule('gui.dialogs') + +local gui = require('gui') +local utils = require('utils') + +local dscreen = dfhack.screen + +MessageBox = defclass(MessageBox, gui.FramedScreen) + +MessageBox.frame_style = gui.GREY_LINE_FRAME + +function MessageBox:init(info) + info = info or {} + self:init_fields{ + text = info.text or {}, + frame_title = info.title, + frame_width = info.frame_width, + on_accept = info.on_accept, + on_cancel = info.on_cancel, + on_close = info.on_close, + text_pen = info.text_pen + } + if type(self.text) == 'string' then + self.text = utils.split_string(self.text, "\n") + end + gui.FramedScreen.init(self, info) + return self +end + +function MessageBox:getWantedFrameSize() + local text = self.text + local w = #(self.frame_title or '') + 2 + w = math.max(w, 20) + w = math.max(self.frame_width or w, w) + for _, l in ipairs(text) do + w = math.max(w, #l) + end + local h = #text+1 + if h > 1 then + h = h+1 + end + return w, #text+2 +end + +function MessageBox:onRenderBody(dc) + if #self.text > 0 then + dc:newline(1):pen(self.text_pen or COLOR_GREY) + for _, l in ipairs(self.text or {}) do + dc:string(l):newline(1) + end + end + + if self.on_accept then + local x,y = self.frame_rect.x1+1, self.frame_rect.y2+1 + dscreen.paintString({fg=COLOR_LIGHTGREEN},x,y,'ESC') + dscreen.paintString({fg=COLOR_GREY},x+3,y,'/') + dscreen.paintString({fg=COLOR_LIGHTGREEN},x+4,y,'y') + end +end + +function MessageBox:onDestroy() + if self.on_close then + self.on_close() + end +end + +function MessageBox:onInput(keys) + if keys.MENU_CONFIRM then + self:dismiss() + if self.on_accept then + self.on_accept() + end + elseif keys.LEAVESCREEN or (keys.SELECT and not self.on_accept) then + self:dismiss() + if self.on_cancel then + self.on_cancel() + end + end +end + +function showMessage(title, text, tcolor, on_close) + mkinstance(MessageBox):init{ + text = text, + title = title, + text = text, + text_pen = tcolor, + on_close = on_close + }:show() +end + +function showYesNoPrompt(title, text, tcolor, on_accept, on_cancel) + mkinstance(MessageBox):init{ + title = title, + text = text, + text_pen = tcolor, + on_accept = on_accept, + on_cancel = on_cancel, + }:show() +end + +InputBox = defclass(InputBox, MessageBox) + +function InputBox:init(info) + info = info or {} + self:init_fields{ + input = info.input or '', + input_pen = info.input_pen, + on_input = info.on_input, + } + MessageBox.init(self, info) + self.on_accept = nil + return self +end + +function InputBox:getWantedFrameSize() + local mw, mh = MessageBox.getWantedFrameSize(self) + return mw, mh+2 +end + +function InputBox:onRenderBody(dc) + MessageBox.onRenderBody(self, dc) + + dc:newline(1) + dc:pen(self.input_pen or COLOR_LIGHTCYAN) + dc:fill(dc.x1+1,dc.y,dc.x2-1,dc.y) + + local cursor = '_' + if math.floor(dfhack.getTickCount()/500) % 2 == 0 then + cursor = ' ' + end + local txt = self.input .. cursor + if #txt > dc.width-2 then + txt = string.sub(txt, #txt-dc.width+3) + -- Add prefix arrow + dc:advance(-1):char(27) + end + dc:string(txt) +end + +function InputBox:onInput(keys) + if keys.SELECT then + self:dismiss() + if self.on_input then + self.on_input(self.input) + end + elseif keys.LEAVESCREEN then + self:dismiss() + if self.on_cancel then + self.on_cancel() + end + elseif keys._STRING then + if keys._STRING == 0 then + self.input = string.sub(self.input, 1, #self.input-1) + else + self.input = self.input .. string.char(keys._STRING) + end + end +end + +function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) + mkinstance(InputBox):init{ + title = title, + text = text, + text_pen = tcolor, + input = input, + on_input = on_input, + on_cancel = on_cancel, + frame_width = min_width, + }:show() +end + + +return _ENV diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 19a4e6f6..9fa473ed 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -381,6 +381,19 @@ function getBuildingCenter(building) return xyz2pos(building.centerx, building.centery, building.z) end +function split_string(self, delimiter) + local result = { } + local from = 1 + local delim_from, delim_to = string.find( self, delimiter, from ) + while delim_from do + table.insert( result, string.sub( self, from , delim_from-1 ) ) + from = delim_to + 1 + delim_from, delim_to = string.find( self, delimiter, from ) + end + table.insert( result, string.sub( self, from ) ) + return result +end + -- Ask a yes-no question function prompt_yes_no(msg,default) local prompt = msg |
