tycho: make the project view use icons

master
an 2019-07-01 01:25:54 -04:00
parent 14c0ef8f2a
commit e3c0b0dd7d
16 changed files with 219 additions and 76 deletions

View File

@ -9,6 +9,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror")
find_package( find_package(
Qt5 5.6.0 Qt5 5.6.0
@ -22,11 +23,14 @@ add_library(
SHARED SHARED
$ENV{OUT_DIR}/bindings.cc $ENV{OUT_DIR}/bindings.cc
$ENV{OUT_DIR}/bindings.h $ENV{OUT_DIR}/bindings.h
cc_headers/mapmodel.h
cc_headers/mapprops.h cc_headers/mapprops.h
cc_headers/menu.h cc_headers/menu.h
cc_headers/project.h cc_headers/project.h
cc_headers/tycho.h cc_headers/tycho.h
cc_source/cc.cc
cc_source/main.cc cc_source/main.cc
cc_source/mapmodel.cc
cc_source/mapprops.cc cc_source/mapprops.cc
cc_source/menu.cc cc_source/menu.cc
cc_source/project.cc cc_source/project.cc
@ -60,6 +64,14 @@ target_link_libraries(
Qt5::Widgets 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) install(TARGETS maraiah-tycho-hermes)
## EOF ## EOF

View File

@ -6,8 +6,8 @@
"implementationModule": "gui" "implementationModule": "gui"
}, },
"objects": { "objects": {
"MapModel": { "AbstractMapModel": {
"type": "Tree", "type": "List",
"functions": { "functions": {
"open": { "open": {
"return": "bool", "return": "bool",
@ -32,18 +32,22 @@
"isDirty": { "isDirty": {
"return": "bool", "return": "bool",
"mut": false "mut": false
},
"propIcon": {
"return": "QString",
"mut": false,
"arguments": [{
"name": "index",
"type": "quint16"
}]
} }
}, },
"properties": { "properties": {
}, },
"itemProperties": { "itemProperties": {
"rowName": { "propIndex": {
"type": "quint64", "type": "quint64",
"roles": [["display"]] "roles": [["display"]]
},
"someNumber": {
"type": "quint64",
"roles": [[], ["display"]]
} }
} }
} }

View File

@ -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

View File

@ -19,6 +19,7 @@ public slots:
void mapNew(); void mapNew();
void mapOpen(); void mapOpen();
void openAbout(); void openAbout();
void openAboutQt();
void openMapProperties(); void openMapProperties();
void updateActions(); void updateActions();

View File

@ -4,6 +4,8 @@
#include "../ui/ui_project.h" #include "../ui/ui_project.h"
class MapModel;
class ProjectModel class ProjectModel
{ {
public: public:

10
tycho/cc_source/cc.cc Normal file
View File

@ -0,0 +1,10 @@
#include "tycho.h"
#include <QMessageBox>
extern "C" {
void critical_msg(char const *title, char const *msg) {
QMessageBox::critical(nullptr, QObject::tr(title), QObject::tr(msg));
}
}
// EOF

View File

@ -0,0 +1,28 @@
#include "tycho.h"
#include "mapmodel.h"
#include <QIcon>
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

View File

@ -2,12 +2,14 @@
#include "mapprops.h" #include "mapprops.h"
#include "menu.h" #include "menu.h"
#include "project.h" #include "project.h"
#include "mapmodel.h"
#include "../ui/ui_about.h" #include "../ui/ui_about.h"
#include "../ui/ui_license.h" #include "../ui/ui_license.h"
#include <QCloseEvent> #include <QCloseEvent>
#include <QFileDialog> #include <QFileDialog>
#include <QMdiSubWindow> #include <QMdiSubWindow>
#include <QMessageBox>
#include <iostream> #include <iostream>
Menu::Menu(QWidget *parent) : Menu::Menu(QWidget *parent) :
@ -44,13 +46,18 @@ void Menu::mapOpen()
this, this,
tr("Open Map File"), tr("Open Map File"),
QString(), 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 (*)"));
if(!fname.isEmpty()) {
QScopedPointer proj{new Project(new MapModel)}; QScopedPointer proj{new Project(new MapModel)};
if(proj->model.open(fname)) { if(proj->model.open(fname)) {
addProject(proj.take()); addProject(proj.take());
} }
}
} }
void Menu::openAbout() void Menu::openAbout()
@ -77,6 +84,11 @@ void Menu::openAbout()
dlg.exec(); dlg.exec();
} }
void Menu::openAboutQt()
{
QMessageBox::aboutQt(this);
}
void Menu::openLicense(QWidget *parent) void Menu::openLicense(QWidget *parent)
{ {
QDialog dlg{parent}; QDialog dlg{parent};

View File

@ -1,5 +1,6 @@
#include "tycho.h" #include "tycho.h"
#include "project.h" #include "project.h"
#include "mapmodel.h"
#include <QCloseEvent> #include <QCloseEvent>
#include <QMessageBox> #include <QMessageBox>
@ -22,6 +23,7 @@ ProjectModel::~ProjectModel()
{ {
switch(modelType) { switch(modelType) {
case Map: delete modelMap; break; case Map: delete modelMap; break;
case Invalid: break;
} }
} }
@ -34,8 +36,8 @@ QAbstractItemModel *ProjectModel::getAbstract() const
{ {
switch(modelType) { switch(modelType) {
case Map: return modelMap; case Map: return modelMap;
case Invalid: Q_UNREACHABLE();
} }
Q_UNREACHABLE();
} }
MapModel *ProjectModel::getMap() const MapModel *ProjectModel::getMap() const
@ -47,6 +49,7 @@ bool ProjectModel::isDirty() const
{ {
switch(modelType) { switch(modelType) {
case Map: return modelMap->isDirty(); case Map: return modelMap->isDirty();
case Invalid: Q_UNREACHABLE();
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -55,6 +58,7 @@ bool ProjectModel::open(QString const &path)
{ {
switch(modelType) { switch(modelType) {
case Map: return modelMap->open(path); case Map: return modelMap->open(path);
case Invalid: Q_UNREACHABLE();
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -63,6 +67,7 @@ bool ProjectModel::saveAs(QString const &path) const
{ {
switch(modelType) { switch(modelType) {
case Map: return modelMap->saveAs(path); case Map: return modelMap->saveAs(path);
case Invalid: Q_UNREACHABLE();
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -71,6 +76,7 @@ bool ProjectModel::save() const
{ {
switch(modelType) { switch(modelType) {
case Map: return modelMap->save(); case Map: return modelMap->save();
case Invalid: Q_UNREACHABLE();
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -86,7 +92,7 @@ Project::Project(ProjectModel &&_model, QWidget *parent) :
setWidget(widget); setWidget(widget);
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
treeView->setModel(model.getAbstract()); listView->setModel(model.getAbstract());
dbgPrintFunc(); dbgPrintFunc();
} }
@ -117,8 +123,7 @@ void Project::closeEvent(QCloseEvent *event)
event->ignore(); event->ignore();
return; return;
default: default:
assert(true); Q_UNREACHABLE();
break;
} }
} }

21
tycho/source/cc.rs Normal file
View File

@ -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<T, U>(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

View File

@ -1,8 +1,8 @@
//! GUI implementation. //! GUI implementation.
mod ffi;
mod map; mod map;
mod qobj;
pub use self::map::MapModel; pub use self::map::AbstractMapModel;
// EOF // EOF

View File

@ -1,69 +1,63 @@
//! Map model. //! Map model.
use super::ffi::*; use super::qobj::*;
use maraiah::map; use maraiah::{backtrace, err::*, map::{self, data::*}};
use memmap::Mmap; use crate::cc;
fn open_f(path: String) -> ResultS<map::Map> impl AbstractMapModel
{ {
let fp = std::fs::File::open(path)?; pub fn open_map(path: String) -> ResultS<EntryDataMap>
let mm = unsafe { Mmap::map(&fp) }?;
map::read(&mm)
}
impl MapModelTrait for MapModel
{
/// Returns a new `MapModel` instance.
fn new(emit: MapModelEmitter, model: MapModelTree) -> Self
{ {
if cfg!(debug_assertions) { let mut fp = maraiah::file::open_mac(path)?;
eprintln!("new MapModel");
let map = map::head::read(&mut fp)?;
let ent = map::entr::read_all(&map)?;
map::data::read_all(map.head(), &ent)
} }
Self { emit, pub fn get(&self, index: usize) -> (&u16, &EntryData)
model, {
map: map::Map::default() } 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 AbstractMapModelTrait for AbstractMapModel
{
/// Returns a new `AbstractMapModel` instance.
fn new(emit: AbstractMapModelEmitter, _: AbstractMapModelList) -> Self
{
if cfg!(debug_assertions) {
eprintln!("new AbstractMapModel");
}
Self{emit, map: EntryDataMap::default()}
} }
/// Returns the emitter of `self`. /// 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 row_count(&self) -> usize {self.map.len()}
fn check_row(&self, index: usize, _row: usize) -> Option<usize> { None }
/// Returns the row `index` is in. fn prop_index(&self, index: usize) -> u64 {(*self.get(index).0).into()}
fn row(&self, index: usize) -> usize { index }
/// Returns the number of rows in `index`. fn prop_icon(&self, index: u16) -> String
fn row_count(&self, index: Option<usize>) -> usize
{ {
match index { match self.get(index.into()).1.get_type() {
Some(_) => 0, EntryType::Image => "image-x-generic".to_string(),
None => 7, 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<usize>, 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<usize>
{
// 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`. /// Opens the map file at `path`.
fn open(&mut self, path: String) -> bool fn open(&mut self, path: String) -> bool
{ {
@ -71,13 +65,18 @@ impl MapModelTrait for MapModel
eprintln!("opening project: {}", &path); eprintln!("opening project: {}", &path);
} }
if let Ok(map) = open_f(&mm) { match Self::open_map(path) {
Ok(map) => {
self.map = map; self.map = map;
true true
} else { }
Err(e) => {
backtrace!(e);
cc::critical_msg("Error opening map", e);
false false
} }
} }
}
/// Saves the project into the original file. /// Saves the project into the original file.
fn save(&self) -> bool fn save(&self) -> bool
@ -100,24 +99,22 @@ impl MapModelTrait for MapModel
} }
/// Returns `true` if the file has been modified from its original state. /// 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) fn drop(&mut self)
{ {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
eprintln!("drop MapModel"); eprintln!("drop AbstractMapModel");
} }
} }
} }
pub struct MapModel pub struct AbstractMapModel {
{ emit: AbstractMapModelEmitter,
emit: MapModelEmitter, map: EntryDataMap,
model: MapModelTree,
map: map::Map,
} }
// EOF // EOF

View File

@ -1,5 +1,6 @@
use maraiah::{err::*, ffi}; use maraiah::{err::*, ffi};
mod cc;
mod gui; mod gui;
mod meta; mod meta;

View File

@ -76,6 +76,7 @@
<string>&amp;Help</string> <string>&amp;Help</string>
</property> </property>
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
<addaction name="actionAboutQt"/>
</widget> </widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuEdit"/> <addaction name="menuEdit"/>
@ -135,12 +136,21 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="icon"> <property name="icon">
<iconset theme="window-close"/> <iconset theme="window-close">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Close</string> <string>&amp;Close</string>
</property> </property>
</action> </action>
<action name="actionAboutQt">
<property name="icon">
<iconset theme="help-about"/>
</property>
<property name="text">
<string>About Qt</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>
@ -259,6 +269,22 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>actionAboutQt</sender>
<signal>triggered()</signal>
<receiver>Menu</receiver>
<slot>openAboutQt()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections> </connections>
<slots> <slots>
<slot>openMapProperties()</slot> <slot>openMapProperties()</slot>
@ -266,5 +292,6 @@
<slot>mapOpen()</slot> <slot>mapOpen()</slot>
<slot>openAbout()</slot> <slot>openAbout()</slot>
<slot>updateActions()</slot> <slot>updateActions()</slot>
<slot>openAboutQt()</slot>
</slots> </slots>
</ui> </ui>

View File

@ -15,7 +15,7 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QTreeView" name="treeView"> <widget class="QListView" name="listView">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
@ -31,6 +31,12 @@
<property name="horizontalScrollBarPolicy"> <property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum> <enum>Qt::ScrollBarAsNeeded</enum>
</property> </property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>