|
|
|
@ -21,6 +21,10 @@
|
|
|
|
|
#include "TileTypes.h"
|
|
|
|
|
#include "DataFuncs.h"
|
|
|
|
|
|
|
|
|
|
// For SDL_GetKeyState
|
|
|
|
|
#include "Hooks.h"
|
|
|
|
|
#include "SDL_keyboard.h"
|
|
|
|
|
|
|
|
|
|
DFHACK_PLUGIN("mousequery");
|
|
|
|
|
REQUIRE_GLOBAL(enabler);
|
|
|
|
|
REQUIRE_GLOBAL(gps);
|
|
|
|
@ -48,6 +52,9 @@ static bool mouse_moved = false;
|
|
|
|
|
|
|
|
|
|
static uint32_t scroll_delay = 100;
|
|
|
|
|
|
|
|
|
|
static bool awaiting_lbut_up, awaiting_rbut_up;
|
|
|
|
|
static enum { None, Left, Right } drag_mode;
|
|
|
|
|
|
|
|
|
|
static df::coord get_mouse_pos(int32_t &mx, int32_t &my)
|
|
|
|
|
{
|
|
|
|
|
df::coord pos;
|
|
|
|
@ -293,156 +300,190 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleMouse(const set<df::interface_key> *input)
|
|
|
|
|
bool handleLeft(df::coord &mpos, int32_t mx, int32_t my)
|
|
|
|
|
{
|
|
|
|
|
int32_t mx, my;
|
|
|
|
|
auto mpos = get_mouse_pos(mx, my);
|
|
|
|
|
if (mpos.x == -30000)
|
|
|
|
|
return false;
|
|
|
|
|
static unsigned char *keystate = 0;
|
|
|
|
|
if (!keystate)
|
|
|
|
|
keystate = SDL_GetKeyState(NULL);
|
|
|
|
|
|
|
|
|
|
auto dims = Gui::getDwarfmodeViewDims();
|
|
|
|
|
if (enabler->mouse_lbut)
|
|
|
|
|
{
|
|
|
|
|
bool cursor_still_here = (last_clicked_x == mpos.x && last_clicked_y == mpos.y && last_clicked_z == mpos.z);
|
|
|
|
|
last_clicked_x = mpos.x;
|
|
|
|
|
last_clicked_y = mpos.y;
|
|
|
|
|
last_clicked_z = mpos.z;
|
|
|
|
|
if (!(keystate[SDL::Key::K_LSHIFT] || keystate[SDL::Key::K_RSHIFT]))
|
|
|
|
|
mpos.z += Gui::getDepthAt(mx, my);
|
|
|
|
|
|
|
|
|
|
df::interface_key key = interface_key::NONE;
|
|
|
|
|
bool designationMode = false;
|
|
|
|
|
bool skipRefresh = false;
|
|
|
|
|
bool cursor_still_here = (last_clicked_x == mpos.x && last_clicked_y == mpos.y && last_clicked_z == mpos.z);
|
|
|
|
|
last_clicked_x = mpos.x;
|
|
|
|
|
last_clicked_y = mpos.y;
|
|
|
|
|
last_clicked_z = mpos.z;
|
|
|
|
|
|
|
|
|
|
if (isInTrackableMode())
|
|
|
|
|
{
|
|
|
|
|
designationMode = true;
|
|
|
|
|
key = df::interface_key::SELECT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
df::interface_key key = interface_key::NONE;
|
|
|
|
|
bool designationMode = false;
|
|
|
|
|
bool skipRefresh = false;
|
|
|
|
|
|
|
|
|
|
if (isInTrackableMode())
|
|
|
|
|
{
|
|
|
|
|
designationMode = true;
|
|
|
|
|
key = df::interface_key::SELECT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (ui->main.mode)
|
|
|
|
|
{
|
|
|
|
|
switch (ui->main.mode)
|
|
|
|
|
case QueryBuilding:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_BUILDITEM;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BuildingItems:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_VIEWUNIT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ViewUnits:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_LOOK;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LookAround:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_BUILDJOB;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Build:
|
|
|
|
|
if (ui_build_selector)
|
|
|
|
|
{
|
|
|
|
|
case QueryBuilding:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_BUILDITEM;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BuildingItems:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_VIEWUNIT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ViewUnits:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_LOOK;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LookAround:
|
|
|
|
|
if (cursor_still_here)
|
|
|
|
|
key = df::interface_key::D_BUILDJOB;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Build:
|
|
|
|
|
if (ui_build_selector)
|
|
|
|
|
if (ui_build_selector->stage < 2)
|
|
|
|
|
{
|
|
|
|
|
designationMode = true;
|
|
|
|
|
key = df::interface_key::SELECT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (ui_build_selector->stage < 2)
|
|
|
|
|
{
|
|
|
|
|
designationMode = true;
|
|
|
|
|
key = df::interface_key::SELECT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
designationMode = true;
|
|
|
|
|
skipRefresh = true;
|
|
|
|
|
key = df::interface_key::SELECT_ALL;
|
|
|
|
|
}
|
|
|
|
|
designationMode = true;
|
|
|
|
|
skipRefresh = true;
|
|
|
|
|
key = df::interface_key::SELECT_ALL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Default:
|
|
|
|
|
break;
|
|
|
|
|
case Default:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enabler->mouse_lbut = 0;
|
|
|
|
|
enabler->mouse_lbut = 0;
|
|
|
|
|
|
|
|
|
|
// Can't check limits earlier as we must be sure we are in query or default mode
|
|
|
|
|
// (so we can clear the button down flag)
|
|
|
|
|
int right_bound = (dims.menu_x1 > 0) ? dims.menu_x1 - 2 : gps->dimx - 2;
|
|
|
|
|
if (mx < 1 || mx > right_bound || my < 1 || my > gps->dimy - 2)
|
|
|
|
|
return false;
|
|
|
|
|
// Can't check limits earlier as we must be sure we are in query or default mode
|
|
|
|
|
// (so we can clear the button down flag)
|
|
|
|
|
auto dims = Gui::getDwarfmodeViewDims();
|
|
|
|
|
int right_bound = (dims.menu_x1 > 0) ? dims.menu_x1 - 2 : gps->dimx - 2;
|
|
|
|
|
if (mx < 1 || mx > right_bound || my < 1 || my > gps->dimy - 2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
|
|
|
|
|
ui->main.mode == df::ui_sidebar_mode::Stockpiles)
|
|
|
|
|
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
|
|
|
|
|
ui->main.mode == df::ui_sidebar_mode::Stockpiles)
|
|
|
|
|
{
|
|
|
|
|
int32_t x, y, z;
|
|
|
|
|
if (Gui::getDesignationCoords(x, y, z))
|
|
|
|
|
{
|
|
|
|
|
int32_t x, y, z;
|
|
|
|
|
if (Gui::getDesignationCoords(x, y, z))
|
|
|
|
|
{
|
|
|
|
|
auto dX = abs(x - mpos.x);
|
|
|
|
|
if (dX > 30)
|
|
|
|
|
return false;
|
|
|
|
|
auto dX = abs(x - mpos.x);
|
|
|
|
|
if (dX > 30)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
auto dY = abs(y - mpos.y);
|
|
|
|
|
if (dY > 30)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
auto dY = abs(y - mpos.y);
|
|
|
|
|
if (dY > 30)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!designationMode)
|
|
|
|
|
{
|
|
|
|
|
Gui::resetDwarfmodeView();
|
|
|
|
|
if (!designationMode)
|
|
|
|
|
{
|
|
|
|
|
Gui::resetDwarfmodeView();
|
|
|
|
|
|
|
|
|
|
if (key == interface_key::NONE)
|
|
|
|
|
key = get_default_query_mode(mpos);
|
|
|
|
|
if (key == interface_key::NONE)
|
|
|
|
|
key = get_default_query_mode(mpos);
|
|
|
|
|
|
|
|
|
|
sendKey(key);
|
|
|
|
|
}
|
|
|
|
|
sendKey(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skipRefresh)
|
|
|
|
|
{
|
|
|
|
|
// Force UI refresh
|
|
|
|
|
moveCursor(mpos, true);
|
|
|
|
|
}
|
|
|
|
|
if (!skipRefresh)
|
|
|
|
|
{
|
|
|
|
|
// Force UI refresh
|
|
|
|
|
moveCursor(mpos, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (designationMode)
|
|
|
|
|
sendKey(key);
|
|
|
|
|
if (designationMode)
|
|
|
|
|
sendKey(key);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleRight(df::coord &mpos, int32_t mx, int32_t my)
|
|
|
|
|
{
|
|
|
|
|
if (isInDesignationMenu() && !box_designation_enabled)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Escape out of query mode
|
|
|
|
|
enabler->mouse_rbut_down = 0;
|
|
|
|
|
enabler->mouse_rbut = 0;
|
|
|
|
|
|
|
|
|
|
using namespace df::enums::ui_sidebar_mode;
|
|
|
|
|
if ((ui->main.mode == QueryBuilding || ui->main.mode == BuildingItems ||
|
|
|
|
|
ui->main.mode == ViewUnits || ui->main.mode == LookAround) ||
|
|
|
|
|
(isInTrackableMode() && tracking_enabled))
|
|
|
|
|
{
|
|
|
|
|
sendKey(df::interface_key::LEAVESCREEN);
|
|
|
|
|
}
|
|
|
|
|
else if (rbutton_enabled && enabler->mouse_rbut)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (isInDesignationMenu() && !box_designation_enabled)
|
|
|
|
|
return false;
|
|
|
|
|
auto dims = Gui::getDwarfmodeViewDims();
|
|
|
|
|
int scroll_trigger_x = dims.menu_x1 / 3;
|
|
|
|
|
int scroll_trigger_y = gps->dimy / 3;
|
|
|
|
|
if (mx < scroll_trigger_x)
|
|
|
|
|
sendKey(interface_key::CURSOR_LEFT_FAST);
|
|
|
|
|
|
|
|
|
|
if (mx > ((dims.menu_x1 > 0) ? dims.menu_x1 : gps->dimx) - scroll_trigger_x)
|
|
|
|
|
sendKey(interface_key::CURSOR_RIGHT_FAST);
|
|
|
|
|
|
|
|
|
|
// Escape out of query mode
|
|
|
|
|
enabler->mouse_rbut_down = 0;
|
|
|
|
|
enabler->mouse_rbut = 0;
|
|
|
|
|
if (my < scroll_trigger_y)
|
|
|
|
|
sendKey(interface_key::CURSOR_UP_FAST);
|
|
|
|
|
|
|
|
|
|
using namespace df::enums::ui_sidebar_mode;
|
|
|
|
|
if ((ui->main.mode == QueryBuilding || ui->main.mode == BuildingItems ||
|
|
|
|
|
ui->main.mode == ViewUnits || ui->main.mode == LookAround) ||
|
|
|
|
|
(isInTrackableMode() && tracking_enabled))
|
|
|
|
|
if (my > gps->dimy - scroll_trigger_y)
|
|
|
|
|
sendKey(interface_key::CURSOR_DOWN_FAST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleMouse(const set<df::interface_key> *input)
|
|
|
|
|
{
|
|
|
|
|
int32_t mx, my;
|
|
|
|
|
auto mpos = get_mouse_pos(mx, my);
|
|
|
|
|
if (mpos.x == -30000)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (enabler->mouse_lbut)
|
|
|
|
|
{
|
|
|
|
|
if (drag_mode == Left)
|
|
|
|
|
{
|
|
|
|
|
sendKey(df::interface_key::LEAVESCREEN);
|
|
|
|
|
awaiting_lbut_up = true;
|
|
|
|
|
enabler->mouse_lbut = false;
|
|
|
|
|
last_move_pos = mpos;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return handleLeft(mpos, mx, my);
|
|
|
|
|
}
|
|
|
|
|
else if (enabler->mouse_rbut)
|
|
|
|
|
{
|
|
|
|
|
if (drag_mode == Right)
|
|
|
|
|
{
|
|
|
|
|
int scroll_trigger_x = dims.menu_x1 / 3;
|
|
|
|
|
int scroll_trigger_y = gps->dimy / 3;
|
|
|
|
|
if (mx < scroll_trigger_x)
|
|
|
|
|
sendKey(interface_key::CURSOR_LEFT_FAST);
|
|
|
|
|
|
|
|
|
|
if (mx > ((dims.menu_x1 > 0) ? dims.menu_x1 : gps->dimx) - scroll_trigger_x)
|
|
|
|
|
sendKey(interface_key::CURSOR_RIGHT_FAST);
|
|
|
|
|
|
|
|
|
|
if (my < scroll_trigger_y)
|
|
|
|
|
sendKey(interface_key::CURSOR_UP_FAST);
|
|
|
|
|
|
|
|
|
|
if (my > gps->dimy - scroll_trigger_y)
|
|
|
|
|
sendKey(interface_key::CURSOR_DOWN_FAST);
|
|
|
|
|
awaiting_rbut_up = true;
|
|
|
|
|
enabler->mouse_rbut = false;
|
|
|
|
|
last_move_pos = mpos;
|
|
|
|
|
}
|
|
|
|
|
else if (rbutton_enabled)
|
|
|
|
|
return handleRight(mpos, mx, my);
|
|
|
|
|
}
|
|
|
|
|
else if (input->count(interface_key::CUSTOM_ALT_M) && isInDesignationMenu())
|
|
|
|
|
{
|
|
|
|
@ -554,10 +595,39 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (awaiting_lbut_up && !enabler->mouse_lbut_down)
|
|
|
|
|
{
|
|
|
|
|
awaiting_lbut_up = false;
|
|
|
|
|
handleLeft(mpos, mx, my);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (awaiting_rbut_up && !enabler->mouse_rbut_down)
|
|
|
|
|
{
|
|
|
|
|
awaiting_rbut_up = false;
|
|
|
|
|
if (rbutton_enabled)
|
|
|
|
|
handleRight(mpos, mx, my);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mpos_valid)
|
|
|
|
|
{
|
|
|
|
|
if (mpos.x != last_move_pos.x || mpos.y != last_move_pos.y || mpos.z != last_move_pos.z)
|
|
|
|
|
{
|
|
|
|
|
awaiting_lbut_up = false;
|
|
|
|
|
awaiting_rbut_up = false;
|
|
|
|
|
|
|
|
|
|
if ((enabler->mouse_lbut_down && drag_mode == Left) || (enabler->mouse_rbut_down && drag_mode == Right))
|
|
|
|
|
{
|
|
|
|
|
int newx = (*df::global::window_x) - (mpos.x - last_move_pos.x);
|
|
|
|
|
int newy = (*df::global::window_y) - (mpos.y - last_move_pos.y);
|
|
|
|
|
|
|
|
|
|
newx = std::max(0, std::min(newx, world->map.x_count - dims.map_x2+1));
|
|
|
|
|
newy = std::max(0, std::min(newy, world->map.y_count - dims.map_y2+1));
|
|
|
|
|
|
|
|
|
|
(*df::global::window_x) = newx;
|
|
|
|
|
(*df::global::window_y) = newy;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mouse_moved = true;
|
|
|
|
|
last_move_pos = mpos;
|
|
|
|
|
}
|
|
|
|
@ -677,6 +747,10 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't change levels
|
|
|
|
|
if (mpos.z != *df::global::window_z)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
last_t = enabler->clock;
|
|
|
|
|
moveCursor(mpos, false);
|
|
|
|
|
}
|
|
|
|
@ -699,6 +773,14 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
|
|
|
|
|
set_to_limit(look_list, 8);
|
|
|
|
|
int disp_y = gps->dimy - look_list - 2;
|
|
|
|
|
|
|
|
|
|
if (mpos.z != *df::global::window_z)
|
|
|
|
|
{
|
|
|
|
|
int y = gps->dimy - 2;
|
|
|
|
|
char buf[6];
|
|
|
|
|
sprintf(buf, "@%d", mpos.z - *df::global::window_z);
|
|
|
|
|
OutputString(COLOR_GREY, disp_x, y, buf, true, left_margin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int c = 0;
|
|
|
|
|
for (auto it = ulist.begin(); it != ulist.end() && c < 8; it++, c++)
|
|
|
|
|
{
|
|
|
|
@ -783,6 +865,15 @@ static command_result mousequery_cmd(color_ostream &out, vector <string> & param
|
|
|
|
|
{
|
|
|
|
|
live_view = (state == "enable");
|
|
|
|
|
}
|
|
|
|
|
else if (cmd == "drag")
|
|
|
|
|
{
|
|
|
|
|
if (state == "left")
|
|
|
|
|
drag_mode = Left;
|
|
|
|
|
else if (state == "right")
|
|
|
|
|
drag_mode = Right;
|
|
|
|
|
else if (state == "disable")
|
|
|
|
|
drag_mode = None;
|
|
|
|
|
}
|
|
|
|
|
else if (cmd[0] == 'd')
|
|
|
|
|
{
|
|
|
|
|
auto l = atoi(state.c_str());
|
|
|
|
@ -828,12 +919,14 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
|
|
|
|
|
PluginCommand(
|
|
|
|
|
"mousequery", "Add mouse functionality to Dwarf Fortress",
|
|
|
|
|
mousequery_cmd, false,
|
|
|
|
|
"mousequery [plugin|rbutton|track|edge|live] [enabled|disabled]\n"
|
|
|
|
|
"mousequery [plugin|rbutton|track|edge|live] [enable|disable]\n"
|
|
|
|
|
" plugin: enable/disable the entire plugin\n"
|
|
|
|
|
" rbutton: enable/disable right mouse button\n"
|
|
|
|
|
" track: enable/disable moving cursor in build and designation mode\n"
|
|
|
|
|
" edge: enable/disable active edge scrolling (when on, will also enable tracking)\n"
|
|
|
|
|
" live: enable/disable query view when unpaused\n\n"
|
|
|
|
|
"mousequery drag [left|right|disable]\n"
|
|
|
|
|
" Enable/disable map dragging with the specified mouse button\n\n"
|
|
|
|
|
"mousequery delay <amount>\n"
|
|
|
|
|
" Set delay when edge scrolling in tracking mode. Omit amount to display current setting.\n"
|
|
|
|
|
));
|
|
|
|
|