summaryrefslogtreecommitdiff
path: root/library/modules/Gui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/modules/Gui.cpp')
-rw-r--r--library/modules/Gui.cpp297
1 files changed, 275 insertions, 22 deletions
diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp
index cd44401f..21156ac0 100644
--- a/library/modules/Gui.cpp
+++ b/library/modules/Gui.cpp
@@ -42,6 +42,8 @@ using namespace std;
using namespace DFHack;
#include "modules/Job.h"
+#include "modules/Screen.h"
+#include "modules/Maps.h"
#include "DataDefs.h"
#include "df/world.h"
@@ -51,8 +53,9 @@ using namespace DFHack;
#include "df/viewscreen_dungeon_monsterstatusst.h"
#include "df/viewscreen_joblistst.h"
#include "df/viewscreen_unitlistst.h"
+#include "df/viewscreen_buildinglistst.h"
#include "df/viewscreen_itemst.h"
-#include "df/viewscreen_layerst.h"
+#include "df/viewscreen_layer.h"
#include "df/viewscreen_layer_workshop_profilest.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
@@ -80,6 +83,8 @@ using namespace DFHack;
#include "df/graphic.h"
#include "df/layer_object_listst.h"
#include "df/assign_trade_status.h"
+#include "df/announcement_flags.h"
+#include "df/announcements.h"
using namespace df::enums;
using df::global::gview;
@@ -87,8 +92,11 @@ using df::global::init;
using df::global::gps;
using df::global::ui;
using df::global::world;
+using df::global::selection_rect;
+using df::global::ui_menu_width;
+using df::global::ui_area_map_width;
-static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx)
+static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx)
{
return virtual_cast<df::layer_object_listst>(vector_get(layer->layer_objects,idx));
}
@@ -166,10 +174,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
else if (id == &df::building_trapst::_identity)
{
auto trap = (df::building_trapst*)selected;
- if (trap->trap_type == trap_type::Lever) {
- focus += "/Lever";
+ focus += "/" + enum_item_key(trap->trap_type);
+ if (trap->trap_type == trap_type::Lever)
jobs = true;
- }
}
else if (ui_building_in_assign && *ui_building_in_assign &&
ui_building_assign_type && ui_building_assign_units &&
@@ -182,6 +189,8 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
focus += unit ? "/Unit" : "/None";
}
}
+ else
+ focus += "/" + enum_item_key(selected->getType());
if (jobs)
{
@@ -204,7 +213,14 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
if (ui_build_selector->building_type < 0)
focus += "/Type";
else if (ui_build_selector->stage != 2)
- focus += "/Position";
+ {
+ if (ui_build_selector->stage != 1)
+ focus += "/NoMaterials";
+ else
+ focus += "/Position";
+
+ focus += "/" + enum_item_key(ui_build_selector->building_type);
+ }
else
{
focus += "/Material";
@@ -317,9 +333,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(layer_military)
focus += "/" + enum_item_key(screen->page);
int cur_list;
- if (list1->bright) cur_list = 0;
- else if (list2->bright) cur_list = 1;
- else if (list3->bright) cur_list = 2;
+ if (list1->active) cur_list = 0;
+ else if (list2->active) cur_list = 1;
+ else if (list3->active) cur_list = 2;
else return;
switch (screen->page)
@@ -405,7 +421,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(layer_assigntrade)
if (unsigned(list_idx) >= num_lists)
return;
- if (list1->bright)
+ if (list1->active)
focus += "/Groups";
else
focus += "/Items";
@@ -443,10 +459,10 @@ DEFINE_GET_FOCUS_STRING_HANDLER(layer_stockpile)
focus += "/On";
- if (list2->bright || list3->bright || screen->list_ids.empty()) {
+ if (list2->active || list3->active || screen->list_ids.empty()) {
focus += "/" + enum_item_key(screen->cur_list);
- if (list3->bright)
+ if (list3->active)
focus += (screen->item_names.empty() ? "/None" : "/Item");
}
}
@@ -466,6 +482,11 @@ std::string Gui::getFocusString(df::viewscreen *top)
return name;
}
+ else if (dfhack_viewscreen::is_instance(top))
+ {
+ auto name = static_cast<dfhack_viewscreen*>(top)->getFocusString();
+ return name.empty() ? "dfhack" : "dfhack/"+name;
+ }
else
{
Core &core = Core::getInstance();
@@ -671,6 +692,8 @@ df::job *Gui::getSelectedJob(color_ostream &out, bool quiet)
return job;
}
+ else if (auto dfscreen = dfhack_viewscreen::try_cast(top))
+ return dfscreen->getSelectedJob();
else
return getSelectedWorkshopJob(out, quiet);
}
@@ -743,7 +766,7 @@ static df::unit *getAnyUnit(df::viewscreen *top)
{
case df::viewscreen_petst::List:
if (!vector_get(screen->is_vermin, screen->cursor))
- return (df::unit*)vector_get(screen->animal, screen->cursor);
+ return vector_get(screen->animal, screen->cursor).unit;
return NULL;
case df::viewscreen_petst::SelectTrainer:
@@ -761,6 +784,9 @@ static df::unit *getAnyUnit(df::viewscreen *top)
return NULL;
}
+ if (auto dfscreen = dfhack_viewscreen::try_cast(top))
+ return dfscreen->getSelectedUnit();
+
if (!Gui::dwarfmode_hotkey(top))
return NULL;
@@ -824,7 +850,7 @@ static df::item *getAnyItem(df::viewscreen *top)
{
auto list1 = getLayerList(screen, 0);
auto list2 = getLayerList(screen, 1);
- if (!list1 || !list2 || !list2->bright)
+ if (!list1 || !list2 || !list2->active)
return NULL;
int list_idx = vector_get(screen->visible_lists, list1->cursor, (int16_t)-1);
@@ -855,6 +881,9 @@ static df::item *getAnyItem(df::viewscreen *top)
return NULL;
}
+ if (auto dfscreen = dfhack_viewscreen::try_cast(top))
+ return dfscreen->getSelectedItem();
+
if (!Gui::dwarfmode_hotkey(top))
return NULL;
@@ -913,10 +942,75 @@ df::item *Gui::getSelectedItem(color_ostream &out, bool quiet)
return item;
}
-//
+static df::building *getAnyBuilding(df::viewscreen *top)
+{
+ using namespace ui_sidebar_mode;
+ using df::global::ui;
+ using df::global::ui_look_list;
+ using df::global::ui_look_cursor;
+ using df::global::world;
+ using df::global::ui_sidebar_menus;
-void Gui::showAnnouncement(std::string message, int color, bool bright)
+ if (auto screen = strict_virtual_cast<df::viewscreen_buildinglistst>(top))
+ return vector_get(screen->buildings, screen->cursor);
+
+ if (auto dfscreen = dfhack_viewscreen::try_cast(top))
+ return dfscreen->getSelectedBuilding();
+
+ if (!Gui::dwarfmode_hotkey(top))
+ return NULL;
+
+ switch (ui->main.mode) {
+ case LookAround:
+ {
+ if (!ui_look_list || !ui_look_cursor)
+ return NULL;
+
+ auto item = vector_get(ui_look_list->items, *ui_look_cursor);
+ if (item && item->type == df::ui_look_list::T_items::Building)
+ return item->building;
+ else
+ return NULL;
+ }
+ case QueryBuilding:
+ case BuildingItems:
+ {
+ return world->selected_building;
+ }
+ case Zones:
+ case ZonesPenInfo:
+ case ZonesPitInfo:
+ case ZonesHospitalInfo:
+ {
+ if (ui_sidebar_menus)
+ return ui_sidebar_menus->zone.selected;
+ return NULL;
+ }
+ default:
+ return NULL;
+ }
+}
+
+bool Gui::any_building_hotkey(df::viewscreen *top)
{
+ return getAnyBuilding(top) != NULL;
+}
+
+df::building *Gui::getSelectedBuilding(color_ostream &out, bool quiet)
+{
+ df::building *building = getAnyBuilding(Core::getTopViewscreen());
+
+ if (!building && !quiet)
+ out.printerr("No building is selected in the UI.\n");
+
+ return building;
+}
+
+//
+
+static void doShowAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
using df::global::world;
using df::global::cur_year;
using df::global::cur_year_tick;
@@ -942,6 +1036,9 @@ void Gui::showAnnouncement(std::string message, int color, bool bright)
{
df::report *new_rep = new df::report();
+ new_rep->type = type;
+ new_rep->pos = pos;
+
new_rep->color = color;
new_rep->bright = bright;
new_rep->year = year;
@@ -963,7 +1060,17 @@ void Gui::showAnnouncement(std::string message, int color, bool bright)
world->status.announcements.push_back(new_rep);
world->status.display_timer = 2000;
}
+}
+
+void Gui::showAnnouncement(std::string message, int color, bool bright)
+{
+ doShowAnnouncement(df::announcement_type(0), df::coord(), message, color, bright);
+}
+void Gui::showZoomAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
+ doShowAnnouncement(type, pos, message, color, bright);
}
void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
@@ -977,17 +1084,163 @@ void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
world->status.popups.push_back(popup);
}
-df::viewscreen * Gui::GetCurrentScreen()
+void Gui::showAutoAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
+ using df::global::announcements;
+
+ df::announcement_flags flags;
+ if (is_valid_enum_item(type) && announcements)
+ flags = announcements->flags[type];
+
+ doShowAnnouncement(type, pos, message, color, bright);
+
+ if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER)
+ {
+ resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE);
+
+ if (flags.bits.RECENTER && pos.isValid())
+ revealInDwarfmodeMap(pos, true);
+ }
+
+ if (flags.bits.DO_MEGA)
+ showPopupAnnouncement(message, color, bright);
+}
+
+df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)
{
df::viewscreen * ws = &gview->view;
- while(ws)
+ while (ws && ws->child)
+ ws = ws->child;
+
+ if (skip_dismissed)
+ {
+ while (ws && Screen::isDismissed(ws) && ws->parent)
+ ws = ws->parent;
+ }
+
+ return ws;
+}
+
+df::coord Gui::getViewportPos()
+{
+ if (!df::global::window_x || !df::global::window_y || !df::global::window_z)
+ return df::coord(0,0,0);
+
+ return df::coord(*df::global::window_x, *df::global::window_y, *df::global::window_z);
+}
+
+df::coord Gui::getCursorPos()
+{
+ using df::global::cursor;
+ if (!cursor)
+ return df::coord();
+
+ return df::coord(cursor->x, cursor->y, cursor->z);
+}
+
+Gui::DwarfmodeDims Gui::getDwarfmodeViewDims()
+{
+ DwarfmodeDims dims;
+
+ auto ws = Screen::getWindowSize();
+ dims.y1 = 1;
+ dims.y2 = ws.y-2;
+ dims.map_x1 = 1;
+ dims.map_x2 = ws.x-2;
+ dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1;
+ dims.menu_forced = false;
+
+ int menu_pos = (ui_menu_width ? *ui_menu_width : 2);
+ int area_pos = (ui_area_map_width ? *ui_area_map_width : 3);
+
+ if (ui && ui->main.mode && menu_pos >= area_pos)
+ {
+ dims.menu_forced = true;
+ menu_pos = area_pos-1;
+ }
+
+ dims.area_on = (area_pos < 3);
+ dims.menu_on = (menu_pos < area_pos);
+
+ if (dims.menu_on)
{
- if(ws->child)
- ws = ws->child;
+ dims.menu_x2 = ws.x - 2;
+ dims.menu_x1 = dims.menu_x2 - Gui::MENU_WIDTH + 1;
+ if (menu_pos == 1)
+ dims.menu_x1 -= Gui::AREA_MAP_WIDTH + 1;
+ dims.map_x2 = dims.menu_x1 - 2;
+ }
+ if (dims.area_on)
+ {
+ dims.area_x2 = ws.x-2;
+ dims.area_x1 = dims.area_x2 - Gui::AREA_MAP_WIDTH + 1;
+ if (dims.menu_on)
+ dims.menu_x2 = dims.area_x1 - 2;
else
- return ws;
+ dims.map_x2 = dims.area_x1 - 2;
+ }
+
+ return dims;
+}
+
+void Gui::resetDwarfmodeView(bool pause)
+{
+ using df::global::cursor;
+
+ if (ui)
+ {
+ ui->follow_unit = -1;
+ ui->follow_item = -1;
+ ui->main.mode = ui_sidebar_mode::Default;
+ }
+
+ if (selection_rect)
+ {
+ selection_rect->start_x = -30000;
+ selection_rect->end_x = -30000;
+ }
+
+ if (cursor)
+ cursor->x = cursor->y = cursor->z = -30000;
+
+ if (pause && df::global::pause_state)
+ *df::global::pause_state = true;
+}
+
+bool Gui::revealInDwarfmodeMap(df::coord pos, bool center)
+{
+ using df::global::window_x;
+ using df::global::window_y;
+ using df::global::window_z;
+
+ if (!window_x || !window_y || !window_z || !world)
+ return false;
+ if (!Maps::isValidTilePos(pos))
+ return false;
+
+ auto dims = getDwarfmodeViewDims();
+ int w = dims.map_x2 - dims.map_x1 + 1;
+ int h = dims.y2 - dims.y1 + 1;
+
+ *window_z = pos.z;
+
+ if (center)
+ {
+ *window_x = pos.x - w/2;
+ *window_y = pos.y - h/2;
}
- return 0;
+ else
+ {
+ while (*window_x + w < pos.x+5) *window_x += 10;
+ while (*window_y + h < pos.y+5) *window_y += 10;
+ while (*window_x + 5 > pos.x) *window_x -= 10;
+ while (*window_y + 5 > pos.y) *window_y -= 10;
+ }
+
+ *window_x = std::max(0, std::min(*window_x, world->map.x_count-w));
+ *window_y = std::max(0, std::min(*window_y, world->map.y_count-h));
+ return true;
}
bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z)