Skip to content

Commit

Permalink
[widgets] add: DoorView widget
Browse files Browse the repository at this point in the history
  • Loading branch information
jd28 committed Jun 15, 2024
1 parent f0e993b commit 9aeb553
Show file tree
Hide file tree
Showing 15 changed files with 956 additions and 1 deletion.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ Feat selection with handy fuzzy searching.

A tree view for NWN dialogs. See dlg above.

### Door View

A widget for doors

![door](screenshots/door-view-2024-06-14.png)

### Placeable View

A widget for placeables
Expand Down
Binary file added screenshots/door-view-2024-06-14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/arclight/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ target_link_libraries(arclight PUBLIC
AreaView
CreatureView
DialogView
DoorView
PlaceableView
WaitingSpinnerWidget
Qt6::Widgets
Expand Down
12 changes: 12 additions & 0 deletions src/arclight/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "widgets/CreatureView/creatureview.h"
#include "widgets/DialogView/dialogmodel.h"
#include "widgets/DialogView/dialogview.h"
#include "widgets/DoorView/doorview.h"
#include "widgets/PlaceableView/placeableview.h"
#include "widgets/QtWaitingSpinner/waitingspinnerwidget.h"
#include "widgets/arclighttreeview.h"
Expand Down Expand Up @@ -95,6 +96,17 @@ void MainWindow::loadCallbacks()
return new CreatureView(utc, this);
});

