Unbake the special help texts.
The text in the various help dialogs that was previously baked into an image is now drawn as text, meaning that it benefits from text unblurring when scaling is active. This entails some small changes to layout, since it's a different font. Dialog engine changes: * A new picture type allowing to draw the inventory button icons directly into a dialog. * A new widget type that simply draws a line between two points.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "dialogxml/widgets/button.hpp"
|
||||
#include "dialogxml/widgets/field.hpp"
|
||||
#include "dialogxml/widgets/ledgroup.hpp"
|
||||
#include "dialogxml/widgets/line.hpp"
|
||||
#include "dialogxml/widgets/message.hpp"
|
||||
#include "dialogxml/widgets/scrollbar.hpp"
|
||||
#include "dialogxml/widgets/scrollpane.hpp"
|
||||
@@ -212,6 +213,8 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
inserted = controls.insert(parse<cButton>(*node, *this)).first;
|
||||
else if(type == "led")
|
||||
inserted = controls.insert(parse<cLed>(*node, *this)).first;
|
||||
else if(type == "line")
|
||||
inserted = controls.insert(parse<cConnector>(*node, *this)).first;
|
||||
else if(type == "group")
|
||||
inserted = controls.insert(parse<cLedGroup>(*node, *this)).first;
|
||||
else if(type == "stack") {
|
||||
@@ -256,6 +259,7 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
case CTRL_UNKNOWN: ctrlType = "???"; break;
|
||||
case CTRL_BTN: ctrlType = "button"; break;
|
||||
case CTRL_LED: ctrlType = "led"; break;
|
||||
case CTRL_LINE: ctrlType = "line"; break;
|
||||
case CTRL_PICT: ctrlType = "pict"; break;
|
||||
case CTRL_FIELD: ctrlType = "field"; break;
|
||||
case CTRL_TEXT: ctrlType = "text"; break;
|
||||
@@ -279,6 +283,7 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
case CTRL_UNKNOWN: ctrlType = "???"; break;
|
||||
case CTRL_BTN: ctrlType = "button"; break;
|
||||
case CTRL_LED: ctrlType = "led"; break;
|
||||
case CTRL_LINE: ctrlType = "line"; break;
|
||||
case CTRL_PICT: ctrlType = "pict"; break;
|
||||
case CTRL_FIELD: ctrlType = "field"; break;
|
||||
case CTRL_TEXT: ctrlType = "text"; break;
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "dialogxml/widgets/button.hpp"
|
||||
#include "dialogxml/widgets/field.hpp"
|
||||
#include "dialogxml/widgets/ledgroup.hpp"
|
||||
#include "dialogxml/widgets/line.hpp"
|
||||
#include "dialogxml/widgets/message.hpp"
|
||||
#include "dialogxml/widgets/pict.hpp"
|
||||
#include "dialogxml/widgets/scrollbar.hpp"
|
||||
@@ -48,6 +49,10 @@ bool cContainer::parseChildControl(ticpp::Element& elem, std::map<std::string,cC
|
||||
auto led = getDialog()->parse<cLed>(elem, *this);
|
||||
inserted = controls.insert(led).first;
|
||||
id = led.first;
|
||||
} else if(tag == "line") {
|
||||
auto line = getDialog()->parse<cConnector>(elem, *this);
|
||||
inserted = controls.insert(line).first;
|
||||
id = line.first;
|
||||
} else if(tag == "group") {
|
||||
auto group = getDialog()->parse<cLedGroup>(elem, *this);
|
||||
inserted = controls.insert(group).first;
|
||||
|
@@ -66,6 +66,7 @@ enum eControlType {
|
||||
CTRL_SCROLL,///< A scrollbar
|
||||
CTRL_PANE, ///< A scroll pane
|
||||
CTRL_MAP, ///< A 2-dimensional grid of identical controls
|
||||
CTRL_LINE, ///< Just a line connecting two points
|
||||
};
|
||||
|
||||
enum ePosition {
|
||||
|
97
src/dialogxml/widgets/line.cpp
Normal file
97
src/dialogxml/widgets/line.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// line.cpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-03-08.
|
||||
//
|
||||
|
||||
#include "line.hpp"
|
||||
#include "dialogxml/dialogs/dialog.hpp"
|
||||
#include "gfx/render_shapes.hpp"
|
||||
|
||||
bool cConnector::manageFormat(eFormat prop, bool set, boost::any* val) {
|
||||
switch(prop) {
|
||||
case TXT_SIZE:
|
||||
if(val) {
|
||||
if(set) thickness = boost::any_cast<short>(*val);
|
||||
else *val = thickness;
|
||||
}
|
||||
break;
|
||||
case TXT_COLOUR:
|
||||
if(val) {
|
||||
if(set) color = boost::any_cast<sf::Color>(*val);
|
||||
else *val = color;
|
||||
}
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cConnector::parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) {
|
||||
if(attr.Name() == "slope") {
|
||||
if(attr.Value() == "positive") flip = true;
|
||||
else if(attr.Value() == "negative") flip = false;
|
||||
else throw xBadVal(tagName, attr.Name(), attr.Value(), attr.Row(), attr.Column(), fname);
|
||||
return true;
|
||||
}
|
||||
return cControl::parseAttribute(attr, tagName, fname);
|
||||
}
|
||||
|
||||
void cConnector::validatePostParse(ticpp::Element& who, std::string fname, const std::set<std::string>& attrs, const std::multiset<std::string>& nodes) {
|
||||
cControl::validatePostParse(who, fname, attrs, nodes);
|
||||
if(!attrs.count("color") && !attrs.count("colour") && getDialog()->getBg() == cDialog::BG_DARK)
|
||||
setColour(sf::Color::White);
|
||||
// Width or height can be zero, but not both
|
||||
if(frame.width() == 0 && frame.height() == 0)
|
||||
throw xBadVal("line", "width", "0", who.Row(), who.Column(), fname);
|
||||
// slope attribute forbidden if either width or height is zero
|
||||
if(attrs.count("slope") && (frame.width() == 0 || frame.height() == 0))
|
||||
throw xBadAttr("line", "slope", who.Row(), who.Column(), fname);
|
||||
}
|
||||
|
||||
cConnector::cConnector(iComponent& parent)
|
||||
: cControl(CTRL_TEXT,parent)
|
||||
, color(parent.getDefTextClr())
|
||||
{}
|
||||
|
||||
bool cConnector::isClickable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cConnector::isFocusable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cConnector::isScrollable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void cConnector::draw(){
|
||||
getWindow().setActive();
|
||||
|
||||
if(visible){
|
||||
location first(flip ? frame.right : frame.left, frame.top);
|
||||
location end(flip ? frame.left : frame.right, frame.bottom);
|
||||
draw_line(getWindow(), first, end, thickness, color);
|
||||
// sf::ConvexShape convex;
|
||||
// convex.setPointCount(4);
|
||||
// convex.setFillColor(color);
|
||||
// convex.setOutlineThickness(0);
|
||||
// if(x2 - x1 == 0) {
|
||||
// convex.setPoint(0, sf::Vector2f(x1 - thickness / 2, y1));
|
||||
// convex.setPoint(1, sf::Vector2f(x1 + thickness / 2, y1));
|
||||
// convex.setPoint(2, sf::Vector2f(x2 + thickness / 2, y2));
|
||||
// convex.setPoint(3, sf::Vector2f(x2 - thickness / 2, y2));
|
||||
// } else {
|
||||
// float alpha = atan2(y2 - y1, x2 - x1);
|
||||
// convex.setPoint(0, sf::Vector2f(x1 - (thickness / 2) * sin(alpha), y1 + (thickness / 2) * cos(alpha)));
|
||||
// convex.setPoint(1, sf::Vector2f(x1 + (thickness / 2) * sin(alpha), y1 - (thickness / 2) * cos(alpha)));
|
||||
// convex.setPoint(2, sf::Vector2f(x2 + (thickness / 2) * sin(alpha), y2 - (thickness / 2) * cos(alpha)));
|
||||
// convex.setPoint(3, sf::Vector2f(x2 - (thickness / 2) * sin(alpha), y2 + (thickness / 2) * cos(alpha)));
|
||||
// }
|
||||
// getWindow().draw(convex);
|
||||
}
|
||||
}
|
||||
|
||||
cConnector::~cConnector() {}
|
42
src/dialogxml/widgets/line.hpp
Normal file
42
src/dialogxml/widgets/line.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// line.hpp
|
||||
// BoE
|
||||
//
|
||||
// Created by Celtic Minstrel on 2025-03-08.
|
||||
//
|
||||
|
||||
#ifndef BOE_DIALOG_LINE_HPP
|
||||
#define BOE_DIALOG_LINE_HPP
|
||||
|
||||
#include "control.hpp"
|
||||
|
||||
/// A simple line drawn between two points.
|
||||
class cConnector : public cControl {
|
||||
public:
|
||||
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
|
||||
void validatePostParse(ticpp::Element& who, std::string fname, const std::set<std::string>& attrs, const std::multiset<std::string>& nodes) override;
|
||||
bool manageFormat(eFormat prop, bool set, boost::any* val) override;
|
||||
/// Create a connector.
|
||||
/// @param parent The parent dialog.
|
||||
explicit cConnector(iComponent& parent);
|
||||
bool isClickable() const override;
|
||||
bool isFocusable() const override;
|
||||
bool isScrollable() const override;
|
||||
virtual ~cConnector();
|
||||
void draw() override;
|
||||
/// @copydoc cControl::getSupportedHandlers
|
||||
///
|
||||
/// @todo Document possible handlers
|
||||
std::set<eDlogEvt> getSupportedHandlers() const override {
|
||||
return {EVT_CLICK};
|
||||
}
|
||||
cConnector& operator=(cConnector& other) = delete;
|
||||
cConnector(cConnector& other) = delete;
|
||||
private:
|
||||
sf::Color color;
|
||||
rectangle to_rect;
|
||||
size_t thickness = 2;
|
||||
bool flip = false;
|
||||
};
|
||||
|
||||
#endif
|
@@ -68,6 +68,7 @@ void cPict::init(){
|
||||
drawPict()[PIC_PARTY_MONST_WIDE] = &cPict::drawPartyMonstWide;
|
||||
drawPict()[PIC_PARTY_MONST_TALL] = &cPict::drawPartyMonstTall;
|
||||
drawPict()[PIC_PARTY_MONST_LG] = &cPict::drawPartyMonstLg;
|
||||
drawPict()[PIC_BTN] = &cPict::drawInvenBtn;
|
||||
}
|
||||
|
||||
std::map<ePicType,void(cPict::*)(short,rectangle)>& cPict::drawPict(){
|
||||
@@ -473,6 +474,8 @@ bool cPict::parseAttribute(ticpp::Attribute& attr, std::string tagName, std::str
|
||||
picType = PIC_TER_MAP;
|
||||
else if(val == "status")
|
||||
picType = PIC_STATUS;
|
||||
else if(val == "btn")
|
||||
picType = PIC_BTN;
|
||||
else throw xBadVal(tagName, name, val, attr.Row(), attr.Column(), fname);
|
||||
return true;
|
||||
} else if(name == "num") {
|
||||
@@ -593,6 +596,25 @@ void cPict::recalcRect() {
|
||||
bounds.width() = 12;
|
||||
bounds.height() = 12;
|
||||
break;
|
||||
case PIC_BTN:
|
||||
switch(picNum) {
|
||||
case 0: case 1:
|
||||
bounds.width() = 12;
|
||||
bounds.height() = 12;
|
||||
break;
|
||||
case 2: case 3: case 4: case 5:
|
||||
bounds.width() = 14;
|
||||
bounds.height() = 12;
|
||||
break;
|
||||
case 6: case 7: case 8: case 9:
|
||||
bounds.width() = 30;
|
||||
bounds.height() = 12;
|
||||
break;
|
||||
case 10: case 11:
|
||||
bounds.width() = 35;
|
||||
bounds.height() = 15;
|
||||
break;
|
||||
} break;
|
||||
case PIC_FULL:
|
||||
case PIC_CUSTOM_FULL:
|
||||
if(drawScaled) break;
|
||||
@@ -675,18 +697,12 @@ std::shared_ptr<const sf::Texture> cPict::getSheetInternal(eSheetType type, size
|
||||
case SHEET_CUSTOM:
|
||||
// TODO: Implement this
|
||||
break;
|
||||
case SHEET_INVENBTN:
|
||||
sout << "invenbtns";
|
||||
break;
|
||||
case SHEET_FULL:
|
||||
purgeable = true;
|
||||
switch(n) {
|
||||
case 1100:
|
||||
sout << "invenhelp";
|
||||
break;
|
||||
case 1200:
|
||||
sout << "stathelp";
|
||||
break;
|
||||
case 1300:
|
||||
sout << "actionhelp";
|
||||
break;
|
||||
case 1400:
|
||||
sout << "outhelp";
|
||||
break;
|
||||
@@ -697,7 +713,7 @@ std::shared_ptr<const sf::Texture> cPict::getSheetInternal(eSheetType type, size
|
||||
sout << "townhelp";
|
||||
break;
|
||||
default:
|
||||
// TODO: The scenario should be allowed to define a sheet1100.png without it being ignored in favour of invenhelp.png
|
||||
// TODO: The scenario should be allowed to define a sheet1400.png without it being ignored in favour of outhelp.png
|
||||
purgeable = false;
|
||||
sout << "sheet" << n;
|
||||
}
|
||||
@@ -1351,6 +1367,29 @@ void cPict::drawPartyPc(short num, rectangle to_rect){
|
||||
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
|
||||
}
|
||||
|
||||
void cPict::drawInvenBtn(short num, rectangle to_rect){
|
||||
static rectangle from_rect[]{
|
||||
{0, 1, 12, 13}, // pc info
|
||||
{0, 13, 12, 25}, // pc switch
|
||||
{12, 0, 24, 14}, // item use
|
||||
{12, 14, 24, 28}, // item give
|
||||
{12, 28, 24, 42}, // item drop
|
||||
{12, 42, 24, 56}, // item info
|
||||
{24, 0, 36, 30}, // ID
|
||||
{36, 0, 48, 30}, // Sell
|
||||
{48, 0, 60, 30}, // Enchant
|
||||
{60, 0, 72, 30}, // Recharge
|
||||
{0, 60, 15, 95}, // Special Items
|
||||
{15, 60, 30, 95}, // Jobs
|
||||
};
|
||||
static const size_t n_pics = std::distance(std::begin(from_rect), std::end(from_rect));
|
||||
if(num >= n_pics) return;
|
||||
auto from_gw = getSheet(SHEET_INVENBTN);
|
||||
if(!from_gw) return;
|
||||
if(filled) fill_rect(getWindow(), to_rect, fillClr);
|
||||
rect_draw_some_item(*from_gw, from_rect[num], getWindow(), to_rect, sf::BlendAlpha);
|
||||
}
|
||||
|
||||
cPict::~cPict() {}
|
||||
|
||||
void cPict::drawAt(sf::RenderWindow& win, rectangle dest, pic_num_t which_g, ePicType type_g, bool framed) {
|
||||
|
@@ -143,6 +143,7 @@ private:
|
||||
void drawPartyScen(short num, rectangle to_rect);
|
||||
void drawPartyItem(short num, rectangle to_rect);
|
||||
void drawPartyPc(short num, rectangle to_rect);
|
||||
void drawInvenBtn(short num, rectangle to_rect);
|
||||
static std::map<ePicType,void(cPict::*)(short,rectangle)>& drawPict();
|
||||
};
|
||||
|
||||
|
@@ -33,6 +33,7 @@ enum ePicType {
|
||||
PIC_TER_MAP = 15, ///< 12x12 map graphic from the terrain map sheet, expanded to 24x24
|
||||
PIC_STATUS = 16, ///< 12x12 status icon
|
||||
PIC_TINY_ITEM = 17, ///< 18x18 item graphic from the small item sheet
|
||||
PIC_BTN = 18, ///< Button graphic from the inventory buttons sheet (various sizes)
|
||||
PIC_MONST_WIDE = 23, ///< 56x36 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
|
||||
PIC_MONST_TALL = 43, ///< 28x72 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
|
||||
PIC_MONST_LG = 63, ///< 56x72 monster graphic from the preset sheets, resized to fit in a 28x36 space
|
||||
@@ -93,6 +94,7 @@ enum eSheetType {
|
||||
SHEET_TER_MAP, ///< The terrain map icons sheet, termap.png
|
||||
SHEET_FULL, ///< Any full sheet
|
||||
SHEET_STATUS, ///< The status icons sheet, staticons.png
|
||||
SHEET_INVENBTN, ///< Inventory buttons sheet, invenbtns.png
|
||||
SHEET_CUSTOM, ///< Any custom graphics sheet
|
||||
// TODO: Vehicle sheet is missing.
|
||||
// TODO: Documentation of full, custom, header, and exported sheets is still lacking.
|
||||
|
Reference in New Issue
Block a user