Add missing nostalgia directory level in src tree
This commit is contained in:
18
src/nostalgia/CMakeLists.txt
Normal file
18
src/nostalgia/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
#setup libraries
|
||||
|
||||
if(NOT WOMBAT_BUILD_TYPE STREQUAL "GBA")
|
||||
find_package(Qt5Widgets)
|
||||
endif()
|
||||
|
||||
#project packages
|
||||
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(player)
|
||||
|
||||
if(NOT WOMBAT_BUILD_TYPE STREQUAL "GBA")
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(studio)
|
||||
endif()
|
2
src/nostalgia/Makefile
Normal file
2
src/nostalgia/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
make:
|
||||
make -j -C ../ ${ARGS}
|
17
src/nostalgia/common/CMakeLists.txt
Normal file
17
src/nostalgia/common/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
add_library(
|
||||
NostalgiaCommon
|
||||
bounds.cpp
|
||||
point.cpp
|
||||
)
|
||||
|
||||
#install(TARGETS NostalgiaCommon DESTINATION lib)
|
||||
install(
|
||||
FILES
|
||||
bounds.hpp
|
||||
common.hpp
|
||||
point.hpp
|
||||
DESTINATION
|
||||
include/wombat/common
|
||||
)
|
41
src/nostalgia/common/bounds.cpp
Normal file
41
src/nostalgia/common/bounds.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include "bounds.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace common {
|
||||
|
||||
Bounds::Bounds() {
|
||||
}
|
||||
|
||||
bool Bounds::intersects(Bounds o) const {
|
||||
return o.x2() >= X && x2() >= o.X && o.y2() >= Y && y2() >= o.Y;
|
||||
}
|
||||
|
||||
bool Bounds::contains(int x, int y) const {
|
||||
return x >= X && y >= Y && x <= x2() && y <= y2();
|
||||
}
|
||||
|
||||
int Bounds::x2() const {
|
||||
return X + Width;
|
||||
}
|
||||
|
||||
int Bounds::y2() const {
|
||||
return Y + Height;
|
||||
}
|
||||
|
||||
Point Bounds::pt1() {
|
||||
return Point(X, Y);
|
||||
}
|
||||
|
||||
Point Bounds::pt2() {
|
||||
return Point(x2(), y2());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
41
src/nostalgia/common/bounds.hpp
Normal file
41
src/nostalgia/common/bounds.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "point.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace common {
|
||||
|
||||
class Bounds {
|
||||
public:
|
||||
int X = 0;
|
||||
int Y = 0;
|
||||
int Width = 0;
|
||||
int Height = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Bounds();
|
||||
|
||||
bool intersects(Bounds other) const;
|
||||
|
||||
bool contains(int x, int y) const;
|
||||
|
||||
int x2() const;
|
||||
|
||||
int y2() const;
|
||||
|
||||
Point pt1();
|
||||
|
||||
Point pt2();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
14
src/nostalgia/common/common.hpp
Normal file
14
src/nostalgia/common/common.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#ifndef NOSTALGIA_COMMON_COMMON_HPP
|
||||
#define NOSTALGIA_COMMON_COMMON_HPP
|
||||
|
||||
#include "bounds.hpp"
|
||||
#include "point.hpp"
|
||||
|
||||
#endif
|
125
src/nostalgia/common/point.cpp
Normal file
125
src/nostalgia/common/point.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include "point.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace common {
|
||||
|
||||
Point::Point() {
|
||||
}
|
||||
|
||||
Point::Point(int x, int y) {
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
Point Point::operator+(common::Point p) const {
|
||||
p.X += X;
|
||||
p.Y += Y;
|
||||
return p;
|
||||
}
|
||||
|
||||
Point Point::operator-(common::Point p) const {
|
||||
auto out = *this;
|
||||
out.X -= p.X;
|
||||
out.Y -= p.Y;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator*(common::Point p) const {
|
||||
p.X *= X;
|
||||
p.Y *= Y;
|
||||
return p;
|
||||
}
|
||||
|
||||
Point Point::operator/(common::Point p) const {
|
||||
auto out = *this;
|
||||
out.X /= p.X;
|
||||
out.Y /= p.Y;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator+=(common::Point p) {
|
||||
X += p.X;
|
||||
Y += p.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator-=(common::Point p) {
|
||||
X -= p.X;
|
||||
Y -= p.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator*=(common::Point p) {
|
||||
X *= p.X;
|
||||
Y *= p.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator/=(common::Point p) {
|
||||
X /= p.X;
|
||||
Y /= p.Y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Point Point::operator+(int i) const {
|
||||
auto out = *this;
|
||||
out.X += i;
|
||||
out.Y += i;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator-(int i) const {
|
||||
auto out = *this;
|
||||
out.X -= i;
|
||||
out.Y -= i;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator*(int i) const {
|
||||
auto out = *this;
|
||||
out.X *= i;
|
||||
out.Y *= i;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator/(int i) const {
|
||||
auto out = *this;
|
||||
out.X /= i;
|
||||
out.Y /= i;
|
||||
return out;
|
||||
}
|
||||
|
||||
Point Point::operator+=(int i) {
|
||||
X += i;
|
||||
Y += i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator-=(int i) {
|
||||
X -= i;
|
||||
Y -= i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator*=(int i) {
|
||||
X *= i;
|
||||
Y *= i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Point Point::operator/=(int i) {
|
||||
X /= i;
|
||||
Y /= i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
59
src/nostalgia/common/point.hpp
Normal file
59
src/nostalgia/common/point.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace nostalgia {
|
||||
namespace common {
|
||||
|
||||
class Point {
|
||||
public:
|
||||
int X = 0;
|
||||
int Y = 0;
|
||||
|
||||
Point();
|
||||
|
||||
Point(int x, int y);
|
||||
|
||||
Point operator+(common::Point p) const;
|
||||
|
||||
Point operator-(common::Point p) const;
|
||||
|
||||
Point operator*(common::Point p) const;
|
||||
|
||||
Point operator/(common::Point p) const;
|
||||
|
||||
|
||||
Point operator+=(common::Point p);
|
||||
|
||||
Point operator-=(common::Point p);
|
||||
|
||||
Point operator*=(common::Point p);
|
||||
|
||||
Point operator/=(common::Point p);
|
||||
|
||||
|
||||
Point operator+(int i) const;
|
||||
|
||||
Point operator-(int i) const;
|
||||
|
||||
Point operator*(int i) const;
|
||||
|
||||
Point operator/(int i) const;
|
||||
|
||||
|
||||
Point operator+=(int i);
|
||||
|
||||
Point operator-=(int i);
|
||||
|
||||
Point operator*=(int i);
|
||||
|
||||
Point operator/=(int i);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
33
src/nostalgia/core/CMakeLists.txt
Normal file
33
src/nostalgia/core/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
if(WOMBAT_BUILD_TYPE STREQUAL "GBA")
|
||||
enable_language(C ASM)
|
||||
set(
|
||||
CPP
|
||||
gba/gfx.cpp
|
||||
gba/media.cpp
|
||||
)
|
||||
elseif(WOMBAT_BUILD_TYPE STREQUAL "Native")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
set(
|
||||
CPP
|
||||
qt/gfx.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
NostalgiaCore
|
||||
${CPP}
|
||||
core.cpp
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
core.hpp
|
||||
gfx.hpp
|
||||
gba/gba.hpp
|
||||
DESTINATION
|
||||
include/nostalgia/core
|
||||
)
|
20
src/nostalgia/core/core.cpp
Normal file
20
src/nostalgia/core/core.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include <ox/std/types.hpp>
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
ox::Error init() {
|
||||
auto err = initGfx();
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
18
src/nostalgia/core/core.hpp
Normal file
18
src/nostalgia/core/core.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
ox::Error init();
|
||||
|
||||
}
|
||||
}
|
48
src/nostalgia/core/gba/addresses.hpp
Normal file
48
src/nostalgia/core/gba/addresses.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// I/O Registers
|
||||
|
||||
#define REG_DISPCNT *((volatile uint32_t*) 0x04000000)
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// background registers
|
||||
|
||||
// background control registers
|
||||
#define REG_BG0CNT *((volatile uint32_t*) 0x04000008)
|
||||
#define REG_BG1CNT *((volatile uint32_t*) 0x0400000a)
|
||||
#define REG_BG2CNT *((volatile uint32_t*) 0x0400000c)
|
||||
#define REG_BG3CNT *((volatile uint32_t*) 0x0400000e)
|
||||
|
||||
// background horizontal scrolling registers
|
||||
#define REG_BG0HOFS *((volatile uint32_t*) 0x04000010)
|
||||
#define REG_BG1HOFS *((volatile uint32_t*) 0x04000014)
|
||||
#define REG_BG2HOFS *((volatile uint32_t*) 0x04000018)
|
||||
#define REG_BG3HOFS *((volatile uint32_t*) 0x0400001c)
|
||||
|
||||
// background vertical scrolling registers
|
||||
#define REG_BG0VOFS *((volatile uint32_t*) 0x04000012)
|
||||
#define REG_BG1VOFS *((volatile uint32_t*) 0x04000016)
|
||||
#define REG_BG2VOFS *((volatile uint32_t*) 0x0400001a)
|
||||
#define REG_BG3VOFS *((volatile uint32_t*) 0x0400001e)
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Memory Addresses
|
||||
|
||||
#define MEM_PALLETE_BG ((uint16_t*) 0x05000000)
|
||||
#define MEM_PALLETE_SPRITE ((uint16_t*) 0x05000200)
|
||||
|
||||
typedef uint16_t BgMapTile[1024];
|
||||
#define MEM_BG_MAP ((BgMapTile*) 0x06000000)
|
||||
|
||||
#define MEM_ROM *((uint8_t*) 0x08000000)
|
36
src/nostalgia/core/gba/gba.hpp
Normal file
36
src/nostalgia/core/gba/gba.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
typedef struct { uint32_t data[8]; } __attribute__((aligned(4))) Tile, Tile4;
|
||||
// d-tile: double-sized tile (8bpp)
|
||||
typedef struct { uint32_t data[16]; } __attribute__((aligned(4))) Tile8;
|
||||
// tile block: 32x16 tiles, 16x16 d-tiles
|
||||
typedef uint16_t Palette[256];
|
||||
typedef Tile CharBlock[512];
|
||||
typedef Tile8 CharBlock8[256];
|
||||
|
||||
struct __attribute__((packed)) GbaImageDataHeader {
|
||||
uint8_t bpp;
|
||||
uint16_t tileCount;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) GbaImageData {
|
||||
GbaImageDataHeader header;
|
||||
Palette __attribute__((packed)) pal;
|
||||
uint8_t tiles[1];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
161
src/nostalgia/core/gba/gfx.cpp
Normal file
161
src/nostalgia/core/gba/gfx.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/fs/filesystem.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
#include "addresses.hpp"
|
||||
#include "media.hpp"
|
||||
#include "gba.hpp"
|
||||
#include "../gfx.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
using namespace ox::fs;
|
||||
|
||||
#define TILE_ADDR ((CharBlock*) 0x06000000)
|
||||
#define TILE8_ADDR ((CharBlock8*) 0x06000000)
|
||||
|
||||
// map ASCII values to the nostalgia charset
|
||||
static char charMap[128] = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
38, // !
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
37, // ,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
27, // 0
|
||||
28, // 1
|
||||
29, // 2
|
||||
30, // 3
|
||||
31, // 4
|
||||
32, // 5
|
||||
33, // 6
|
||||
34, // 7
|
||||
35, // 8
|
||||
36, // 9
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1, // A
|
||||
2, // B
|
||||
3, // C
|
||||
4, // D
|
||||
5, // E
|
||||
6, // F
|
||||
7, // G
|
||||
8, // H
|
||||
9, // I
|
||||
10, // J
|
||||
11, // K
|
||||
12, // L
|
||||
13, // M
|
||||
14, // N
|
||||
15, // O
|
||||
16, // P
|
||||
17, // Q
|
||||
18, // R
|
||||
19, // S
|
||||
20, // T
|
||||
21, // U
|
||||
22, // V
|
||||
23, // W
|
||||
24, // X
|
||||
25, // Y
|
||||
26, // Z
|
||||
};
|
||||
|
||||
ox::Error initGfx() {
|
||||
/* Sprite Mode ----\ */
|
||||
/* ---\| */
|
||||
/* Background 0 -\|| */
|
||||
/* Objects -----\||| */
|
||||
/* |||| */
|
||||
REG_DISPCNT = 0x1100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initConsole() {
|
||||
auto charsetInode = 101;
|
||||
auto fs = (FileStore32*) findMedia();
|
||||
|
||||
GbaImageDataHeader imgData;
|
||||
fs->read(101, 0, sizeof(imgData), &imgData, nullptr);
|
||||
|
||||
REG_BG0CNT = (28 << 8) | 1;
|
||||
if (fs) {
|
||||
// load palette
|
||||
fs->read(charsetInode, sizeof(GbaImageDataHeader),
|
||||
512, (uint16_t*) &MEM_PALLETE_BG[0], nullptr);
|
||||
|
||||
if (imgData.bpp == 4) {
|
||||
fs->read(charsetInode, __builtin_offsetof(GbaImageData, tiles),
|
||||
sizeof(Tile) * imgData.tileCount, (uint16_t*) &TILE_ADDR[0][1], nullptr);
|
||||
} else {
|
||||
REG_BG0CNT |= (1 << 7); // set to use 8 bits per pixel
|
||||
fs->read(charsetInode, __builtin_offsetof(GbaImageData, tiles),
|
||||
sizeof(Tile8) * imgData.tileCount, (uint16_t*) &TILE8_ADDR[0][1], nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void puts(int loc, const char *str) {
|
||||
for (int i = 0; str[i]; i++) {
|
||||
MEM_BG_MAP[28][loc + i] = charMap[(int) str[i]];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
36
src/nostalgia/core/gba/media.cpp
Normal file
36
src/nostalgia/core/gba/media.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/fs/filesystem.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
#include "addresses.hpp"
|
||||
#include "media.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
uint8_t *findMedia() {
|
||||
// put the header in the wrong order to prevent mistaking this code for the
|
||||
// media section
|
||||
const static auto headerP2 = "_HEADER_________";
|
||||
const static auto headerP1 = "NOSTALGIA_MEDIA";
|
||||
const static auto headerP1Len = 15;
|
||||
const static auto headerP2Len = 16;
|
||||
const static auto headerLen = headerP1Len + headerP2Len + 1;
|
||||
|
||||
for (auto current = &MEM_ROM; current < ((uint8_t*) 0x0a000000); current += headerLen) {
|
||||
if (ox_memcmp(current, headerP1, headerP1Len) == 0 &&
|
||||
ox_memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) {
|
||||
return current + headerLen;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
19
src/nostalgia/core/gba/media.hpp
Normal file
19
src/nostalgia/core/gba/media.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
uint8_t *findMedia();
|
||||
|
||||
}
|
||||
}
|
22
src/nostalgia/core/gfx.hpp
Normal file
22
src/nostalgia/core/gfx.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
ox::Error initGfx();
|
||||
|
||||
void initConsole();
|
||||
|
||||
void puts(int loc, const char *str);
|
||||
|
||||
}
|
||||
}
|
25
src/nostalgia/core/qt/gfx.cpp
Normal file
25
src/nostalgia/core/qt/gfx.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace core {
|
||||
|
||||
ox::Error initGfx() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initConsole() {
|
||||
}
|
||||
|
||||
void puts(int loc, const char *str) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
26
src/nostalgia/player/CMakeLists.txt
Normal file
26
src/nostalgia/player/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(nostalgia)
|
||||
|
||||
add_executable(
|
||||
nostalgia
|
||||
main.cpp
|
||||
)
|
||||
|
||||
if(COMMAND OBJCOPY_FILE)
|
||||
set_target_properties(nostalgia
|
||||
PROPERTIES
|
||||
LINK_FLAGS ${LINKER_FLAGS}
|
||||
COMPILER_FLAGS "-mthumb -mthumb-interwork"
|
||||
)
|
||||
|
||||
OBJCOPY_FILE(nostalgia)
|
||||
#PADBIN_FILE(nostalgia)
|
||||
endif()
|
||||
|
||||
target_link_libraries(
|
||||
nostalgia
|
||||
NostalgiaCore
|
||||
OxStd
|
||||
OxFS
|
||||
)
|
20
src/nostalgia/player/main.cpp
Normal file
20
src/nostalgia/player/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <nostalgia/core/core.hpp>
|
||||
|
||||
using namespace nostalgia;
|
||||
|
||||
int main() {
|
||||
core::init();
|
||||
core::initConsole();
|
||||
core::puts(9 * 32 + 8, "HELLO,WORLD!");
|
||||
core::puts(10 * 32 + 8, "01234 56789");
|
||||
while (1);
|
||||
return 0;
|
||||
}
|
35
src/nostalgia/studio/CMakeLists.txt
Normal file
35
src/nostalgia/studio/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(nostalgia-studio)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_executable(
|
||||
nostalgia-studio
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
nostalgia-studio
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
OxClArgs
|
||||
OxFS
|
||||
OxStd
|
||||
NostalgiaCommon
|
||||
NostalgiaCore
|
||||
NostalgiaStudio
|
||||
NostalgiaStudioJson
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
nostalgia-studio
|
||||
RUNTIME DESTINATION
|
||||
bin
|
||||
)
|
||||
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(json)
|
40
src/nostalgia/studio/json/CMakeLists.txt
Normal file
40
src/nostalgia/studio/json/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(NostalgiaStudioJson)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_library(
|
||||
NostalgiaStudioJson
|
||||
json_read.cpp
|
||||
json_write.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaStudioJson
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
json.hpp
|
||||
json_read.hpp
|
||||
json_write.hpp
|
||||
DESTINATION
|
||||
include/nostalgia/studio/json
|
||||
)
|
||||
|
||||
|
||||
add_executable(
|
||||
NostalgiaStudioJsonTest
|
||||
test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaStudioJsonTest
|
||||
NostalgiaStudioJson
|
||||
)
|
||||
|
||||
add_test("Test\\ NostalgiaStudioJson" NostalgiaStudioJsonTest)
|
31
src/nostalgia/studio/json/json.hpp
Normal file
31
src/nostalgia/studio/json/json.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json_read.hpp"
|
||||
#include "json_write.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
class JsonOperator {
|
||||
|
||||
public:
|
||||
virtual int op(QString fieldName, int *dest) = 0;
|
||||
|
||||
virtual int op(QString fieldName, bool *dest) = 0;
|
||||
|
||||
virtual int op(QString fieldName, double *dest) = 0;
|
||||
|
||||
virtual int op(QString fieldName, QString *dest) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
18
src/nostalgia/studio/json/json_operator.hpp
Normal file
18
src/nostalgia/studio/json/json_operator.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
}
|
||||
}
|
89
src/nostalgia/studio/json/json_read.cpp
Normal file
89
src/nostalgia/studio/json/json_read.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "json_read.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
JsonReader::JsonReader(QJsonObject &obj): m_src(obj) {
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QString fieldName, int *dest) {
|
||||
if (m_src.contains(fieldName)) {
|
||||
return op(m_src[fieldName], dest);
|
||||
} else {
|
||||
return JSON_ERR_FIELD_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QString fieldName, bool *dest) {
|
||||
if (m_src.contains(fieldName)) {
|
||||
return op(m_src[fieldName], dest);
|
||||
} else {
|
||||
return JSON_ERR_FIELD_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QString fieldName, double *dest) {
|
||||
if (m_src.contains(fieldName)) {
|
||||
return op(m_src[fieldName], dest);
|
||||
} else {
|
||||
return JSON_ERR_FIELD_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QString fieldName, QString *dest) {
|
||||
if (m_src.contains(fieldName)) {
|
||||
return op(m_src[fieldName], dest);
|
||||
} else {
|
||||
return JSON_ERR_FIELD_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ox::Error JsonReader::op(QJsonValueRef src, int *dest) {
|
||||
if (src.isDouble()) {
|
||||
*dest = src.toInt();
|
||||
return 0;
|
||||
} else {
|
||||
return JSON_ERR_UNEXPECTED_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QJsonValueRef src, bool *dest) {
|
||||
if (src.isBool()) {
|
||||
*dest = src.toBool();
|
||||
return 0;
|
||||
} else {
|
||||
return JSON_ERR_UNEXPECTED_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QJsonValueRef src, double *dest) {
|
||||
if (src.isDouble()) {
|
||||
*dest = src.toDouble();
|
||||
return 0;
|
||||
} else {
|
||||
return JSON_ERR_UNEXPECTED_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error JsonReader::op(QJsonValueRef src, QString *dest) {
|
||||
if (src.isString()) {
|
||||
*dest = src.toString();
|
||||
return 0;
|
||||
} else {
|
||||
return JSON_ERR_UNEXPECTED_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
83
src/nostalgia/studio/json/json_read.hpp
Normal file
83
src/nostalgia/studio/json/json_read.hpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include "json_operator.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
enum {
|
||||
JSON_ERR_FIELD_MISSING,
|
||||
JSON_ERR_UNEXPECTED_TYPE,
|
||||
};
|
||||
|
||||
class JsonReader {
|
||||
|
||||
private:
|
||||
QJsonObject &m_src;
|
||||
|
||||
public:
|
||||
JsonReader(QJsonObject &obj);
|
||||
|
||||
ox::Error op(QString fieldName, int *dest);
|
||||
|
||||
ox::Error op(QString fieldName, bool *dest);
|
||||
|
||||
ox::Error op(QString fieldName, double *dest);
|
||||
|
||||
ox::Error op(QString fieldName, QString *dest);
|
||||
|
||||
template<typename T>
|
||||
ox::Error op(QString fieldName, T *dest);
|
||||
|
||||
template<typename T>
|
||||
ox::Error op(QString fieldName, QVector<T> *dest);
|
||||
|
||||
private:
|
||||
ox::Error op(QJsonValueRef src, int *dest);
|
||||
|
||||
ox::Error op(QJsonValueRef src, bool *dest);
|
||||
|
||||
ox::Error op(QJsonValueRef src, double *dest);
|
||||
|
||||
ox::Error op(QJsonValueRef src, QString *dest);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error JsonReader::op(QString fieldName, T *dest) {
|
||||
auto obj = m_src[fieldName].toObject();
|
||||
auto reader = JsonReader(obj);
|
||||
return ioOp(&reader, dest);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error JsonReader::op(QString fieldName, QVector<T> *dest) {
|
||||
ox::Error err = 0;
|
||||
auto a = m_src[fieldName].toArray();
|
||||
dest->resize(a.size());
|
||||
for (int i = 0; i < dest->size(); i++) {
|
||||
err |= op(a[i], &dest->at(i));
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int read(QString json, T *dest) {
|
||||
auto obj = QJsonDocument::fromJson(json.toUtf8()).object();
|
||||
JsonReader rdr(obj);
|
||||
return ioOp(&rdr, dest);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
16
src/nostalgia/studio/json/json_write.cpp
Normal file
16
src/nostalgia/studio/json/json_write.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "json_write.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
|
||||
}
|
||||
}
|
16
src/nostalgia/studio/json/json_write.hpp
Normal file
16
src/nostalgia/studio/json/json_write.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
|
||||
}
|
||||
}
|
86
src/nostalgia/studio/json/test.cpp
Normal file
86
src/nostalgia/studio/json/test.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "json.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
using namespace nostalgia::studio;
|
||||
|
||||
struct TestStructNest {
|
||||
bool Bool;
|
||||
int Int;
|
||||
double Double;
|
||||
QString String;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int ioOp(T *io, TestStructNest *obj) {
|
||||
Error err = 0;
|
||||
err |= io->op("Bool", &obj->Bool);
|
||||
err |= io->op("Int", &obj->Int);
|
||||
err |= io->op("Double", &obj->Double);
|
||||
err |= io->op("String", &obj->String);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct TestStruct {
|
||||
bool Bool;
|
||||
int Int;
|
||||
double Double;
|
||||
QString String;
|
||||
TestStructNest Struct;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int ioOp(T *io, TestStruct *obj) {
|
||||
Error err = 0;
|
||||
err |= io->op("Bool", &obj->Bool);
|
||||
err |= io->op("Int", &obj->Int);
|
||||
err |= io->op("Double", &obj->Double);
|
||||
err |= io->op("String", &obj->String);
|
||||
err |= io->op("Struct", &obj->Struct);
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char **args) {
|
||||
int err = 0;
|
||||
auto json =
|
||||
"{"
|
||||
" \"Bool\": true,"
|
||||
" \"Int\": 42,"
|
||||
" \"Double\": 42.42,"
|
||||
" \"String\": \"Test String\","
|
||||
" \"Struct\": {"
|
||||
" \"Bool\": true,"
|
||||
" \"Int\": 42,"
|
||||
" \"Double\": 42.42,"
|
||||
" \"String\": \"Test String\""
|
||||
" }"
|
||||
"}";
|
||||
TestStruct ts;
|
||||
read(json, &ts);
|
||||
|
||||
cout << ts.Bool << endl;
|
||||
cout << ts.Int << endl;
|
||||
cout << ts.Double << endl;
|
||||
cout << ts.String.toStdString() << endl;
|
||||
|
||||
err |= !(ts.Bool) << 0;
|
||||
err |= !(ts.Int == 42) << 1;
|
||||
err |= !(ts.Double == 42.42) << 2;
|
||||
err |= !(ts.String == "Test String") << 3;
|
||||
|
||||
err |= !(ts.Struct.Bool) << 4;
|
||||
err |= !(ts.Struct.Int == 42) << 5;
|
||||
err |= !(ts.Struct.Double == 42.42) << 6;
|
||||
err |= !(ts.Struct.String == "Test String") << 7;
|
||||
|
||||
return err;
|
||||
}
|
37
src/nostalgia/studio/lib/CMakeLists.txt
Normal file
37
src/nostalgia/studio/lib/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(NostalgiaStudio)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_library(
|
||||
NostalgiaStudio
|
||||
newwizard.cpp
|
||||
oxfstreeview.cpp
|
||||
project.cpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
NostalgiaStudio
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaStudio
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
OxFS
|
||||
OxStd
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
newwizard.hpp
|
||||
oxfstreeview.hpp
|
||||
project.hpp
|
||||
DESTINATION
|
||||
include/nostalgia/studio/lib
|
||||
)
|
259
src/nostalgia/studio/lib/newwizard.cpp
Normal file
259
src/nostalgia/studio/lib/newwizard.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include "newwizard.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
using std::function;
|
||||
|
||||
WizardSelect::WizardSelect() {
|
||||
m_listWidget = new QListWidget(this);
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->addWidget(m_listWidget);
|
||||
setLayout(layout);
|
||||
|
||||
connect(m_listWidget, &QListWidget::currentRowChanged, this, &WizardSelect::itemSelected);
|
||||
connect(m_listWidget, &QListWidget::itemSelectionChanged, [this]() {
|
||||
m_complete = true;
|
||||
emit completeChanged();
|
||||
}
|
||||
);
|
||||
connect(m_listWidget, &QListWidget::doubleClicked, [this]() {
|
||||
wizard()->next();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void WizardSelect::initializePage() {
|
||||
emit completeChanged();
|
||||
}
|
||||
|
||||
void WizardSelect::addOption(QString name, function<QVector<QWizardPage*>()> makePage) {
|
||||
m_options[name] = makePage;
|
||||
m_listWidget->addItem(name);
|
||||
}
|
||||
|
||||
bool WizardSelect::isComplete() const {
|
||||
return m_complete;
|
||||
}
|
||||
|
||||
void WizardSelect::itemSelected(int row) {
|
||||
if (row > -1) {
|
||||
auto w = wizard();
|
||||
|
||||
if (nextId() > -1) {
|
||||
w->removePage(nextId());
|
||||
}
|
||||
|
||||
auto selected = m_listWidget->currentItem()->text();
|
||||
if (m_options.contains(selected)) {
|
||||
for (auto p : m_options[selected]()) {
|
||||
w->addPage(p);
|
||||
}
|
||||
// for some reason the continue button only appears correctly after remove runs
|
||||
w->removePage(w->addPage(new QWizardPage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WizardConclusionPage::WizardConclusionPage(QString msg, QVector<QString> fields) {
|
||||
m_baseMsg = msg;
|
||||
m_fields = fields;
|
||||
setLayout(new QVBoxLayout(this));
|
||||
}
|
||||
|
||||
WizardConclusionPage::~WizardConclusionPage() {
|
||||
}
|
||||
|
||||
void WizardConclusionPage::initializePage() {
|
||||
QString msg = m_baseMsg;
|
||||
for (auto field : m_fields) {
|
||||
msg = msg.arg(this->field(field).toString());
|
||||
}
|
||||
|
||||
auto text = new QLabel(msg, this);
|
||||
if (m_text) {
|
||||
layout()->replaceWidget(m_text, text);
|
||||
delete m_text;
|
||||
} else {
|
||||
layout()->addWidget(text);
|
||||
}
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
|
||||
WizardFormPage::WizardFormPage() {
|
||||
m_layout = new QGridLayout(this);
|
||||
m_layout->setColumnMinimumWidth(0, 20);
|
||||
this->setLayout(m_layout);
|
||||
}
|
||||
|
||||
WizardFormPage::~WizardFormPage() {
|
||||
for (auto l : m_subLayout) {
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
void WizardFormPage::initializePage() {
|
||||
for (auto it = m_fields.begin(); it != m_fields.end(); it++) {
|
||||
auto key = it.key();
|
||||
auto le = m_fields[key].lineEdit;
|
||||
auto defaultVal = it.value().defaultValue;
|
||||
if (le) {
|
||||
le->setText(defaultVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WizardFormPage::validatePage() {
|
||||
bool retval = true;
|
||||
|
||||
// check validators
|
||||
for (auto f : m_fields) {
|
||||
if (f.validator != nullptr) {
|
||||
if (f.validator(f.lineEdit->text()) != 0) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear error
|
||||
if (retval) {
|
||||
showValidationError("");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void WizardFormPage::addLineEdit(QString displayName, QString fieldName, QString defaultVal, function<int(QString)> validator) {
|
||||
auto lbl = new QLabel(displayName, this);
|
||||
auto le = new QLineEdit(this);
|
||||
lbl->setBuddy(le);
|
||||
|
||||
m_layout->addWidget(lbl, m_currentLine, 0);
|
||||
m_layout->addWidget(le, m_currentLine, 1);
|
||||
|
||||
auto field = &m_fields[fieldName];
|
||||
|
||||
field->defaultValue = defaultVal;
|
||||
field->lineEdit = le;
|
||||
field->validator = validator;
|
||||
|
||||
registerField(fieldName, le);
|
||||
|
||||
connect(le, &QLineEdit::textChanged, [this, fieldName, le, field](QString txt) {
|
||||
if (field->value == "" && txt != "") {
|
||||
m_validFields++;
|
||||
} else if (field->value != "" && txt == "") {
|
||||
m_validFields--;
|
||||
}
|
||||
field->value = txt;
|
||||
emit completeChanged();
|
||||
}
|
||||
);
|
||||
|
||||
m_currentLine++;
|
||||
}
|
||||
|
||||
void WizardFormPage::addDirBrowse(QString displayName, QString fieldName, QString defaultVal) {
|
||||
auto layout = new QHBoxLayout();
|
||||
auto lbl = new QLabel(displayName, this);
|
||||
auto le = new QLineEdit("", this);
|
||||
auto btn = new QPushButton("Browse...", this);
|
||||
lbl->setBuddy(le);
|
||||
|
||||
layout->addWidget(le);
|
||||
layout->addWidget(btn);
|
||||
m_layout->addWidget(lbl, m_currentLine, 0);
|
||||
m_layout->addLayout(layout, m_currentLine, 1);
|
||||
|
||||
m_subLayout.push_back(layout);
|
||||
m_fields[fieldName].defaultValue = defaultVal;
|
||||
m_fields[fieldName].lineEdit = le;
|
||||
m_fields[fieldName].validator = [this](QString path) {
|
||||
if (!QDir(path).exists()) {
|
||||
showValidationError(tr("Specified Project Path directory does not exist."));
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
registerField(fieldName, le);
|
||||
|
||||
connect(le, &QLineEdit::textChanged, [this, fieldName, le](QString txt) {
|
||||
if (m_fields[fieldName].value == "" && txt != "") {
|
||||
m_validFields++;
|
||||
} else if (m_fields[fieldName].value != "" && txt == "") {
|
||||
m_validFields--;
|
||||
}
|
||||
m_fields[fieldName].value = txt;
|
||||
emit completeChanged();
|
||||
}
|
||||
);
|
||||
|
||||
connect(btn, &QPushButton::clicked, [this, defaultVal, le]() {
|
||||
auto p = QFileDialog::getExistingDirectory(this, tr("Select Directory..."), defaultVal);
|
||||
if (p != "") {
|
||||
le->setText(p);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
m_currentLine++;
|
||||
}
|
||||
|
||||
void WizardFormPage::showValidationError(QString msg) {
|
||||
// create label if it is null
|
||||
if (!m_errorMsg) {
|
||||
m_errorMsg = new QLabel(this);
|
||||
m_layout->addWidget(m_errorMsg, m_currentLine, 0, m_currentLine, 2);
|
||||
|
||||
// set text color
|
||||
auto pal = m_errorMsg->palette();
|
||||
pal.setColor(m_errorMsg->backgroundRole(), Qt::red);
|
||||
pal.setColor(m_errorMsg->foregroundRole(), Qt::red);
|
||||
m_errorMsg->setPalette(pal);
|
||||
}
|
||||
|
||||
// set message
|
||||
if (msg != "") {
|
||||
m_errorMsg->setText(tr("Error: ") + msg);
|
||||
} else {
|
||||
m_errorMsg->setText("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Wizard::Wizard(QWidget *parent): QWizard(parent) {
|
||||
setWindowTitle(tr("New..."));
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
void Wizard::setAccept(std::function<void()> acceptFunc) {
|
||||
m_acceptFunc = acceptFunc;
|
||||
}
|
||||
|
||||
void Wizard::accept() {
|
||||
m_acceptFunc();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
111
src/nostalgia/studio/lib/newwizard.hpp
Normal file
111
src/nostalgia/studio/lib/newwizard.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <QDir>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
#include <QWizard>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
class WizardSelect: public QWizardPage {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QMap<QString, std::function<QVector<QWizardPage*>()>> m_options;
|
||||
QListWidget *m_listWidget = nullptr;
|
||||
bool m_complete = false;
|
||||
|
||||
public:
|
||||
WizardSelect();
|
||||
|
||||
void addOption(QString name, std::function<QVector<QWizardPage*>()> makePage);
|
||||
|
||||
void initializePage() override;
|
||||
|
||||
bool isComplete() const override;
|
||||
|
||||
private slots:
|
||||
void itemSelected(int row);
|
||||
};
|
||||
|
||||
|
||||
class WizardFormPage: public QWizardPage {
|
||||
Q_OBJECT
|
||||
private:
|
||||
struct Field {
|
||||
QString defaultValue = "";
|
||||
QString value = "";
|
||||
QLineEdit *lineEdit = nullptr;
|
||||
std::function<int(QString)> validator;
|
||||
};
|
||||
QLabel *m_errorMsg = nullptr;
|
||||
QGridLayout *m_layout = nullptr;
|
||||
QVector<QLayout*> m_subLayout;
|
||||
QMap<QString, Field> m_fields;
|
||||
int m_currentLine = 0;
|
||||
int m_validFields = 0;
|
||||
|
||||
public:
|
||||
WizardFormPage();
|
||||
|
||||
~WizardFormPage();
|
||||
|
||||
void initializePage() override;
|
||||
|
||||
bool validatePage() override;
|
||||
|
||||
void addLineEdit(QString displayName, QString fieldName,
|
||||
QString defaultVal = "",
|
||||
std::function<int(QString)> validator = [](QString) { return 0; });
|
||||
|
||||
void addDirBrowse(QString displayName, QString fieldName, QString defaultVal = QDir::homePath());
|
||||
|
||||
void showValidationError(QString msg);
|
||||
};
|
||||
|
||||
|
||||
class WizardConclusionPage: public QWizardPage {
|
||||
Q_OBJECT
|
||||
private:
|
||||
QString m_baseMsg = "";
|
||||
QLabel *m_text = nullptr;
|
||||
QVector<QString> m_fields;
|
||||
|
||||
public:
|
||||
WizardConclusionPage(QString msg, QVector<QString> field);
|
||||
|
||||
virtual ~WizardConclusionPage();
|
||||
|
||||
void initializePage() override;
|
||||
};
|
||||
|
||||
|
||||
class Wizard: public QWizard {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
std::function<void()> m_acceptFunc;
|
||||
|
||||
public:
|
||||
Wizard(QWidget *parent = 0);
|
||||
|
||||
void setAccept(std::function<void()> acceptFunc);
|
||||
|
||||
void accept();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
173
src/nostalgia/studio/lib/oxfstreeview.cpp
Normal file
173
src/nostalgia/studio/lib/oxfstreeview.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include "oxfstreeview.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
using namespace ox;
|
||||
|
||||
OxFSFile::OxFSFile(FileSystem *fs, QString path, OxFSFile *parentItem) {
|
||||
m_fs = fs;
|
||||
m_path = path;
|
||||
m_parentItem = parentItem;
|
||||
}
|
||||
|
||||
OxFSFile::~OxFSFile() {
|
||||
qDeleteAll(m_childItems);
|
||||
}
|
||||
|
||||
void OxFSFile::appendChild(OxFSFile*) {
|
||||
}
|
||||
|
||||
OxFSFile *OxFSFile::child(int row) {
|
||||
if (m_fs) {
|
||||
QVector<DirectoryListing<QString>> ls;
|
||||
m_fs->ls(m_path.toUtf8(), &ls);
|
||||
auto ch = new OxFSFile(m_fs, m_path + "/" + ls[row].name, this);
|
||||
m_childItems.push_back(ch);
|
||||
return ch;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int OxFSFile::childCount() const {
|
||||
if (m_fs) {
|
||||
QVector<DirectoryListing<QString>> ls;
|
||||
m_fs->ls(m_path.toUtf8(), &ls);
|
||||
return ls.size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int OxFSFile::columnCount() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant OxFSFile::data(int) const {
|
||||
return m_path.mid(m_path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
int OxFSFile::row() const {
|
||||
if (m_parentItem) {
|
||||
return m_parentItem->m_childItems.indexOf(const_cast<OxFSFile*>(this));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
OxFSFile *OxFSFile::parentItem() {
|
||||
return m_parentItem;
|
||||
}
|
||||
|
||||
|
||||
// OxFSModel
|
||||
|
||||
OxFSModel::OxFSModel(FileSystem *fs, QObject *parent) {
|
||||
m_rootItem = new OxFSFile(fs, "");
|
||||
}
|
||||
|
||||
OxFSModel::~OxFSModel() {
|
||||
if (m_rootItem) {
|
||||
delete m_rootItem;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OxFSModel::data(const QModelIndex &index, int role) const {
|
||||
if (!index.isValid() || role != Qt::DisplayRole) {
|
||||
return QVariant();
|
||||
} else {
|
||||
OxFSFile *item = static_cast<OxFSFile*>(index.internalPointer());
|
||||
return item->data(index.column());
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags OxFSModel::flags(const QModelIndex &index) const {
|
||||
if (!index.isValid()) {
|
||||
return 0;
|
||||
} else {
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OxFSModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
return QVariant();
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
return m_rootItem->data(section);
|
||||
} else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex OxFSModel::index(int row, int column, const QModelIndex &parent) const {
|
||||
if (!hasIndex(row, column, parent)) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
OxFSFile *parentItem;
|
||||
if (!parent.isValid()) {
|
||||
parentItem = m_rootItem;
|
||||
} else {
|
||||
parentItem = static_cast<OxFSFile*>(parent.internalPointer());
|
||||
}
|
||||
|
||||
OxFSFile *childItem = parentItem->child(row);
|
||||
if (childItem) {
|
||||
return createIndex(row, column, childItem);
|
||||
} else {
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex OxFSModel::parent(const QModelIndex &index) const {
|
||||
if (!index.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
OxFSFile *childItem = static_cast<OxFSFile*>(index.internalPointer());
|
||||
OxFSFile *parentItem = childItem->parentItem();
|
||||
if (parentItem == m_rootItem) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
|
||||
int OxFSModel::rowCount(const QModelIndex &parent) const {
|
||||
if (parent.column() > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OxFSFile *parentItem;
|
||||
if (!parent.isValid()) {
|
||||
parentItem = m_rootItem;
|
||||
} else {
|
||||
parentItem = static_cast<OxFSFile*>(parent.internalPointer());
|
||||
}
|
||||
|
||||
return parentItem->childCount();
|
||||
}
|
||||
|
||||
int OxFSModel::columnCount(const QModelIndex &parent) const {
|
||||
if (parent.isValid()) {
|
||||
return static_cast<OxFSFile*>(parent.internalPointer())->columnCount();
|
||||
} else {
|
||||
return m_rootItem->columnCount();
|
||||
}
|
||||
}
|
||||
|
||||
void OxFSModel::setupModelData(const QStringList &lines, OxFSFile *parent) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
79
src/nostalgia/studio/lib/oxfstreeview.hpp
Normal file
79
src/nostalgia/studio/lib/oxfstreeview.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QVector>
|
||||
#include <QVariant>
|
||||
|
||||
#include <ox/fs/filesystem.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
class OxFSFile {
|
||||
private:
|
||||
ox::FileSystem *m_fs = nullptr;
|
||||
OxFSFile *m_parentItem = nullptr;
|
||||
QString m_path;
|
||||
QVector<OxFSFile*> m_childItems;
|
||||
|
||||
public:
|
||||
OxFSFile(ox::FileSystem *fs, QString path, OxFSFile *parentItem = nullptr);
|
||||
|
||||
~OxFSFile();
|
||||
|
||||
void appendChild(OxFSFile *child);
|
||||
|
||||
OxFSFile *child(int row);
|
||||
|
||||
int childCount() const;
|
||||
|
||||
int columnCount() const;
|
||||
|
||||
QVariant data(int column) const;
|
||||
|
||||
int row() const;
|
||||
|
||||
OxFSFile *parentItem();
|
||||
};
|
||||
|
||||
class OxFSModel: public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
OxFSFile *m_rootItem = nullptr;
|
||||
|
||||
public:
|
||||
explicit OxFSModel(ox::FileSystem *fs, QObject *parent = 0);
|
||||
|
||||
~OxFSModel();
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
private:
|
||||
void setupModelData(const QStringList &lines, OxFSFile *parent);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
75
src/nostalgia/studio/lib/project.cpp
Normal file
75
src/nostalgia/studio/lib/project.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDir>
|
||||
#include <project.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
using namespace ox;
|
||||
|
||||
QString Project::ROM_FILE = "/ROM.oxfs";
|
||||
|
||||
Project::Project(QString path) {
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
Project::~Project() {
|
||||
if (m_fs) {
|
||||
delete m_fs;
|
||||
}
|
||||
}
|
||||
|
||||
void Project::create() {
|
||||
QDir().mkpath(m_path);
|
||||
|
||||
m_romBuff = QSharedPointer<QByteArray>(new QByteArray(1024, 0));
|
||||
FileSystem32::format(m_romBuff->data(), m_romBuff->size(), true);
|
||||
m_fs = createFileSystem(m_romBuff->data(), m_romBuff->size());
|
||||
|
||||
m_fs->mkdir("/Tilesets");
|
||||
|
||||
QFile file(m_path + ROM_FILE);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(*m_romBuff);
|
||||
file.close();
|
||||
}
|
||||
|
||||
int Project::open() {
|
||||
QFile file(m_path + ROM_FILE);
|
||||
m_romBuff = QSharedPointer<QByteArray>(new QByteArray(file.size(), 0));
|
||||
if (file.exists()) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
if (file.read(m_romBuff->data(), file.size()) > 0) {
|
||||
m_fs = createFileSystem(m_romBuff->data(), m_romBuff->size());
|
||||
|
||||
m_fs->mkdir("/Tilesets");
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Project::save() {
|
||||
QFile file(m_path + ROM_FILE);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(*m_romBuff);
|
||||
file.close();
|
||||
}
|
||||
|
||||
FileSystem *Project::romFS() {
|
||||
return m_fs;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
43
src/nostalgia/studio/lib/project.hpp
Normal file
43
src/nostalgia/studio/lib/project.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <ox/fs/filesystem.hpp>
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
class Project: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static QString ROM_FILE;
|
||||
|
||||
QString m_path = "";
|
||||
QSharedPointer<QByteArray> m_romBuff;
|
||||
ox::FileSystem *m_fs = nullptr;
|
||||
|
||||
public:
|
||||
Project(QString path);
|
||||
|
||||
~Project();
|
||||
|
||||
void create();
|
||||
|
||||
int open();
|
||||
|
||||
void save();
|
||||
|
||||
ox::FileSystem *romFS();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
44
src/nostalgia/studio/main.cpp
Normal file
44
src/nostalgia/studio/main.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <ox/clargs/clargs.hpp>
|
||||
#include "json/json.hpp"
|
||||
#include "mainwindow.hpp"
|
||||
|
||||
using namespace nostalgia::studio;
|
||||
using namespace ox;
|
||||
|
||||
int run(int argc, char **args) {
|
||||
ClArgs clargs(argc, (const char**) args);
|
||||
QString argProfilePath = clargs.getString("profile").c_str();
|
||||
|
||||
NostalgiaStudioProfile config;
|
||||
|
||||
// load in config file
|
||||
QFile file(argProfilePath);
|
||||
if (file.exists()) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QTextStream in(&file);
|
||||
read(in.readAll(), &config);
|
||||
}
|
||||
|
||||
QApplication app(argc, args);
|
||||
app.setApplicationName(config.appName);
|
||||
|
||||
MainWindow w(config);
|
||||
w.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
int main(int argc, char **args) {
|
||||
return run(argc, args);
|
||||
}
|
186
src/nostalgia/studio/mainwindow.cpp
Normal file
186
src/nostalgia/studio/mainwindow.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMenuBar>
|
||||
#include <QTabBar>
|
||||
#include <QVector>
|
||||
|
||||
#include "lib/newwizard.hpp"
|
||||
#include "lib/oxfstreeview.hpp"
|
||||
#include "lib/project.hpp"
|
||||
#include "mainwindow.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
MainWindow::MainWindow(NostalgiaStudioProfile config, QWidget *parent) {
|
||||
auto screenSize = QApplication::desktop()->screenGeometry();
|
||||
|
||||
// set window to 75% of screen width, and center NostalgiaStudioProfile
|
||||
auto sizePct = 0.75;
|
||||
resize(screenSize.width() * sizePct, screenSize.height() * sizePct);
|
||||
move(-x(), -y());
|
||||
move(screenSize.width() * (1 - sizePct) / 2, screenSize.height() * (1 - sizePct) / 2);
|
||||
|
||||
setWindowTitle(config.appName);
|
||||
|
||||
auto tabbar = new QTabBar(this);
|
||||
setCentralWidget(tabbar);
|
||||
|
||||
setupMenu();
|
||||
setupProjectExplorer();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
if (m_projectExplorer->model()) {
|
||||
delete m_projectExplorer->model();
|
||||
}
|
||||
for (auto f : m_cleanupTasks) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setupMenu() {
|
||||
auto menu = menuBar();
|
||||
auto fileMenu = menu->addMenu(tr("&File"));
|
||||
m_viewMenu = menu->addMenu(tr("&View"));
|
||||
|
||||
// New...
|
||||
addAction(
|
||||
fileMenu,
|
||||
tr("&New..."),
|
||||
tr(""),
|
||||
QKeySequence::New,
|
||||
this,
|
||||
SLOT(showNewWizard())
|
||||
);
|
||||
|
||||
// Open Project
|
||||
addAction(
|
||||
fileMenu,
|
||||
tr("&Open Project"),
|
||||
tr(""),
|
||||
QKeySequence::Open,
|
||||
this,
|
||||
SLOT(openProject())
|
||||
);
|
||||
|
||||
// Exit
|
||||
addAction(
|
||||
fileMenu,
|
||||
tr("E&xit"),
|
||||
tr("Exit the application"),
|
||||
QKeySequence::Quit,
|
||||
QApplication::quit
|
||||
);
|
||||
}
|
||||
|
||||
void MainWindow::setupProjectExplorer() {
|
||||
// setup dock
|
||||
auto dock = new QDockWidget(tr("&Project"), this);
|
||||
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||
addDockWidget(Qt::LeftDockWidgetArea, dock);
|
||||
resizeDocks({dock}, {(int) (width() * 0.25)}, Qt::Horizontal);
|
||||
|
||||
// setup tree view
|
||||
m_projectExplorer = new QTreeView(dock);
|
||||
m_projectExplorer->header()->hide();
|
||||
dock->setWidget(m_projectExplorer);
|
||||
}
|
||||
|
||||
void MainWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockWidget) {
|
||||
QMainWindow::addDockWidget(area, dockWidget);
|
||||
m_viewMenu->addAction(dockWidget->toggleViewAction());
|
||||
m_dockWidgets.push_back(dockWidget);
|
||||
}
|
||||
|
||||
void MainWindow::addAction(QMenu *menu, QString text, QString toolTip,
|
||||
QKeySequence::StandardKey key, const QObject *tgt, const char *cb) {
|
||||
auto action = menu->addAction(text);
|
||||
action->setShortcuts(key);
|
||||
action->setStatusTip(toolTip);
|
||||
auto conn = connect(action, SIGNAL(triggered()), tgt, cb);
|
||||
m_cleanupTasks.push_back([this, conn]() {
|
||||
QObject::disconnect(conn);
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::addAction(QMenu *menu, QString text, QString toolTip,
|
||||
QKeySequence::StandardKey key, void (*cb)()) {
|
||||
auto action = menu->addAction(text);
|
||||
action->setShortcuts(key);
|
||||
action->setStatusTip(toolTip);
|
||||
auto conn = connect(action, &QAction::triggered, cb);
|
||||
m_cleanupTasks.push_back([this, conn]() {
|
||||
QObject::disconnect(conn);
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::openProject() {
|
||||
auto p = QFileDialog::getExistingDirectory(this, tr("Select Project Directory..."), QDir::homePath());
|
||||
auto project = QSharedPointer<Project>(new Project(p));
|
||||
auto err = project->open();
|
||||
if (err == 0) {
|
||||
m_project = project;
|
||||
m_projectExplorer->setModel(new OxFSModel(m_project->romFS()));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showNewWizard() {
|
||||
const QString PROJECT_NAME = "projectName";
|
||||
const QString PROJECT_PATH = "projectPath";
|
||||
Wizard wizard;
|
||||
auto ws = new WizardSelect();
|
||||
wizard.addPage(ws);
|
||||
ws->addOption(tr("Project"),
|
||||
[&wizard, PROJECT_NAME, PROJECT_PATH]() {
|
||||
QVector<QWizardPage*> pgs;
|
||||
auto pg = new WizardFormPage();
|
||||
pg->addLineEdit(tr("Project &Name:"), PROJECT_NAME + "*", "", [PROJECT_PATH, pg, &wizard](QString projectName) {
|
||||
auto projectPath = wizard.field(PROJECT_PATH).toString();
|
||||
auto path = projectPath + "/" + projectName;
|
||||
if (!QDir(path).exists()) {
|
||||
return 0;
|
||||
} else {
|
||||
pg->showValidationError(tr("This project directory already exists."));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
);
|
||||
pg->addDirBrowse(tr("Project &Path:"), PROJECT_PATH + "*");
|
||||
pgs.push_back(pg);
|
||||
pgs.push_back(new WizardConclusionPage(tr("Creating project: ") + "%1/%2", {PROJECT_PATH, PROJECT_NAME}));
|
||||
|
||||
return pgs;
|
||||
}
|
||||
);
|
||||
wizard.setAccept([&wizard, ws, PROJECT_NAME, PROJECT_PATH]() {
|
||||
auto projectName = wizard.field(PROJECT_NAME).toString();
|
||||
auto projectPath = wizard.field(PROJECT_PATH).toString();
|
||||
if (QDir(projectPath).exists()) {
|
||||
auto path = projectPath + "/" + projectName;
|
||||
if (!QDir(path).exists()) {
|
||||
Project(path).create();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
wizard.show();
|
||||
wizard.exec();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
99
src/nostalgia/studio/mainwindow.hpp
Normal file
99
src/nostalgia/studio/mainwindow.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QMainWindow>
|
||||
#include <QModelIndex>
|
||||
#include <QPoint>
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QTreeView>
|
||||
#include <QVector>
|
||||
#include <functional>
|
||||
|
||||
#include <ox/std/types.hpp>
|
||||
|
||||
#include "lib/project.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
namespace studio {
|
||||
|
||||
struct NostalgiaStudioState {
|
||||
QString currentProjectPath;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int ioOp(T *io, NostalgiaStudioState *obj) {
|
||||
ox::Error err = 0;
|
||||
err |= io->op("current_project_path", &obj->currentProjectPath);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
struct NostalgiaStudioProfile {
|
||||
QString appName;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int ioOp(T *io, NostalgiaStudioProfile *obj) {
|
||||
ox::Error err = 0;
|
||||
err |= io->op("app_name", &obj->appName);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
class MainWindow: public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QString EditorSettings;
|
||||
static const QString AppTitle;
|
||||
|
||||
private:
|
||||
QSharedPointer<Project> m_project;
|
||||
QPointer<QMenu> m_viewMenu;
|
||||
QVector<std::function<void()>> m_cleanupTasks;
|
||||
QVector<QPointer<QDockWidget>> m_dockWidgets;
|
||||
QTreeView *m_projectExplorer = nullptr;
|
||||
|
||||
public:
|
||||
MainWindow(NostalgiaStudioProfile config, QWidget *parent = 0);
|
||||
|
||||
virtual ~MainWindow();
|
||||
|
||||
void openProject(QString);
|
||||
|
||||
private:
|
||||
void setupDockWidgets();
|
||||
|
||||
void setupMenu();
|
||||
|
||||
void setupProjectExplorer();
|
||||
|
||||
void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget);
|
||||
|
||||
void addAction(QMenu *menu, QString text, QString toolTip,
|
||||
QKeySequence::StandardKey key, const QObject *tgt, const char *cb);
|
||||
|
||||
void addAction(QMenu *menu, QString text, QString toolTip,
|
||||
QKeySequence::StandardKey key, void (*cb)());
|
||||
|
||||
int readSettings(QString path);
|
||||
|
||||
int writeSettings(QString path);
|
||||
|
||||
private slots:
|
||||
void openProject();
|
||||
|
||||
void showNewWizard();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
3
src/nostalgia/studio/profile.json
Normal file
3
src/nostalgia/studio/profile.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"app_name": "Nostalgia Studio"
|
||||
}
|
25
src/nostalgia/tools/CMakeLists.txt
Normal file
25
src/nostalgia/tools/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(nost-pack)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_executable(nost-pack pack.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
nost-pack
|
||||
Qt5::Widgets
|
||||
OxClArgs
|
||||
OxFS
|
||||
OxStd
|
||||
NostalgiaCommon
|
||||
NostalgiaCore
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
nost-pack
|
||||
RUNTIME DESTINATION
|
||||
bin
|
||||
)
|
159
src/nostalgia/tools/pack.cpp
Normal file
159
src/nostalgia/tools/pack.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2016-2017 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QMap>
|
||||
#include <nostalgia/core/gba/gba.hpp>
|
||||
#include <nostalgia/common/point.hpp>
|
||||
#include <ox/clargs/clargs.hpp>
|
||||
#include <ox/fs/filesystem.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
using namespace nostalgia::core;
|
||||
using namespace nostalgia::common;
|
||||
|
||||
uint8_t *loadFileBuff(QString path, ::size_t *sizeOut = nullptr) {
|
||||
auto file = fopen(path.toUtf8(), "rb");
|
||||
if (file) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
const auto size = ftell(file);
|
||||
rewind(file);
|
||||
auto buff = new uint8_t[size];
|
||||
auto itemsRead = fread(buff, size, 1, file);
|
||||
fclose(file);
|
||||
if (sizeOut) {
|
||||
*sizeOut = itemsRead ? size : 0;
|
||||
}
|
||||
return buff;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t toGbaColor(QColor c) {
|
||||
auto r = ((uint32_t) c.red()) >> 3;
|
||||
auto g = ((uint32_t) c.green()) >> 3;
|
||||
auto b = ((uint32_t) c.blue()) >> 3;
|
||||
return (r << 10) | (g << 5) | (b << 0);
|
||||
}
|
||||
|
||||
int pointToIdx(int w, int x, int y) {
|
||||
const auto colLength = 64;
|
||||
const auto rowLength = (w / 8) * colLength;
|
||||
const auto colStart = colLength * (x / 8);
|
||||
const auto rowStart = rowLength * (y / 8);
|
||||
const auto colOffset = x % 8;
|
||||
const auto rowOffset = (y % 8) * 8;
|
||||
return colStart + colOffset + rowStart + rowOffset;
|
||||
}
|
||||
|
||||
int run(ClArgs args) {
|
||||
Error err = 0;
|
||||
int argInode = args.getInt("inode");
|
||||
QString argInPath = args.getString("img").c_str();
|
||||
QString argFsPath = args.getString("fs").c_str();
|
||||
auto argCompact = args.getBool("c");
|
||||
auto argTiles = args.getInt("tiles");
|
||||
auto argBpp = args.getInt("bpp");
|
||||
|
||||
QImage src(argInPath);
|
||||
|
||||
if (!src.isNull()) {
|
||||
if (argTiles == 0) {
|
||||
argTiles = (src.width() * src.height()) / 64;
|
||||
}
|
||||
if (argBpp != 4 && argBpp != 8) {
|
||||
argBpp = 8;
|
||||
}
|
||||
|
||||
QMap<QRgb, int> colors;
|
||||
const auto imgDataBuffSize = sizeof(GbaImageData) + 1 + argTiles * 64;
|
||||
uint8_t imgDataBuff[imgDataBuffSize];
|
||||
memset(&imgDataBuff, 0, imgDataBuffSize);
|
||||
GbaImageData *id = (GbaImageData*) imgDataBuff;
|
||||
id->header.bpp = argBpp;
|
||||
id->header.tileCount = argTiles;
|
||||
int colorId = 0;
|
||||
|
||||
// copy pixels as color ids
|
||||
for (int x = 0; x < src.colorCount(); x++) {
|
||||
for (int y = 0; y < src.colorCount(); y++) {
|
||||
auto destI = pointToIdx(src.width(), x, y);
|
||||
if (destI <= argTiles * 64) {
|
||||
auto c = src.pixel(x, y);
|
||||
// assign color a color id for the palette
|
||||
if (!colors.contains(c)) {
|
||||
colors[c] = colorId;
|
||||
colorId++;
|
||||
}
|
||||
// set pixel color
|
||||
if (argBpp == 4) {
|
||||
if (destI % 2) { // is odd number pixel
|
||||
id->tiles[destI / 2] |= colors[c] << 4;
|
||||
} else {
|
||||
id->tiles[destI / 2] |= colors[c];
|
||||
}
|
||||
} else {
|
||||
id->tiles[destI] = colors[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// store colors in palette with the corresponding color id
|
||||
for (auto key : colors.keys()) {
|
||||
auto colorId = colors[key];
|
||||
id->pal[colorId] = toGbaColor(key);
|
||||
}
|
||||
|
||||
|
||||
size_t fsBuffSize;
|
||||
auto fsBuff = loadFileBuff(argFsPath, &fsBuffSize);
|
||||
if (fsBuff && !err) {
|
||||
auto fs = createFileSystem(fsBuff, fsBuffSize);
|
||||
|
||||
if (fs) {
|
||||
fs = expandCopyCleanup(fs, fs->size() + fs->spaceNeeded(imgDataBuffSize));
|
||||
fsBuff = fs->buff(); // update fsBuff pointer in case there is a new buff
|
||||
err |= fs->write(argInode, imgDataBuff, imgDataBuffSize);
|
||||
|
||||
if (argCompact) {
|
||||
fs->resize();
|
||||
}
|
||||
|
||||
auto fsFile = fopen(argFsPath.toUtf8(), "wb");
|
||||
if (fsFile) {
|
||||
err = fwrite(fsBuff, fs->size(), 1, fsFile) != 1;
|
||||
err |= fclose(fsFile);
|
||||
if (err) {
|
||||
cerr << "Could not write to file system file.\n";
|
||||
}
|
||||
} else {
|
||||
err = 2;
|
||||
}
|
||||
|
||||
delete fs;
|
||||
} else {
|
||||
err = 3;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] fsBuff;
|
||||
} else {
|
||||
err = 4;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
return run(ClArgs(argc, args));
|
||||
}
|
Reference in New Issue
Block a user