type_to_view_.emplace(nw::ResourceType::utd,
[this](nw::Resource res) -> ArclightView* {
nw::Gff gff(nw::kernel::resman().demand(res));
if (!gff.valid()) {
LOG_F(ERROR, "[utd] failed to open file: {}", res.filename());
return nullptr;
}
auto utd = new nw::Door();
nw::deserialize(utd, gff.toplevel(), nw::SerializationProfile::blueprint);
return new DoorView(utd, this);
});
type_to_view_.emplace(nw::ResourceType::utp,
[this](nw::Resource res) -> ArclightView* {
nw::Gff gff(nw::kernel::resman().demand(res));
Expand Down
1 change: 1 addition & 0 deletions src/widgets/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_subdirectory(AreaView)
add_subdirectory(ContainerView)
add_subdirectory(CreatureView)
add_subdirectory(DialogView)
add_subdirectory(DoorView)
add_subdirectory(LanguageMenu)
add_subdirectory(PlaceableView)
add_subdirectory(qtpropertybrowser)
Expand Down
39 changes: 39 additions & 0 deletions src/widgets/DoorView/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
find_package(Qt6 REQUIRED COMPONENTS Widgets)
find_package(Qt6 REQUIRED COMPONENTS OpenGL OpenGLWidgets)

add_library(DoorView STATIC
doorgeneralview.h
doorgeneralview.cpp
doorgeneralview.ui
doorproperties.h
doorproperties.cpp
doorview.h
doorview.cpp
doorview.ui
)

target_compile_definitions(DoorView PUBLIC -DGLM_ENABLE_EXPERIMENTAL)

target_include_directories(DoorView PRIVATE
./
../
${CMAKE_SOURCE_DIR}/external/rollnw/external
${CMAKE_SOURCE_DIR}/external/rollnw/external/sqlite-3.45.2
${CMAKE_SOURCE_DIR}/external/rollnw/external/minizip/include
${CMAKE_SOURCE_DIR}/external/rollnw/lib
${CMAKE_SOURCE_DIR}/external/ZFontIcon
${CMAKE_SOURCE_DIR}/external/
)

target_link_libraries(DoorView PRIVATE
arclight-widgets
arclight-external
nw
Qt6::Widgets
Qt6::Core
Qt6::Gui
Qt6::OpenGL
Qt6::OpenGLWidgets
nw
renderer
)
111 changes: 111 additions & 0 deletions src/widgets/DoorView/doorgeneralview.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "doorgeneralview.h"
#include "ui_doorgeneralview.h"

#include "doorproperties.h"

#include "nw/formats/Image.hpp"
#include "nw/kernel/Resources.hpp"
#include "nw/kernel/Rules.hpp"
#include "nw/kernel/TwoDACache.hpp"
#include "nw/objects/Door.hpp"

DoorGeneralView::DoorGeneralView(nw::Door* obj, QWidget* parent)
: QWidget(parent)
, ui(new Ui::DoorGeneralView)
, obj_{obj}
{
ui->setupUi(this);

if (auto portraits_2da = nw::kernel::twodas().get("portraits")) {
auto base = portraits_2da->get<std::string>(obj_->portrait_id, "BaseResRef");
if (base) {
auto base_resref = fmt::format("po_{}m", *base);
auto portrait = nw::kernel::resman().demand_in_order(nw::Resref(base_resref),
{nw::ResourceType::dds, nw::ResourceType::tga});

if (portrait.bytes.size()) {
auto img = nw::Image(std::move(portrait));
QImage qi(img.data(), img.width(), img.height(),
img.channels() == 4 ? QImage::Format_RGBA8888 : QImage::Format_RGB888);
if (qi.height() > 128 || qi.width() > 128) {
qi = qi.scaled(128, 128, Qt::KeepAspectRatio);
}

// These are pre-flipped
if (img.is_bio_dds()) { qi.mirror(); }

QRect rect(0, 0, 64, 100); // This is specific to medium portraits
qi = qi.copy(rect);
ui->portrait->setPixmap(QPixmap::fromImage(qi));
}
}
} else {
LOG_F(ERROR, "Failed to load portraits.2da");
}

ui->name->setLocString(obj->common.name);
ui->tag->setText(QString::fromStdString(std::string(obj->tag().view())));
ui->resref->setText(QString::fromStdString(obj->common.resref.string()));
ui->resref->setEnabled(obj->common.resref.empty());
ui->properties->setObject(obj_);

auto doortypes = nw::kernel::twodas().get("doortypes");
if (doortypes) {
int name;
std::string model;
int added = 0;
for (size_t i = 0; i < doortypes->rows(); ++i) {
if (!doortypes->get_to(i, "StringRefGame", name)) { continue; }
ui->appearance->addItem(QString::fromStdString(nw::kernel::strings().get(uint32_t(name))), int(i));
++i;
if (obj_->appearance == i) {
ui->appearance->setCurrentIndex(added);
}
++added;
}
} else {
throw std::runtime_error("[door] failed to load doortypes.2da");
}
// Not sorting the appearance combo due to special "Use Generic Doors"

auto genericdoors = nw::kernel::twodas().get("genericdoors");
if (genericdoors) {
int name;
std::string model;
int added = 0;
for (size_t i = 0; i < genericdoors->rows(); ++i) {
if (!genericdoors->get_to(i, "Name", name)) { continue; }
ui->generic->addItem(QString::fromStdString(nw::kernel::strings().get(uint32_t(name))), int(i));
++i;
if (obj_->generic_type == i) {
ui->generic->setCurrentIndex(added);
}
++added;
}
} else {
throw std::runtime_error("[door] failed to load genericdoors.2da");
}
ui->generic->model()->sort(0);
ui->generic->setEnabled(obj_->appearance == 0);

connect(ui->appearance, &QComboBox::currentIndexChanged, this, &DoorGeneralView::onAppearanceChanged);
connect(ui->generic, &QComboBox::currentIndexChanged, this, &DoorGeneralView::onGenericChanged);
}

DoorGeneralView::~DoorGeneralView()
{
delete ui;
}

void DoorGeneralView::onAppearanceChanged(int value)
{
obj_->appearance = static_cast<uint32_t>(ui->appearance->itemData(value).toInt());
ui->generic->setEnabled(obj_->appearance == 0);
emit appearanceChanged();
}

void DoorGeneralView::onGenericChanged(int value)
{
obj_->generic_type = static_cast<uint32_t>(ui->generic->itemData(value).toInt());
emit appearanceChanged();
}
34 changes: 34 additions & 0 deletions src/widgets/DoorView/doorgeneralview.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef DOORGENERALVIEW_H
#define DOORGENERALVIEW_H

#include <QWidget>

namespace nw {
struct Door;
struct Resref;
}

namespace Ui {
class DoorGeneralView;
}

class DoorGeneralView : public QWidget {
Q_OBJECT

public:
explicit DoorGeneralView(nw::Door* obj, QWidget* parent = nullptr);
~DoorGeneralView();

signals:
void appearanceChanged();

private slots:
void onAppearanceChanged(int value);
void onGenericChanged(int value);

private:
Ui::DoorGeneralView* ui = nullptr;
nw::Door* obj_ = nullptr;
};

#endif // DOORGENERALVIEW_H
Loading

0 comments on commit 9aeb553

Please sign in to comment.