diff --git a/tycho/CMakeLists.txt b/tycho/CMakeLists.txt index 3eb2249..210bdd6 100644 --- a/tycho/CMakeLists.txt +++ b/tycho/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror") find_package( Qt5 5.6.0 @@ -22,11 +23,14 @@ add_library( SHARED $ENV{OUT_DIR}/bindings.cc $ENV{OUT_DIR}/bindings.h + cc_headers/mapmodel.h cc_headers/mapprops.h cc_headers/menu.h cc_headers/project.h cc_headers/tycho.h + cc_source/cc.cc cc_source/main.cc + cc_source/mapmodel.cc cc_source/mapprops.cc cc_source/menu.cc cc_source/project.cc @@ -60,6 +64,14 @@ target_link_libraries( Qt5::Widgets ) +target_compile_definitions( + maraiah-tycho-hermes + PUBLIC + -DQT_DEPRECATED_WARNINGS + -DQT_STRICT_ITERATORS + -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT +) + install(TARGETS maraiah-tycho-hermes) ## EOF diff --git a/tycho/bindings.json b/tycho/bindings.json index dd1f0cb..3c3b1a3 100644 --- a/tycho/bindings.json +++ b/tycho/bindings.json @@ -6,8 +6,8 @@ "implementationModule": "gui" }, "objects": { - "MapModel": { - "type": "Tree", + "AbstractMapModel": { + "type": "List", "functions": { "open": { "return": "bool", @@ -32,18 +32,22 @@ "isDirty": { "return": "bool", "mut": false + }, + "propIcon": { + "return": "QString", + "mut": false, + "arguments": [{ + "name": "index", + "type": "quint16" + }] } }, "properties": { }, "itemProperties": { - "rowName": { + "propIndex": { "type": "quint64", "roles": [["display"]] - }, - "someNumber": { - "type": "quint64", - "roles": [[], ["display"]] } } } diff --git a/tycho/cc_headers/mapmodel.h b/tycho/cc_headers/mapmodel.h new file mode 100644 index 0000000..acb5a67 --- /dev/null +++ b/tycho/cc_headers/mapmodel.h @@ -0,0 +1,17 @@ +#pragma once + +#include "bindings.h" + +class MapModel : public AbstractMapModel +{ + Q_OBJECT + +public: + explicit MapModel(QObject *parent = nullptr); + ~MapModel(); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) + const override; +}; + +// EOF diff --git a/tycho/cc_headers/menu.h b/tycho/cc_headers/menu.h index e6d7c55..e3cad69 100644 --- a/tycho/cc_headers/menu.h +++ b/tycho/cc_headers/menu.h @@ -19,6 +19,7 @@ public slots: void mapNew(); void mapOpen(); void openAbout(); + void openAboutQt(); void openMapProperties(); void updateActions(); diff --git a/tycho/cc_headers/project.h b/tycho/cc_headers/project.h index 7eed791..6c3d97a 100644 --- a/tycho/cc_headers/project.h +++ b/tycho/cc_headers/project.h @@ -4,6 +4,8 @@ #include "../ui/ui_project.h" +class MapModel; + class ProjectModel { public: diff --git a/tycho/cc_source/cc.cc b/tycho/cc_source/cc.cc new file mode 100644 index 0000000..ec81f56 --- /dev/null +++ b/tycho/cc_source/cc.cc @@ -0,0 +1,10 @@ +#include "tycho.h" +#include + +extern "C" { + void critical_msg(char const *title, char const *msg) { + QMessageBox::critical(nullptr, QObject::tr(title), QObject::tr(msg)); + } +} + +// EOF diff --git a/tycho/cc_source/mapmodel.cc b/tycho/cc_source/mapmodel.cc new file mode 100644 index 0000000..e944cd6 --- /dev/null +++ b/tycho/cc_source/mapmodel.cc @@ -0,0 +1,28 @@ +#include "tycho.h" +#include "mapmodel.h" + +#include + +MapModel::MapModel(QObject *parent) : + AbstractMapModel(parent) +{ +} + +MapModel::~MapModel() +{ +} + +QVariant MapModel::data(const QModelIndex &index, int role) const +{ + switch(role) { + case Qt::DecorationRole: { + auto name = propIcon(index.row()); + auto icon = name.front() == ':' ? QIcon(name) : QIcon::fromTheme(name); + return QVariant::fromValue(icon); + } + default: + return AbstractMapModel::data(index, role); + } +} + +// EOF diff --git a/tycho/cc_source/menu.cc b/tycho/cc_source/menu.cc index 4611dba..c6be78e 100644 --- a/tycho/cc_source/menu.cc +++ b/tycho/cc_source/menu.cc @@ -2,12 +2,14 @@ #include "mapprops.h" #include "menu.h" #include "project.h" +#include "mapmodel.h" #include "../ui/ui_about.h" #include "../ui/ui_license.h" #include #include #include +#include #include Menu::Menu(QWidget *parent) : @@ -44,12 +46,17 @@ void Menu::mapOpen() this, tr("Open Map File"), QString(), - tr("Marathon Map files (*.scen *.sceA Map)")); + tr("Marathon Map files (*.scen *.sceA Map);;" + "Marathon Physics files (*.phys *.phyA Physics);;" + "Aleph One Image files (*.imgA);;" + "All files (*)")); - QScopedPointer proj{new Project(new MapModel)}; + if(!fname.isEmpty()) { + QScopedPointer proj{new Project(new MapModel)}; - if(proj->model.open(fname)) { - addProject(proj.take()); + if(proj->model.open(fname)) { + addProject(proj.take()); + } } } @@ -77,6 +84,11 @@ void Menu::openAbout() dlg.exec(); } +void Menu::openAboutQt() +{ + QMessageBox::aboutQt(this); +} + void Menu::openLicense(QWidget *parent) { QDialog dlg{parent}; diff --git a/tycho/cc_source/project.cc b/tycho/cc_source/project.cc index 1068140..2a86dd6 100644 --- a/tycho/cc_source/project.cc +++ b/tycho/cc_source/project.cc @@ -1,5 +1,6 @@ #include "tycho.h" #include "project.h" +#include "mapmodel.h" #include #include @@ -22,6 +23,7 @@ ProjectModel::~ProjectModel() { switch(modelType) { case Map: delete modelMap; break; + case Invalid: break; } } @@ -34,8 +36,8 @@ QAbstractItemModel *ProjectModel::getAbstract() const { switch(modelType) { case Map: return modelMap; + case Invalid: Q_UNREACHABLE(); } - Q_UNREACHABLE(); } MapModel *ProjectModel::getMap() const @@ -47,6 +49,7 @@ bool ProjectModel::isDirty() const { switch(modelType) { case Map: return modelMap->isDirty(); + case Invalid: Q_UNREACHABLE(); } Q_UNREACHABLE(); } @@ -55,6 +58,7 @@ bool ProjectModel::open(QString const &path) { switch(modelType) { case Map: return modelMap->open(path); + case Invalid: Q_UNREACHABLE(); } Q_UNREACHABLE(); } @@ -63,6 +67,7 @@ bool ProjectModel::saveAs(QString const &path) const { switch(modelType) { case Map: return modelMap->saveAs(path); + case Invalid: Q_UNREACHABLE(); } Q_UNREACHABLE(); } @@ -71,6 +76,7 @@ bool ProjectModel::save() const { switch(modelType) { case Map: return modelMap->save(); + case Invalid: Q_UNREACHABLE(); } Q_UNREACHABLE(); } @@ -86,7 +92,7 @@ Project::Project(ProjectModel &&_model, QWidget *parent) : setWidget(widget); setAttribute(Qt::WA_DeleteOnClose); - treeView->setModel(model.getAbstract()); + listView->setModel(model.getAbstract()); dbgPrintFunc(); } @@ -117,8 +123,7 @@ void Project::closeEvent(QCloseEvent *event) event->ignore(); return; default: - assert(true); - break; + Q_UNREACHABLE(); } } diff --git a/tycho/source/cc.rs b/tycho/source/cc.rs new file mode 100644 index 0000000..d4811d2 --- /dev/null +++ b/tycho/source/cc.rs @@ -0,0 +1,21 @@ +//! C++ functions. + +mod ffi { + extern "C" { + pub fn critical_msg(title: maraiah::ffi::NT, msg: maraiah::ffi::NT); + } +} + +pub fn critical_msg(title: T, msg: U) + where T: ToString, + U: ToString +{ + let title = std::ffi::CString::new(title.to_string()).unwrap(); + let msg = std::ffi::CString::new(msg.to_string()).unwrap(); + + unsafe { + ffi::critical_msg(title.as_ptr(), msg.as_ptr()); + } +} + +// EOF diff --git a/tycho/source/gui.rs b/tycho/source/gui.rs index 7ba0178..d616258 100644 --- a/tycho/source/gui.rs +++ b/tycho/source/gui.rs @@ -1,8 +1,8 @@ //! GUI implementation. -mod ffi; mod map; +mod qobj; -pub use self::map::MapModel; +pub use self::map::AbstractMapModel; // EOF diff --git a/tycho/source/gui/map.rs b/tycho/source/gui/map.rs index cb18c0c..a283615 100644 --- a/tycho/source/gui/map.rs +++ b/tycho/source/gui/map.rs @@ -1,69 +1,63 @@ //! Map model. -use super::ffi::*; -use maraiah::map; -use memmap::Mmap; +use super::qobj::*; +use maraiah::{backtrace, err::*, map::{self, data::*}}; +use crate::cc; -fn open_f(path: String) -> ResultS +impl AbstractMapModel { - let fp = std::fs::File::open(path)?; - let mm = unsafe { Mmap::map(&fp) }?; + pub fn open_map(path: String) -> ResultS + { + let mut fp = maraiah::file::open_mac(path)?; - map::read(&mm) + let map = map::head::read(&mut fp)?; + let ent = map::entr::read_all(&map)?; + + map::data::read_all(map.head(), &ent) + } + + pub fn get(&self, index: usize) -> (&u16, &EntryData) + { + self.map.iter().nth(index).unwrap() + } + + /* + pub fn get_mut(&mut self, index: usize) -> (&u16, &mut EntryData) + { + self.map.iter_mut().nth(index).unwrap() + } + */ } -impl MapModelTrait for MapModel +impl AbstractMapModelTrait for AbstractMapModel { - /// Returns a new `MapModel` instance. - fn new(emit: MapModelEmitter, model: MapModelTree) -> Self + /// Returns a new `AbstractMapModel` instance. + fn new(emit: AbstractMapModelEmitter, _: AbstractMapModelList) -> Self { if cfg!(debug_assertions) { - eprintln!("new MapModel"); + eprintln!("new AbstractMapModel"); } - Self { emit, - model, - map: map::Map::default() } + Self{emit, map: EntryDataMap::default()} } /// Returns the emitter of `self`. - fn emit(&mut self) -> &mut MapModelEmitter { &mut self.emit } + fn emit(&mut self) -> &mut AbstractMapModelEmitter {&mut self.emit} - /// Checks if `row` exists in the leaf `index`. - fn check_row(&self, index: usize, _row: usize) -> Option { None } + fn row_count(&self) -> usize {self.map.len()} - /// Returns the row `index` is in. - fn row(&self, index: usize) -> usize { index } + fn prop_index(&self, index: usize) -> u64 {(*self.get(index).0).into()} - /// Returns the number of rows in `index`. - fn row_count(&self, index: Option) -> usize + fn prop_icon(&self, index: u16) -> String { - match index { - Some(_) => 0, - None => 7, + match self.get(index.into()).1.get_type() { + EntryType::Image => "image-x-generic".to_string(), + EntryType::Map => ":/tycho/color/map.png".to_string(), + EntryType::Other => "image-missing".to_string(), + EntryType::Physics => "applications-system".to_string(), } } - /// Returns the leaf index of `row` in the leaf `index`. - fn index(&self, index: Option, row: usize) -> usize - { - match index { - Some(_) => unreachable!(), - None => row, - } - } - - /// Returns the parent index of the leaf `index`, if any. - fn parent(&self, _index: usize) -> Option - { - // no parents! - None - } - - fn row_name(&self, row: usize) -> u64 { row as u64 + 1 } - - fn some_number(&self, row: usize) -> u64 { 69420 } - /// Opens the map file at `path`. fn open(&mut self, path: String) -> bool { @@ -71,11 +65,16 @@ impl MapModelTrait for MapModel eprintln!("opening project: {}", &path); } - if let Ok(map) = open_f(&mm) { - self.map = map; - true - } else { - false + match Self::open_map(path) { + Ok(map) => { + self.map = map; + true + } + Err(e) => { + backtrace!(e); + cc::critical_msg("Error opening map", e); + false + } } } @@ -100,24 +99,22 @@ impl MapModelTrait for MapModel } /// Returns `true` if the file has been modified from its original state. - fn is_dirty(&self) -> bool { false } + fn is_dirty(&self) -> bool {false} } -impl Drop for MapModel +impl Drop for AbstractMapModel { fn drop(&mut self) { if cfg!(debug_assertions) { - eprintln!("drop MapModel"); + eprintln!("drop AbstractMapModel"); } } } -pub struct MapModel -{ - emit: MapModelEmitter, - model: MapModelTree, - map: map::Map, +pub struct AbstractMapModel { + emit: AbstractMapModelEmitter, + map: EntryDataMap, } // EOF diff --git a/tycho/source/gui/ffi.rs b/tycho/source/gui/qobj.rs similarity index 100% rename from tycho/source/gui/ffi.rs rename to tycho/source/gui/qobj.rs diff --git a/tycho/source/main.rs b/tycho/source/main.rs index 79dbf54..e2d6820 100644 --- a/tycho/source/main.rs +++ b/tycho/source/main.rs @@ -1,5 +1,6 @@ use maraiah::{err::*, ffi}; +mod cc; mod gui; mod meta; diff --git a/tycho/ui/menu.ui b/tycho/ui/menu.ui index 954eef4..d7955c8 100644 --- a/tycho/ui/menu.ui +++ b/tycho/ui/menu.ui @@ -76,6 +76,7 @@ &Help + @@ -135,12 +136,21 @@ false - + + .. &Close + + + + + + About Qt + + @@ -259,6 +269,22 @@ + + actionAboutQt + triggered() + Menu + openAboutQt() + + + -1 + -1 + + + 399 + 299 + + + openMapProperties() @@ -266,5 +292,6 @@ mapOpen() openAbout() updateActions() + openAboutQt() diff --git a/tycho/ui/project.ui b/tycho/ui/project.ui index d2ec69d..d5a21d4 100644 --- a/tycho/ui/project.ui +++ b/tycho/ui/project.ui @@ -15,7 +15,7 @@ - + QFrame::NoFrame @@ -31,6 +31,12 @@ Qt::ScrollBarAsNeeded + + QListView::IconMode + + + true +