From 767c1b9368243a152e4aa10eaf1eb71753e79c45 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 19 Nov 2012 18:11:26 +0400 Subject: [PATCH] Duplicate the lua Painter class in C++. --- library/include/Types.h | 22 ++++++ library/include/modules/Gui.h | 5 ++ library/include/modules/Screen.h | 128 +++++++++++++++++++++++++++++++ library/modules/Screen.cpp | 15 ++++ 4 files changed, 170 insertions(+) diff --git a/library/include/Types.h b/library/include/Types.h index 98dbb7e74..5412b443b 100644 --- a/library/include/Types.h +++ b/library/include/Types.h @@ -74,6 +74,28 @@ namespace DFHack uint32_t xpNxtLvl; }; + typedef std::pair rect2d; + + inline rect2d intersect(rect2d a, rect2d b) { + df::coord2d g1 = a.first, g2 = a.second; + df::coord2d c1 = b.first, c2 = b.second; + df::coord2d rc1 = df::coord2d(std::max(g1.x, c1.x), std::max(g1.y, c1.y)); + df::coord2d rc2 = df::coord2d(std::min(g2.x, c2.x), std::min(g2.y, c2.y)); + return rect2d(rc1, rc2); + } + + inline rect2d mkrect_xy(int x1, int y1, int x2, int y2) { + return rect2d(df::coord2d(x1, y1), df::coord2d(x2, y2)); + } + + inline rect2d mkrect_wh(int x, int y, int w, int h) { + return rect2d(df::coord2d(x, y), df::coord2d(x+w-1, y+h-1)); + } + + inline df::coord2d rect_size(const rect2d &rect) { + return rect.second - rect.first + df::coord2d(1,1); + } + DFHACK_EXPORT int getdir(std::string dir, std::vector &files); DFHACK_EXPORT bool hasEnding (std::string const &fullString, std::string const &ending); diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 147f27883..794cb89ff 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -29,6 +29,8 @@ distribution. #include "ColorText.h" #include +#include "Types.h" + #include "DataDefs.h" #include "df/init.h" #include "df/ui.h" @@ -116,6 +118,9 @@ namespace DFHack int map_x1, map_x2, menu_x1, menu_x2, area_x1, area_x2; int y1, y2; bool menu_on, area_on, menu_forced; + + rect2d map() { return mkrect_xy(map_x1, y1, map_x2, y2); } + rect2d menu() { return mkrect_xy(menu_x1, y1, menu_x2, y2); } }; DFHACK_EXPORT DwarfmodeDims getDwarfmodeViewDims(); diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index d8b5774e9..f0b649810 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -27,6 +27,7 @@ distribution. #include "Module.h" #include "BitArray.h" #include "ColorText.h" +#include "Types.h" #include #include "DataDefs.h" @@ -94,11 +95,67 @@ namespace DFHack : ch(ch), fg(fg), bg(bg), bold(bold), tile(tile), tile_mode(TileColor), tile_fg(tile_fg), tile_bg(tile_bg) {} + + void adjust(int8_t nfg) { fg = nfg&7; bold = !!(nfg&8); } + void adjust(int8_t nfg, bool nbold) { fg = nfg; bold = nbold; } + void adjust(int8_t nfg, int8_t nbg) { adjust(nfg); bg = nbg; } + void adjust(int8_t nfg, bool nbold, int8_t nbg) { adjust(nfg, nbold); bg = nbg; } + + Pen color(int8_t nfg) const { Pen cp(*this); cp.adjust(nfg); return cp; } + Pen color(int8_t nfg, bool nbold) const { Pen cp(*this); cp.adjust(nfg, nbold); return cp; } + Pen color(int8_t nfg, int8_t nbg) const { Pen cp(*this); cp.adjust(nfg, nbg); return cp; } + Pen color(int8_t nfg, bool nbold, int8_t nbg) const { Pen cp(*this); cp.adjust(nfg, nbold, nbg); return cp; } + + Pen chtile(char ch) { Pen cp(*this); cp.ch = ch; return cp; } + Pen chtile(char ch, int tile) { Pen cp(*this); cp.ch = ch; cp.tile = tile; return cp; } + }; + + struct ViewRect { + rect2d view, clip; + + ViewRect(rect2d area) : view(area), clip(area) {} + ViewRect(rect2d area, rect2d clip) : view(area), clip(clip) {} + + bool isDefunct() const { + return clip.first.x > clip.second.x || clip.first.y > clip.second.y; + } + int width() const { return view.second.x-view.first.x+1; } + int height() const { return view.second.y-view.first.y+1; } + df::coord2d local(df::coord2d pos) const { + return df::coord2d(pos.x - view.first.x, pos.y - view.first.y); + } + df::coord2d global(df::coord2d pos) const { + return df::coord2d(pos.x + view.first.x, pos.y + view.first.y); + } + df::coord2d global(int x, int y) const { + return df::coord2d(x + view.first.x, y + view.first.y); + } + bool inClipGlobal(int x, int y) const { + return x >= clip.first.x && x <= clip.second.x && + y >= clip.first.y && y <= clip.second.y; + } + bool inClipGlobal(df::coord2d pos) const { + return inClipGlobal(pos.x, pos.y); + } + bool inClipLocal(int x, int y) const { + return inClipGlobal(x + view.first.x, y + view.first.y); + } + bool inClipLocal(df::coord2d pos) const { + return inClipLocal(pos.x, pos.y); + } + ViewRect viewport(rect2d area) const { + rect2d nview(global(area.first), global(area.second)); + return ViewRect(nview, intersect(nview, clip)); + } }; DFHACK_EXPORT df::coord2d getMousePos(); DFHACK_EXPORT df::coord2d getWindowSize(); + inline rect2d getScreenRect() { + return rect2d(df::coord2d(0,0), getWindowSize()-df::coord2d(1,1)); + } + /// Returns the state of [GRAPHICS:YES/NO] DFHACK_EXPORT bool inGraphicsMode(); @@ -133,6 +190,77 @@ namespace DFHack /// Retrieve the string representation of the bound key. DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key); + + /// A painter class that implements a clipping area and cursor/pen state + struct DFHACK_EXPORT Painter : ViewRect { + df::coord2d gcursor; + Pen cur_pen, cur_key_pen; + + static const Pen default_pen; + static const Pen default_key_pen; + + Painter(const ViewRect &area, const Pen &pen = default_pen, const Pen &kpen = default_key_pen) + : ViewRect(area), gcursor(area.view.first), cur_pen(pen), cur_key_pen(kpen) + {} + + df::coord2d cursor() const { return local(gcursor); } + int cursorX() const { return gcursor.x - view.first.x; } + int cursorY() const { return gcursor.y - view.first.y; } + + bool isValidPos() const { return inClipGlobal(gcursor); } + + Painter viewport(rect2d area) const { + return Painter(ViewRect::viewport(area), cur_pen, cur_key_pen); + } + + Painter &seek(df::coord2d pos) { gcursor = global(pos); return *this; } + Painter &seek(int x, int y) { gcursor = global(x,y); return *this; } + Painter &advance(int dx) { gcursor.x += dx; return *this; } + Painter &advance(int dx, int dy) { gcursor.x += dx; gcursor.y += dy; return *this; } + Painter &newline(int dx = 0) { gcursor.y++; gcursor.x = view.first.x + dx; return *this; } + + const Pen &pen() const { return cur_pen; } + Painter &pen(const Pen &np) { cur_pen = np; return *this; } + Painter &pen(int8_t fg) { cur_pen.adjust(fg); return *this; } + + const Pen &key_pen() const { return cur_key_pen; } + Painter &key_pen(const Pen &np) { cur_key_pen = np; return *this; } + Painter &key_pen(int8_t fg) { cur_key_pen.adjust(fg); return *this; } + + Painter &clear() { + fillRect(Pen(' ',0,0,false), clip.first.x, clip.first.y, clip.second.x, clip.second.y); + return *this; + } + + Painter &fill(const rect2d &area, const Pen &pen) { + rect2d irect = intersect(area, clip); + fillRect(pen, irect.first.x, irect.first.y, irect.second.x, irect.second.y); + return *this; + } + Painter &fill(const rect2d &area) { return fill(area, cur_pen); } + + Painter &tile(const Pen &pen) { + if (isValidPos()) paintTile(pen, gcursor.x, gcursor.y); + return advance(1); + } + Painter &tile() { return tile(cur_pen); } + Painter &tile(char ch) { return tile(cur_pen.chtile(ch)); } + Painter &tile(char ch, int tileid) { return tile(cur_pen.chtile(ch, tileid)); } + + Painter &string(const std::string &str, const Pen &pen) { + do_paint_string(str, pen); return advance(str.size()); + } + Painter &string(const std::string &str) { return string(str, cur_pen); } + Painter &string(const std::string &str, int8_t fg) { return string(str, cur_pen.color(fg)); } + + Painter &key(df::interface_key kc, const Pen &pen) { + return string(getKeyDisplay(kc), pen); + } + Painter &key(df::interface_key kc) { return key(kc, cur_key_pen); } + + private: + void do_paint_string(const std::string &str, const Pen &pen); + }; } class DFHACK_EXPORT dfhack_viewscreen : public df::viewscreen { diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index e8d23261b..f2d1f2d5d 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -234,6 +234,21 @@ bool Screen::invalidate() return true; } +const Pen Screen::Painter::default_pen(0,COLOR_GREY,0); +const Pen Screen::Painter::default_key_pen(0,COLOR_LIGHTGREEN,0); + +void Screen::Painter::do_paint_string(const std::string &str, const Pen &pen) +{ + if (gcursor.y < clip.first.y || gcursor.y > clip.second.y) + return; + + int dx = std::max(0, int(clip.first.x - gcursor.x)); + int len = std::min((int)str.size(), int(clip.second.x - gcursor.x + 1)); + + if (len > dx) + paintString(pen, gcursor.x + dx, gcursor.y, str.substr(dx, len-dx)); +} + bool Screen::findGraphicsTile(const std::string &pagename, int x, int y, int *ptile, int *pgs) { if (!gps || !texture || x < 0 || y < 0) return false;