mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-20 02:11:29 +02:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6ea4bc031f | ||
|
676a3adbf7 | ||
|
b27e0a719d | ||
|
a62aa94b65 | ||
|
9762a092d2 | ||
|
05526571e7 | ||
|
3bd29088d1 | ||
|
26643a43de | ||
|
7e8958b102 | ||
|
edac93b800 | ||
|
0730f847e5 | ||
|
5ae0c80ee8 | ||
|
d0ef8e7488 | ||
|
6c3aec7dc9 | ||
|
4016ae1d43 | ||
|
9e53c51b58 | ||
|
ce2b543679 | ||
|
1a29b59225 | ||
|
1926561ced | ||
|
e2db2c24fc | ||
|
8a53e9ed22 | ||
|
5286481d8d | ||
|
440a59c879 | ||
|
96e9333ec2 | ||
|
775c111fef | ||
|
3ffa44cef9 | ||
|
f28d70f9e6 | ||
|
73fdbf893f | ||
|
da5263bfc3 | ||
|
449a3ad426 |
@@ -1,7 +1,7 @@
|
||||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := compatibility
|
||||
ui := ui-qt
|
||||
profile := accuracy
|
||||
ui := ui-phoenix
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
@@ -62,9 +62,11 @@ endif
|
||||
install:
|
||||
ifeq ($(platform),x)
|
||||
install -D -m 755 out/bsnes $(DESTDIR)$(prefix)/bin/bsnes
|
||||
install -D -m 644 qt/data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||
install -D -m 644 qt/data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||
gconftool-2 --type bool --set /desktop/gnome/interface/menus_have_icons true
|
||||
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
|
||||
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
|
||||
test -d ~/.bsnes || mkdir ~/.bsnes
|
||||
cp data/cheats.xml ~/.bsnes/cheats.xml
|
||||
chmod 777 ~/.bsnes ~/.bsnes/cheats.xml
|
||||
endif
|
||||
|
||||
uninstall:
|
||||
@@ -88,6 +90,6 @@ clean: ui_clean
|
||||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
|
||||
tar -cjf bsnes.tar.bz2 data launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="*"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
File diff suppressed because it is too large
Load Diff
@@ -16,10 +16,10 @@ int main(int argc, char **argv) {
|
||||
unused = realpath(nall::utf8_t(argw[0]), path);
|
||||
#endif
|
||||
string realPath = dir(path);
|
||||
string basePath = string(dir(path), "bsnes.cfg");
|
||||
string basePath = string(dir(path), "bsnes-qt.cfg");
|
||||
unused = userpath(path);
|
||||
if(!strend(path, "/") && !strend(path, "\\")) strcat(path, "/");
|
||||
string userPath = string(path, ".bsnes/bsnes.cfg");
|
||||
string userPath = string(path, ".bsnes/bsnes-qt.cfg");
|
||||
|
||||
configuration config;
|
||||
string profile;
|
||||
|
@@ -8,8 +8,8 @@
|
||||
#include "x86.c"
|
||||
#elif defined(__GNUC__) && defined(__amd64__)
|
||||
#include "amd64.c"
|
||||
#elif defined(__GNUC__) && defined(__powerpc__) && defined(__ELF__)
|
||||
#include "ppc-elf.c"
|
||||
#elif defined(__GNUC__) && defined(_ARCH_PPC)
|
||||
#include "ppc.c"
|
||||
#elif defined(__GNUC__)
|
||||
#include "sjlj.c"
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
libco
|
||||
version: 0.15 (2009-10-12)
|
||||
version: 0.16 (2010-12-24)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
|
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
* libco.ppc-elf
|
||||
* author: Kernigh
|
||||
* license: public domain
|
||||
*
|
||||
* PowerPC 32-bit ELF implementation of libco (for compile with GCC),
|
||||
* ported from PowerPC Mac OS X implementation (ppc.s) by Vas Crabb.
|
||||
* This ELF version works for OpenBSD, and might also work for FreeBSD,
|
||||
* NetBSD and Linux.
|
||||
*
|
||||
* Note 1: This implementation does not handle the AltiVec/VMX
|
||||
* registers, because the ELF ABI does not mention them,
|
||||
* and my OpenBSD system is not using them.
|
||||
*
|
||||
* Note 2: If you want position-independent code, then you must
|
||||
* define __PIC__. gcc -fpic or -fPIC defines __PIC__, but
|
||||
* gcc -fpie or -fPIE might not. If you want to use -fpie
|
||||
* or -fPIE, then you might need a manual definition:
|
||||
* gcc -fpie -D__PIC__=1
|
||||
* gcc -fPIE -D__PIC__=2
|
||||
*
|
||||
* The ELF ABI is "System V Application Binary Interface, PowerPC
|
||||
* Processor Supplement", which you can get from
|
||||
* <http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf>
|
||||
* (PDF file, hosted by Linux Foundation).
|
||||
*
|
||||
* ELF and Mac OS X use similar conventions to allocate the registers,
|
||||
* and to pass arguments and return values through registers. The main
|
||||
* differences are that ELF has a slightly different stack format, that
|
||||
* symbols are different (and without an extra underscore at the start),
|
||||
* and that the assembly syntax is different.
|
||||
*
|
||||
* A function may destroy the values of volatile registers, but must
|
||||
* preserve the values of nonvolatile registers. So the co_switch()
|
||||
* function only saves the nonvolatile registers.
|
||||
*
|
||||
* [nonvolatile registers in ELF]
|
||||
* %r1, %r14..%r31
|
||||
* %f14..%f31
|
||||
* %cr2..%cr4 in cr
|
||||
*
|
||||
* [volatile registers in ELF]
|
||||
* %r0, %r3..%r10
|
||||
* %f0..%f13
|
||||
* %cr0, %cr1, %cr5..%cr7 in cr
|
||||
* ctr, lr, xer
|
||||
*
|
||||
* lr (link register) is volatile, but it contains the return address,
|
||||
* so co_switch must save lr.
|
||||
*
|
||||
* %r13 is the small data pointer. This is constant across threads, so
|
||||
* co_switch() does not touch %r13.
|
||||
*
|
||||
* %r2 is a reserved register, so co_switch() does not touch %r2. Some
|
||||
* systems might borrow an idea from the PowerPC Embedded ABI, and might
|
||||
* use %r2 as a small read-only data pointer, which is constant across
|
||||
* threads.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void * cothread_t;
|
||||
|
||||
/*
|
||||
* co_active_context is either in a global offset table (if we are
|
||||
* compiling -fPIC or -fPIE) or has an absolute position.
|
||||
*/
|
||||
static void *co_main_stack_pointer;
|
||||
static cothread_t co_active_context = &co_main_stack_pointer;
|
||||
|
||||
extern cothread_t co_active() {
|
||||
return co_active_context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Embedded assembly.
|
||||
*
|
||||
* We are not using the percent-sign substitution feature,
|
||||
* so we must write "%r1", not "%%r1".
|
||||
*
|
||||
* We always write 'bl malloc@plt', not 'bl malloc'. The '@plt'
|
||||
* is necessary in position-indepent code and seems to have no
|
||||
* significant effect in fixed-position code.
|
||||
*
|
||||
* We never use the 'lmw' or 'stmw' instructions. The ELF ABI
|
||||
* mentions that these instructions "are usually slower than
|
||||
* a sequence of other instructions that have the same effect."
|
||||
* We instead use sequences of 'lwz' or 'stz' instructions.
|
||||
*/
|
||||
__asm__("\n"
|
||||
"### embedded assembly \n"
|
||||
".section \".text\" \n"
|
||||
" .balign 4 \n"
|
||||
" \n"
|
||||
/*
|
||||
* void co_switch(co_thread to %r3)
|
||||
*
|
||||
* Allocate our stack frame of 240 bytes:
|
||||
* Old New Value
|
||||
* 4(%r1) 244(%r1) return address, used by us
|
||||
* 0(%r1) 240(%r1) frame pointer
|
||||
* 232(%r1) %f31
|
||||
* 224(%r1) %f30
|
||||
* ...
|
||||
* 96(%r1) %f14
|
||||
* 92(%r1) %r31
|
||||
* 88(%r1) %r30
|
||||
* ...
|
||||
* 24(%r1) %r14
|
||||
* 20(%r1) condition register
|
||||
* 8(%r1) padding of 12 bytes
|
||||
* 4(%r1) return address, never used
|
||||
* 0(%r1) frame pointer
|
||||
*
|
||||
* Save our registers in our stack frame.
|
||||
* Save our stack pointer in 0(%r4).
|
||||
* Switch to the stack of the other thread.
|
||||
* Restore registers and return.
|
||||
*/
|
||||
" .globl co_switch \n"
|
||||
" .type co_switch, @function \n"
|
||||
"co_switch: \n"
|
||||
" mflr %r0 # %r0 = return address \n"
|
||||
" mfcr %r9 # %r9 = condition register \n"
|
||||
" stwu %r1, -240(%r1) # allocate stack frame \n"
|
||||
" \n"
|
||||
" stw %r0, 244(%r1) # save return address \n"
|
||||
" stfd %f31, 232(%r1) # save floating-point regs \n"
|
||||
" stfd %f30, 224(%r1) \n"
|
||||
" stfd %f29, 216(%r1) \n"
|
||||
" stfd %f28, 208(%r1) \n"
|
||||
" stfd %f27, 200(%r1) \n"
|
||||
" stfd %f26, 192(%r1) \n"
|
||||
" stfd %f25, 184(%r1) \n"
|
||||
" stfd %f24, 176(%r1) \n"
|
||||
" stfd %f23, 168(%r1) \n"
|
||||
" stfd %f22, 160(%r1) \n"
|
||||
" stfd %f21, 152(%r1) \n"
|
||||
" stfd %f20, 144(%r1) \n"
|
||||
" stfd %f19, 136(%r1) \n"
|
||||
" stfd %f18, 128(%r1) \n"
|
||||
" stfd %f17, 120(%r1) \n"
|
||||
" stfd %f16, 112(%r1) \n"
|
||||
" stfd %f16, 104(%r1) \n"
|
||||
" stfd %f14, 96(%r1) \n"
|
||||
" stw %r31, 92(%r1) # save general-purpose regs \n"
|
||||
" stw %r30, 88(%r1) \n"
|
||||
" stw %r29, 84(%r1) \n"
|
||||
" stw %r28, 80(%r1) \n"
|
||||
" stw %r27, 76(%r1) \n"
|
||||
" stw %r26, 72(%r1) \n"
|
||||
" stw %r25, 68(%r1) \n"
|
||||
" stw %r24, 64(%r1) \n"
|
||||
" stw %r23, 60(%r1) \n"
|
||||
" stw %r22, 56(%r1) \n"
|
||||
" stw %r21, 52(%r1) \n"
|
||||
" stw %r20, 48(%r1) \n"
|
||||
" stw %r19, 44(%r1) \n"
|
||||
" stw %r18, 40(%r1) \n"
|
||||
" stw %r17, 36(%r1) \n"
|
||||
" stw %r16, 32(%r1) \n"
|
||||
" stw %r15, 28(%r1) \n"
|
||||
" stw %r14, 24(%r1) \n"
|
||||
" stw %r9, 20(%r1) # save condition reg \n"
|
||||
" \n"
|
||||
" # save current context, set new context \n"
|
||||
" # %r4 = co_active_context \n"
|
||||
" # co_active_context = %r3 \n"
|
||||
#if __PIC__ == 2
|
||||
" # position-independent code, large model (-fPIC) \n"
|
||||
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
|
||||
" mflr %r8 # %r8 = address of got \n"
|
||||
" addis %r7, %r8, co_active_context@got@ha \n"
|
||||
" lwz %r6, co_active_context@got@l(%r7) \n"
|
||||
" lwz %r4, 0(%r6) \n"
|
||||
" stw %r3, 0(%r6) \n"
|
||||
#elif __PIC__ == 1
|
||||
" # position-independent code, small model (-fpic) \n"
|
||||
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
|
||||
" mflr %r8 # %r8 = address of got \n"
|
||||
" lwz %r7, co_active_context@got(%r8) \n"
|
||||
" lwz %r4, 0(%r7) \n"
|
||||
" stw %r3, 0(%r7) \n"
|
||||
#else
|
||||
" # fixed-position code \n"
|
||||
" lis %r8, co_active_context@ha \n"
|
||||
" lwz %r4, co_active_context@l(%r8) \n"
|
||||
" stw %r3, co_active_context@l(%r8) \n"
|
||||
#endif
|
||||
" \n"
|
||||
" # save current stack pointer \n"
|
||||
" stw %r1, 0(%r4) \n"
|
||||
" # get new stack pointer \n"
|
||||
" lwz %r1, 0(%r3) \n"
|
||||
" \n"
|
||||
" lwz %r0, 244(%r1) # get return address \n"
|
||||
" lfd %f31, 232(%r1) # restore floating-point regs \n"
|
||||
" lfd %f30, 224(%r1) \n"
|
||||
" lfd %f29, 216(%r1) \n"
|
||||
" lfd %f28, 208(%r1) \n"
|
||||
" lfd %f27, 200(%r1) \n"
|
||||
" lfd %f26, 192(%r1) \n"
|
||||
" lfd %f25, 184(%r1) \n"
|
||||
" lfd %f24, 176(%r1) \n"
|
||||
" lfd %f23, 168(%r1) \n"
|
||||
" lfd %f22, 160(%r1) \n"
|
||||
" lfd %f21, 152(%r1) \n"
|
||||
" lfd %f20, 144(%r1) \n"
|
||||
" lfd %f19, 136(%r1) \n"
|
||||
" lfd %f18, 128(%r1) \n"
|
||||
" lfd %f17, 120(%r1) \n"
|
||||
" lfd %f16, 112(%r1) \n"
|
||||
" lfd %f16, 104(%r1) \n"
|
||||
" lfd %f14, 96(%r1) \n"
|
||||
" lwz %r31, 92(%r1) # restore general-purpose regs \n"
|
||||
" lwz %r30, 88(%r1) \n"
|
||||
" lwz %r29, 84(%r1) \n"
|
||||
" lwz %r28, 80(%r1) \n"
|
||||
" lwz %r27, 76(%r1) \n"
|
||||
" lwz %r26, 72(%r1) \n"
|
||||
" lwz %r25, 68(%r1) \n"
|
||||
" lwz %r24, 64(%r1) \n"
|
||||
" lwz %r23, 60(%r1) \n"
|
||||
" lwz %r22, 56(%r1) \n"
|
||||
" lwz %r21, 52(%r1) \n"
|
||||
" lwz %r20, 48(%r1) \n"
|
||||
" lwz %r19, 44(%r1) \n"
|
||||
" lwz %r18, 40(%r1) \n"
|
||||
" lwz %r17, 36(%r1) \n"
|
||||
" lwz %r16, 32(%r1) \n"
|
||||
" lwz %r15, 28(%r1) \n"
|
||||
" lwz %r14, 24(%r1) \n"
|
||||
" lwz %r9, 20(%r1) # get condition reg \n"
|
||||
" \n"
|
||||
" addi %r1, %r1, 240 # free stack frame \n"
|
||||
" mtlr %r0 # restore return address \n"
|
||||
" mtcr %r9 # restore condition register \n"
|
||||
" blr # return \n"
|
||||
" .size co_switch, . - co_switch \n"
|
||||
" \n"
|
||||
/*
|
||||
* cothread_t %r3 co_create(unsigned int stack_size %r3,
|
||||
* void (*coentry %r4)())
|
||||
*
|
||||
* Allocate a new stack, such that when you co_switch to that
|
||||
* stack, then co_switch returns to coentry.
|
||||
*/
|
||||
" .globl co_create \n"
|
||||
" .type co_create, @function \n"
|
||||
"co_create: \n"
|
||||
" mflr %r0 # %r0 = return address \n"
|
||||
" stwu %r1, -16(%r1) # allocate my stack frame \n"
|
||||
" stw %r0, 20(%r1) # save return address \n"
|
||||
" stw %r31, 12(%r1) # save %r31 \n"
|
||||
" stw %r30, 8(%r1) # save %r30 \n"
|
||||
" \n"
|
||||
" mr %r30, %r3 # %r30 = stack_size \n"
|
||||
" mr %r31, %r4 # %r31 = coentry \n"
|
||||
" \n"
|
||||
" # Call malloc(stack_size %r3) to allocate stack; \n"
|
||||
" # malloc() probably uses good alignment. \n"
|
||||
" # \n"
|
||||
" bl malloc@plt # returns %r3 = low end \n"
|
||||
" cmpwi %r3, 0 # if returned NULL, \n"
|
||||
" beq- 1f # then abort \n"
|
||||
" \n"
|
||||
" # we return %r3 = low end of stack \n"
|
||||
" add %r4, %r3, %r30 # %r4 = high end of stack \n"
|
||||
" \n"
|
||||
" # uncomment if malloc() uses wrong alignment \n"
|
||||
" #rlwinm %r4,%r4,0,0,27 # force 16-byte alignment \n"
|
||||
" \n"
|
||||
/*
|
||||
* Allocate two stack frames:
|
||||
* 16 bytes for stack frame with return address
|
||||
* 240 bytes for co_switch stack frame
|
||||
*
|
||||
* Old New Value
|
||||
* -8(%r4) 248(%r5) padding of 8 bytes
|
||||
* -12(%r4) 244(%r5) return address = coentry
|
||||
* -16(%r4) 240(%r5) frame pointer = NULL
|
||||
* 232(%r5) %f31 = 0
|
||||
* ...
|
||||
* 20(%r5) condition register = 0
|
||||
* 0(%r5) frame pointer
|
||||
*/
|
||||
" li %r9, (240-20)/4+1 \n"
|
||||
" addi %r5, %r4, -16 # allocate first stack frame \n"
|
||||
" li %r0, 0 \n"
|
||||
" stwu %r5, -240(%r5) # allocate second stack frame \n"
|
||||
" li %r8, 20 \n"
|
||||
" mtctr %r9 # loop %r9 times \n"
|
||||
"2: # loop to store zero to 20(%r5) through 240(%r5) \n"
|
||||
" stwx %r0, %r5, %r8 \n"
|
||||
" addi %r8, %r8, 4 # index += 4 \n"
|
||||
" bdnz+ 2b # ctr -= 1, branch if nonzero \n"
|
||||
" \n"
|
||||
" stw %r31, 244(%r5) # return address = coentry \n"
|
||||
" stw %r5, 0(%r3) # save stack pointer \n"
|
||||
" \n"
|
||||
" lwz %r0, 20(%r1) # get return address \n"
|
||||
" lwz %r31, 12(%r1) # restore %r31 \n"
|
||||
" lwz %r30, 8(%r1) # restore %r30 \n"
|
||||
" mtlr %r0 # restore return address \n"
|
||||
" addi %r1, %r1, 16 # free stack frame \n"
|
||||
" blr # return \n"
|
||||
" \n"
|
||||
"1: b abort@plt # branch 1f to abort \n"
|
||||
" .size co_create, . - co_create \n"
|
||||
" \n"
|
||||
/*
|
||||
* void co_delete(cothread_t) => void free(void *)
|
||||
*/
|
||||
" .globl co_delete \n"
|
||||
" .type co_delete, @function \n"
|
||||
"co_delete: \n"
|
||||
" b free@plt \n"
|
||||
" \n"
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
407
bsnes/libco/ppc.c
Executable file
407
bsnes/libco/ppc.c
Executable file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
libco.ppc (2010-10-17)
|
||||
author: blargg
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
/* PowerPC 32/64 using embedded or external asm, with optional
|
||||
floating-point and AltiVec save/restore */
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
|
||||
|
||||
#if LIBCO_MPROTECT
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* State format (offsets in 32-bit words)
|
||||
|
||||
+0 Pointer to swap code
|
||||
Rest of function descriptor for entry function
|
||||
+8 PC
|
||||
+10 SP
|
||||
Special regs
|
||||
GPRs
|
||||
FPRs
|
||||
VRs
|
||||
stack
|
||||
*/
|
||||
|
||||
enum { state_size = 1024 };
|
||||
enum { above_stack = 2048 };
|
||||
enum { stack_align = 256 };
|
||||
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
|
||||
/**** Determine environment ****/
|
||||
|
||||
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
|
||||
|
||||
/* Whether function calls are indirect through a descriptor,
|
||||
or are directly to function */
|
||||
#ifndef LIBCO_PPCDESC
|
||||
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
|
||||
#define LIBCO_PPCDESC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LIBCO_PPC_ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
/* Swap code is in ppc.S */
|
||||
void co_swap_asm( cothread_t, cothread_t );
|
||||
#define CO_SWAP_ASM( x, y ) co_swap_asm( x, y )
|
||||
|
||||
#else
|
||||
|
||||
/* Swap code is here in array. Please leave dieassembly comments,
|
||||
as they make it easy to see what it does, and reorder instructions
|
||||
if one wants to see whether that improves performance. */
|
||||
static const uint32_t libco_ppc_code [] = {
|
||||
#if LIBCO_PPC64
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0xf8240028, /* std r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0xf9c40048, /* std r14,72(r4) */
|
||||
0xf9e40050, /* std r15,80(r4) */
|
||||
0xfa040058, /* std r16,88(r4) */
|
||||
0xfa240060, /* std r17,96(r4) */
|
||||
0xfa440068, /* std r18,104(r4) */
|
||||
0xfa640070, /* std r19,112(r4) */
|
||||
0xfa840078, /* std r20,120(r4) */
|
||||
0xfaa40080, /* std r21,128(r4) */
|
||||
0xfac40088, /* std r22,136(r4) */
|
||||
0xfae40090, /* std r23,144(r4) */
|
||||
0xfb040098, /* std r24,152(r4) */
|
||||
0xfb2400a0, /* std r25,160(r4) */
|
||||
0xfb4400a8, /* std r26,168(r4) */
|
||||
0xfb6400b0, /* std r27,176(r4) */
|
||||
0xfb8400b8, /* std r28,184(r4) */
|
||||
0xfba400c0, /* std r29,192(r4) */
|
||||
0xfbc400c8, /* std r30,200(r4) */
|
||||
0xfbe400d0, /* std r31,208(r4) */
|
||||
0xf9240020, /* std r9,32(r4) */
|
||||
0xe8e30020, /* ld r7,32(r3) */
|
||||
0xe8230028, /* ld r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030,/*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0xe9c30048, /* ld r14,72(r3) */
|
||||
0xe9e30050, /* ld r15,80(r3) */
|
||||
0xea030058, /* ld r16,88(r3) */
|
||||
0xea230060, /* ld r17,96(r3) */
|
||||
0xea430068, /* ld r18,104(r3) */
|
||||
0xea630070, /* ld r19,112(r3) */
|
||||
0xea830078, /* ld r20,120(r3) */
|
||||
0xeaa30080, /* ld r21,128(r3) */
|
||||
0xeac30088, /* ld r22,136(r3) */
|
||||
0xeae30090, /* ld r23,144(r3) */
|
||||
0xeb030098, /* ld r24,152(r3) */
|
||||
0xeb2300a0, /* ld r25,160(r3) */
|
||||
0xeb4300a8, /* ld r26,168(r3) */
|
||||
0xeb6300b0, /* ld r27,176(r3) */
|
||||
0xeb8300b8, /* ld r28,184(r3) */
|
||||
0xeba300c0, /* ld r29,192(r3) */
|
||||
0xebc300c8, /* ld r30,200(r3) */
|
||||
0xebe300d0, /* ld r31,208(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#else
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0x90240028, /* stw r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0x91a4003c, /* stw r13,60(r4) */
|
||||
0x91c40040, /* stw r14,64(r4) */
|
||||
0x91e40044, /* stw r15,68(r4) */
|
||||
0x92040048, /* stw r16,72(r4) */
|
||||
0x9224004c, /* stw r17,76(r4) */
|
||||
0x92440050, /* stw r18,80(r4) */
|
||||
0x92640054, /* stw r19,84(r4) */
|
||||
0x92840058, /* stw r20,88(r4) */
|
||||
0x92a4005c, /* stw r21,92(r4) */
|
||||
0x92c40060, /* stw r22,96(r4) */
|
||||
0x92e40064, /* stw r23,100(r4) */
|
||||
0x93040068, /* stw r24,104(r4) */
|
||||
0x9324006c, /* stw r25,108(r4) */
|
||||
0x93440070, /* stw r26,112(r4) */
|
||||
0x93640074, /* stw r27,116(r4) */
|
||||
0x93840078, /* stw r28,120(r4) */
|
||||
0x93a4007c, /* stw r29,124(r4) */
|
||||
0x93c40080, /* stw r30,128(r4) */
|
||||
0x93e40084, /* stw r31,132(r4) */
|
||||
0x91240020, /* stw r9,32(r4) */
|
||||
0x80e30020, /* lwz r7,32(r3) */
|
||||
0x80230028, /* lwz r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030,/*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0x81a3003c, /* lwz r13,60(r3) */
|
||||
0x81c30040, /* lwz r14,64(r3) */
|
||||
0x81e30044, /* lwz r15,68(r3) */
|
||||
0x82030048, /* lwz r16,72(r3) */
|
||||
0x8223004c, /* lwz r17,76(r3) */
|
||||
0x82430050, /* lwz r18,80(r3) */
|
||||
0x82630054, /* lwz r19,84(r3) */
|
||||
0x82830058, /* lwz r20,88(r3) */
|
||||
0x82a3005c, /* lwz r21,92(r3) */
|
||||
0x82c30060, /* lwz r22,96(r3) */
|
||||
0x82e30064, /* lwz r23,100(r3) */
|
||||
0x83030068, /* lwz r24,104(r3) */
|
||||
0x8323006c, /* lwz r25,108(r3) */
|
||||
0x83430070, /* lwz r26,112(r3) */
|
||||
0x83630074, /* lwz r27,116(r3) */
|
||||
0x83830078, /* lwz r28,120(r3) */
|
||||
0x83a3007c, /* lwz r29,124(r3) */
|
||||
0x83c30080, /* lwz r30,128(r3) */
|
||||
0x83e30084, /* lwz r31,132(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#endif
|
||||
|
||||
#ifndef LIBCO_PPC_NOFP
|
||||
0xd9c400e0, /* stfd f14,224(r4) */
|
||||
0xd9e400e8, /* stfd f15,232(r4) */
|
||||
0xda0400f0, /* stfd f16,240(r4) */
|
||||
0xda2400f8, /* stfd f17,248(r4) */
|
||||
0xda440100, /* stfd f18,256(r4) */
|
||||
0xda640108, /* stfd f19,264(r4) */
|
||||
0xda840110, /* stfd f20,272(r4) */
|
||||
0xdaa40118, /* stfd f21,280(r4) */
|
||||
0xdac40120, /* stfd f22,288(r4) */
|
||||
0xdae40128, /* stfd f23,296(r4) */
|
||||
0xdb040130, /* stfd f24,304(r4) */
|
||||
0xdb240138, /* stfd f25,312(r4) */
|
||||
0xdb440140, /* stfd f26,320(r4) */
|
||||
0xdb640148, /* stfd f27,328(r4) */
|
||||
0xdb840150, /* stfd f28,336(r4) */
|
||||
0xdba40158, /* stfd f29,344(r4) */
|
||||
0xdbc40160, /* stfd f30,352(r4) */
|
||||
0xdbe40168, /* stfd f31,360(r4) */
|
||||
0xc9c300e0, /* lfd f14,224(r3) */
|
||||
0xc9e300e8, /* lfd f15,232(r3) */
|
||||
0xca0300f0, /* lfd f16,240(r3) */
|
||||
0xca2300f8, /* lfd f17,248(r3) */
|
||||
0xca430100, /* lfd f18,256(r3) */
|
||||
0xca630108, /* lfd f19,264(r3) */
|
||||
0xca830110, /* lfd f20,272(r3) */
|
||||
0xcaa30118, /* lfd f21,280(r3) */
|
||||
0xcac30120, /* lfd f22,288(r3) */
|
||||
0xcae30128, /* lfd f23,296(r3) */
|
||||
0xcb030130, /* lfd f24,304(r3) */
|
||||
0xcb230138, /* lfd f25,312(r3) */
|
||||
0xcb430140, /* lfd f26,320(r3) */
|
||||
0xcb630148, /* lfd f27,328(r3) */
|
||||
0xcb830150, /* lfd f28,336(r3) */
|
||||
0xcba30158, /* lfd f29,344(r3) */
|
||||
0xcbc30160, /* lfd f30,352(r3) */
|
||||
0xcbe30168, /* lfd f31,360(r3) */
|
||||
#endif
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
0x7ca042a6, /* mfvrsave r5 */
|
||||
0x39040180, /* addi r8,r4,384 */
|
||||
0x39240190, /* addi r9,r4,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x90a40034, /* stw r5,52(r4) */
|
||||
0x4182005c, /* beq- 2 */
|
||||
0x7e8041ce, /* stvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea049ce, /* stvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec041ce, /* stvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee049ce, /* stvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0041ce, /* stvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2049ce, /* stvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4041ce, /* stvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6049ce, /* stvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8041ce, /* stvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa049ce, /* stvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc041ce, /* stvx v30,r0,r8 */
|
||||
0x7fe049ce, /* stvx v31,r0,r9 */
|
||||
0x80a30034,/*2:lwz r5,52(r3) */
|
||||
0x39030180, /* addi r8,r3,384 */
|
||||
0x39230190, /* addi r9,r3,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x7ca043a6, /* mtvrsave r5 */
|
||||
0x4d820420, /* beqctr */
|
||||
0x7e8040ce, /* lvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea048ce, /* lvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec040ce, /* lvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee048ce, /* lvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0040ce, /* lvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2048ce, /* lvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4040ce, /* lvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6048ce, /* lvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8040ce, /* lvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa048ce, /* lvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc040ce, /* lvx v30,r0,r8 */
|
||||
0x7fe048ce, /* lvx v31,r0,r9 */
|
||||
#endif
|
||||
|
||||
0x4e800420, /* bctr */
|
||||
};
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
/* Function call goes through indirect descriptor */
|
||||
#define CO_SWAP_ASM( x, y ) \
|
||||
((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y )
|
||||
#else
|
||||
/* Function call goes directly to code */
|
||||
#define CO_SWAP_ASM( x, y ) \
|
||||
((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static uint32_t* co_create_( unsigned size, uintptr_t entry )
|
||||
{
|
||||
uint32_t* t = (uint32_t*) malloc( size );
|
||||
|
||||
(void) entry;
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
if ( t )
|
||||
{
|
||||
/* Copy entry's descriptor */
|
||||
memcpy( t, (void*) entry, sizeof (void*) * 3 );
|
||||
|
||||
/* Set function pointer to swap routine */
|
||||
#ifdef LIBCO_PPC_ASM
|
||||
*(const void**) t = *(void**) &co_swap_asm;
|
||||
#else
|
||||
*(const void**) t = libco_ppc_code;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
cothread_t co_create( unsigned int size, void (*entry_)( void ) )
|
||||
{
|
||||
uintptr_t entry = (uintptr_t) entry_;
|
||||
uint32_t* t = NULL;
|
||||
|
||||
/* Be sure main thread was successfully allocated */
|
||||
if ( co_active() )
|
||||
{
|
||||
size += state_size + above_stack + stack_align;
|
||||
t = co_create_( size, entry );
|
||||
}
|
||||
|
||||
if ( t )
|
||||
{
|
||||
uintptr_t sp;
|
||||
int shift;
|
||||
|
||||
/* Save current registers into new thread, so that any special ones will
|
||||
have proper values when thread is begun */
|
||||
CO_SWAP_ASM( t, t );
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
/* Get real address */
|
||||
entry = (uintptr_t) *(void**) entry;
|
||||
#endif
|
||||
|
||||
/* Put stack near end of block, and align */
|
||||
sp = (uintptr_t) t + size - above_stack;
|
||||
sp -= sp % stack_align;
|
||||
|
||||
/* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
|
||||
save and restore them as 64 bits, regardless of the size the ABI
|
||||
uses. So, we manually write pointers at the proper size. We always
|
||||
save and restore at the same address, and since PPC is big-endian,
|
||||
we must put the low byte first on PPC32. */
|
||||
|
||||
/* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
|
||||
and don't have to care how many bits uintptr_t is. */
|
||||
#if LIBCO_PPC64
|
||||
shift = 16;
|
||||
#else
|
||||
shift = 0;
|
||||
#endif
|
||||
|
||||
/* Set up so entry will be called on next swap */
|
||||
t [8] = (uint32_t) (entry >> shift >> shift);
|
||||
t [9] = (uint32_t) entry;
|
||||
|
||||
t [10] = (uint32_t) (sp >> shift >> shift);
|
||||
t [11] = (uint32_t) sp;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void co_delete( cothread_t t )
|
||||
{
|
||||
free( t );
|
||||
}
|
||||
|
||||
static void co_init_( void )
|
||||
{
|
||||
#if LIBCO_MPROTECT
|
||||
/* TODO: pre- and post-pad PPC code so that this doesn't make other
|
||||
data executable and writable */
|
||||
long page_size = sysconf( _SC_PAGESIZE );
|
||||
if ( page_size > 0 )
|
||||
{
|
||||
uintptr_t align = page_size;
|
||||
uintptr_t begin = (uintptr_t) libco_ppc_code;
|
||||
uintptr_t end = begin + sizeof libco_ppc_code;
|
||||
|
||||
/* Align beginning and end */
|
||||
end += align - 1;
|
||||
end -= end % align;
|
||||
begin -= begin % align;
|
||||
|
||||
mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC );
|
||||
}
|
||||
#endif
|
||||
|
||||
co_active_handle = co_create_( state_size, (uintptr_t) &co_switch );
|
||||
}
|
||||
|
||||
cothread_t co_active()
|
||||
{
|
||||
if ( !co_active_handle )
|
||||
co_init_();
|
||||
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
void co_switch( cothread_t t )
|
||||
{
|
||||
cothread_t old = co_active_handle;
|
||||
co_active_handle = t;
|
||||
|
||||
CO_SWAP_ASM( t, old );
|
||||
}
|
@@ -1,478 +0,0 @@
|
||||
;*****
|
||||
;libco.ppc (2007-11-29)
|
||||
;author: Vas Crabb
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform PowerPC implementation of libco
|
||||
;special thanks to byuu for writing the original version
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- gcc; mac os x; ppc
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- GPR1, GPR13 - GPR31
|
||||
;- FPR14 - FPR31
|
||||
;- V20 - V31
|
||||
;- VRSAVE, CR2 - CR4
|
||||
;
|
||||
;[volatile registers]
|
||||
;- GPR0, GPR2 - GPR12
|
||||
;- FPR0 - FPR13
|
||||
;- V0 - V19
|
||||
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
|
||||
;*****
|
||||
|
||||
|
||||
;Declare some target-specific stuff
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.machine ppc
|
||||
|
||||
|
||||
;Constants
|
||||
|
||||
.cstring
|
||||
.align 2
|
||||
|
||||
_sysctl_altivec:
|
||||
.ascii "hw.optional.altivec\0"
|
||||
|
||||
|
||||
;Declare space for variables
|
||||
|
||||
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
|
||||
.lcomm _co_primary_buffer,1024,2 ;buffer (will be zeroed by loader)
|
||||
|
||||
.data
|
||||
.align 2
|
||||
|
||||
_co_active_context:
|
||||
.long _co_primary_buffer
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
|
||||
;Declare exported names
|
||||
|
||||
.globl _co_active
|
||||
.globl _co_create
|
||||
.globl _co_delete
|
||||
.globl _co_switch
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_active:
|
||||
mflr r0 ;GPR0 = return address
|
||||
bcl 20,31,L_co_active$spb
|
||||
L_co_active$spb:
|
||||
mflr r2 ;GPR2 set for position-independance
|
||||
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
|
||||
lwz r3,lo16(_co_active_context-L_co_active$spb)(r3)
|
||||
mtlr r0 ;LR = return address
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;GPR3 = heapsize
|
||||
;GPR4 = coentry
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_create:
|
||||
mflr r0 ;GPR0 = return address
|
||||
stmw r30,-8(r1) ;save GPR30 and GPR31
|
||||
stw r0,8(r1) ;save return address
|
||||
stwu r1,-(2*4+16+24)(r1) ;allocate 16 bytes for locals/parameters
|
||||
|
||||
;create heap space (stack + register storage)
|
||||
addi r31,r3,1024-24 ;subtract space for linkage
|
||||
mr r30,r4 ;GPR30 = coentry
|
||||
addi r3,r3,1024 ;allocate extra memory for contextual info
|
||||
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
|
||||
add r4,r3,r31 ;GPR4 points to top-of-stack
|
||||
rlwinm r5,r4,0,0,27 ;force 16-byte alignment
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
stw r30,8(r5) ;store entry point
|
||||
addi r6,0,2+19+18*2+12*4+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
|
||||
addi r0,0,0
|
||||
addi r7,0,4 ;start at 4(GPR5)
|
||||
mtctr r6
|
||||
L_co_create$clear_loop:
|
||||
stwx r0,r5,r7 ;clear a word
|
||||
addi r7,r7,-4 ;increment pointer
|
||||
bdnz L_co_create$clear_loop ;loop
|
||||
stwu r5,-448(r5) ;store top of stack
|
||||
|
||||
;initialize context memory heap and return
|
||||
stw r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
|
||||
lwz r1,0(r1) ;deallocate stack frame
|
||||
lwz r8,8(r1) ;fetch return address
|
||||
lmw r30,-8(r1) ;restore GPR30 and GPR31
|
||||
mtlr r8 ;return address in LR
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
|
||||
_co_delete:
|
||||
b L_free$stub ;free(GPR3)
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
;
|
||||
;Frame looks like:
|
||||
;
|
||||
;Old New Value
|
||||
; 8(r1) 456(r1) Saved LR
|
||||
; 4(r1) 452(r1) Saved CR
|
||||
; 0(r1) 448(r1) Old GPR1
|
||||
; -4(r1) 444(r1) Saved GPR31
|
||||
; -8(r1) 440(r1) Saved GPR30
|
||||
;... ... ...
|
||||
; -72(r1) 376(r1) Saved GPR14
|
||||
; -76(r1) 372(r1) Saved GPR13
|
||||
; -80(r1) 368(r1) Saved VRSAVE
|
||||
; -84(r1) 364(r1) +++
|
||||
; -88(r1) 360(r1) Saved FPR31
|
||||
; -92(r1) 356(r1) +++
|
||||
; -96(r1) 352(r1) Saved FPR30
|
||||
;... ... ...
|
||||
;-212(r1) 236(r1) +++
|
||||
;-216(r1) 232(r1) Saved FPR15
|
||||
;-220(r1) 228(r1) +++
|
||||
;-224(r1) 224(r1) Saved FPR14
|
||||
;-228(r1) 220(r1) +++ value
|
||||
;-232(r1) 216(r1) +++ len
|
||||
;-236(r1) 212(r1) +++
|
||||
;-240(r1) 208(r1) Saved VR31
|
||||
;-244(r1) 204(r1) +++
|
||||
;-248(r1) 200(r1) +++
|
||||
;-252(r1) 196(r1) +++
|
||||
;-256(r1) 192(r1) Saved VR30
|
||||
;... ... ...
|
||||
;-388(r1) 60(r1) +++
|
||||
;-392(r1) 56(r1) +++
|
||||
;-396(r1) 52(r1) +++
|
||||
;-400(r1) 48(r1) Saved VR21
|
||||
;-404(r1) 44(r1) +++
|
||||
;-408(r1) 40(r1) +++ Param 5 (GPR7)
|
||||
;-412(r1) 36(r1) +++ Param 4 (GPR6)
|
||||
;-416(r1) 32(r1) Saved VR20 Param 3 (GPR5)
|
||||
;-420(r1) 28(r1) - Param 2 (GPR4)
|
||||
;-424(r1) 24(r1) - Param 1 (GPR3)
|
||||
;-428(r1) 20(r1) - Reserved
|
||||
;-432(r1) 16(r1) - Reserved
|
||||
;-436(r1) 12(r1) - Reserved
|
||||
;-440(r1) 8(r1) - New LR
|
||||
;-444(r1) 4(r1) - New CR
|
||||
;-448(r1) 0(r1) Saved GPR1
|
||||
|
||||
|
||||
_co_switch:
|
||||
stmw r13,-76(r1) ;save preserved GPRs
|
||||
stfd f14,-224(r1) ;save preserved FPRs
|
||||
stfd f15,-216(r1)
|
||||
stfd f16,-208(r1)
|
||||
stfd f17,-200(r1)
|
||||
stfd f18,-192(r1)
|
||||
stfd f19,-184(r1)
|
||||
stfd f20,-176(r1)
|
||||
stfd f21,-168(r1)
|
||||
stfd f22,-160(r1)
|
||||
stfd f23,-152(r1)
|
||||
stfd f24,-144(r1)
|
||||
stfd f25,-136(r1)
|
||||
stfd f26,-128(r1)
|
||||
stfd f27,-120(r1)
|
||||
stfd f28,-112(r1)
|
||||
stfd f29,-104(r1)
|
||||
stfd f30,-96(r1)
|
||||
stfd f31,-88(r1)
|
||||
mflr r0 ;save return address
|
||||
stw r0,8(r1)
|
||||
mfcr r2 ;save condition codes
|
||||
stw r2,4(r1)
|
||||
stwu r1,-448(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
|
||||
|
||||
mr r30,r3 ;save new context pointer
|
||||
bcl 20,31,L_co_switch$spb ;get address of co_active_context
|
||||
L_co_switch$spb:
|
||||
mflr r31
|
||||
|
||||
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
|
||||
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
|
||||
andis. r9,r8,0x8000 ;is it initialised?
|
||||
bne+ L_co_switch$initialised
|
||||
|
||||
addi r0,0,4 ;len = sizeof(int)
|
||||
stw r0,216(r1)
|
||||
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
|
||||
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
|
||||
addi r4,r1,220 ;GPR4 = &value
|
||||
addi r5,r1,216 ;GPR5 = &len
|
||||
addi r6,0,0 ;newp = 0
|
||||
addi r7,0,0 ;newlen = 0
|
||||
bl L_sysctlbyname$stub ;call sysctlbyname
|
||||
lwz r2,220(r1) ;fetch result
|
||||
addis r8,0,0x8000 ;set initialised bit
|
||||
cmpwi cr5,r3,0 ;assume error means not present
|
||||
cmpwi cr6,r2,0 ;test result
|
||||
blt- cr5,L_co_switch$store_environ
|
||||
beq cr6,L_co_switch$store_environ
|
||||
oris r8,r8,0x4000 ;set the flag to say we have it!
|
||||
L_co_switch$store_environ:
|
||||
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
|
||||
L_co_switch$initialised:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$save_no_vmx
|
||||
mfspr r11,256 ;save VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
stw r11,368(r1)
|
||||
beq L_co_switch$save_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,32 ;starting index
|
||||
beq L_co_switch$save_skip_vr20
|
||||
stvx v20,r1,r2 ;save VR20
|
||||
L_co_switch$save_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$save_skip_vr21
|
||||
stvx v21,r1,r2 ;save VR21
|
||||
L_co_switch$save_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$save_skip_vr22
|
||||
stvx v22,r1,r2 ;save VR22
|
||||
L_co_switch$save_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$save_skip_vr23
|
||||
stvx v23,r1,r2 ;save VR23
|
||||
L_co_switch$save_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$save_skip_vr24
|
||||
stvx v24,r1,r2 ;save VR24
|
||||
L_co_switch$save_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$save_skip_vr25
|
||||
stvx v25,r1,r2 ;save VR25
|
||||
L_co_switch$save_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$save_skip_vr26
|
||||
stvx v26,r1,r2 ;save VR26
|
||||
L_co_switch$save_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$save_skip_vr27
|
||||
stvx v27,r1,r2 ;save VR27
|
||||
L_co_switch$save_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$save_skip_vr28
|
||||
stvx v28,r1,r2 ;save VR28
|
||||
L_co_switch$save_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$save_skip_vr29
|
||||
stvx v29,r1,r2 ;save VR29
|
||||
L_co_switch$save_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$save_skip_vr30
|
||||
stvx v30,r1,r2 ;save VR30
|
||||
L_co_switch$save_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$save_skip_vr31
|
||||
stvx v31,r1,r2 ;save VR31
|
||||
L_co_switch$save_skip_vr31:
|
||||
L_co_switch$save_no_vmx:
|
||||
|
||||
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
|
||||
lwz r5,lo16(_co_active_context-L_co_switch$spb)(r4)
|
||||
stw r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
|
||||
stw r1,0(r5) ;save current stack pointer
|
||||
lwz r1,0(r30) ;get new stack pointer
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$restore_no_vmx
|
||||
lwz r11,368(r1) ;restore VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
mtspr 256,r11
|
||||
beq L_co_switch$restore_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,32 ;starting index
|
||||
beq L_co_switch$restore_skip_vr20
|
||||
lvx v20,r1,r2 ;restore VR20
|
||||
L_co_switch$restore_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$restore_skip_vr21
|
||||
lvx v21,r1,r2 ;restore VR21
|
||||
L_co_switch$restore_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$restore_skip_vr22
|
||||
lvx v22,r1,r2 ;restore VR22
|
||||
L_co_switch$restore_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$restore_skip_vr23
|
||||
lvx v23,r1,r2 ;restore VR23
|
||||
L_co_switch$restore_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$restore_skip_vr24
|
||||
lvx v24,r1,r2 ;restore VR24
|
||||
L_co_switch$restore_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$restore_skip_vr25
|
||||
lvx v25,r1,r2 ;restore VR25
|
||||
L_co_switch$restore_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$restore_skip_vr26
|
||||
lvx v26,r1,r2 ;restore VR26
|
||||
L_co_switch$restore_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$restore_skip_vr27
|
||||
lvx v27,r1,r2 ;restore VR27
|
||||
L_co_switch$restore_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$restore_skip_vr28
|
||||
lvx v28,r1,r2 ;restore VR28
|
||||
L_co_switch$restore_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$restore_skip_vr29
|
||||
lvx v29,r1,r2 ;restore VR29
|
||||
L_co_switch$restore_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$restore_skip_vr30
|
||||
lvx v30,r1,r2 ;restore VR30
|
||||
L_co_switch$restore_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$restore_skip_vr31
|
||||
lvx v31,r1,r2 ;restore VR31
|
||||
L_co_switch$restore_skip_vr31:
|
||||
L_co_switch$restore_no_vmx:
|
||||
|
||||
lwz r1,0(r1) ;deallocate stack frame
|
||||
lwz r6,8(r1) ;return address in GPR6
|
||||
lwz r7,4(r1) ;condition codes in GPR7
|
||||
addi r0,0,0 ;make thread main crash if it returns
|
||||
lmw r13,-76(r1) ;restore preserved GPRs
|
||||
lfd f14,-224(r1) ;restore preserved FPRs
|
||||
lfd f15,-216(r1)
|
||||
lfd f16,-208(r1)
|
||||
lfd f17,-200(r1)
|
||||
lfd f18,-192(r1)
|
||||
lfd f19,-184(r1)
|
||||
lfd f20,-176(r1)
|
||||
lfd f21,-168(r1)
|
||||
lfd f22,-160(r1)
|
||||
lfd f23,-152(r1)
|
||||
lfd f24,-144(r1)
|
||||
lfd f25,-136(r1)
|
||||
lfd f26,-128(r1)
|
||||
lfd f27,-120(r1)
|
||||
lfd f28,-112(r1)
|
||||
lfd f29,-104(r1)
|
||||
lfd f30,-96(r1)
|
||||
lfd f31,-88(r1)
|
||||
mtlr r0
|
||||
mtctr r6 ;restore return address
|
||||
mtcrf 32,r7 ;restore preserved condition codes
|
||||
mtcrf 16,r7
|
||||
mtcrf 8,r7
|
||||
bctr ;return
|
||||
|
||||
|
||||
|
||||
;Import external functions
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_malloc$stub:
|
||||
.indirect_symbol _malloc
|
||||
mflr r0
|
||||
bcl 20,31,L_malloc$spb
|
||||
L_malloc$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_malloc$lazy_ptr:
|
||||
.indirect_symbol _malloc
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_free$stub:
|
||||
.indirect_symbol _free
|
||||
mflr r0
|
||||
bcl 20,31,L_free$spb
|
||||
L_free$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_free$lazy_ptr:
|
||||
.indirect_symbol _free
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_sysctlbyname$stub:
|
||||
.indirect_symbol _sysctlbyname
|
||||
mflr r0
|
||||
bcl 20,31,L_sysctlbyname$spb
|
||||
L_sysctlbyname$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_sysctlbyname$lazy_ptr:
|
||||
.indirect_symbol _sysctlbyname
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
;This needs to be here!
|
||||
|
||||
.subsections_via_symbols
|
||||
|
@@ -1,513 +0,0 @@
|
||||
;*****
|
||||
;libco.ppc64 (2007-12-05)
|
||||
;author: Vas Crabb
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform 64-bit PowerPC implementation of libco
|
||||
;special thanks to byuu for writing the original version
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- gcc; mac os x; ppc64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- GPR1, GPR13 - GPR31
|
||||
;- FPR14 - FPR31
|
||||
;- V20 - V31
|
||||
;- VRSAVE, CR2 - CR4
|
||||
;
|
||||
;[volatile registers]
|
||||
;- GPR0, GPR2 - GPR12
|
||||
;- FPR0 - FPR13
|
||||
;- V0 - V19
|
||||
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
|
||||
;*****
|
||||
|
||||
|
||||
;Declare some target-specific stuff
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.machine ppc64
|
||||
|
||||
|
||||
;Constants
|
||||
|
||||
.cstring
|
||||
.align 3
|
||||
|
||||
_sysctl_altivec:
|
||||
.ascii "hw.optional.altivec\0"
|
||||
|
||||
|
||||
;Declare space for variables
|
||||
|
||||
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
|
||||
.lcomm _co_primary_buffer,1024,3 ;buffer (will be zeroed by loader)
|
||||
|
||||
.data
|
||||
.align 3
|
||||
|
||||
_co_active_context:
|
||||
.quad _co_primary_buffer
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
|
||||
;Declare exported names
|
||||
|
||||
.globl _co_active
|
||||
.globl _co_create
|
||||
.globl _co_delete
|
||||
.globl _co_switch
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_active:
|
||||
mflr r0 ;GPR0 = return address
|
||||
bcl 20,31,L_co_active$spb
|
||||
L_co_active$spb:
|
||||
mflr r2 ;GPR2 set for position-independance
|
||||
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
|
||||
ld r3,lo16(_co_active_context-L_co_active$spb)(r3)
|
||||
mtlr r0 ;LR = return address
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;GPR3 = heapsize
|
||||
;GPR4 = coentry
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_create:
|
||||
mflr r0 ;GPR0 = return address
|
||||
std r30,-16(r1) ;save GPR30 and GPR31
|
||||
std r31,-8(r1)
|
||||
std r0,16(r1) ;save return address
|
||||
stdu r1,-(2*8+16+48)(r1) ;allocate 16 bytes for locals/parameters
|
||||
|
||||
;create heap space (stack + register storage)
|
||||
addi r31,r3,1024-48 ;subtract space for linkage
|
||||
mr r30,r4 ;GPR30 = coentry
|
||||
addi r3,r3,1024 ;allocate extra memory for contextual info
|
||||
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
|
||||
add r4,r3,r31 ;GPR4 points to top-of-stack
|
||||
rldicr r5,r4,0,59 ;force 16-byte alignment
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
std r30,16(r5) ;store entry point
|
||||
addi r6,0,2+19+18+12*2+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
|
||||
addi r0,0,0
|
||||
addi r7,0,8 ;start at 8(GPR5)
|
||||
mtctr r6
|
||||
L_co_create$clear_loop:
|
||||
stdx r0,r5,r7 ;clear a double
|
||||
addi r7,r7,-8 ;increment pointer
|
||||
bdnz L_co_create$clear_loop ;loop
|
||||
stdu r5,-544(r5) ;store top of stack
|
||||
|
||||
;initialize context memory heap and return
|
||||
addis r9,0,0x8000 ;GPR13 not set (system TLS)
|
||||
std r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
|
||||
stw r9,8(r3) ;this is a flag word
|
||||
ld r1,0(r1) ;deallocate stack frame
|
||||
ld r8,16(r1) ;fetch return address
|
||||
ld r30,-16(r1) ;restore GPR30 and GPR31
|
||||
ld r31,-8(r1)
|
||||
mtlr r8 ;return address in LR
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
|
||||
_co_delete:
|
||||
b L_free$stub ;free(GPR3)
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
;
|
||||
;Frame looks like:
|
||||
;
|
||||
;Old New Value
|
||||
; 16(r1) 560(r1) Saved LR
|
||||
; 8(r1) 552(r1) Saved CR
|
||||
; 0(r1) 544(r1) Old GPR1
|
||||
; -8(r1) 536(r1) Saved GPR31
|
||||
; -16(r1) 528(r1) Saved GPR30
|
||||
;... ... ...
|
||||
;-144(r1) 400(r1) Saved GPR14
|
||||
;-152(r1) 392(r1) Saved GPR13
|
||||
;-160(r1) 384(r1) Saved FPR31
|
||||
;-168(r1) 376(r1) Saved FPR30
|
||||
;... ... ...
|
||||
;-288(r1) 256(r1) Saved FPR15
|
||||
;-296(r1) 248(r1) Saved FPR14
|
||||
;-304(r1) 240(r1) Saved VRSAVE
|
||||
;-312(r1) 232(r1) +++ value
|
||||
;-320(r1) 224(r1) Saved VR31 len
|
||||
;-328(r1) 216(r1) +++
|
||||
;-336(r1) 208(r1) Saved VR30
|
||||
;... ... ...
|
||||
;-456(r1) 88(r1) +++
|
||||
;-464(r1) 80(r1) Saved VR22 Param 5 (GPR7)
|
||||
;-472(r1) 72(r1) +++ Param 4 (GPR6)
|
||||
;-480(r1) 64(r1) Saved VR21 Param 3 (GPR5)
|
||||
;-488(r1) 56(r1) +++ Param 2 (GPR4)
|
||||
;-496(r1) 48(r1) Saved VR20 Param 1 (GPR3)
|
||||
;-504(r1) 40(r1) - Reserved
|
||||
;-512(r1) 32(r1) - Reserved
|
||||
;-520(r1) 24(r1) - Reserved
|
||||
;-528(r1) 16(r1) - New LR
|
||||
;-536(r1) 8(r1) - New CR
|
||||
;-544(r1) 0(r1) Saved GPR1
|
||||
|
||||
|
||||
_co_switch:
|
||||
std r13,-152(r1) ;save preserved GPRs
|
||||
std r14,-144(r1)
|
||||
std r15,-136(r1)
|
||||
std r16,-128(r1)
|
||||
std r17,-120(r1)
|
||||
std r18,-112(r1)
|
||||
std r19,-104(r1)
|
||||
std r20,-96(r1)
|
||||
std r21,-88(r1)
|
||||
std r22,-80(r1)
|
||||
std r23,-72(r1)
|
||||
std r24,-64(r1)
|
||||
std r25,-56(r1)
|
||||
std r26,-48(r1)
|
||||
std r27,-40(r1)
|
||||
std r28,-32(r1)
|
||||
std r29,-24(r1)
|
||||
std r30,-16(r1)
|
||||
std r31,-8(r1)
|
||||
mflr r0 ;save return address
|
||||
std r0,16(r1)
|
||||
mfcr r2 ;save condition codes
|
||||
stw r2,8(r1)
|
||||
stdu r1,-544(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
|
||||
stfd f14,248(r1) ;save preserved FPRs
|
||||
stfd f15,256(r1)
|
||||
stfd f16,264(r1)
|
||||
stfd f17,272(r1)
|
||||
stfd f18,280(r1)
|
||||
stfd f19,288(r1)
|
||||
stfd f20,296(r1)
|
||||
stfd f21,304(r1)
|
||||
stfd f22,312(r1)
|
||||
stfd f23,320(r1)
|
||||
stfd f24,328(r1)
|
||||
stfd f25,336(r1)
|
||||
stfd f26,344(r1)
|
||||
stfd f27,352(r1)
|
||||
stfd f28,360(r1)
|
||||
stfd f29,368(r1)
|
||||
stfd f30,376(r1)
|
||||
stfd f31,384(r1)
|
||||
|
||||
mr r30,r3 ;save new context pointer
|
||||
bcl 20,31,L_co_switch$spb ;get address of co_active_context
|
||||
L_co_switch$spb:
|
||||
mflr r31
|
||||
|
||||
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
|
||||
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
|
||||
andis. r9,r8,0x8000 ;is it initialised?
|
||||
bne+ L_co_switch$initialised
|
||||
|
||||
addi r0,0,4 ;len = sizeof(int)
|
||||
std r0,224(r1)
|
||||
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
|
||||
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
|
||||
addi r4,r1,232 ;GPR4 = &value
|
||||
addi r5,r1,224 ;GPR5 = &len
|
||||
addi r6,0,0 ;newp = 0
|
||||
addi r7,0,0 ;newlen = 0
|
||||
bl L_sysctlbyname$stub ;call sysctlbyname
|
||||
lwz r2,232(r1) ;fetch result
|
||||
addis r8,0,0x8000 ;set initialised bit
|
||||
cmpdi cr5,r3,0 ;assume error means not present
|
||||
cmpwi cr6,r2,0 ;test result
|
||||
blt- cr5,L_co_switch$store_environ
|
||||
beq cr6,L_co_switch$store_environ
|
||||
oris r8,r8,0x4000 ;set the flag to say we have it!
|
||||
L_co_switch$store_environ:
|
||||
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
|
||||
L_co_switch$initialised:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$save_no_vmx
|
||||
mfspr r11,256 ;save VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
stw r11,240(r1)
|
||||
beq L_co_switch$save_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,48 ;starting index
|
||||
beq L_co_switch$save_skip_vr20
|
||||
stvx v20,r1,r2 ;save VR20
|
||||
L_co_switch$save_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$save_skip_vr21
|
||||
stvx v21,r1,r2 ;save VR21
|
||||
L_co_switch$save_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$save_skip_vr22
|
||||
stvx v22,r1,r2 ;save VR22
|
||||
L_co_switch$save_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$save_skip_vr23
|
||||
stvx v23,r1,r2 ;save VR23
|
||||
L_co_switch$save_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$save_skip_vr24
|
||||
stvx v24,r1,r2 ;save VR24
|
||||
L_co_switch$save_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$save_skip_vr25
|
||||
stvx v25,r1,r2 ;save VR25
|
||||
L_co_switch$save_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$save_skip_vr26
|
||||
stvx v26,r1,r2 ;save VR26
|
||||
L_co_switch$save_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$save_skip_vr27
|
||||
stvx v27,r1,r2 ;save VR27
|
||||
L_co_switch$save_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$save_skip_vr28
|
||||
stvx v28,r1,r2 ;save VR28
|
||||
L_co_switch$save_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$save_skip_vr29
|
||||
stvx v29,r1,r2 ;save VR29
|
||||
L_co_switch$save_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$save_skip_vr30
|
||||
stvx v30,r1,r2 ;save VR30
|
||||
L_co_switch$save_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$save_skip_vr31
|
||||
stvx v31,r1,r2 ;save VR31
|
||||
L_co_switch$save_skip_vr31:
|
||||
L_co_switch$save_no_vmx:
|
||||
|
||||
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
|
||||
ld r5,lo16(_co_active_context-L_co_switch$spb)(r4)
|
||||
std r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
|
||||
std r1,0(r5) ;save current stack pointer
|
||||
ld r1,0(r30) ;get new stack pointer
|
||||
lwz r12,8(r30) ;have we already set GPR13 (system TLS)?
|
||||
andis. r0,r12,0x8000
|
||||
beq+ L_co_switch$gpr13_set
|
||||
std r13,392(r1)
|
||||
xoris r12,r12,0x8000
|
||||
stw r12,8(r30)
|
||||
L_co_switch$gpr13_set:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$restore_no_vmx
|
||||
lwz r11,240(r1) ;restore VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
mtspr 256,r11
|
||||
beq L_co_switch$restore_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,48 ;starting index
|
||||
beq L_co_switch$restore_skip_vr20
|
||||
lvx v20,r1,r2 ;restore VR20
|
||||
L_co_switch$restore_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$restore_skip_vr21
|
||||
lvx v21,r1,r2 ;restore VR21
|
||||
L_co_switch$restore_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$restore_skip_vr22
|
||||
lvx v22,r1,r2 ;restore VR22
|
||||
L_co_switch$restore_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$restore_skip_vr23
|
||||
lvx v23,r1,r2 ;restore VR23
|
||||
L_co_switch$restore_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$restore_skip_vr24
|
||||
lvx v24,r1,r2 ;restore VR24
|
||||
L_co_switch$restore_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$restore_skip_vr25
|
||||
lvx v25,r1,r2 ;restore VR25
|
||||
L_co_switch$restore_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$restore_skip_vr26
|
||||
lvx v26,r1,r2 ;restore VR26
|
||||
L_co_switch$restore_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$restore_skip_vr27
|
||||
lvx v27,r1,r2 ;restore VR27
|
||||
L_co_switch$restore_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$restore_skip_vr28
|
||||
lvx v28,r1,r2 ;restore VR28
|
||||
L_co_switch$restore_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$restore_skip_vr29
|
||||
lvx v29,r1,r2 ;restore VR29
|
||||
L_co_switch$restore_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$restore_skip_vr30
|
||||
lvx v30,r1,r2 ;restore VR30
|
||||
L_co_switch$restore_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$restore_skip_vr31
|
||||
lvx v31,r1,r2 ;restore VR31
|
||||
L_co_switch$restore_skip_vr31:
|
||||
L_co_switch$restore_no_vmx:
|
||||
|
||||
lfd f14,248(r1) ;restore preserved FPRs
|
||||
lfd f15,256(r1)
|
||||
lfd f16,264(r1)
|
||||
lfd f17,272(r1)
|
||||
lfd f18,280(r1)
|
||||
lfd f19,288(r1)
|
||||
lfd f20,296(r1)
|
||||
lfd f21,304(r1)
|
||||
lfd f22,312(r1)
|
||||
lfd f23,320(r1)
|
||||
lfd f24,328(r1)
|
||||
lfd f25,336(r1)
|
||||
lfd f26,344(r1)
|
||||
lfd f27,352(r1)
|
||||
lfd f28,360(r1)
|
||||
lfd f29,368(r1)
|
||||
lfd f30,376(r1)
|
||||
lfd f31,384(r1)
|
||||
addi r0,0,0 ;make thread main crash if it returns
|
||||
ld r1,0(r1) ;deallocate stack frame
|
||||
ld r6,16(r1) ;return address in GPR6
|
||||
lwz r7,8(r1) ;condition codes in GPR7
|
||||
ld r13,-152(r1) ;restore preserved GPRs
|
||||
ld r14,-144(r1)
|
||||
ld r15,-136(r1)
|
||||
ld r16,-128(r1)
|
||||
ld r17,-120(r1)
|
||||
ld r18,-112(r1)
|
||||
ld r19,-104(r1)
|
||||
ld r20,-96(r1)
|
||||
ld r21,-88(r1)
|
||||
ld r22,-80(r1)
|
||||
ld r23,-72(r1)
|
||||
ld r24,-64(r1)
|
||||
ld r25,-56(r1)
|
||||
ld r26,-48(r1)
|
||||
ld r27,-40(r1)
|
||||
ld r28,-32(r1)
|
||||
ld r29,-24(r1)
|
||||
ld r30,-16(r1)
|
||||
ld r31,-8(r1)
|
||||
mtlr r0
|
||||
mtctr r6 ;restore return address
|
||||
mtcrf 32,r7 ;restore preserved condition codes
|
||||
mtcrf 16,r7
|
||||
mtcrf 8,r7
|
||||
bctr ;return
|
||||
|
||||
|
||||
|
||||
;Import external functions
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_malloc$stub:
|
||||
.indirect_symbol _malloc
|
||||
mflr r0
|
||||
bcl 20,31,L_malloc$spb
|
||||
L_malloc$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_malloc$lazy_ptr:
|
||||
.indirect_symbol _malloc
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_free$stub:
|
||||
.indirect_symbol _free
|
||||
mflr r0
|
||||
bcl 20,31,L_free$spb
|
||||
L_free$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_free$lazy_ptr:
|
||||
.indirect_symbol _free
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_sysctlbyname$stub:
|
||||
.indirect_symbol _sysctlbyname
|
||||
mflr r0
|
||||
bcl 20,31,L_sysctlbyname$spb
|
||||
L_sysctlbyname$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_sysctlbyname$lazy_ptr:
|
||||
.indirect_symbol _sysctlbyname
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
;This needs to be here!
|
||||
|
||||
.subsections_via_symbols
|
||||
|
@@ -45,11 +45,11 @@ namespace nall {
|
||||
|
||||
void set(string s) {
|
||||
switch(type) {
|
||||
case boolean_t: *(bool*)data = (s == "true"); break;
|
||||
case signed_t: *(signed*)data = strsigned(s); break;
|
||||
case unsigned_t: *(unsigned*)data = strunsigned(s); break;
|
||||
case double_t: *(double*)data = strdouble(s); break;
|
||||
case string_t: s.trim("\""); *(string*)data = s; break;
|
||||
case boolean_t: *(bool*)data = (s == "true"); break;
|
||||
case signed_t: *(signed*)data = integer(s); break;
|
||||
case unsigned_t: *(unsigned*)data = decimal(s); break;
|
||||
case double_t: *(double*)data = fp(s); break;
|
||||
case string_t: s.trim("\""); *(string*)data = s; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -102,7 +102,7 @@ namespace nall {
|
||||
|
||||
virtual bool save(const char *filename) const {
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode_write)) {
|
||||
if(fp.open(filename, file::mode::write)) {
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
string output;
|
||||
output << list[i].name << " = " << list[i].get();
|
||||
|
@@ -27,7 +27,7 @@ namespace nall {
|
||||
bool import(const char *filename) {
|
||||
string data;
|
||||
if(data.readfile(filename) == false) return false;
|
||||
data.ltrim_once("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
||||
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
|
||||
data.replace("\r", "");
|
||||
|
||||
lstring line;
|
||||
@@ -43,8 +43,8 @@ namespace nall {
|
||||
part[1].trim();
|
||||
|
||||
//remove quotes
|
||||
part[0].trim_once("\"");
|
||||
part[1].trim_once("\"");
|
||||
part[0].trim<1>("\"");
|
||||
part[1].trim<1>("\"");
|
||||
|
||||
unsigned n = index_input.size();
|
||||
index_input[n] = part[0];
|
||||
|
@@ -16,13 +16,20 @@
|
||||
namespace nall {
|
||||
|
||||
struct directory {
|
||||
static lstring folders(const char *pathname);
|
||||
static lstring files(const char *pathname);
|
||||
static lstring contents(const char *pathname);
|
||||
static bool exists(const string &pathname);
|
||||
static lstring folders(const string &pathname, const string &pattern = "*");
|
||||
static lstring files(const string &pathname, const string &pattern = "*");
|
||||
static lstring contents(const string &pathname, const string &pattern = "*");
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
inline lstring directory::folders(const char *pathname) {
|
||||
inline bool directory::exists(const string &pathname) {
|
||||
DWORD result = GetFileAttributes(utf16_t(pathname));
|
||||
if(result == INVALID_FILE_ATTRIBUTES) return false;
|
||||
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
||||
lstring list;
|
||||
string path = pathname;
|
||||
path.transform("/", "\\");
|
||||
@@ -34,23 +41,25 @@ struct directory {
|
||||
if(handle != INVALID_HANDLE_VALUE) {
|
||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
list.append(string(utf8_t(data.cFileName), "/"));
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||
}
|
||||
}
|
||||
while(FindNextFile(handle, &data) != false) {
|
||||
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
||||
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
list.append(string(utf8_t(data.cFileName), "/"));
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(string(name, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
FindClose(handle);
|
||||
}
|
||||
sort(&list[0], list.size());
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
inline lstring directory::files(const char *pathname) {
|
||||
inline lstring directory::files(const string &pathname, const string &pattern) {
|
||||
lstring list;
|
||||
string path = pathname;
|
||||
path.transform("/", "\\");
|
||||
@@ -61,27 +70,36 @@ struct directory {
|
||||
handle = FindFirstFile(utf16_t(path), &data);
|
||||
if(handle != INVALID_HANDLE_VALUE) {
|
||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
list.append(utf8_t(data.cFileName));
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
while(FindNextFile(handle, &data) != false) {
|
||||
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
||||
list.append(utf8_t(data.cFileName));
|
||||
string name = utf8_t(data.cFileName);
|
||||
if(wildcard(name, pattern)) list.append(name);
|
||||
}
|
||||
}
|
||||
FindClose(handle);
|
||||
}
|
||||
sort(&list[0], list.size());
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
inline lstring directory::contents(const char *pathname) {
|
||||
lstring folders = directory::folders(pathname);
|
||||
lstring files = directory::files(pathname);
|
||||
inline lstring directory::contents(const string &pathname, const string &pattern) {
|
||||
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
|
||||
lstring files = directory::files(pathname, pattern);
|
||||
foreach(file, files) folders.append(file);
|
||||
return folders;
|
||||
}
|
||||
#else
|
||||
inline lstring directory::folders(const char *pathname) {
|
||||
inline bool directory::exists(const string &pathname) {
|
||||
DIR *dp = opendir(pathname);
|
||||
if(!dp) return false;
|
||||
closedir(dp);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline lstring directory::folders(const string &pathname, const string &pattern) {
|
||||
lstring list;
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
@@ -90,16 +108,18 @@ struct directory {
|
||||
while(ep = readdir(dp)) {
|
||||
if(!strcmp(ep->d_name, ".")) continue;
|
||||
if(!strcmp(ep->d_name, "..")) continue;
|
||||
if(ep->d_type & DT_DIR) list.append(string(ep->d_name, "/"));
|
||||
if(ep->d_type & DT_DIR) {
|
||||
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
sort(&list[0], list.size());
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
inline lstring directory::files(const char *pathname) {
|
||||
inline lstring directory::files(const string &pathname, const string &pattern) {
|
||||
lstring list;
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
@@ -108,17 +128,19 @@ struct directory {
|
||||
while(ep = readdir(dp)) {
|
||||
if(!strcmp(ep->d_name, ".")) continue;
|
||||
if(!strcmp(ep->d_name, "..")) continue;
|
||||
if((ep->d_type & DT_DIR) == 0) list.append(ep->d_name);
|
||||
if((ep->d_type & DT_DIR) == 0) {
|
||||
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
sort(&list[0], list.size());
|
||||
if(list.size() > 0) sort(&list[0], list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
inline lstring directory::contents(const char *pathname) {
|
||||
lstring folders = directory::folders(pathname);
|
||||
lstring files = directory::files(pathname);
|
||||
inline lstring directory::contents(const string &pathname, const string &pattern) {
|
||||
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
|
||||
lstring files = directory::files(pathname, pattern);
|
||||
foreach(file, files) folders.append(file);
|
||||
return folders;
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ namespace nall {
|
||||
struct library {
|
||||
bool opened() const { return handle; }
|
||||
bool open(const char*, const char* = "");
|
||||
bool open_absolute(const char*);
|
||||
void* sym(const char*);
|
||||
void close();
|
||||
|
||||
@@ -40,6 +41,12 @@ namespace nall {
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const char *name) {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const char *name) {
|
||||
if(!handle) return 0;
|
||||
return dlsym((void*)handle, name);
|
||||
@@ -58,6 +65,12 @@ namespace nall {
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const char *name) {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)dlopen(name, RTLD_LAZY);
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const char *name) {
|
||||
if(!handle) return 0;
|
||||
return dlsym((void*)handle, name);
|
||||
@@ -76,6 +89,12 @@ namespace nall {
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline bool library::open_absolute(const char *name) {
|
||||
if(handle) close();
|
||||
handle = (uintptr_t)LoadLibraryW(utf16_t(name));
|
||||
return handle;
|
||||
}
|
||||
|
||||
inline void* library::sym(const char *name) {
|
||||
if(!handle) return 0;
|
||||
return (void*)GetProcAddress((HMODULE)handle, name);
|
||||
|
@@ -26,12 +26,12 @@ namespace nall {
|
||||
|
||||
class file {
|
||||
public:
|
||||
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
||||
enum SeekMode { seek_absolute, seek_relative };
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
enum class index : unsigned { absolute, relative };
|
||||
|
||||
uint8_t read() {
|
||||
if(!fp) return 0xff; //file not open
|
||||
if(file_mode == mode_write) return 0xff; //reads not permitted
|
||||
if(file_mode == mode::write) return 0xff; //reads not permitted
|
||||
if(file_offset >= file_size) return 0xff; //cannot read past end of file
|
||||
buffer_sync();
|
||||
return buffer[(file_offset++) & buffer_mask];
|
||||
@@ -59,8 +59,8 @@ namespace nall {
|
||||
}
|
||||
|
||||
void write(uint8_t data) {
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode_read) return; //writes not permitted
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode::read) return; //writes not permitted
|
||||
buffer_sync();
|
||||
buffer[(file_offset++) & buffer_mask] = data;
|
||||
buffer_dirty = true;
|
||||
@@ -95,19 +95,19 @@ namespace nall {
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void seek(int offset, SeekMode mode = seek_absolute) {
|
||||
void seek(int offset, index index_ = index::absolute) {
|
||||
if(!fp) return; //file not open
|
||||
buffer_flush();
|
||||
|
||||
uintmax_t req_offset = file_offset;
|
||||
switch(mode) {
|
||||
case seek_absolute: req_offset = offset; break;
|
||||
case seek_relative: req_offset += offset; break;
|
||||
switch(index_) {
|
||||
case index::absolute: req_offset = offset; break;
|
||||
case index::relative: req_offset += offset; break;
|
||||
}
|
||||
|
||||
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
|
||||
if(req_offset > file_size) {
|
||||
if(file_mode == mode_read) { //cannot seek past end of file
|
||||
if(file_mode == mode::read) { //cannot seek past end of file
|
||||
req_offset = file_size;
|
||||
} else { //pad file to requested location
|
||||
file_offset = file_size;
|
||||
@@ -174,20 +174,20 @@ namespace nall {
|
||||
return fp;
|
||||
}
|
||||
|
||||
bool open(const char *fn, FileMode mode) {
|
||||
bool open(const char *fn, mode mode_) {
|
||||
if(fp) return false;
|
||||
|
||||
switch(file_mode = mode) {
|
||||
switch(file_mode = mode_) {
|
||||
#if !defined(_WIN32)
|
||||
case mode_read: fp = fopen(fn, "rb"); break;
|
||||
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
||||
case mode_readwrite: fp = fopen(fn, "rb+"); break;
|
||||
case mode_writeread: fp = fopen(fn, "wb+"); break;
|
||||
case mode::read: fp = fopen(fn, "rb"); break;
|
||||
case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
|
||||
case mode::readwrite: fp = fopen(fn, "rb+"); break;
|
||||
case mode::writeread: fp = fopen(fn, "wb+"); break;
|
||||
#else
|
||||
case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
||||
case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
||||
case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
|
||||
case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
|
||||
case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
|
||||
#endif
|
||||
}
|
||||
if(!fp) return false;
|
||||
@@ -213,7 +213,7 @@ namespace nall {
|
||||
fp = 0;
|
||||
file_offset = 0;
|
||||
file_size = 0;
|
||||
file_mode = mode_read;
|
||||
file_mode = mode::read;
|
||||
}
|
||||
|
||||
~file() {
|
||||
@@ -231,7 +231,7 @@ namespace nall {
|
||||
FILE *fp;
|
||||
unsigned file_offset;
|
||||
unsigned file_size;
|
||||
FileMode file_mode;
|
||||
mode file_mode;
|
||||
|
||||
void buffer_sync() {
|
||||
if(!fp) return; //file not open
|
||||
@@ -245,14 +245,14 @@ namespace nall {
|
||||
}
|
||||
|
||||
void buffer_flush() {
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode_read) return; //buffer cannot be written to
|
||||
if(buffer_offset < 0) return; //buffer unused
|
||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
||||
if(!fp) return; //file not open
|
||||
if(file_mode == mode::read) return; //buffer cannot be written to
|
||||
if(buffer_offset < 0) return; //buffer unused
|
||||
if(buffer_dirty == false) return; //buffer unmodified since read
|
||||
fseek(fp, buffer_offset, SEEK_SET);
|
||||
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
|
||||
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
|
||||
buffer_offset = -1; //invalidate buffer
|
||||
buffer_offset = -1; //invalidate buffer
|
||||
buffer_dirty = false;
|
||||
}
|
||||
};
|
||||
|
@@ -19,14 +19,16 @@
|
||||
namespace nall {
|
||||
class filemap {
|
||||
public:
|
||||
enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread };
|
||||
enum class mode : unsigned { read, write, readwrite, writeread };
|
||||
|
||||
bool open(const char *filename, filemode mode) { return p_open(filename, mode); }
|
||||
bool opened() const { return p_opened(); }
|
||||
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
|
||||
void close() { return p_close(); }
|
||||
unsigned size() const { return p_size; }
|
||||
uint8_t* handle() { return p_handle; }
|
||||
const uint8_t* handle() const { return p_handle; }
|
||||
uint8_t* data() { return p_handle; }
|
||||
const uint8_t* data() const { return p_handle; }
|
||||
filemap() : p_size(0), p_handle(0) { p_ctor(); }
|
||||
filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); }
|
||||
~filemap() { p_dtor(); }
|
||||
|
||||
private:
|
||||
@@ -40,31 +42,35 @@ namespace nall {
|
||||
|
||||
HANDLE p_filehandle, p_maphandle;
|
||||
|
||||
bool p_open(const char *filename, filemode mode) {
|
||||
bool p_opened() const {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
bool p_open(const char *filename, mode mode_) {
|
||||
int desired_access, creation_disposition, flprotect, map_access;
|
||||
|
||||
switch(mode) {
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode_read:
|
||||
case mode::read:
|
||||
desired_access = GENERIC_READ;
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
flprotect = PAGE_READONLY;
|
||||
map_access = FILE_MAP_READ;
|
||||
break;
|
||||
case mode_write:
|
||||
case mode::write:
|
||||
//write access requires read access
|
||||
desired_access = GENERIC_WRITE;
|
||||
creation_disposition = CREATE_ALWAYS;
|
||||
flprotect = PAGE_READWRITE;
|
||||
map_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode_readwrite:
|
||||
case mode::readwrite:
|
||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||
creation_disposition = OPEN_EXISTING;
|
||||
flprotect = PAGE_READWRITE;
|
||||
map_access = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
case mode_writeread:
|
||||
case mode::writeread:
|
||||
desired_access = GENERIC_READ | GENERIC_WRITE;
|
||||
creation_disposition = CREATE_NEW;
|
||||
flprotect = PAGE_READWRITE;
|
||||
@@ -122,30 +128,34 @@ namespace nall {
|
||||
|
||||
int p_fd;
|
||||
|
||||
bool p_open(const char *filename, filemode mode) {
|
||||
bool p_opened() const {
|
||||
return p_handle;
|
||||
}
|
||||
|
||||
bool p_open(const char *filename, mode mode_) {
|
||||
int open_flags, mmap_flags;
|
||||
|
||||
switch(mode) {
|
||||
switch(mode_) {
|
||||
default: return false;
|
||||
case mode_read:
|
||||
case mode::read:
|
||||
open_flags = O_RDONLY;
|
||||
mmap_flags = PROT_READ;
|
||||
break;
|
||||
case mode_write:
|
||||
case mode::write:
|
||||
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
|
||||
mmap_flags = PROT_WRITE;
|
||||
break;
|
||||
case mode_readwrite:
|
||||
case mode::readwrite:
|
||||
open_flags = O_RDWR;
|
||||
mmap_flags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
case mode_writeread:
|
||||
case mode::writeread:
|
||||
open_flags = O_RDWR | O_CREAT;
|
||||
mmap_flags = PROT_READ | PROT_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
p_fd = ::open(filename, open_flags);
|
||||
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
if(p_fd < 0) return false;
|
||||
|
||||
struct stat p_stat;
|
||||
|
@@ -1,90 +1,59 @@
|
||||
#ifndef NALL_FUNCTION_HPP
|
||||
#define NALL_FUNCTION_HPP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> class function;
|
||||
|
||||
template<typename R, typename... P>
|
||||
class function<R (P...)> {
|
||||
private:
|
||||
struct base1 { virtual void func1(P...) {} };
|
||||
struct base2 { virtual void func2(P...) {} };
|
||||
struct derived : base1, virtual base2 {};
|
||||
template<typename R, typename... P> class function<R (P...)> {
|
||||
struct container {
|
||||
virtual R operator()(P... p) const = 0;
|
||||
virtual container* copy() const = 0;
|
||||
virtual ~container() {}
|
||||
} *callback;
|
||||
|
||||
struct data_t {
|
||||
R (*callback)(const data_t&, P...);
|
||||
union {
|
||||
R (*callback_global)(P...);
|
||||
struct {
|
||||
R (derived::*callback_member)(P...);
|
||||
void *object;
|
||||
};
|
||||
};
|
||||
} data;
|
||||
struct global : container {
|
||||
R (*function)(P...);
|
||||
R operator()(P... p) const { return function(std::forward<P>(p)...); }
|
||||
container* copy() const { return new global(function); }
|
||||
global(R (*function)(P...)) : function(function) {}
|
||||
};
|
||||
|
||||
static R callback_global(const data_t &data, P... p) {
|
||||
return data.callback_global(p...);
|
||||
}
|
||||
template<typename C> struct member : container {
|
||||
R (C::*function)(P...);
|
||||
C *object;
|
||||
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
|
||||
container* copy() const { return new member(function, object); }
|
||||
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
static R callback_member(const data_t &data, P... p) {
|
||||
return (((C*)data.object)->*((R (C::*&)(P...))data.callback_member))(p...);
|
||||
}
|
||||
template<typename L> struct lambda : container {
|
||||
L object;
|
||||
R operator()(P... p) const { return object(std::forward<P>(p)...); }
|
||||
container* copy() const { return new lambda(object); }
|
||||
lambda(const L& object) : object(object) {}
|
||||
};
|
||||
|
||||
public:
|
||||
R operator()(P... p) const { return data.callback(data, p...); }
|
||||
operator bool() const { return data.callback; }
|
||||
void reset() { data.callback = 0; }
|
||||
operator bool() const { return callback; }
|
||||
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
|
||||
void reset() { if(callback) { delete callback; callback = 0; } }
|
||||
|
||||
function& operator=(const function &source) {
|
||||
if(this != &source) {
|
||||
if(callback) { delete callback; callback = 0; }
|
||||
if(source.callback) callback = source.callback->copy();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
function& operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
|
||||
function(const function &source) { operator=(source); }
|
||||
|
||||
//no pointer
|
||||
function() {
|
||||
data.callback = 0;
|
||||
}
|
||||
|
||||
//symbolic link pointer (nall/dl.hpp::sym, etc)
|
||||
function(void *callback) {
|
||||
data.callback = callback ? &callback_global : 0;
|
||||
data.callback_global = (R (*)(P...))callback;
|
||||
}
|
||||
|
||||
//global function pointer
|
||||
function(R (*callback)(P...)) {
|
||||
data.callback = &callback_global;
|
||||
data.callback_global = callback;
|
||||
}
|
||||
|
||||
//member function pointer
|
||||
template<typename C>
|
||||
function(R (C::*callback)(P...), C *object) {
|
||||
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
|
||||
data.callback = &callback_member<C>;
|
||||
(R (C::*&)(P...))data.callback_member = callback;
|
||||
data.object = object;
|
||||
}
|
||||
|
||||
//const member function pointer
|
||||
template<typename C>
|
||||
function(R (C::*callback)(P...) const, C *object) {
|
||||
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
|
||||
data.callback = &callback_member<C>;
|
||||
(R (C::*&)(P...))data.callback_member = (R (C::*&)(P...))callback;
|
||||
data.object = object;
|
||||
}
|
||||
|
||||
//lambda function pointer
|
||||
template<typename T>
|
||||
function(T callback) {
|
||||
static_assert(std::is_same<R, typename std::result_of<T(P...)>::type>::value, "lambda mismatch");
|
||||
data.callback = &callback_global;
|
||||
data.callback_global = (R (*)(P...))callback;
|
||||
}
|
||||
function() : callback(0) {}
|
||||
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
|
||||
function(R (*function)(P...)) { callback = new global(function); }
|
||||
template<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
|
||||
template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }
|
||||
template<typename L> function(const L& object) { callback = new lambda<L>(object); }
|
||||
~function() { if(callback) delete callback; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -92,7 +92,7 @@ struct Keyboard {
|
||||
string s(name);
|
||||
if(!strbegin(name, "KB")) return 0;
|
||||
s.ltrim("KB");
|
||||
unsigned id = strunsigned(s);
|
||||
unsigned id = decimal(s);
|
||||
auto pos = strpos(s, "::");
|
||||
if(!pos) return 0;
|
||||
s = substr(s, pos() + 2);
|
||||
@@ -189,7 +189,7 @@ struct Mouse {
|
||||
string s(name);
|
||||
if(!strbegin(name, "MS")) return 0;
|
||||
s.ltrim("MS");
|
||||
unsigned id = strunsigned(s);
|
||||
unsigned id = decimal(s);
|
||||
auto pos = strpos(s, "::");
|
||||
if(!pos) return 0;
|
||||
s = substr(s, pos() + 2);
|
||||
@@ -313,7 +313,7 @@ struct Joypad {
|
||||
string s(name);
|
||||
if(!strbegin(name, "JP")) return 0;
|
||||
s.ltrim("JP");
|
||||
unsigned id = strunsigned(s);
|
||||
unsigned id = decimal(s);
|
||||
auto pos = strpos(s, "::");
|
||||
if(!pos) return 0;
|
||||
s = substr(s, pos() + 2);
|
||||
|
@@ -112,6 +112,7 @@ namespace nall {
|
||||
imode = Size;
|
||||
idata = 0;
|
||||
isize = 0;
|
||||
icapacity = 0;
|
||||
}
|
||||
|
||||
serializer(unsigned capacity) {
|
||||
|
868
bsnes/nall/snes/cartridge.hpp
Executable file
868
bsnes/nall/snes/cartridge.hpp
Executable file
@@ -0,0 +1,868 @@
|
||||
#ifndef NALL_SNES_CARTRIDGE_HPP
|
||||
#define NALL_SNES_CARTRIDGE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
class SNESCartridge {
|
||||
public:
|
||||
string xmlMemoryMap;
|
||||
inline SNESCartridge(const uint8_t *data, unsigned size);
|
||||
|
||||
//private:
|
||||
inline void read_header(const uint8_t *data, unsigned size);
|
||||
inline unsigned find_header(const uint8_t *data, unsigned size);
|
||||
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
|
||||
inline unsigned gameboy_ram_size(const uint8_t *data, unsigned size);
|
||||
inline bool gameboy_has_rtc(const uint8_t *data, unsigned size);
|
||||
|
||||
enum HeaderField {
|
||||
CartName = 0x00,
|
||||
Mapper = 0x15,
|
||||
RomType = 0x16,
|
||||
RomSize = 0x17,
|
||||
RamSize = 0x18,
|
||||
CartRegion = 0x19,
|
||||
Company = 0x1a,
|
||||
Version = 0x1b,
|
||||
Complement = 0x1c, //inverse checksum
|
||||
Checksum = 0x1e,
|
||||
ResetVector = 0x3c,
|
||||
};
|
||||
|
||||
enum Mode {
|
||||
ModeNormal,
|
||||
ModeBsxSlotted,
|
||||
ModeBsx,
|
||||
ModeSufamiTurbo,
|
||||
ModeSuperGameBoy,
|
||||
};
|
||||
|
||||
enum Type {
|
||||
TypeNormal,
|
||||
TypeBsxSlotted,
|
||||
TypeBsxBios,
|
||||
TypeBsx,
|
||||
TypeSufamiTurboBios,
|
||||
TypeSufamiTurbo,
|
||||
TypeSuperGameBoy1Bios,
|
||||
TypeSuperGameBoy2Bios,
|
||||
TypeGameBoy,
|
||||
TypeUnknown,
|
||||
};
|
||||
|
||||
enum Region {
|
||||
NTSC,
|
||||
PAL,
|
||||
};
|
||||
|
||||
enum MemoryMapper {
|
||||
LoROM,
|
||||
HiROM,
|
||||
ExLoROM,
|
||||
ExHiROM,
|
||||
SuperFXROM,
|
||||
SA1ROM,
|
||||
SPC7110ROM,
|
||||
BSCLoROM,
|
||||
BSCHiROM,
|
||||
BSXROM,
|
||||
STROM,
|
||||
};
|
||||
|
||||
enum DSP1MemoryMapper {
|
||||
DSP1Unmapped,
|
||||
DSP1LoROM1MB,
|
||||
DSP1LoROM2MB,
|
||||
DSP1HiROM,
|
||||
};
|
||||
|
||||
bool loaded; //is a base cartridge inserted?
|
||||
unsigned crc32; //crc32 of all cartridges (base+slot(s))
|
||||
unsigned rom_size;
|
||||
unsigned ram_size;
|
||||
|
||||
Mode mode;
|
||||
Type type;
|
||||
Region region;
|
||||
MemoryMapper mapper;
|
||||
DSP1MemoryMapper dsp1_mapper;
|
||||
|
||||
bool has_bsx_slot;
|
||||
bool has_superfx;
|
||||
bool has_sa1;
|
||||
bool has_srtc;
|
||||
bool has_sdd1;
|
||||
bool has_spc7110;
|
||||
bool has_spc7110rtc;
|
||||
bool has_cx4;
|
||||
bool has_dsp1;
|
||||
bool has_dsp2;
|
||||
bool has_dsp3;
|
||||
bool has_dsp4;
|
||||
bool has_obc1;
|
||||
bool has_st010;
|
||||
bool has_st011;
|
||||
bool has_st018;
|
||||
};
|
||||
|
||||
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
||||
read_header(data, size);
|
||||
|
||||
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
|
||||
if(type == TypeBsx) {
|
||||
xml << "<cartridge/>";
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeSufamiTurbo) {
|
||||
xml << "<cartridge/>";
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
if(type == TypeGameBoy) {
|
||||
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
|
||||
if(gameboy_ram_size(data, size) > 0) {
|
||||
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
|
||||
}
|
||||
xml << "</cartridge>\n";
|
||||
xmlMemoryMap = xml;
|
||||
return;
|
||||
}
|
||||
|
||||
xml << "<cartridge";
|
||||
if(region == NTSC) {
|
||||
xml << " region='NTSC'";
|
||||
} else {
|
||||
xml << " region='PAL'";
|
||||
}
|
||||
xml << ">\n";
|
||||
|
||||
if(type == TypeSuperGameBoy1Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <supergameboy revision='1'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </supergameboy>\n";
|
||||
} else if(type == TypeSuperGameBoy2Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <supergameboy revision='2'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </supergameboy>\n";
|
||||
} else if(has_spc7110) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-cf:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
xml << " <spc7110>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-483f'/>\n";
|
||||
xml << " <map address='80-bf:4800-483f'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
if(has_spc7110rtc) {
|
||||
xml << " <rtc>\n";
|
||||
xml << " <map address='00-3f:4840-4842'/>\n";
|
||||
xml << " <map address='80-bf:4840-4842'/>\n";
|
||||
xml << " </rtc>\n";
|
||||
}
|
||||
xml << " <dcu>\n";
|
||||
xml << " <map address='50:0000-ffff'/>\n";
|
||||
xml << " </dcu>\n";
|
||||
xml << " </spc7110>\n";
|
||||
} else if(mapper == LoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-ffff'/>\n";
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
}
|
||||
} else if(mapper == HiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
}
|
||||
} else if(mapper == ExLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
}
|
||||
} else if(mapper == ExHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='400000'/>\n";
|
||||
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
|
||||
if(ram_size > 0) {
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
} else {
|
||||
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
|
||||
}
|
||||
xml << " </ram>\n";
|
||||
}
|
||||
} else if(mapper == SuperFXROM) {
|
||||
xml << " <superfx revision='2'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:3000-32ff'/>\n";
|
||||
xml << " <map address='80-bf:3000-32ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </superfx>\n";
|
||||
} else if(mapper == SA1ROM) {
|
||||
xml << " <sa1>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <iram size='800'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
|
||||
xml << " </iram>\n";
|
||||
xml << " <bwram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </bwram>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:2200-23ff'/>\n";
|
||||
xml << " <map address='80-bf:2200-23ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sa1>\n";
|
||||
} else if(mapper == BSCLoROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='linear' address='c0-ef:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
} else if(mapper == BSCHiROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram size='" << hex(ram_size) << "'>\n";
|
||||
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <slot>\n";
|
||||
xml << " <map mode='shadow' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
|
||||
xml << " <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </bsx>\n";
|
||||
} else if(mapper == BSXROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <bsx>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:5000-5fff'/>\n";
|
||||
xml << " <map address='80-bf:5000-5fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </bsx>\n";
|
||||
} else if(mapper == STROM) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-1f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-9f:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <sufamiturbo>\n";
|
||||
xml << " <slot id='A'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " <slot id='B'>\n";
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <ram>\n";
|
||||
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
|
||||
xml << " </ram>\n";
|
||||
xml << " </slot>\n";
|
||||
xml << " </sufamiturbo>\n";
|
||||
}
|
||||
|
||||
if(has_srtc) {
|
||||
xml << " <srtc>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:2800-2801'/>\n";
|
||||
xml << " <map address='80-bf:2800-2801'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </srtc>\n";
|
||||
}
|
||||
|
||||
if(has_sdd1) {
|
||||
xml << " <sdd1>\n";
|
||||
xml << " <mcu>\n";
|
||||
xml << " <map address='c0-ff:0000-ffff'/>\n";
|
||||
xml << " </mcu>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:4800-4807'/>\n";
|
||||
xml << " <map address='80-bf:4800-4807'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </sdd1>\n";
|
||||
}
|
||||
|
||||
if(has_cx4) {
|
||||
xml << " <cx4>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </cx4>\n";
|
||||
}
|
||||
|
||||
if(has_dsp1) {
|
||||
xml << " <upd77c25 program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
|
||||
if(dsp1_mapper == DSP1LoROM1MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
} else if(dsp1_mapper == DSP1LoROM2MB) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='60-6f:0000-3fff'/>\n";
|
||||
xml << " <map address='e0-ef:0000-3fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='60-6f:4000-7fff'/>\n";
|
||||
xml << " <map address='e0-ef:4000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
} else if(dsp1_mapper == DSP1HiROM) {
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='00-1f:6000-6fff'/>\n";
|
||||
xml << " <map address='80-9f:6000-6fff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='00-1f:7000-7fff'/>\n";
|
||||
xml << " <map address='80-9f:7000-7fff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
}
|
||||
xml << " </upd77c25>\n";
|
||||
}
|
||||
|
||||
if(has_dsp2) {
|
||||
xml << " <upd77c25 program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </upd77c25>\n";
|
||||
}
|
||||
|
||||
if(has_dsp3) {
|
||||
xml << " <upd77c25 program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='20-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='a0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='20-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='a0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </upd77c25>\n";
|
||||
}
|
||||
|
||||
if(has_dsp4) {
|
||||
xml << " <upd77c25 program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
|
||||
xml << " <dr>\n";
|
||||
xml << " <map address='30-3f:8000-bfff'/>\n";
|
||||
xml << " <map address='b0-bf:8000-bfff'/>\n";
|
||||
xml << " </dr>\n";
|
||||
xml << " <sr>\n";
|
||||
xml << " <map address='30-3f:c000-ffff'/>\n";
|
||||
xml << " <map address='b0-bf:c000-ffff'/>\n";
|
||||
xml << " </sr>\n";
|
||||
xml << " </upd77c25>\n";
|
||||
}
|
||||
|
||||
if(has_obc1) {
|
||||
xml << " <obc1>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </obc1>\n";
|
||||
}
|
||||
|
||||
if(has_st010) {
|
||||
xml << " <setadsp program='ST-0010'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </setadsp>\n";
|
||||
}
|
||||
|
||||
if(has_st011) {
|
||||
//ST-0011 addresses not verified; chip is unsupported
|
||||
xml << " <setadsp program='ST-0011'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='68-6f:0000-0fff'/>\n";
|
||||
xml << " <map address='e8-ef:0000-0fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </setadsp>\n";
|
||||
}
|
||||
|
||||
if(has_st018) {
|
||||
xml << " <setarisc program='ST-0018'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:3800-38ff'/>\n";
|
||||
xml << " <map address='80-bf:3800-38ff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </setarisc>\n";
|
||||
}
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
xmlMemoryMap = xml;
|
||||
}
|
||||
|
||||
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
|
||||
type = TypeUnknown;
|
||||
mapper = LoROM;
|
||||
dsp1_mapper = DSP1Unmapped;
|
||||
region = NTSC;
|
||||
rom_size = size;
|
||||
ram_size = 0;
|
||||
|
||||
has_bsx_slot = false;
|
||||
has_superfx = false;
|
||||
has_sa1 = false;
|
||||
has_srtc = false;
|
||||
has_sdd1 = false;
|
||||
has_spc7110 = false;
|
||||
has_spc7110rtc = false;
|
||||
has_cx4 = false;
|
||||
has_dsp1 = false;
|
||||
has_dsp2 = false;
|
||||
has_dsp3 = false;
|
||||
has_dsp4 = false;
|
||||
has_obc1 = false;
|
||||
has_st010 = false;
|
||||
has_st011 = false;
|
||||
has_st018 = false;
|
||||
|
||||
//=====================
|
||||
//detect Game Boy carts
|
||||
//=====================
|
||||
|
||||
if(size >= 0x0140) {
|
||||
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
|
||||
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
|
||||
type = TypeGameBoy;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(size < 32768) {
|
||||
type = TypeUnknown;
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned index = find_header(data, size);
|
||||
const uint8_t mapperid = data[index + Mapper];
|
||||
const uint8_t rom_type = data[index + RomType];
|
||||
const uint8_t rom_size = data[index + RomSize];
|
||||
const uint8_t company = data[index + Company];
|
||||
const uint8_t regionid = data[index + CartRegion] & 0x7f;
|
||||
|
||||
ram_size = 1024 << (data[index + RamSize] & 7);
|
||||
if(ram_size == 1024) ram_size = 0; //no RAM present
|
||||
|
||||
//0, 1, 13 = NTSC; 2 - 12 = PAL
|
||||
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
|
||||
|
||||
//=======================
|
||||
//detect BS-X flash carts
|
||||
//=======================
|
||||
|
||||
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
|
||||
if(data[index + 0x14] == 0x00) {
|
||||
const uint8_t n15 = data[index + 0x15];
|
||||
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
|
||||
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
|
||||
type = TypeBsx;
|
||||
mapper = BSXROM;
|
||||
region = NTSC; //BS-X only released in Japan
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=========================
|
||||
//detect Sufami Turbo carts
|
||||
//=========================
|
||||
|
||||
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
|
||||
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
|
||||
type = TypeSufamiTurboBios;
|
||||
} else {
|
||||
type = TypeSufamiTurbo;
|
||||
}
|
||||
mapper = STROM;
|
||||
region = NTSC; //Sufami Turbo only released in Japan
|
||||
return; //RAM size handled outside this routine
|
||||
}
|
||||
|
||||
//==========================
|
||||
//detect Super Game Boy BIOS
|
||||
//==========================
|
||||
|
||||
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
|
||||
type = TypeSuperGameBoy2Bios;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
|
||||
type = TypeSuperGameBoy1Bios;
|
||||
return;
|
||||
}
|
||||
|
||||
//=====================
|
||||
//detect standard carts
|
||||
//=====================
|
||||
|
||||
//detect presence of BS-X flash cartridge connector (reads extended header information)
|
||||
if(data[index - 14] == 'Z') {
|
||||
if(data[index - 11] == 'J') {
|
||||
uint8_t n13 = data[index - 13];
|
||||
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
|
||||
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
|
||||
has_bsx_slot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(has_bsx_slot) {
|
||||
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
|
||||
//BS-X base cart
|
||||
type = TypeBsxBios;
|
||||
mapper = BSXROM;
|
||||
region = NTSC; //BS-X only released in Japan
|
||||
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
|
||||
} else {
|
||||
type = TypeBsxSlotted;
|
||||
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
|
||||
region = NTSC; //BS-X slotted cartridges only released in Japan
|
||||
}
|
||||
} else {
|
||||
//standard cart
|
||||
type = TypeNormal;
|
||||
|
||||
if(index == 0x7fc0 && size >= 0x401000) {
|
||||
mapper = ExLoROM;
|
||||
} else if(index == 0x7fc0 && mapperid == 0x32) {
|
||||
mapper = ExLoROM;
|
||||
} else if(index == 0x7fc0) {
|
||||
mapper = LoROM;
|
||||
} else if(index == 0xffc0) {
|
||||
mapper = HiROM;
|
||||
} else { //index == 0x40ffc0
|
||||
mapper = ExHiROM;
|
||||
}
|
||||
}
|
||||
|
||||
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
|
||||
has_superfx = true;
|
||||
mapper = SuperFXROM;
|
||||
ram_size = 1024 << (data[index - 3] & 7);
|
||||
if(ram_size == 1024) ram_size = 0;
|
||||
}
|
||||
|
||||
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
|
||||
has_sa1 = true;
|
||||
mapper = SA1ROM;
|
||||
}
|
||||
|
||||
if(mapperid == 0x35 && rom_type == 0x55) {
|
||||
has_srtc = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
|
||||
has_sdd1 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
|
||||
has_spc7110 = true;
|
||||
has_spc7110rtc = (rom_type == 0xf9);
|
||||
mapper = SPC7110ROM;
|
||||
}
|
||||
|
||||
if(mapperid == 0x20 && rom_type == 0xf3) {
|
||||
has_cx4 = true;
|
||||
}
|
||||
|
||||
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
|
||||
has_dsp1 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
|
||||
has_dsp1 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
|
||||
has_dsp1 = true;
|
||||
}
|
||||
|
||||
if(has_dsp1 == true) {
|
||||
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
|
||||
dsp1_mapper = DSP1LoROM1MB;
|
||||
} else if((mapperid & 0x2f) == 0x20) {
|
||||
dsp1_mapper = DSP1LoROM2MB;
|
||||
} else if((mapperid & 0x2f) == 0x21) {
|
||||
dsp1_mapper = DSP1HiROM;
|
||||
}
|
||||
}
|
||||
|
||||
if(mapperid == 0x20 && rom_type == 0x05) {
|
||||
has_dsp2 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
|
||||
has_dsp3 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0x03) {
|
||||
has_dsp4 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0x25) {
|
||||
has_obc1 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
|
||||
has_st010 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
|
||||
has_st011 = true;
|
||||
}
|
||||
|
||||
if(mapperid == 0x30 && rom_type == 0xf5) {
|
||||
has_st018 = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
|
||||
unsigned score_lo = score_header(data, size, 0x007fc0);
|
||||
unsigned score_hi = score_header(data, size, 0x00ffc0);
|
||||
unsigned score_ex = score_header(data, size, 0x40ffc0);
|
||||
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
|
||||
|
||||
if(score_lo >= score_hi && score_lo >= score_ex) {
|
||||
return 0x007fc0;
|
||||
} else if(score_hi >= score_ex) {
|
||||
return 0x00ffc0;
|
||||
} else {
|
||||
return 0x40ffc0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
|
||||
if(size < addr + 64) return 0; //image too small to contain header at this location?
|
||||
int score = 0;
|
||||
|
||||
uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
|
||||
uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
|
||||
uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
|
||||
|
||||
uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
|
||||
uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
|
||||
|
||||
//$00:[000-7fff] contains uninitialized RAM and MMIO.
|
||||
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
|
||||
if(resetvector < 0x8000) return 0;
|
||||
|
||||
//some images duplicate the header in multiple locations, and others have completely
|
||||
//invalid header information that cannot be relied upon.
|
||||
//below code will analyze the first opcode executed at the specified reset vector to
|
||||
//determine the probability that this is the correct header.
|
||||
|
||||
//most likely opcodes
|
||||
if(resetop == 0x78 //sei
|
||||
|| resetop == 0x18 //clc (clc; xce)
|
||||
|| resetop == 0x38 //sec (sec; xce)
|
||||
|| resetop == 0x9c //stz $nnnn (stz $4200)
|
||||
|| resetop == 0x4c //jmp $nnnn
|
||||
|| resetop == 0x5c //jml $nnnnnn
|
||||
) score += 8;
|
||||
|
||||
//plausible opcodes
|
||||
if(resetop == 0xc2 //rep #$nn
|
||||
|| resetop == 0xe2 //sep #$nn
|
||||
|| resetop == 0xad //lda $nnnn
|
||||
|| resetop == 0xae //ldx $nnnn
|
||||
|| resetop == 0xac //ldy $nnnn
|
||||
|| resetop == 0xaf //lda $nnnnnn
|
||||
|| resetop == 0xa9 //lda #$nn
|
||||
|| resetop == 0xa2 //ldx #$nn
|
||||
|| resetop == 0xa0 //ldy #$nn
|
||||
|| resetop == 0x20 //jsr $nnnn
|
||||
|| resetop == 0x22 //jsl $nnnnnn
|
||||
) score += 4;
|
||||
|
||||
//implausible opcodes
|
||||
if(resetop == 0x40 //rti
|
||||
|| resetop == 0x60 //rts
|
||||
|| resetop == 0x6b //rtl
|
||||
|| resetop == 0xcd //cmp $nnnn
|
||||
|| resetop == 0xec //cpx $nnnn
|
||||
|| resetop == 0xcc //cpy $nnnn
|
||||
) score -= 4;
|
||||
|
||||
//least likely opcodes
|
||||
if(resetop == 0x00 //brk #$nn
|
||||
|| resetop == 0x02 //cop #$nn
|
||||
|| resetop == 0xdb //stp
|
||||
|| resetop == 0x42 //wdm
|
||||
|| resetop == 0xff //sbc $nnnnnn,x
|
||||
) score -= 8;
|
||||
|
||||
//at times, both the header and reset vector's first opcode will match ...
|
||||
//fallback and rely on info validity in these cases to determine more likely header.
|
||||
|
||||
//a valid checksum is the biggest indicator of a valid header.
|
||||
if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
|
||||
|
||||
if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
|
||||
if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
|
||||
if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
|
||||
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
|
||||
|
||||
if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
|
||||
if(data[addr + RomType] < 0x08) score++;
|
||||
if(data[addr + RomSize] < 0x10) score++;
|
||||
if(data[addr + RamSize] < 0x08) score++;
|
||||
if(data[addr + CartRegion] < 14) score++;
|
||||
|
||||
if(score < 0) score = 0;
|
||||
return score;
|
||||
}
|
||||
|
||||
unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
|
||||
if(size < 512) return 0;
|
||||
switch(data[0x0149]) {
|
||||
case 0x00: return 0 * 1024;
|
||||
case 0x01: return 8 * 1024;
|
||||
case 0x02: return 8 * 1024;
|
||||
case 0x03: return 32 * 1024;
|
||||
case 0x04: return 128 * 1024;
|
||||
case 0x05: return 128 * 1024;
|
||||
default: return 128 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
|
||||
if(size < 512) return false;
|
||||
if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
458
bsnes/nall/snes/cpu.hpp
Executable file
458
bsnes/nall/snes/cpu.hpp
Executable file
@@ -0,0 +1,458 @@
|
||||
#ifndef NALL_SNES_CPU_HPP
|
||||
#define NALL_SNES_CPU_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct SNESCPU {
|
||||
enum : unsigned {
|
||||
Implied, //
|
||||
Constant, //#$00
|
||||
AccumConstant, //#$00
|
||||
IndexConstant, //#$00
|
||||
Direct, //$00
|
||||
DirectX, //$00,x
|
||||
DirectY, //$00,y
|
||||
IDirect, //($00)
|
||||
IDirectX, //($00,x)
|
||||
IDirectY, //($00),y
|
||||
ILDirect, //[$00]
|
||||
ILDirectY, //[$00],y
|
||||
Address, //$0000
|
||||
AddressX, //$0000,x
|
||||
AddressY, //$0000,y
|
||||
IAddressX, //($0000,x)
|
||||
ILAddress, //[$0000]
|
||||
PAddress, //PBR:$0000
|
||||
PIAddress, //PBR:($0000)
|
||||
Long, //$000000
|
||||
LongX, //$000000,x
|
||||
Stack, //$00,s
|
||||
IStackY, //($00,s),y
|
||||
BlockMove, //$00,$00
|
||||
RelativeShort, //+/- $00
|
||||
RelativeLong, //+/- $0000
|
||||
};
|
||||
|
||||
struct OpcodeInfo {
|
||||
char name[4];
|
||||
unsigned mode;
|
||||
};
|
||||
|
||||
static const OpcodeInfo opcodeInfo[256];
|
||||
|
||||
static unsigned getOpcodeLength(bool accum, bool index, uint8_t opcode);
|
||||
static string disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb);
|
||||
};
|
||||
|
||||
const SNESCPU::OpcodeInfo SNESCPU::opcodeInfo[256] = {
|
||||
//0x00 - 0x0f
|
||||
{ "brk", Constant },
|
||||
{ "ora", IDirectX },
|
||||
{ "cop", Constant },
|
||||
{ "ora", Stack },
|
||||
|
||||
{ "tsb", Direct },
|
||||
{ "ora", Direct },
|
||||
{ "asl", Direct },
|
||||
{ "ora", ILDirect },
|
||||
|
||||
{ "php", Implied },
|
||||
{ "ora", AccumConstant },
|
||||
{ "asl", Implied },
|
||||
{ "phd", Implied },
|
||||
|
||||
{ "tsb", Address },
|
||||
{ "ora", Address },
|
||||
{ "asl", Address },
|
||||
{ "ora", Long },
|
||||
|
||||
//0x10 - 0x1f
|
||||
{ "bpl", RelativeShort },
|
||||
{ "ora", IDirectY },
|
||||
{ "ora", IDirect },
|
||||
{ "ora", IStackY },
|
||||
|
||||
{ "trb", Direct },
|
||||
{ "ora", DirectX },
|
||||
{ "asl", DirectX },
|
||||
{ "ora", ILDirectY },
|
||||
|
||||
{ "clc", Implied },
|
||||
{ "ora", AddressY },
|
||||
{ "inc", Implied },
|
||||
{ "tcs", Implied },
|
||||
|
||||
{ "trb", Address },
|
||||
{ "ora", AddressX },
|
||||
{ "asl", AddressX },
|
||||
{ "ora", LongX },
|
||||
|
||||
//0x20 - 0x2f
|
||||
{ "jsr", Address },
|
||||
{ "and", IDirectX },
|
||||
{ "jsl", Long },
|
||||
{ "and", Stack },
|
||||
|
||||
{ "bit", Direct },
|
||||
{ "and", Direct },
|
||||
{ "rol", Direct },
|
||||
{ "and", ILDirect },
|
||||
|
||||
{ "plp", Implied },
|
||||
{ "and", AccumConstant },
|
||||
{ "rol", Implied },
|
||||
{ "pld", Implied },
|
||||
|
||||
{ "bit", Address },
|
||||
{ "and", Address },
|
||||
{ "rol", Address },
|
||||
{ "and", Long },
|
||||
|
||||
//0x30 - 0x3f
|
||||
{ "bmi", RelativeShort },
|
||||
{ "and", IDirectY },
|
||||
{ "and", IDirect },
|
||||
{ "and", IStackY },
|
||||
|
||||
{ "bit", DirectX },
|
||||
{ "and", DirectX },
|
||||
{ "rol", DirectX },
|
||||
{ "and", ILDirectY },
|
||||
|
||||
{ "sec", Implied },
|
||||
{ "and", AddressY },
|
||||
{ "dec", Implied },
|
||||
{ "tsc", Implied },
|
||||
|
||||
{ "bit", AddressX },
|
||||
{ "and", AddressX },
|
||||
{ "rol", AddressX },
|
||||
{ "and", LongX },
|
||||
|
||||
//0x40 - 0x4f
|
||||
{ "rti", Implied },
|
||||
{ "eor", IDirectX },
|
||||
{ "wdm", Constant },
|
||||
{ "eor", Stack },
|
||||
|
||||
{ "mvp", BlockMove },
|
||||
{ "eor", Direct },
|
||||
{ "lsr", Direct },
|
||||
{ "eor", ILDirect },
|
||||
|
||||
{ "pha", Implied },
|
||||
{ "eor", AccumConstant },
|
||||
{ "lsr", Implied },
|
||||
{ "phk", Implied },
|
||||
|
||||
{ "jmp", PAddress },
|
||||
{ "eor", Address },
|
||||
{ "lsr", Address },
|
||||
{ "eor", Long },
|
||||
|
||||
//0x50 - 0x5f
|
||||
{ "bvc", RelativeShort },
|
||||
{ "eor", IDirectY },
|
||||
{ "eor", IDirect },
|
||||
{ "eor", IStackY },
|
||||
|
||||
{ "mvn", BlockMove },
|
||||
{ "eor", DirectX },
|
||||
{ "lsr", DirectX },
|
||||
{ "eor", ILDirectY },
|
||||
|
||||
{ "cli", Implied },
|
||||
{ "eor", AddressY },
|
||||
{ "phy", Implied },
|
||||
{ "tcd", Implied },
|
||||
|
||||
{ "jml", Long },
|
||||
{ "eor", AddressX },
|
||||
{ "lsr", AddressX },
|
||||
{ "eor", LongX },
|
||||
|
||||
//0x60 - 0x6f
|
||||
{ "rts", Implied },
|
||||
{ "adc", IDirectX },
|
||||
{ "per", Address },
|
||||
{ "adc", Stack },
|
||||
|
||||
{ "stz", Direct },
|
||||
{ "adc", Direct },
|
||||
{ "ror", Direct },
|
||||
{ "adc", ILDirect },
|
||||
|
||||
{ "pla", Implied },
|
||||
{ "adc", AccumConstant },
|
||||
{ "ror", Implied },
|
||||
{ "rtl", Implied },
|
||||
|
||||
{ "jmp", PIAddress },
|
||||
{ "adc", Address },
|
||||
{ "ror", Address },
|
||||
{ "adc", Long },
|
||||
|
||||
//0x70 - 0x7f
|
||||
{ "bvs", RelativeShort },
|
||||
{ "adc", IDirectY },
|
||||
{ "adc", IDirect },
|
||||
{ "adc", IStackY },
|
||||
|
||||
{ "stz", DirectX },
|
||||
{ "adc", DirectX },
|
||||
{ "ror", DirectX },
|
||||
{ "adc", ILDirectY },
|
||||
|
||||
{ "sei", Implied },
|
||||
{ "adc", AddressY },
|
||||
{ "ply", Implied },
|
||||
{ "tdc", Implied },
|
||||
|
||||
{ "jmp", IAddressX },
|
||||
{ "adc", AddressX },
|
||||
{ "ror", AddressX },
|
||||
{ "adc", LongX },
|
||||
|
||||
//0x80 - 0x8f
|
||||
{ "bra", RelativeShort },
|
||||
{ "sta", IDirectX },
|
||||
{ "brl", RelativeLong },
|
||||
{ "sta", Stack },
|
||||
|
||||
{ "sty", Direct },
|
||||
{ "sta", Direct },
|
||||
{ "stx", Direct },
|
||||
{ "sta", ILDirect },
|
||||
|
||||
{ "dey", Implied },
|
||||
{ "bit", AccumConstant },
|
||||
{ "txa", Implied },
|
||||
{ "phb", Implied },
|
||||
|
||||
{ "sty", Address },
|
||||
{ "sta", Address },
|
||||
{ "stx", Address },
|
||||
{ "sta", Long },
|
||||
|
||||
//0x90 - 0x9f
|
||||
{ "bcc", RelativeShort },
|
||||
{ "sta", IDirectY },
|
||||
{ "sta", IDirect },
|
||||
{ "sta", IStackY },
|
||||
|
||||
{ "sty", DirectX },
|
||||
{ "sta", DirectX },
|
||||
{ "stx", DirectY },
|
||||
{ "sta", ILDirectY },
|
||||
|
||||
{ "tya", Implied },
|
||||
{ "sta", AddressY },
|
||||
{ "txs", Implied },
|
||||
{ "txy", Implied },
|
||||
|
||||
{ "stz", Address },
|
||||
{ "sta", AddressX },
|
||||
{ "stz", AddressX },
|
||||
{ "sta", LongX },
|
||||
|
||||
//0xa0 - 0xaf
|
||||
{ "ldy", IndexConstant },
|
||||
{ "lda", IDirectX },
|
||||
{ "ldx", IndexConstant },
|
||||
{ "lda", Stack },
|
||||
|
||||
{ "ldy", Direct },
|
||||
{ "lda", Direct },
|
||||
{ "ldx", Direct },
|
||||
{ "lda", ILDirect },
|
||||
|
||||
{ "tay", Implied },
|
||||
{ "lda", AccumConstant },
|
||||
{ "tax", Implied },
|
||||
{ "plb", Implied },
|
||||
|
||||
{ "ldy", Address },
|
||||
{ "lda", Address },
|
||||
{ "ldx", Address },
|
||||
{ "lda", Long },
|
||||
|
||||
//0xb0 - 0xbf
|
||||
{ "bcs", RelativeShort },
|
||||
{ "lda", IDirectY },
|
||||
{ "lda", IDirect },
|
||||
{ "lda", IStackY },
|
||||
|
||||
{ "ldy", DirectX },
|
||||
{ "lda", DirectX },
|
||||
{ "ldx", DirectY },
|
||||
{ "lda", ILDirectY },
|
||||
|
||||
{ "clv", Implied },
|
||||
{ "lda", AddressY },
|
||||
{ "tsx", Implied },
|
||||
{ "tyx", Implied },
|
||||
|
||||
{ "ldy", AddressX },
|
||||
{ "lda", AddressX },
|
||||
{ "ldx", AddressY },
|
||||
{ "lda", LongX },
|
||||
|
||||
//0xc0 - 0xcf
|
||||
{ "cpy", IndexConstant },
|
||||
{ "cmp", IDirectX },
|
||||
{ "rep", Constant },
|
||||
{ "cmp", Stack },
|
||||
|
||||
{ "cpy", Direct },
|
||||
{ "cmp", Direct },
|
||||
{ "dec", Direct },
|
||||
{ "cmp", ILDirect },
|
||||
|
||||
{ "iny", Implied },
|
||||
{ "cmp", AccumConstant },
|
||||
{ "dex", Implied },
|
||||
{ "wai", Implied },
|
||||
|
||||
{ "cpy", Address },
|
||||
{ "cmp", Address },
|
||||
{ "dec", Address },
|
||||
{ "cmp", Long },
|
||||
|
||||
//0xd0 - 0xdf
|
||||
{ "bne", RelativeShort },
|
||||
{ "cmp", IDirectY },
|
||||
{ "cmp", IDirect },
|
||||
{ "cmp", IStackY },
|
||||
|
||||
{ "pei", IDirect },
|
||||
{ "cmp", DirectX },
|
||||
{ "dec", DirectX },
|
||||
{ "cmp", ILDirectY },
|
||||
|
||||
{ "cld", Implied },
|
||||
{ "cmp", AddressY },
|
||||
{ "phx", Implied },
|
||||
{ "stp", Implied },
|
||||
|
||||
{ "jmp", ILAddress },
|
||||
{ "cmp", AddressX },
|
||||
{ "dec", AddressX },
|
||||
{ "cmp", LongX },
|
||||
|
||||
//0xe0 - 0xef
|
||||
{ "cpx", IndexConstant },
|
||||
{ "sbc", IDirectX },
|
||||
{ "sep", Constant },
|
||||
{ "sbc", Stack },
|
||||
|
||||
{ "cpx", Direct },
|
||||
{ "sbc", Direct },
|
||||
{ "inc", Direct },
|
||||
{ "sbc", ILDirect },
|
||||
|
||||
{ "inx", Implied },
|
||||
{ "sbc", AccumConstant },
|
||||
{ "nop", Implied },
|
||||
{ "xba", Implied },
|
||||
|
||||
{ "cpx", Address },
|
||||
{ "sbc", Address },
|
||||
{ "inc", Address },
|
||||
{ "sbc", Long },
|
||||
|
||||
//0xf0 - 0xff
|
||||
{ "beq", RelativeShort },
|
||||
{ "sbc", IDirectY },
|
||||
{ "sbc", IDirect },
|
||||
{ "sbc", IStackY },
|
||||
|
||||
{ "pea", Address },
|
||||
{ "sbc", DirectX },
|
||||
{ "inc", DirectX },
|
||||
{ "sbc", ILDirectY },
|
||||
|
||||
{ "sed", Implied },
|
||||
{ "sbc", AddressY },
|
||||
{ "plx", Implied },
|
||||
{ "xce", Implied },
|
||||
|
||||
{ "jsr", IAddressX },
|
||||
{ "sbc", AddressX },
|
||||
{ "inc", AddressX },
|
||||
{ "sbc", LongX },
|
||||
};
|
||||
|
||||
inline unsigned SNESCPU::getOpcodeLength(bool accum, bool index, uint8_t opcode) {
|
||||
switch(opcodeInfo[opcode].mode) { default:
|
||||
case Implied: return 1;
|
||||
case Constant: return 2;
|
||||
case AccumConstant: return 3 - accum;
|
||||
case IndexConstant: return 3 - index;
|
||||
case Direct: return 2;
|
||||
case DirectX: return 2;
|
||||
case DirectY: return 2;
|
||||
case IDirect: return 2;
|
||||
case IDirectX: return 2;
|
||||
case IDirectY: return 2;
|
||||
case ILDirect: return 2;
|
||||
case ILDirectY: return 2;
|
||||
case Address: return 3;
|
||||
case AddressX: return 3;
|
||||
case AddressY: return 3;
|
||||
case IAddressX: return 3;
|
||||
case ILAddress: return 3;
|
||||
case PAddress: return 3;
|
||||
case PIAddress: return 3;
|
||||
case Long: return 4;
|
||||
case LongX: return 4;
|
||||
case Stack: return 2;
|
||||
case IStackY: return 2;
|
||||
case BlockMove: return 3;
|
||||
case RelativeShort: return 2;
|
||||
case RelativeLong: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
inline string SNESCPU::disassemble(unsigned pc, bool accum, bool index, uint8_t opcode, uint8_t pl, uint8_t ph, uint8_t pb) {
|
||||
string name = opcodeInfo[opcode].name;
|
||||
unsigned mode = opcodeInfo[opcode].mode;
|
||||
|
||||
if(mode == Implied) return name;
|
||||
if(mode == Constant) return { name, " #$", hex<2>(pl) };
|
||||
if(mode == AccumConstant) return { name, " #$", accum ? "" : hex<2>(ph), hex<2>(pl) };
|
||||
if(mode == IndexConstant) return { name, " #$", index ? "" : hex<2>(ph), hex<2>(pl) };
|
||||
if(mode == Direct) return { name, " $", hex<2>(pl) };
|
||||
if(mode == DirectX) return { name, " $", hex<2>(pl), ",x" };
|
||||
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
|
||||
if(mode == IDirect) return { name, " ($", hex<2>(pl), ")" };
|
||||
if(mode == IDirectX) return { name, " ($", hex<2>(pl), ",x)" };
|
||||
if(mode == IDirectY) return { name, " ($", hex<2>(pl), "),y" };
|
||||
if(mode == ILDirect) return { name, " [$", hex<2>(pl), "]" };
|
||||
if(mode == ILDirectY) return { name, " [$", hex<2>(pl), "],y" };
|
||||
if(mode == Address) return { name, " $", hex<2>(ph), hex<2>(pl) };
|
||||
if(mode == AddressX) return { name, " $", hex<2>(ph), hex<2>(pl), ",x" };
|
||||
if(mode == AddressY) return { name, " $", hex<2>(ph), hex<2>(pl), ",y" };
|
||||
if(mode == IAddressX) return { name, " ($", hex<2>(ph), hex<2>(pl), ",x)" };
|
||||
if(mode == ILAddress) return { name, " [$", hex<2>(ph), hex<2>(pl), "]" };
|
||||
if(mode == PAddress) return { name, " $", hex<2>(ph), hex<2>(pl) };
|
||||
if(mode == PIAddress) return { name, " ($", hex<2>(ph), hex<2>(pl), ")" };
|
||||
if(mode == Long) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl) };
|
||||
if(mode == LongX) return { name, " $", hex<2>(pb), hex<2>(ph), hex<2>(pl), ",x" };
|
||||
if(mode == Stack) return { name, " $", hex<2>(pl), ",s" };
|
||||
if(mode == IStackY) return { name, " ($", hex<2>(pl), ",s),y" };
|
||||
if(mode == BlockMove) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
|
||||
if(mode == RelativeShort) {
|
||||
unsigned addr = (pc + 2) + (int8_t)(pl << 0);
|
||||
return { name, " $", hex<4>(addr) };
|
||||
}
|
||||
if(mode == RelativeLong) {
|
||||
unsigned addr = (pc + 3) + (int16_t)((ph << 8) + (pl << 0));
|
||||
return { name, " $", hex<4>(addr) };
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
639
bsnes/nall/snes/smp.hpp
Executable file
639
bsnes/nall/snes/smp.hpp
Executable file
@@ -0,0 +1,639 @@
|
||||
#ifndef NALL_SNES_SMP_HPP
|
||||
#define NALL_SNES_SMP_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct SNESSMP {
|
||||
enum : unsigned {
|
||||
Implied, //
|
||||
TVector, //0
|
||||
Direct, //$00
|
||||
DirectRelative, //$00,+/-$00
|
||||
ADirect, //a,$00
|
||||
AAbsolute, //a,$0000
|
||||
AIX, //a,(x)
|
||||
AIDirectX, //a,($00+x)
|
||||
AConstant, //a,#$00
|
||||
DirectDirect, //$00,$00
|
||||
CAbsoluteBit, //c,$0000:0
|
||||
Absolute, //$0000
|
||||
P, //p
|
||||
AbsoluteA, //$0000,a
|
||||
Relative, //+/-$00
|
||||
ADirectX, //a,$00+x
|
||||
AAbsoluteX, //a,$0000+x
|
||||
AAbsoluteY, //a,$0000+y
|
||||
AIDirectY, //a,($00)+y
|
||||
DirectConstant, //$00,#$00
|
||||
IXIY, //(x),(y)
|
||||
DirectX, //$00+x
|
||||
A, //a
|
||||
X, //x
|
||||
XAbsolute, //x,$0000
|
||||
IAbsoluteX, //($0000+x)
|
||||
CNAbsoluteBit, //c,!$0000:0
|
||||
XDirect, //x,$00
|
||||
PVector, //$ff00
|
||||
YaDirect, //ya,$00
|
||||
XA, //x,a
|
||||
YAbsolute, //y,$0000
|
||||
Y, //y
|
||||
AX, //a,x
|
||||
YDirect, //y,$00
|
||||
YConstant, //y,#$00
|
||||
XSp, //x,sp
|
||||
YaX, //ya,x
|
||||
IXPA, //(x)+,a
|
||||
SpX, //sp,x
|
||||
AIXP, //a,(x)+
|
||||
DirectA, //$00,a
|
||||
IXA, //(x),a
|
||||
IDirectXA, //($00+x),a
|
||||
XConstant, //x,#$00
|
||||
AbsoluteX, //$0000,x
|
||||
AbsoluteBitC, //$0000:0,c
|
||||
DirectY, //$00,y
|
||||
AbsoluteY, //$0000,y
|
||||
Ya, //ya
|
||||
DirectXA, //$00+x,a
|
||||
AbsoluteXA, //$0000+x,a
|
||||
AbsoluteYA, //$0000+y,a
|
||||
IDirectYA, //($00)+y,a
|
||||
DirectYX, //$00+y,x
|
||||
DirectYa, //$00,ya
|
||||
DirectXY, //$00+x,y
|
||||
AY, //a,y
|
||||
DirectXRelative, //$00+x,+/-$00
|
||||
XDirectY, //x,$00+y
|
||||
YDirectX, //y,$00+x
|
||||
YA, //y,a
|
||||
YRelative, //y,+/-$00
|
||||
};
|
||||
|
||||
struct OpcodeInfo {
|
||||
char name[6];
|
||||
unsigned mode;
|
||||
};
|
||||
|
||||
static const OpcodeInfo opcodeInfo[256];
|
||||
|
||||
static unsigned getOpcodeLength(uint8_t opcode);
|
||||
static string disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph);
|
||||
static string disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph);
|
||||
};
|
||||
|
||||
const SNESSMP::OpcodeInfo SNESSMP::opcodeInfo[256] = {
|
||||
//0x00 - 0x0f
|
||||
{ "nop ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set0 ", Direct },
|
||||
{ "bbs0 ", DirectRelative },
|
||||
|
||||
{ "or ", ADirect },
|
||||
{ "or ", AAbsolute },
|
||||
{ "or ", AIX },
|
||||
{ "or ", AIDirectX },
|
||||
|
||||
{ "or ", AConstant },
|
||||
{ "or ", DirectDirect },
|
||||
{ "or1 ", CAbsoluteBit },
|
||||
{ "asl ", Direct },
|
||||
|
||||
{ "asl ", Absolute },
|
||||
{ "push ", P },
|
||||
{ "tset ", AbsoluteA },
|
||||
{ "brk ", Implied },
|
||||
|
||||
//0x10 - 0x1f
|
||||
{ "bpl ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr0 ", Direct },
|
||||
{ "bbc0 ", DirectRelative },
|
||||
|
||||
{ "or ", ADirectX },
|
||||
{ "or ", AAbsoluteX },
|
||||
{ "or ", AAbsoluteY },
|
||||
{ "or ", AIDirectY },
|
||||
|
||||
{ "or ", DirectConstant },
|
||||
{ "or ", IXIY },
|
||||
{ "decw ", Direct },
|
||||
{ "asl ", DirectX },
|
||||
|
||||
{ "asl ", A },
|
||||
{ "dec ", X },
|
||||
{ "cmp ", XAbsolute },
|
||||
{ "jmp ", IAbsoluteX },
|
||||
|
||||
//0x20 - 0x2f
|
||||
{ "clrp ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set1 ", Direct },
|
||||
{ "bbs1 ", DirectRelative },
|
||||
|
||||
{ "and ", ADirect },
|
||||
{ "and ", AAbsolute },
|
||||
{ "and ", AIX },
|
||||
{ "and ", AIDirectX },
|
||||
|
||||
{ "and ", AConstant },
|
||||
{ "and ", DirectDirect },
|
||||
{ "or1 ", CNAbsoluteBit },
|
||||
{ "rol ", Direct },
|
||||
|
||||
{ "rol ", Absolute },
|
||||
{ "push ", A },
|
||||
{ "cbne ", DirectRelative },
|
||||
{ "bra ", Relative },
|
||||
|
||||
//0x30 - 0x3f
|
||||
{ "bmi ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr1 ", Direct },
|
||||
{ "bbc1 ", DirectRelative },
|
||||
|
||||
{ "and ", ADirectX },
|
||||
{ "and ", AAbsoluteX },
|
||||
{ "and ", AAbsoluteY },
|
||||
{ "and ", AIDirectY },
|
||||
|
||||
{ "and ", DirectConstant },
|
||||
{ "and ", IXIY },
|
||||
{ "incw ", Direct },
|
||||
{ "rol ", DirectX },
|
||||
|
||||
{ "rol ", A },
|
||||
{ "inc ", X },
|
||||
{ "cmp ", XDirect },
|
||||
{ "call ", Absolute },
|
||||
|
||||
//0x40 - 0x4f
|
||||
{ "setp ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set2 ", Direct },
|
||||
{ "bbs2 ", DirectRelative },
|
||||
|
||||
{ "eor ", ADirect },
|
||||
{ "eor ", AAbsolute },
|
||||
{ "eor ", AIX },
|
||||
{ "eor ", AIDirectX },
|
||||
|
||||
{ "eor ", AConstant },
|
||||
{ "eor ", DirectDirect },
|
||||
{ "and1 ", CAbsoluteBit },
|
||||
{ "lsr ", Direct },
|
||||
|
||||
{ "lsr ", Absolute },
|
||||
{ "push ", X },
|
||||
{ "tclr ", AbsoluteA },
|
||||
{ "pcall", PVector },
|
||||
|
||||
//0x50 - 0x5f
|
||||
{ "bvc ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr2 ", Direct },
|
||||
{ "bbc2 ", DirectRelative },
|
||||
|
||||
{ "eor ", ADirectX },
|
||||
{ "eor ", AAbsoluteX },
|
||||
{ "eor ", AAbsoluteY },
|
||||
{ "eor ", AIDirectY },
|
||||
|
||||
{ "eor ", DirectConstant },
|
||||
{ "eor ", IXIY },
|
||||
{ "cmpw ", YaDirect },
|
||||
{ "lsr ", DirectX },
|
||||
|
||||
{ "lsr ", A },
|
||||
{ "mov ", XA },
|
||||
{ "cmp ", YAbsolute },
|
||||
{ "jmp ", Absolute },
|
||||
|
||||
//0x60 - 0x6f
|
||||
{ "clrc ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set3 ", Direct },
|
||||
{ "bbs3 ", DirectRelative },
|
||||
|
||||
{ "cmp ", ADirect },
|
||||
{ "cmp ", AAbsolute },
|
||||
{ "cmp ", AIX },
|
||||
{ "cmp ", AIDirectX },
|
||||
|
||||
{ "cmp ", AConstant },
|
||||
{ "cmp ", DirectDirect },
|
||||
{ "and1 ", CNAbsoluteBit },
|
||||
{ "ror ", Direct },
|
||||
|
||||
{ "ror ", Absolute },
|
||||
{ "push ", Y },
|
||||
{ "dbnz ", DirectRelative },
|
||||
{ "ret ", Implied },
|
||||
|
||||
//0x70 - 0x7f
|
||||
{ "bvs ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr3 ", Direct },
|
||||
{ "bbc3 ", DirectRelative },
|
||||
|
||||
{ "cmp ", ADirectX },
|
||||
{ "cmp ", AAbsoluteX },
|
||||
{ "cmp ", AAbsoluteY },
|
||||
{ "cmp ", AIDirectY },
|
||||
|
||||
{ "cmp ", DirectConstant },
|
||||
{ "cmp ", IXIY },
|
||||
{ "addw ", YaDirect },
|
||||
{ "ror ", DirectX },
|
||||
|
||||
{ "ror ", A },
|
||||
{ "mov ", AX },
|
||||
{ "cmp ", YDirect },
|
||||
{ "reti ", Implied },
|
||||
|
||||
//0x80 - 0x8f
|
||||
{ "setc ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set4 ", Direct },
|
||||
{ "bbs4 ", DirectRelative },
|
||||
|
||||
{ "adc ", ADirect },
|
||||
{ "adc ", AAbsolute },
|
||||
{ "adc ", AIX },
|
||||
{ "adc ", AIDirectX },
|
||||
|
||||
{ "adc ", AConstant },
|
||||
{ "adc ", DirectDirect },
|
||||
{ "eor1 ", CAbsoluteBit },
|
||||
{ "dec ", Direct },
|
||||
|
||||
{ "dec ", Absolute },
|
||||
{ "mov ", YConstant },
|
||||
{ "pop ", P },
|
||||
{ "mov ", DirectConstant },
|
||||
|
||||
//0x90 - 0x9f
|
||||
{ "bcc ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr4 ", Direct },
|
||||
{ "bbc4 ", DirectRelative },
|
||||
|
||||
{ "adc ", ADirectX },
|
||||
{ "adc ", AAbsoluteX },
|
||||
{ "adc ", AAbsoluteY },
|
||||
{ "adc ", AIDirectY },
|
||||
|
||||
{ "adc ", DirectRelative },
|
||||
{ "adc ", IXIY },
|
||||
{ "subw ", YaDirect },
|
||||
{ "dec ", DirectX },
|
||||
|
||||
{ "dec ", A },
|
||||
{ "mov ", XSp },
|
||||
{ "div ", YaX },
|
||||
{ "xcn ", A },
|
||||
|
||||
//0xa0 - 0xaf
|
||||
{ "ei ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set5 ", Direct },
|
||||
{ "bbs5 ", DirectRelative },
|
||||
|
||||
{ "sbc ", ADirect },
|
||||
{ "sbc ", AAbsolute },
|
||||
{ "sbc ", AIX },
|
||||
{ "sbc ", AIDirectX },
|
||||
|
||||
{ "sbc ", AConstant },
|
||||
{ "sbc ", DirectDirect },
|
||||
{ "mov1 ", CAbsoluteBit },
|
||||
{ "inc ", Direct },
|
||||
|
||||
{ "inc ", Absolute },
|
||||
{ "cmp ", YConstant },
|
||||
{ "pop ", A },
|
||||
{ "mov ", IXPA },
|
||||
|
||||
//0xb0 - 0xbf
|
||||
{ "bcs ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr5 ", Direct },
|
||||
{ "bbc5 ", DirectRelative },
|
||||
|
||||
{ "sbc ", ADirectX },
|
||||
{ "sbc ", AAbsoluteX },
|
||||
{ "sbc ", AAbsoluteY },
|
||||
{ "sbc ", AIDirectY },
|
||||
|
||||
{ "sbc ", DirectConstant },
|
||||
{ "sbc ", IXIY },
|
||||
{ "movw ", YaDirect },
|
||||
{ "inc ", DirectX },
|
||||
|
||||
{ "inc ", A },
|
||||
{ "mov ", SpX },
|
||||
{ "das ", A },
|
||||
{ "mov ", AIXP },
|
||||
|
||||
//0xc0 - 0xcf
|
||||
{ "di ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set6 ", Direct },
|
||||
{ "bbs6 ", DirectRelative },
|
||||
|
||||
{ "mov ", DirectA },
|
||||
{ "mov ", AbsoluteA },
|
||||
{ "mov ", IXA },
|
||||
{ "mov ", IDirectXA },
|
||||
|
||||
{ "cmp ", XConstant },
|
||||
{ "mov ", AbsoluteX },
|
||||
{ "mov1 ", AbsoluteBitC },
|
||||
{ "mov ", DirectY },
|
||||
|
||||
{ "mov ", AbsoluteY },
|
||||
{ "mov ", XConstant },
|
||||
{ "pop ", X },
|
||||
{ "mul ", Ya },
|
||||
|
||||
//0xd0 - 0xdf
|
||||
{ "bne ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr6 ", Relative },
|
||||
{ "bbc6 ", DirectRelative },
|
||||
|
||||
{ "mov ", DirectXA },
|
||||
{ "mov ", AbsoluteXA },
|
||||
{ "mov ", AbsoluteYA },
|
||||
{ "mov ", IDirectYA },
|
||||
|
||||
{ "mov ", DirectX },
|
||||
{ "mov ", DirectYX },
|
||||
{ "movw ", DirectYa },
|
||||
{ "mov ", DirectXY },
|
||||
|
||||
{ "dec ", Y },
|
||||
{ "mov ", AY },
|
||||
{ "cbne ", DirectXRelative },
|
||||
{ "daa ", A },
|
||||
|
||||
//0xe0 - 0xef
|
||||
{ "clrv ", Implied },
|
||||
{ "tcall", TVector },
|
||||
{ "set7 ", Direct },
|
||||
{ "bbs7 ", DirectRelative },
|
||||
|
||||
{ "mov ", ADirect },
|
||||
{ "mov ", AAbsolute },
|
||||
{ "mov ", AIX },
|
||||
{ "mov ", AIDirectX },
|
||||
|
||||
{ "mov ", AConstant },
|
||||
{ "mov ", XAbsolute },
|
||||
{ "not1 ", CAbsoluteBit },
|
||||
{ "mov ", YDirect },
|
||||
|
||||
{ "mov ", YAbsolute },
|
||||
{ "notc ", Implied },
|
||||
{ "pop ", Y },
|
||||
{ "sleep", Implied },
|
||||
|
||||
//0xf0 - 0xff
|
||||
{ "beq ", Relative },
|
||||
{ "tcall", TVector },
|
||||
{ "clr7 ", Direct },
|
||||
{ "bbc7 ", DirectRelative },
|
||||
|
||||
{ "mov ", ADirectX },
|
||||
{ "mov ", AAbsoluteX },
|
||||
{ "mov ", AAbsoluteY },
|
||||
{ "mov ", AIDirectY },
|
||||
|
||||
{ "mov ", XDirect },
|
||||
{ "mov ", XDirectY },
|
||||
{ "mov ", DirectDirect },
|
||||
{ "mov ", YDirectX },
|
||||
|
||||
{ "inc ", Y },
|
||||
{ "mov ", YA },
|
||||
{ "dbz ", YRelative },
|
||||
{ "stop ", Implied },
|
||||
};
|
||||
|
||||
inline unsigned SNESSMP::getOpcodeLength(uint8_t opcode) {
|
||||
switch(opcodeInfo[opcode].mode) { default:
|
||||
case Implied: return 1; //
|
||||
case TVector: return 1; //0
|
||||
case Direct: return 2; //$00
|
||||
case DirectRelative: return 3; //$00,+/-$00
|
||||
case ADirect: return 2; //a,$00
|
||||
case AAbsolute: return 3; //a,$0000
|
||||
case AIX: return 1; //a,(x)
|
||||
case AIDirectX: return 2; //a,($00+x)
|
||||
case AConstant: return 2; //a,#$00
|
||||
case DirectDirect: return 3; //$00,$00
|
||||
case CAbsoluteBit: return 3; //c,$0000:0
|
||||
case Absolute: return 3; //$0000
|
||||
case P: return 1; //p
|
||||
case AbsoluteA: return 3; //$0000,a
|
||||
case Relative: return 2; //+/-$00
|
||||
case ADirectX: return 2; //a,$00+x
|
||||
case AAbsoluteX: return 3; //a,$0000+x
|
||||
case AAbsoluteY: return 3; //a,$0000+y
|
||||
case AIDirectY: return 2; //a,($00)+y
|
||||
case DirectConstant: return 3; //$00,#$00
|
||||
case IXIY: return 1; //(x),(y)
|
||||
case DirectX: return 2; //$00+x
|
||||
case A: return 1; //a
|
||||
case X: return 1; //x
|
||||
case XAbsolute: return 3; //x,$0000
|
||||
case IAbsoluteX: return 3; //($0000+x)
|
||||
case CNAbsoluteBit: return 3; //c,!$0000:0
|
||||
case XDirect: return 2; //x,$00
|
||||
case PVector: return 2; //$ff00
|
||||
case YaDirect: return 2; //ya,$00
|
||||
case XA: return 1; //x,a
|
||||
case YAbsolute: return 3; //y,$0000
|
||||
case Y: return 1; //y
|
||||
case AX: return 1; //a,x
|
||||
case YDirect: return 2; //y,$00
|
||||
case YConstant: return 2; //y,#$00
|
||||
case XSp: return 1; //x,sp
|
||||
case YaX: return 1; //ya,x
|
||||
case IXPA: return 1; //(x)+,a
|
||||
case SpX: return 1; //sp,x
|
||||
case AIXP: return 1; //a,(x)+
|
||||
case DirectA: return 2; //$00,a
|
||||
case IXA: return 1; //(x),a
|
||||
case IDirectXA: return 2; //($00+x),a
|
||||
case XConstant: return 2; //x,#$00
|
||||
case AbsoluteX: return 3; //$0000,x
|
||||
case AbsoluteBitC: return 3; //$0000:0,c
|
||||
case DirectY: return 2; //$00,y
|
||||
case AbsoluteY: return 3; //$0000,y
|
||||
case Ya: return 1; //ya
|
||||
case DirectXA: return 2; //$00+x,a
|
||||
case AbsoluteXA: return 3; //$0000+x,a
|
||||
case AbsoluteYA: return 3; //$0000+y,a
|
||||
case IDirectYA: return 2; //($00)+y,a
|
||||
case DirectYX: return 2; //$00+y,x
|
||||
case DirectYa: return 2; //$00,ya
|
||||
case DirectXY: return 2; //$00+x,y
|
||||
case AY: return 1; //a,y
|
||||
case DirectXRelative: return 3; //$00+x,+/-$00
|
||||
case XDirectY: return 2; //x,$00+y
|
||||
case YDirectX: return 2; //y,$00+x
|
||||
case YA: return 1; //y,a
|
||||
case YRelative: return 2; //y,+/-$00
|
||||
}
|
||||
}
|
||||
|
||||
inline string SNESSMP::disassemble(uint16_t pc, uint8_t opcode, uint8_t pl, uint8_t ph) {
|
||||
string name = opcodeInfo[opcode].name;
|
||||
unsigned mode = opcodeInfo[opcode].mode;
|
||||
unsigned pa = (ph << 8) + pl;
|
||||
|
||||
if(mode == Implied) return name;
|
||||
if(mode == TVector) return { name, " ", opcode >> 4 };
|
||||
if(mode == Direct) return { name, " $", hex<2>(pl) };
|
||||
if(mode == DirectRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == ADirect) return { name, " a,$", hex<2>(pl) };
|
||||
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
|
||||
if(mode == AIX) return { name, "a,(x)" };
|
||||
if(mode == AIDirectX) return { name, " a,($", hex<2>(pl), "+x)" };
|
||||
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
|
||||
if(mode == DirectDirect) return { name, " $", hex<2>(ph), ",$", hex<2>(pl) };
|
||||
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == Absolute) return { name, " $", hex<4>(pa) };
|
||||
if(mode == P) return { name, " p" };
|
||||
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
|
||||
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
|
||||
if(mode == ADirectX) return { name, " a,$", hex<2>(pl), "+x" };
|
||||
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
|
||||
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
|
||||
if(mode == AIDirectY) return { name, " a,($", hex<2>(pl), ")+y" };
|
||||
if(mode == DirectConstant) return { name, " $", hex<2>(ph), ",#$", hex<2>(pl) };
|
||||
if(mode == IXIY) return { name, " (x),(y)" };
|
||||
if(mode == DirectX) return { name, " $", hex<2>(pl), "+x" };
|
||||
if(mode == A) return { name, " a" };
|
||||
if(mode == X) return { name, " x" };
|
||||
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
|
||||
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
|
||||
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == XDirect) return { name, " x,$", hex<2>(pl) };
|
||||
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
|
||||
if(mode == YaDirect) return { name, " ya,$", hex<2>(pl) };
|
||||
if(mode == XA) return { name, " x,a" };
|
||||
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
|
||||
if(mode == Y) return { name, " y" };
|
||||
if(mode == AX) return { name, " a,x" };
|
||||
if(mode == YDirect) return { name, " y,$", hex<2>(pl) };
|
||||
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
|
||||
if(mode == XSp) return { name, " x,sp" };
|
||||
if(mode == YaX) return { name, " ya,x" };
|
||||
if(mode == IXPA) return { name, " (x)+,a" };
|
||||
if(mode == SpX) return { name, " sp,x" };
|
||||
if(mode == AIXP) return { name, " a,(x)+" };
|
||||
if(mode == DirectA) return { name, " $", hex<2>(pl), ",a" };
|
||||
if(mode == IXA) return { name, " (x),a" };
|
||||
if(mode == IDirectXA) return { name, " ($", hex<2>(pl), "+x),a" };
|
||||
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
|
||||
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
|
||||
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
|
||||
if(mode == DirectY) return { name, " $", hex<2>(pl), ",y" };
|
||||
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
|
||||
if(mode == Ya) return { name, " ya" };
|
||||
if(mode == DirectXA) return { name, " $", hex<2>(pl), "+x,a" };
|
||||
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
|
||||
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
|
||||
if(mode == IDirectYA) return { name, " ($", hex<2>(pl), ")+y,a" };
|
||||
if(mode == DirectYX) return { name, " $", hex<2>(pl), "+y,x" };
|
||||
if(mode == DirectYa) return { name, " $", hex<2>(pl), ",ya" };
|
||||
if(mode == DirectXY) return { name, " $", hex<2>(pl), "+x,y" };
|
||||
if(mode == AY) return { name, " a,y" };
|
||||
if(mode == DirectXRelative) return { name, " $", hex<2>(pl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == XDirectY) return { name, " x,$", hex<2>(pl), "+y" };
|
||||
if(mode == YDirectX) return { name, " y,$", hex<2>(pl), "+x" };
|
||||
if(mode == YA) return { name, " y,a" };
|
||||
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
inline string SNESSMP::disassemble(uint16_t pc, bool p, uint8_t opcode, uint8_t pl, uint8_t ph) {
|
||||
string name = opcodeInfo[opcode].name;
|
||||
unsigned mode = opcodeInfo[opcode].mode;
|
||||
unsigned pdl = (p << 8) + pl;
|
||||
unsigned pdh = (p << 8) + ph;
|
||||
unsigned pa = (ph << 8) + pl;
|
||||
|
||||
if(mode == Implied) return name;
|
||||
if(mode == TVector) return { name, " ", opcode >> 4 };
|
||||
if(mode == Direct) return { name, " $", hex<3>(pdl) };
|
||||
if(mode == DirectRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == ADirect) return { name, " a,$", hex<3>(pdl) };
|
||||
if(mode == AAbsolute) return { name, " a,$", hex<4>(pa) };
|
||||
if(mode == AIX) return { name, "a,(x)" };
|
||||
if(mode == AIDirectX) return { name, " a,($", hex<3>(pdl), "+x)" };
|
||||
if(mode == AConstant) return { name, " a,#$", hex<2>(pl) };
|
||||
if(mode == DirectDirect) return { name, " $", hex<3>(pdh), ",$", hex<3>(pdl) };
|
||||
if(mode == CAbsoluteBit) return { name, " c,$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == Absolute) return { name, " $", hex<4>(pa) };
|
||||
if(mode == P) return { name, " p" };
|
||||
if(mode == AbsoluteA) return { name, " $", hex<4>(pa), ",a" };
|
||||
if(mode == Relative) return { name, " $", hex<4>(pc + 2 + (int8_t)pl) };
|
||||
if(mode == ADirectX) return { name, " a,$", hex<3>(pdl), "+x" };
|
||||
if(mode == AAbsoluteX) return { name, " a,$", hex<4>(pa), "+x" };
|
||||
if(mode == AAbsoluteY) return { name, " a,$", hex<4>(pa), "+y" };
|
||||
if(mode == AIDirectY) return { name, " a,($", hex<3>(pdl), ")+y" };
|
||||
if(mode == DirectConstant) return { name, " $", hex<3>(pdh), ",#$", hex<2>(pl) };
|
||||
if(mode == IXIY) return { name, " (x),(y)" };
|
||||
if(mode == DirectX) return { name, " $", hex<3>(pdl), "+x" };
|
||||
if(mode == A) return { name, " a" };
|
||||
if(mode == X) return { name, " x" };
|
||||
if(mode == XAbsolute) return { name, " x,$", hex<4>(pa) };
|
||||
if(mode == IAbsoluteX) return { name, " ($", hex<4>(pa), "+x)" };
|
||||
if(mode == CNAbsoluteBit) return { name, " c,!$", hex<4>(pa & 0x1fff), ":", pa >> 13 };
|
||||
if(mode == XDirect) return { name, " x,$", hex<3>(pdl) };
|
||||
if(mode == PVector) return { name, " $ff", hex<2>(pl) };
|
||||
if(mode == YaDirect) return { name, " ya,$", hex<3>(pdl) };
|
||||
if(mode == XA) return { name, " x,a" };
|
||||
if(mode == YAbsolute) return { name, " y,$", hex<4>(pa) };
|
||||
if(mode == Y) return { name, " y" };
|
||||
if(mode == AX) return { name, " a,x" };
|
||||
if(mode == YDirect) return { name, " y,$", hex<3>(pdl) };
|
||||
if(mode == YConstant) return { name, " y,#$", hex<2>(pl) };
|
||||
if(mode == XSp) return { name, " x,sp" };
|
||||
if(mode == YaX) return { name, " ya,x" };
|
||||
if(mode == IXPA) return { name, " (x)+,a" };
|
||||
if(mode == SpX) return { name, " sp,x" };
|
||||
if(mode == AIXP) return { name, " a,(x)+" };
|
||||
if(mode == DirectA) return { name, " $", hex<3>(pdl), ",a" };
|
||||
if(mode == IXA) return { name, " (x),a" };
|
||||
if(mode == IDirectXA) return { name, " ($", hex<3>(pdl), "+x),a" };
|
||||
if(mode == XConstant) return { name, " x,#$", hex<2>(pl) };
|
||||
if(mode == AbsoluteX) return { name, " $", hex<4>(pa), ",x" };
|
||||
if(mode == AbsoluteBitC) return { name, " $", hex<4>(pa & 0x1fff), ":", pa >> 13, ",c" };
|
||||
if(mode == DirectY) return { name, " $", hex<3>(pdl), ",y" };
|
||||
if(mode == AbsoluteY) return { name, " $", hex<4>(pa), ",y" };
|
||||
if(mode == Ya) return { name, " ya" };
|
||||
if(mode == DirectXA) return { name, " $", hex<3>(pdl), "+x,a" };
|
||||
if(mode == AbsoluteXA) return { name, " $", hex<4>(pa), "+x,a" };
|
||||
if(mode == AbsoluteYA) return { name, " $", hex<4>(pa), "+y,a" };
|
||||
if(mode == IDirectYA) return { name, " ($", hex<3>(pdl), ")+y,a" };
|
||||
if(mode == DirectYX) return { name, " $", hex<3>(pdl), "+y,x" };
|
||||
if(mode == DirectYa) return { name, " $", hex<3>(pdl), ",ya" };
|
||||
if(mode == DirectXY) return { name, " $", hex<3>(pdl), "+x,y" };
|
||||
if(mode == AY) return { name, " a,y" };
|
||||
if(mode == DirectXRelative) return { name, " $", hex<3>(pdl), ",$", hex<4>(pc + 3 + (int8_t)ph) };
|
||||
if(mode == XDirectY) return { name, " x,$", hex<3>(pdl), "+y" };
|
||||
if(mode == YDirectX) return { name, " y,$", hex<3>(pdl), "+x" };
|
||||
if(mode == YA) return { name, " y,a" };
|
||||
if(mode == YRelative) return { name, " y,$", hex<4>(pc + 2 + (int8_t)pl) };
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -2,6 +2,7 @@
|
||||
#define NALL_STRING_HPP
|
||||
|
||||
#include <initializer_list>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
#include <nall/string/base.hpp>
|
||||
@@ -11,8 +12,8 @@
|
||||
#include <nall/string/compare.hpp>
|
||||
#include <nall/string/convert.hpp>
|
||||
#include <nall/string/filename.hpp>
|
||||
#include <nall/string/match.hpp>
|
||||
#include <nall/string/math.hpp>
|
||||
#include <nall/string/platform.hpp>
|
||||
#include <nall/string/strl.hpp>
|
||||
#include <nall/string/strpos.hpp>
|
||||
#include <nall/string/trim.hpp>
|
||||
@@ -20,6 +21,7 @@
|
||||
#include <nall/string/split.hpp>
|
||||
#include <nall/string/utility.hpp>
|
||||
#include <nall/string/variadic.hpp>
|
||||
#include <nall/string/wrapper.hpp>
|
||||
#include <nall/string/xml.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
@@ -17,7 +17,6 @@ namespace nall {
|
||||
class string {
|
||||
public:
|
||||
inline void reserve(unsigned);
|
||||
inline unsigned length() const;
|
||||
|
||||
inline string& assign(const char*);
|
||||
inline string& append(const char*);
|
||||
@@ -26,6 +25,35 @@ namespace nall {
|
||||
inline string& append(unsigned int value);
|
||||
inline string& append(double value);
|
||||
|
||||
inline bool readfile(const char*);
|
||||
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
|
||||
inline unsigned length() const;
|
||||
|
||||
inline bool equals(const char*) const;
|
||||
inline bool iequals(const char*) const;
|
||||
|
||||
inline bool wildcard(const char*) const;
|
||||
inline bool iwildcard(const char*) const;
|
||||
|
||||
inline bool beginswith(const char*) const;
|
||||
inline bool ibeginswith(const char*) const;
|
||||
inline bool endswith(const char*) const;
|
||||
inline bool iendswith(const char*) const;
|
||||
|
||||
inline string& lower();
|
||||
inline string& upper();
|
||||
inline string& transform(const char *before, const char *after);
|
||||
|
||||
template<unsigned limit = 0> inline string& ltrim(const char *key = " ");
|
||||
template<unsigned limit = 0> inline string& rtrim(const char *key = " ");
|
||||
template<unsigned limit = 0> inline string& trim (const char *key = " ");
|
||||
|
||||
inline optional<unsigned> position(const char *key) const;
|
||||
inline optional<unsigned> qposition(const char *key) const;
|
||||
|
||||
template<typename T> inline string& operator= (T value);
|
||||
template<typename T> inline string& operator<<(T value);
|
||||
|
||||
@@ -48,20 +76,6 @@ namespace nall {
|
||||
inline string(string&&);
|
||||
inline ~string();
|
||||
|
||||
inline bool readfile(const char*);
|
||||
inline string& replace (const char*, const char*);
|
||||
inline string& qreplace(const char*, const char*);
|
||||
|
||||
inline string& lower();
|
||||
inline string& upper();
|
||||
inline string& transform(const char *before, const char *after);
|
||||
inline string& ltrim(const char *key = " ");
|
||||
inline string& rtrim(const char *key = " ");
|
||||
inline string& trim (const char *key = " ");
|
||||
inline string& ltrim_once(const char *key = " ");
|
||||
inline string& rtrim_once(const char *key = " ");
|
||||
inline string& trim_once (const char *key = " ");
|
||||
|
||||
protected:
|
||||
char *data;
|
||||
unsigned size;
|
||||
@@ -76,9 +90,9 @@ namespace nall {
|
||||
public:
|
||||
template<typename T> inline lstring& operator<<(T value);
|
||||
|
||||
inline optional<unsigned> find(const char*);
|
||||
inline void split (const char*, const char*, unsigned = 0);
|
||||
inline void qsplit(const char*, const char*, unsigned = 0);
|
||||
inline optional<unsigned> find(const char*) const;
|
||||
template<unsigned limit = 0> inline void split (const char*, const char*);
|
||||
template<unsigned limit = 0> inline void qsplit(const char*, const char*);
|
||||
|
||||
lstring();
|
||||
lstring(std::initializer_list<string>);
|
||||
@@ -87,7 +101,9 @@ namespace nall {
|
||||
//compare.hpp
|
||||
inline char chrlower(char c);
|
||||
inline char chrupper(char c);
|
||||
inline int stricmp(const char *dest, const char *src);
|
||||
inline int stricmp(const char *str1, const char *str2);
|
||||
inline bool wildcard(const char *str, const char *pattern);
|
||||
inline bool iwildcard(const char *str, const char *pattern);
|
||||
inline bool strbegin (const char *str, const char *key);
|
||||
inline bool stribegin(const char *str, const char *key);
|
||||
inline bool strend (const char *str, const char *key);
|
||||
@@ -97,42 +113,44 @@ namespace nall {
|
||||
inline char* strlower(char *str);
|
||||
inline char* strupper(char *str);
|
||||
inline char* strtr(char *dest, const char *before, const char *after);
|
||||
inline uintmax_t strhex (const char *str);
|
||||
inline intmax_t strsigned (const char *str);
|
||||
inline uintmax_t strunsigned(const char *str);
|
||||
inline uintmax_t strbin (const char *str);
|
||||
inline double strdouble (const char *str);
|
||||
|
||||
//match.hpp
|
||||
inline bool match(const char *pattern, const char *str);
|
||||
inline uintmax_t hex (const char *str);
|
||||
inline intmax_t integer(const char *str);
|
||||
inline uintmax_t decimal(const char *str);
|
||||
inline uintmax_t binary (const char *str);
|
||||
inline double fp (const char *str);
|
||||
|
||||
//math.hpp
|
||||
inline bool strint (const char *str, int &result);
|
||||
inline bool strmath(const char *str, int &result);
|
||||
|
||||
//platform.hpp
|
||||
inline string realpath(const char *name);
|
||||
inline string userpath();
|
||||
inline string currentpath();
|
||||
|
||||
//strl.hpp
|
||||
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(char *dest, const char *src, unsigned length);
|
||||
|
||||
//strpos.hpp
|
||||
inline optional<unsigned> strpos(const char *str, const char *key);
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key);
|
||||
|
||||
//trim.hpp
|
||||
inline char* ltrim(char *str, const char *key = " ");
|
||||
inline char* rtrim(char *str, const char *key = " ");
|
||||
inline char* trim (char *str, const char *key = " ");
|
||||
inline char* ltrim_once(char *str, const char *key = " ");
|
||||
inline char* rtrim_once(char *str, const char *key = " ");
|
||||
inline char* trim_once (char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
|
||||
template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
|
||||
|
||||
//utility.hpp
|
||||
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
|
||||
inline unsigned strlcat(string &dest, const char *src, unsigned length);
|
||||
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
|
||||
inline string& strtr(string &dest, const char *before, const char *after);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string strbin(uintmax_t value);
|
||||
inline unsigned strdouble(char *str, double value);
|
||||
inline string strdouble(double value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string integer(intmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string decimal(uintmax_t value);
|
||||
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
|
||||
inline unsigned fp(char *str, double value);
|
||||
inline string fp(double value);
|
||||
|
||||
//variadic.hpp
|
||||
template<typename... Args> inline void print(Args&&... args);
|
||||
|
@@ -5,9 +5,9 @@ namespace nall {
|
||||
|
||||
//this is needed, as C++0x does not support explicit template specialization inside classes
|
||||
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
|
||||
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
|
||||
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
|
||||
template<> inline string to_string<double> (double v) { return strdouble(v); }
|
||||
template<> inline string to_string<signed int> (signed int v) { return integer(v); }
|
||||
template<> inline string to_string<unsigned int> (unsigned int v) { return decimal(v); }
|
||||
template<> inline string to_string<double> (double v) { return fp(v); }
|
||||
template<> inline string to_string<char*> (char *v) { return v; }
|
||||
template<> inline string to_string<const char*> (const char *v) { return v; }
|
||||
template<> inline string to_string<string> (string v) { return v; }
|
||||
|
@@ -11,14 +11,52 @@ char chrupper(char c) {
|
||||
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
int stricmp(const char *dest, const char *src) {
|
||||
while(*dest) {
|
||||
if(chrlower(*dest) != chrlower(*src)) break;
|
||||
dest++;
|
||||
src++;
|
||||
int stricmp(const char *str1, const char *str2) {
|
||||
while(*str1) {
|
||||
if(chrlower(*str1) != chrlower(*str2)) break;
|
||||
str1++, str2++;
|
||||
}
|
||||
return (int)chrlower(*str1) - (int)chrlower(*str2);
|
||||
}
|
||||
|
||||
return (int)chrlower(*dest) - (int)chrlower(*src);
|
||||
bool wildcard(const char *s, const char *p) {
|
||||
const char *cp = 0, *mp = 0;
|
||||
while(*s && *p != '*') {
|
||||
if(*p != '?' && *s != *p) return false;
|
||||
p++, s++;
|
||||
}
|
||||
while(*s) {
|
||||
if(*p == '*') {
|
||||
if(!*++p) return true;
|
||||
mp = p, cp = s + 1;
|
||||
} else if(*p == '?' || *p == *s) {
|
||||
p++, s++;
|
||||
} else {
|
||||
p = mp, s = cp++;
|
||||
}
|
||||
}
|
||||
while(*p == '*') p++;
|
||||
return !*p;
|
||||
}
|
||||
|
||||
bool iwildcard(const char *s, const char *p) {
|
||||
const char *cp = 0, *mp = 0;
|
||||
while(*s && *p != '*') {
|
||||
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
|
||||
p++, s++;
|
||||
}
|
||||
while(*s) {
|
||||
if(*p == '*') {
|
||||
if(!*++p) return true;
|
||||
mp = p, cp = s + 1;
|
||||
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
|
||||
p++, s++;
|
||||
} else {
|
||||
p = mp, s = cp++;
|
||||
}
|
||||
}
|
||||
while(*p == '*') p++;
|
||||
return !*p;
|
||||
}
|
||||
|
||||
bool strbegin(const char *str, const char *key) {
|
||||
|
@@ -40,11 +40,7 @@ char* strtr(char *dest, const char *before, const char *after) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
string& string::lower() { nall::strlower(data); return *this; }
|
||||
string& string::upper() { nall::strupper(data); return *this; }
|
||||
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
|
||||
|
||||
uintmax_t strhex(const char *str) {
|
||||
uintmax_t hex(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
@@ -64,7 +60,7 @@ uintmax_t strhex(const char *str) {
|
||||
return result;
|
||||
}
|
||||
|
||||
intmax_t strsigned(const char *str) {
|
||||
intmax_t integer(const char *str) {
|
||||
if(!str) return 0;
|
||||
intmax_t result = 0;
|
||||
bool negate = false;
|
||||
@@ -85,7 +81,7 @@ intmax_t strsigned(const char *str) {
|
||||
return !negate ? result : -result;
|
||||
}
|
||||
|
||||
uintmax_t strunsigned(const char *str) {
|
||||
uintmax_t decimal(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
@@ -99,7 +95,7 @@ uintmax_t strunsigned(const char *str) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uintmax_t strbin(const char *str) {
|
||||
uintmax_t binary(const char *str) {
|
||||
if(!str) return 0;
|
||||
uintmax_t result = 0;
|
||||
|
||||
@@ -117,7 +113,7 @@ uintmax_t strbin(const char *str) {
|
||||
return result;
|
||||
}
|
||||
|
||||
double strdouble(const char *str) {
|
||||
double fp(const char *str) {
|
||||
if(!str) return 0.0;
|
||||
bool negate = false;
|
||||
|
||||
|
@@ -11,10 +11,6 @@ void string::reserve(unsigned size_) {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned string::length() const {
|
||||
return strlen(data);
|
||||
}
|
||||
|
||||
string& string::assign(const char *s) {
|
||||
unsigned length = strlen(s);
|
||||
reserve(length);
|
||||
@@ -30,9 +26,9 @@ string& string::append(const char *s) {
|
||||
}
|
||||
|
||||
string& string::append(bool value) { append(value ? "true" : "false"); return *this; }
|
||||
string& string::append(signed int value) { append(strsigned(value)); return *this; }
|
||||
string& string::append(unsigned int value) { append(strunsigned(value)); return *this; }
|
||||
string& string::append(double value) { append(strdouble(value)); return *this; }
|
||||
string& string::append(signed int value) { append(integer(value)); return *this; }
|
||||
string& string::append(unsigned int value) { append(decimal(value)); return *this; }
|
||||
string& string::append(double value) { append(fp(value)); return *this; }
|
||||
|
||||
string::operator const char*() const {
|
||||
return data;
|
||||
@@ -122,7 +118,7 @@ bool string::readfile(const char *filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
optional<unsigned> lstring::find(const char *key) {
|
||||
optional<unsigned> lstring::find(const char *key) const {
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
if(operator[](i) == key) return { true, i };
|
||||
}
|
||||
|
@@ -3,7 +3,9 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
|
||||
// "foo/bar.c" -> "foo/"
|
||||
// "foo/" -> "foo/"
|
||||
// "bar.c" -> "./"
|
||||
inline string dir(char const *name) {
|
||||
string result = name;
|
||||
for(signed i = strlen(result); i >= 0; i--) {
|
||||
|
@@ -1,76 +0,0 @@
|
||||
#ifndef NALL_STRING_MATCH_HPP
|
||||
#define NALL_STRING_MATCH_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
bool match(const char *p, const char *s) {
|
||||
const char *p_ = 0, *s_ = 0;
|
||||
|
||||
for(;;) {
|
||||
if(!*s) {
|
||||
while(*p == '*') p++;
|
||||
return !*p;
|
||||
}
|
||||
|
||||
//wildcard match
|
||||
if(*p == '*') {
|
||||
p_ = p++, s_ = s;
|
||||
continue;
|
||||
}
|
||||
|
||||
//any match
|
||||
if(*p == '?') {
|
||||
p++, s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//ranged match
|
||||
if(*p == '{') {
|
||||
#define pattern(name_, rule_) \
|
||||
if(strbegin(p, name_)) { \
|
||||
if(rule_) { \
|
||||
p += sizeof(name_) - 1, s++; \
|
||||
continue; \
|
||||
} \
|
||||
goto failure; \
|
||||
}
|
||||
|
||||
pattern("{alpha}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))
|
||||
pattern("{alphanumeric}", (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || (*s >= '0' && *s <= '9'))
|
||||
pattern("{binary}", (*s == '0' || *s == '1'))
|
||||
pattern("{hex}", (*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f'))
|
||||
pattern("{lowercase}", (*s >= 'a' && *s <= 'z'))
|
||||
pattern("{numeric}", (*s >= '0' && *s <= '9'))
|
||||
pattern("{uppercase}", (*s >= 'A' && *s <= 'Z'))
|
||||
pattern("{whitespace}", (*s == ' ' || *s == '\t'))
|
||||
|
||||
#undef pattern
|
||||
goto failure;
|
||||
}
|
||||
|
||||
//reserved character match
|
||||
if(*p == '\\') {
|
||||
p++;
|
||||
//fallthrough
|
||||
}
|
||||
|
||||
//literal match
|
||||
if(*p == *s) {
|
||||
p++, *s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//attempt wildcard rematch
|
||||
failure:
|
||||
if(p_) {
|
||||
p = p_, s = s_ + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
41
bsnes/nall/string/platform.hpp
Executable file
41
bsnes/nall/string/platform.hpp
Executable file
@@ -0,0 +1,41 @@
|
||||
#ifndef NALL_STRING_PLATFORM_HPP
|
||||
#define NALL_STRING_PLATFORM_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
string realpath(const char *name) {
|
||||
char path[PATH_MAX];
|
||||
if(::realpath(name, path)) {
|
||||
string result(path);
|
||||
result.transform("\\", "/");
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string userpath() {
|
||||
char path[PATH_MAX];
|
||||
if(::userpath(path)) {
|
||||
string result(path);
|
||||
result.transform("\\", "/");
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string currentpath() {
|
||||
char path[PATH_MAX];
|
||||
if(::getcwd(path)) {
|
||||
string result(path);
|
||||
result.transform("\\", "/");
|
||||
if(result.endswith("/") == false) result.append("/");
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -3,7 +3,8 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
void lstring::split(const char *key, const char *src, unsigned limit) {
|
||||
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
@@ -21,7 +22,8 @@ void lstring::split(const char *key, const char *src, unsigned limit) {
|
||||
operator[](split_count++) = src + lp;
|
||||
}
|
||||
|
||||
void lstring::qsplit(const char *key, const char *src, unsigned limit) {
|
||||
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
|
||||
unsigned limit = Limit;
|
||||
reset();
|
||||
|
||||
int ssl = strlen(src), ksl = strlen(key);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
inline optional<unsigned> strpos(const char *str, const char *key) {
|
||||
optional<unsigned> strpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
@@ -18,7 +18,7 @@ inline optional<unsigned> strpos(const char *str, const char *key) {
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
inline optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
optional<unsigned> qstrpos(const char *str, const char *key) {
|
||||
unsigned ssl = strlen(str), ksl = strlen(key);
|
||||
if(ksl > ssl) return { false, 0 };
|
||||
|
||||
|
@@ -3,7 +3,9 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
char* ltrim(char *str, const char *key) {
|
||||
//limit defaults to zero, which will underflow on first compare; equivalent to no limit
|
||||
template<unsigned Limit> char* ltrim(char *str, const char *key) {
|
||||
unsigned limit = Limit;
|
||||
if(!key || !*key) return str;
|
||||
while(strbegin(str, key)) {
|
||||
char *dest = str, *src = str + strlen(key);
|
||||
@@ -12,50 +14,25 @@ char* ltrim(char *str, const char *key) {
|
||||
if(!*dest) break;
|
||||
dest++;
|
||||
}
|
||||
if(--limit == 0) break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* rtrim(char *str, const char *key) {
|
||||
template<unsigned Limit> char* rtrim(char *str, const char *key) {
|
||||
unsigned limit = Limit;
|
||||
if(!key || !*key) return str;
|
||||
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
char* trim(char *str, const char *key) {
|
||||
return ltrim(rtrim(str, key), key);
|
||||
}
|
||||
|
||||
char* ltrim_once(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
if(strbegin(str, key)) {
|
||||
char *dest = str, *src = str + strlen(key);
|
||||
while(true) {
|
||||
*dest = *src++;
|
||||
if(!*dest) break;
|
||||
dest++;
|
||||
}
|
||||
while(strend(str, key)) {
|
||||
str[strlen(str) - strlen(key)] = 0;
|
||||
if(--limit == 0) break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* rtrim_once(char *str, const char *key) {
|
||||
if(!key || !*key) return str;
|
||||
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
|
||||
return str;
|
||||
template<unsigned limit> char* trim(char *str, const char *key) {
|
||||
return ltrim<limit>(rtrim<limit>(str, key), key);
|
||||
}
|
||||
|
||||
char* trim_once(char *str, const char *key) {
|
||||
return ltrim_once(rtrim_once(str, key), key);
|
||||
}
|
||||
|
||||
string& string::ltrim(const char *key) { nall::ltrim(data, key); return *this; }
|
||||
string& string::rtrim(const char *key) { nall::rtrim(data, key); return *this; }
|
||||
string& string::trim (const char *key) { nall::trim (data, key); return *this; }
|
||||
string& string::ltrim_once(const char *key) { nall::ltrim_once(data, key); return *this; }
|
||||
string& string::rtrim_once(const char *key) { nall::rtrim_once(data, key); return *this; }
|
||||
string& string::trim_once (const char *key) { nall::trim_once (data, key); return *this; }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -27,7 +27,7 @@ string substr(const char *src, unsigned start, unsigned length) {
|
||||
|
||||
/* arithmetic <> string */
|
||||
|
||||
template<unsigned length, char padding> string strhex(uintmax_t value) {
|
||||
template<unsigned length, char padding> string hex(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -51,7 +51,7 @@ template<unsigned length, char padding> string strhex(uintmax_t value) {
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strsigned(intmax_t value) {
|
||||
template<unsigned length, char padding> string integer(intmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -77,7 +77,7 @@ template<unsigned length, char padding> string strsigned(intmax_t value) {
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strunsigned(uintmax_t value) {
|
||||
template<unsigned length, char padding> string decimal(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -99,7 +99,7 @@ template<unsigned length, char padding> string strunsigned(uintmax_t value) {
|
||||
return output;
|
||||
}
|
||||
|
||||
template<unsigned length, char padding> string strbin(uintmax_t value) {
|
||||
template<unsigned length, char padding> string binary(uintmax_t value) {
|
||||
string output;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -124,7 +124,7 @@ template<unsigned length, char padding> string strbin(uintmax_t value) {
|
||||
//using sprintf is certainly not the most ideal method to convert
|
||||
//a double to a string ... but attempting to parse a double by
|
||||
//hand, digit-by-digit, results in subtle rounding errors.
|
||||
unsigned strdouble(char *str, double value) {
|
||||
unsigned fp(char *str, double value) {
|
||||
char buffer[256];
|
||||
sprintf(buffer, "%f", value);
|
||||
|
||||
@@ -145,10 +145,10 @@ unsigned strdouble(char *str, double value) {
|
||||
return length + 1;
|
||||
}
|
||||
|
||||
string strdouble(double value) {
|
||||
string fp(double value) {
|
||||
string temp;
|
||||
temp.reserve(strdouble(0, value));
|
||||
strdouble(temp(), value);
|
||||
temp.reserve(fp(0, value));
|
||||
fp(temp(), value);
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
33
bsnes/nall/string/wrapper.hpp
Executable file
33
bsnes/nall/string/wrapper.hpp
Executable file
@@ -0,0 +1,33 @@
|
||||
#ifndef NALL_STRING_WRAPPER_HPP
|
||||
#define NALL_STRING_WRAPPER_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
unsigned string::length() const { return strlen(data); }
|
||||
|
||||
bool string::equals(const char *str) const { return !strcmp(data, str); }
|
||||
bool string::iequals(const char *str) const { return !stricmp(data, str); }
|
||||
|
||||
bool string::wildcard(const char *str) const { return nall::wildcard(data, str); }
|
||||
bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); }
|
||||
|
||||
bool string::beginswith(const char *str) const { return strbegin(data, str); }
|
||||
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
|
||||
|
||||
bool string::endswith(const char *str) const { return strend(data, str); }
|
||||
bool string::iendswith(const char *str) const { return striend(data, str); }
|
||||
|
||||
string& string::lower() { nall::strlower(data); return *this; }
|
||||
string& string::upper() { nall::strupper(data); return *this; }
|
||||
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
|
||||
|
||||
template<unsigned limit> string& string::ltrim(const char *key) { nall::ltrim<limit>(data, key); return *this; }
|
||||
template<unsigned limit> string& string::rtrim(const char *key) { nall::rtrim<limit>(data, key); return *this; }
|
||||
template<unsigned limit> string& string::trim (const char *key) { nall::trim <limit>(data, key); return *this; }
|
||||
|
||||
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
|
||||
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -75,11 +75,12 @@ inline string xml_element::parse() const {
|
||||
|
||||
if(strbegin(source, "<![CDATA[")) {
|
||||
if(auto pos = strpos(source, "]]>")) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data << cdata;
|
||||
offset += strlen(cdata);
|
||||
|
||||
source += offset + 3;
|
||||
if(pos() - 9 > 0) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data << cdata;
|
||||
offset += strlen(cdata);
|
||||
}
|
||||
source += 9 + offset + 3;
|
||||
continue;
|
||||
} else {
|
||||
return "";
|
||||
@@ -138,8 +139,8 @@ inline bool xml_element::parse_head(string data) {
|
||||
xml_attribute attr;
|
||||
attr.name = side[0];
|
||||
attr.content = side[1];
|
||||
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim_once("\"");
|
||||
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim_once("'");
|
||||
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
|
||||
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
|
||||
else throw "...";
|
||||
attribute.append(attr);
|
||||
}
|
||||
@@ -185,10 +186,10 @@ inline bool xml_element::parse_body(const char *&data) {
|
||||
|
||||
if(strend(tag, "?") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim_once("?");
|
||||
tag.rtrim<1>("?");
|
||||
} else if(strend(tag, "/") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim_once("/");
|
||||
tag.rtrim<1>("/");
|
||||
}
|
||||
|
||||
parse_head(tag);
|
||||
|
@@ -1,190 +1,223 @@
|
||||
#ifndef NALL_UPS_HPP
|
||||
#define NALL_UPS_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/crc32.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
class ups {
|
||||
public:
|
||||
enum result {
|
||||
ok,
|
||||
patch_unreadable,
|
||||
patch_unwritable,
|
||||
patch_invalid,
|
||||
input_invalid,
|
||||
output_invalid,
|
||||
patch_crc32_invalid,
|
||||
input_crc32_invalid,
|
||||
output_crc32_invalid,
|
||||
};
|
||||
|
||||
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
|
||||
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
|
||||
struct ups {
|
||||
enum class result : unsigned {
|
||||
unknown,
|
||||
success,
|
||||
patch_unwritable,
|
||||
patch_invalid,
|
||||
source_invalid,
|
||||
target_invalid,
|
||||
target_too_small,
|
||||
patch_checksum_invalid,
|
||||
source_checksum_invalid,
|
||||
target_checksum_invalid,
|
||||
};
|
||||
|
||||
crc32 = ~0;
|
||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
||||
function<void (unsigned offset, unsigned length)> progress;
|
||||
|
||||
//header
|
||||
write('U');
|
||||
write('P');
|
||||
write('S');
|
||||
write('1');
|
||||
encptr(x_size);
|
||||
encptr(y_size);
|
||||
result create(
|
||||
const uint8_t *sourcedata, unsigned sourcelength,
|
||||
const uint8_t *targetdata, unsigned targetlength,
|
||||
const char *patchfilename
|
||||
) {
|
||||
source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata;
|
||||
source_length = sourcelength, target_length = targetlength;
|
||||
source_offset = target_offset = 0;
|
||||
source_checksum = target_checksum = patch_checksum = ~0;
|
||||
|
||||
//body
|
||||
unsigned max_size = max(x_size, y_size);
|
||||
unsigned relative = 0;
|
||||
for(unsigned i = 0; i < max_size;) {
|
||||
uint8_t x = i < x_size ? x_data[i] : 0x00;
|
||||
uint8_t y = i < y_size ? y_data[i] : 0x00;
|
||||
if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable;
|
||||
|
||||
if(x == y) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
patch_write('U');
|
||||
patch_write('P');
|
||||
patch_write('S');
|
||||
patch_write('1');
|
||||
encode(source_length);
|
||||
encode(target_length);
|
||||
|
||||
encptr(i++ - relative);
|
||||
write(x ^ y);
|
||||
unsigned output_length = source_length > target_length ? source_length : target_length;
|
||||
unsigned relative = 0;
|
||||
for(unsigned offset = 0; offset < output_length;) {
|
||||
uint8_t x = source_read();
|
||||
uint8_t y = target_read();
|
||||
|
||||
while(true) {
|
||||
if(i >= max_size) {
|
||||
write(0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
x = i < x_size ? x_data[i] : 0x00;
|
||||
y = i < y_size ? y_data[i] : 0x00;
|
||||
i++;
|
||||
write(x ^ y);
|
||||
if(x == y) break;
|
||||
}
|
||||
|
||||
relative = i;
|
||||
if(x == y) {
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
//footer
|
||||
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3));
|
||||
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
|
||||
uint32_t p_crc32 = ~crc32;
|
||||
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
|
||||
encode(offset++ - relative);
|
||||
patch_write(x ^ y);
|
||||
|
||||
fp.close();
|
||||
return ok;
|
||||
}
|
||||
|
||||
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
|
||||
if(p_size < 18) return patch_invalid;
|
||||
p_buffer = p_data;
|
||||
|
||||
crc32 = ~0;
|
||||
|
||||
//header
|
||||
if(read() != 'U') return patch_invalid;
|
||||
if(read() != 'P') return patch_invalid;
|
||||
if(read() != 'S') return patch_invalid;
|
||||
if(read() != '1') return patch_invalid;
|
||||
|
||||
unsigned px_size = decptr();
|
||||
unsigned py_size = decptr();
|
||||
|
||||
//mirror
|
||||
if(x_size != px_size && x_size != py_size) return input_invalid;
|
||||
y_size = (x_size == px_size) ? py_size : px_size;
|
||||
y_data = new uint8_t[y_size]();
|
||||
|
||||
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
|
||||
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
|
||||
|
||||
//body
|
||||
unsigned relative = 0;
|
||||
while(p_buffer < p_data + p_size - 12) {
|
||||
relative += decptr();
|
||||
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
if(x && relative < y_size) {
|
||||
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
|
||||
y_data[relative] = x ^ y;
|
||||
}
|
||||
relative++;
|
||||
if(!x) break;
|
||||
}
|
||||
}
|
||||
|
||||
//footer
|
||||
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
|
||||
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
|
||||
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
|
||||
uint32_t p_crc32 = ~crc32;
|
||||
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
|
||||
|
||||
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
|
||||
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
|
||||
|
||||
if(px_size != py_size) {
|
||||
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
|
||||
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
|
||||
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
|
||||
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
|
||||
} else {
|
||||
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
|
||||
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
|
||||
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
|
||||
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
|
||||
}
|
||||
|
||||
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
|
||||
return ok;
|
||||
}
|
||||
|
||||
private:
|
||||
file fp;
|
||||
uint32_t crc32;
|
||||
const uint8_t *p_buffer;
|
||||
|
||||
uint8_t read() {
|
||||
uint8_t n = *p_buffer++;
|
||||
crc32 = crc32_adjust(crc32, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void write(uint8_t n) {
|
||||
fp.write(n);
|
||||
crc32 = crc32_adjust(crc32, n);
|
||||
}
|
||||
|
||||
void encptr(uint64_t offset) {
|
||||
while(true) {
|
||||
uint64_t x = offset & 0x7f;
|
||||
offset >>= 7;
|
||||
if(offset == 0) {
|
||||
write(0x80 | x);
|
||||
if(offset >= output_length) {
|
||||
patch_write(0x00);
|
||||
break;
|
||||
}
|
||||
write(x);
|
||||
offset--;
|
||||
|
||||
x = source_read();
|
||||
y = target_read();
|
||||
offset++;
|
||||
patch_write(x ^ y);
|
||||
if(x == y) break;
|
||||
}
|
||||
|
||||
relative = offset;
|
||||
}
|
||||
|
||||
uint64_t decptr() {
|
||||
uint64_t offset = 0, shift = 1;
|
||||
source_checksum = ~source_checksum;
|
||||
target_checksum = ~target_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8));
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8));
|
||||
uint32_t patch_result_checksum = ~patch_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8));
|
||||
|
||||
patch_file.close();
|
||||
return result::success;
|
||||
}
|
||||
|
||||
result apply(
|
||||
const uint8_t *patchdata, unsigned patchlength,
|
||||
const uint8_t *sourcedata, unsigned sourcelength,
|
||||
uint8_t *targetdata, unsigned &targetlength
|
||||
) {
|
||||
patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata;
|
||||
patch_length = patchlength, source_length = sourcelength, target_length = targetlength;
|
||||
patch_offset = source_offset = target_offset = 0;
|
||||
patch_checksum = source_checksum = target_checksum = ~0;
|
||||
|
||||
if(patch_length < 18) return result::patch_invalid;
|
||||
if(patch_read() != 'U') return result::patch_invalid;
|
||||
if(patch_read() != 'P') return result::patch_invalid;
|
||||
if(patch_read() != 'S') return result::patch_invalid;
|
||||
if(patch_read() != '1') return result::patch_invalid;
|
||||
|
||||
unsigned source_read_length = decode();
|
||||
unsigned target_read_length = decode();
|
||||
|
||||
if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid;
|
||||
targetlength = (source_length == source_read_length ? target_read_length : source_read_length);
|
||||
if(target_length < targetlength) return result::target_too_small;
|
||||
target_length = targetlength;
|
||||
|
||||
while(patch_offset < patch_length - 12) {
|
||||
unsigned length = decode();
|
||||
while(length--) target_write(source_read());
|
||||
while(true) {
|
||||
uint8_t x = read();
|
||||
offset += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
uint8_t patch_xor = patch_read();
|
||||
target_write(patch_xor ^ source_read());
|
||||
if(patch_xor == 0) break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
while(source_offset < source_length) target_write(source_read());
|
||||
while(target_offset < target_length) target_write(source_read());
|
||||
|
||||
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
|
||||
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
|
||||
for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8);
|
||||
uint32_t patch_result_checksum = ~patch_checksum;
|
||||
source_checksum = ~source_checksum;
|
||||
target_checksum = ~target_checksum;
|
||||
for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8);
|
||||
|
||||
if(patch_result_checksum != patch_read_checksum) return result::patch_invalid;
|
||||
if(source_checksum == source_read_checksum && source_length == source_read_length) {
|
||||
if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success;
|
||||
return result::target_invalid;
|
||||
} else if(source_checksum == target_read_checksum && source_length == target_read_length) {
|
||||
if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success;
|
||||
return result::target_invalid;
|
||||
} else {
|
||||
return result::source_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *patch_data, *source_data, *target_data;
|
||||
unsigned patch_length, source_length, target_length;
|
||||
unsigned patch_offset, source_offset, target_offset;
|
||||
unsigned patch_checksum, source_checksum, target_checksum;
|
||||
file patch_file;
|
||||
|
||||
uint8_t patch_read() {
|
||||
if(patch_offset < patch_length) {
|
||||
uint8_t n = patch_data[patch_offset++];
|
||||
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||
return n;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
uint8_t source_read() {
|
||||
if(source_offset < source_length) {
|
||||
uint8_t n = source_data[source_offset++];
|
||||
source_checksum = crc32_adjust(source_checksum, n);
|
||||
return n;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
uint8_t target_read() {
|
||||
uint8_t result = 0x00;
|
||||
if(target_offset < target_length) {
|
||||
result = target_data[target_offset];
|
||||
target_checksum = crc32_adjust(target_checksum, result);
|
||||
}
|
||||
if(((target_offset++ & 255) == 0) && progress) {
|
||||
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void patch_write(uint8_t n) {
|
||||
patch_file.write(n);
|
||||
patch_checksum = crc32_adjust(patch_checksum, n);
|
||||
}
|
||||
|
||||
void target_write(uint8_t n) {
|
||||
if(target_offset < target_length) {
|
||||
target_data[target_offset] = n;
|
||||
target_checksum = crc32_adjust(target_checksum, n);
|
||||
}
|
||||
if(((target_offset++ & 255) == 0) && progress) {
|
||||
progress(target_offset, source_length > target_length ? source_length : target_length);
|
||||
}
|
||||
}
|
||||
|
||||
void encode(uint64_t offset) {
|
||||
while(true) {
|
||||
uint64_t x = offset & 0x7f;
|
||||
offset >>= 7;
|
||||
if(offset == 0) {
|
||||
patch_write(0x80 | x);
|
||||
break;
|
||||
}
|
||||
patch_write(x);
|
||||
offset--;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t decode() {
|
||||
uint64_t offset = 0, shift = 1;
|
||||
while(true) {
|
||||
uint8_t x = patch_read();
|
||||
offset += (x & 0x7f) * shift;
|
||||
if(x & 0x80) break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -2,8 +2,9 @@ static void Button_tick(Button *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_button_new_with_label(text);
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
|
@@ -22,6 +22,7 @@ void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi
|
||||
canvas->pitch = width * sizeof(uint32_t);
|
||||
|
||||
object->widget = gtk_drawing_area_new();
|
||||
widget->parent = &parent;
|
||||
GdkColor color;
|
||||
color.pixel = color.red = color.green = color.blue = 0;
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
|
@@ -2,8 +2,9 @@ static void CheckBox_tick(CheckBox *self) {
|
||||
if(self->onTick && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_check_button_new_with_label(text);
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
|
@@ -2,8 +2,9 @@ void ComboBox_change(ComboBox *self) {
|
||||
if(self->object->locked == false && self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_combo_box_new_text();
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);
|
||||
|
||||
@@ -27,7 +28,7 @@ void ComboBox::reset() {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
void ComboBox::addItem(const string &text) {
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(object->widget), text);
|
||||
if(counter++ == 0) setSelection(0);
|
||||
}
|
||||
|
@@ -2,8 +2,9 @@ static void EditBox_change(EditBox *self) {
|
||||
if(self->object->locked == false && self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
widget->parent = &parent;
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
@@ -41,8 +42,17 @@ string EditBox::text() {
|
||||
return text;
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
void EditBox::setText(const string &text) {
|
||||
object->locked = true;
|
||||
gtk_text_buffer_set_text(object->textBuffer, text, -1);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
void EditBox::setCursorPosition(unsigned position) {
|
||||
GtkTextMark *mark = gtk_text_buffer_get_mark(object->textBuffer, "insert");
|
||||
GtkTextIter iter;
|
||||
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
|
||||
gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter)));
|
||||
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
|
||||
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(object->subWidget), mark);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
bool Font::create(const string &name, unsigned size, Font::Style style) {
|
||||
font->font = pango_font_description_new();
|
||||
pango_font_description_set_family(font->font, name);
|
||||
pango_font_description_set_size(font->font, size * PANGO_SCALE);
|
||||
|
@@ -27,6 +27,7 @@ namespace phoenix {
|
||||
#include "checkbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "hexeditor.cpp"
|
||||
#include "horizontalslider.cpp"
|
||||
#include "label.cpp"
|
||||
#include "listbox.cpp"
|
||||
@@ -37,12 +38,30 @@ namespace phoenix {
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
Window Window::None;
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
void OS::initialize() {
|
||||
static bool initialized = false;
|
||||
if(initialized == true) return;
|
||||
initialized = true;
|
||||
|
||||
int argc = 1;
|
||||
char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
gtk_init(&argc, &argvp);
|
||||
|
||||
gtk_rc_parse_string(
|
||||
"style \"phoenix-gtk\"\n"
|
||||
"{\n"
|
||||
" GtkComboBox::appears-as-list = 1\n"
|
||||
" GtkTreeView::vertical-separator = 0\n"
|
||||
"}\n"
|
||||
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
|
||||
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
|
||||
);
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
@@ -69,7 +88,7 @@ unsigned OS::desktopHeight() {
|
||||
return gdk_screen_get_height(gdk_screen_get_default());
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
string OS::folderSelect(Window &parent, const string &path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
@@ -90,10 +109,11 @@ string OS::folderSelect(Window &parent, const char *path) {
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
if(name.endswith("/") == false) name.append("/");
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
@@ -130,7 +150,7 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileSave(Window &parent, const string &filter, const string &path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
@@ -167,25 +187,4 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
return name;
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
os = new OS::Data;
|
||||
int argc = 1;
|
||||
char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
gtk_init(&argc, &argvp);
|
||||
|
||||
gtk_rc_parse_string(
|
||||
"style \"phoenix-gtk\"\n"
|
||||
"{\n"
|
||||
" GtkComboBox::appears-as-list = 1\n"
|
||||
" GtkTreeView::vertical-separator = 0\n"
|
||||
"}\n"
|
||||
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
|
||||
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -12,13 +12,20 @@ struct Object {
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
@@ -30,16 +37,19 @@ inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style
|
||||
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
|
||||
|
||||
struct Action : Object {
|
||||
void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
Action();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *action;
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Window &parent, const nall::string &text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
};
|
||||
|
||||
struct MenuSeparator : Action {
|
||||
@@ -48,20 +58,20 @@ struct MenuSeparator : Action {
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
void create(MenuRadioItem &parent, const nall::string &text);
|
||||
bool checked();
|
||||
void setChecked();
|
||||
private:
|
||||
@@ -76,31 +86,37 @@ struct Widget : Object {
|
||||
void setEnabled(bool enabled = true);
|
||||
virtual bool focused();
|
||||
virtual void setFocused();
|
||||
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *widget;
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool focused();
|
||||
void setFocused();
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setTitle(const nall::string &text);
|
||||
void setStatusText(const nall::string &text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
static Window None;
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
@@ -116,16 +132,16 @@ struct Canvas : Widget {
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned item);
|
||||
ComboBox();
|
||||
@@ -135,12 +151,34 @@ private:
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setFocused();
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
void setCursorPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct HexEditor : Widget {
|
||||
nall::function<uint8_t (unsigned)> onRead;
|
||||
nall::function<void (unsigned, uint8_t)> onWrite;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setSize(unsigned size);
|
||||
void setOffset(unsigned offset);
|
||||
void setColumns(unsigned columns);
|
||||
void setRows(unsigned rows);
|
||||
void update();
|
||||
HexEditor();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *hexEditor;
|
||||
bool keyPress(unsigned scancode);
|
||||
void scroll(unsigned position);
|
||||
void setScroll();
|
||||
void updateScroll();
|
||||
unsigned cursorPosition();
|
||||
void setCursorPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct HorizontalSlider : Widget {
|
||||
@@ -151,21 +189,25 @@ struct HorizontalSlider : Widget {
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setText(const char *text);
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setText(const nall::string &text);
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
nall::function<void (unsigned)> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setFocused();
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void setCheckable(bool checkable = true);
|
||||
void setFont(Font &font);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
void setItem(unsigned row, const nall::string &text);
|
||||
bool checked(unsigned row);
|
||||
void setChecked(unsigned row, bool checked = true);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
@@ -176,13 +218,13 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
private:
|
||||
@@ -190,11 +232,12 @@ private:
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setEditable(bool editable = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
};
|
||||
|
||||
struct VerticalSlider : Widget {
|
||||
@@ -221,30 +264,24 @@ struct MessageWindow : Object {
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
void run();
|
||||
void main();
|
||||
void quit();
|
||||
unsigned desktopWidth();
|
||||
unsigned desktopHeight();
|
||||
nall::string folderSelect(Window &parent, const char *path = "");
|
||||
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
|
||||
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
|
||||
static bool pending();
|
||||
static void run();
|
||||
static void main();
|
||||
static void quit();
|
||||
static unsigned desktopWidth();
|
||||
static unsigned desktopHeight();
|
||||
static nall::string folderSelect(Window &parent, const nall::string &path = "");
|
||||
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
private:
|
||||
OS();
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
}
|
||||
|
266
bsnes/phoenix/gtk/hexeditor.cpp
Executable file
266
bsnes/phoenix/gtk/hexeditor.cpp
Executable file
@@ -0,0 +1,266 @@
|
||||
static bool HexEditor_keyPress(GtkWidget *widget, GdkEventKey *event, HexEditor *self) {
|
||||
return self->keyPress(event->keyval);
|
||||
}
|
||||
|
||||
static bool HexEditor_scroll(GtkRange *range, GtkScrollType scroll, gdouble value, HexEditor *self) {
|
||||
self->scroll((unsigned)value);
|
||||
return false;
|
||||
}
|
||||
|
||||
void HexEditor::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
widget->parent = &parent;
|
||||
|
||||
hexEditor->size = 0;
|
||||
hexEditor->offset = 0;
|
||||
hexEditor->columns = 16;
|
||||
hexEditor->rows = 16;
|
||||
|
||||
object->widget = gtk_hbox_new(false, 0);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
|
||||
hexEditor->container = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hexEditor->container), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(hexEditor->container), GTK_SHADOW_ETCHED_IN);
|
||||
|
||||
hexEditor->widget = gtk_text_view_new();
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(hexEditor->widget), GTK_WRAP_NONE);
|
||||
gtk_container_add(GTK_CONTAINER(hexEditor->container), hexEditor->widget);
|
||||
g_signal_connect(G_OBJECT(hexEditor->widget), "key-press-event", G_CALLBACK(HexEditor_keyPress), (gpointer)this);
|
||||
|
||||
hexEditor->scroll = gtk_vscrollbar_new((GtkAdjustment*)0);
|
||||
gtk_range_set_range(GTK_RANGE(hexEditor->scroll), 0, 256);
|
||||
gtk_range_set_increments(GTK_RANGE(hexEditor->scroll), 1, 16);
|
||||
gtk_widget_set_sensitive(hexEditor->scroll, false);
|
||||
g_signal_connect(G_OBJECT(hexEditor->scroll), "change-value", G_CALLBACK(HexEditor_scroll), (gpointer)this);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(object->widget), hexEditor->container, true, true, 0);
|
||||
gtk_box_pack_start(GTK_BOX(object->widget), hexEditor->scroll, false, false, 1);
|
||||
|
||||
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(hexEditor->widget));
|
||||
hexEditor->cursor = gtk_text_buffer_get_mark(object->textBuffer, "insert");
|
||||
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
|
||||
gtk_widget_show(hexEditor->scroll);
|
||||
gtk_widget_show(hexEditor->widget);
|
||||
gtk_widget_show(hexEditor->container);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void HexEditor::setSize(unsigned size) {
|
||||
hexEditor->size = size;
|
||||
setScroll();
|
||||
}
|
||||
|
||||
void HexEditor::setOffset(unsigned offset) {
|
||||
hexEditor->offset = offset;
|
||||
setScroll();
|
||||
updateScroll();
|
||||
}
|
||||
|
||||
void HexEditor::setColumns(unsigned columns) {
|
||||
hexEditor->columns = columns;
|
||||
setScroll();
|
||||
}
|
||||
|
||||
void HexEditor::setRows(unsigned rows) {
|
||||
hexEditor->rows = rows;
|
||||
setScroll();
|
||||
}
|
||||
|
||||
void HexEditor::update() {
|
||||
if(!onRead) {
|
||||
gtk_text_buffer_set_text(object->textBuffer, "", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned position = cursorPosition();
|
||||
|
||||
string output;
|
||||
unsigned offset = hexEditor->offset;
|
||||
for(unsigned row = 0; row < hexEditor->rows; row++) {
|
||||
output.append(hex<8>(offset));
|
||||
output.append(" ");
|
||||
|
||||
string hexdata;
|
||||
string ansidata = " ";
|
||||
for(unsigned column = 0; column < hexEditor->columns; column++) {
|
||||
if(offset < hexEditor->size) {
|
||||
uint8_t data = onRead(offset++);
|
||||
hexdata.append(hex<2>(data));
|
||||
hexdata.append(" ");
|
||||
char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 };
|
||||
ansidata.append(buffer);
|
||||
} else {
|
||||
hexdata.append(" ");
|
||||
ansidata.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
output.append(hexdata);
|
||||
output.append(ansidata);
|
||||
if(offset >= hexEditor->size) break;
|
||||
if(row != hexEditor->rows - 1) output.append("\n");
|
||||
}
|
||||
|
||||
gtk_text_buffer_set_text(object->textBuffer, output, -1);
|
||||
if(position == 0) position = 10; //start at first position where hex values can be entered
|
||||
setCursorPosition(position);
|
||||
}
|
||||
|
||||
HexEditor::HexEditor() {
|
||||
hexEditor = new HexEditor::Data;
|
||||
}
|
||||
|
||||
//internal
|
||||
|
||||
bool HexEditor::keyPress(unsigned scancode) {
|
||||
if(!onRead && !onWrite) return false;
|
||||
|
||||
unsigned position = cursorPosition();
|
||||
unsigned lineWidth = 10 + (hexEditor->columns * 3) + 1 + (hexEditor->columns) + 1;
|
||||
unsigned cursorY = position / lineWidth;
|
||||
unsigned cursorX = position % lineWidth;
|
||||
|
||||
if(scancode == GDK_Home) {
|
||||
setCursorPosition(cursorY * lineWidth + 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_End) {
|
||||
setCursorPosition(cursorY * lineWidth + 10 + (hexEditor->columns * 3 - 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Up) {
|
||||
if(cursorY != 0) return false;
|
||||
|
||||
signed newOffset = hexEditor->offset - hexEditor->columns;
|
||||
if(newOffset >= 0) {
|
||||
setOffset(newOffset);
|
||||
update();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Down) {
|
||||
if(cursorY != hexEditor->rows - 1) return false;
|
||||
|
||||
signed newOffset = hexEditor->offset + hexEditor->columns;
|
||||
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
|
||||
setOffset(newOffset);
|
||||
update();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Page_Up) {
|
||||
signed newOffset = hexEditor->offset - hexEditor->columns * hexEditor->rows;
|
||||
if(newOffset >= 0) {
|
||||
setOffset(newOffset);
|
||||
update();
|
||||
} else {
|
||||
setOffset(0);
|
||||
update();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(scancode == GDK_Page_Down) {
|
||||
signed newOffset = hexEditor->offset + hexEditor->columns * hexEditor->rows;
|
||||
for(unsigned n = 0; n < hexEditor->rows; n++) {
|
||||
if(newOffset + hexEditor->columns * hexEditor->rows - (hexEditor->columns - 1) <= hexEditor->size) {
|
||||
setOffset(newOffset);
|
||||
update();
|
||||
break;
|
||||
}
|
||||
newOffset -= hexEditor->columns;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//convert scancode to hex nibble
|
||||
if(scancode >= '0' && scancode <= '9') scancode = scancode - '0';
|
||||
else if(scancode >= 'A' && scancode <= 'F') scancode = scancode - 'A' + 10;
|
||||
else if(scancode >= 'a' && scancode <= 'f') scancode = scancode - 'a' + 10;
|
||||
else return false; //not a valid hex value
|
||||
|
||||
if(cursorX >= 10) {
|
||||
//not on an offset
|
||||
cursorX -= 10;
|
||||
if((cursorX % 3) != 2) {
|
||||
//not on a space
|
||||
bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low
|
||||
cursorX /= 3;
|
||||
if(cursorX < hexEditor->columns) {
|
||||
//not in ANSI region
|
||||
unsigned offset = hexEditor->offset + (cursorY * hexEditor->columns + cursorX);
|
||||
|
||||
if(offset >= hexEditor->size) return false; //do not edit past end of file
|
||||
uint8_t data = onRead(offset);
|
||||
|
||||
//write modified value
|
||||
if(cursorNibble == 1) {
|
||||
data = (data & 0xf0) | (scancode << 0);
|
||||
} else {
|
||||
data = (data & 0x0f) | (scancode << 4);
|
||||
}
|
||||
onWrite(offset, data);
|
||||
|
||||
//auto-advance cursor to next nibble/byte
|
||||
position++;
|
||||
if(cursorNibble && cursorX != hexEditor->columns - 1) position++;
|
||||
setCursorPosition(position);
|
||||
|
||||
//refresh output to reflect modified data
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HexEditor::scroll(unsigned position) {
|
||||
unsigned rows = hexEditor->size / hexEditor->columns;
|
||||
if(position >= rows) position = rows - 1;
|
||||
setOffset(position * hexEditor->columns);
|
||||
update();
|
||||
}
|
||||
|
||||
void HexEditor::setScroll() {
|
||||
unsigned rows = hexEditor->size / hexEditor->columns;
|
||||
if(rows) rows--;
|
||||
if(rows) {
|
||||
gtk_range_set_range(GTK_RANGE(hexEditor->scroll), 0, rows);
|
||||
gtk_widget_set_sensitive(hexEditor->scroll, true);
|
||||
} else {
|
||||
gtk_widget_set_sensitive(hexEditor->scroll, false);
|
||||
}
|
||||
}
|
||||
|
||||
void HexEditor::updateScroll() {
|
||||
unsigned row = hexEditor->offset / hexEditor->columns;
|
||||
gtk_range_set_value(GTK_RANGE(hexEditor->scroll), row);
|
||||
}
|
||||
|
||||
unsigned HexEditor::cursorPosition() {
|
||||
GtkTextIter iter;
|
||||
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
|
||||
return gtk_text_iter_get_offset(&iter);
|
||||
}
|
||||
|
||||
void HexEditor::setCursorPosition(unsigned position) {
|
||||
GtkTextIter iter;
|
||||
gtk_text_buffer_get_iter_at_mark(object->textBuffer, &iter, hexEditor->cursor);
|
||||
|
||||
//GTK+ will throw a hundred errors on the terminal
|
||||
//if you set an iterator past the end of the text buffer
|
||||
GtkTextIter endIter;
|
||||
gtk_text_buffer_get_end_iter(object->textBuffer, &iter);
|
||||
unsigned endPosition = gtk_text_iter_get_offset(&iter);
|
||||
|
||||
gtk_text_iter_set_offset(&iter, min(position, endPosition));
|
||||
gtk_text_buffer_place_cursor(object->textBuffer, &iter);
|
||||
}
|
@@ -8,6 +8,7 @@ void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned w
|
||||
object->position = 0;
|
||||
length += (length == 0);
|
||||
object->widget = gtk_hscale_new_with_range(0, length - 1, 1);
|
||||
widget->parent = &parent;
|
||||
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this);
|
||||
|
@@ -1,5 +1,6 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_label_new(text);
|
||||
widget->parent = &parent;
|
||||
gtk_misc_set_alignment(GTK_MISC(object->widget), 0.0, 0.5);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
@@ -7,6 +8,6 @@ void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsig
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void Label::setText(const char *text) {
|
||||
void Label::setText(const string &text) {
|
||||
gtk_label_set_text(GTK_LABEL(object->widget), text);
|
||||
}
|
||||
|
@@ -1,3 +1,10 @@
|
||||
static void ListBox_activate(ListBox *self) {
|
||||
signed selection = -1;
|
||||
if(auto position = self->selection()) selection = position();
|
||||
self->listBox->selection = selection;
|
||||
if(self->onActivate) self->onActivate();
|
||||
}
|
||||
|
||||
static void ListBox_change(ListBox *self) {
|
||||
signed selection = -1;
|
||||
if(auto position = self->selection()) selection = position();
|
||||
@@ -6,25 +13,25 @@ static void ListBox_change(ListBox *self) {
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
static void ListBox_activate(ListBox *self) {
|
||||
signed selection = -1;
|
||||
if(auto position = self->selection()) selection = position();
|
||||
self->listBox->selection = selection;
|
||||
if(self->onActivate) self->onActivate();
|
||||
static void ListBox_tick(GtkCellRendererToggle *cell, gchar *path_string, ListBox *self) {
|
||||
unsigned index = decimal(path_string);
|
||||
self->setChecked(index, !self->checked(index));
|
||||
if(self->onTick) self->onTick(index);
|
||||
}
|
||||
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
listBox->selection = -1;
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
widget->parent = &parent;
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
list.split("\t", string("\t", text));
|
||||
|
||||
GType *v = (GType*)malloc(list.size() * sizeof(GType));
|
||||
for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING;
|
||||
for(unsigned i = 0; i < list.size(); i++) v[i] = (i == 0 ? G_TYPE_BOOLEAN : G_TYPE_STRING);
|
||||
listBox->store = gtk_list_store_newv(list.size(), v);
|
||||
free(v);
|
||||
|
||||
@@ -32,20 +39,30 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
|
||||
g_object_unref(G_OBJECT(listBox->store));
|
||||
|
||||
//alternate color of each row if there is more than one column
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 2);
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false);
|
||||
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
listBox->column[i].renderer = gtk_cell_renderer_text_new();
|
||||
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
|
||||
list[i], listBox->column[i].renderer, "text", i, (void*)0
|
||||
);
|
||||
if(i == 0) {
|
||||
listBox->column[i].renderer = gtk_cell_renderer_toggle_new();
|
||||
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
|
||||
"", listBox->column[i].renderer, "active", i, (void*)0
|
||||
);
|
||||
gtk_tree_view_column_set_resizable(listBox->column[i].column, false);
|
||||
gtk_tree_view_column_set_visible(listBox->column[i].column, listBox->checkable);
|
||||
g_signal_connect(listBox->column[i].renderer, "toggled", G_CALLBACK(ListBox_tick), (gpointer)this);
|
||||
} else {
|
||||
listBox->column[i].renderer = gtk_cell_renderer_text_new();
|
||||
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
|
||||
"", listBox->column[i].renderer, "text", i, (void*)0
|
||||
);
|
||||
gtk_tree_view_column_set_resizable(listBox->column[i].column, true);
|
||||
}
|
||||
listBox->column[i].label = gtk_label_new(list[i]);
|
||||
gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(listBox->column[i].column), listBox->column[i].label);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(object->subWidget), listBox->column[i].column);
|
||||
gtk_widget_show(listBox->column[i].label);
|
||||
}
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false);
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 3); //>= 2 + one for the checkbox column
|
||||
gtk_tree_view_set_search_column(GTK_TREE_VIEW(object->subWidget), 1);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(object->subWidget), "cursor-changed", G_CALLBACK(ListBox_change), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(object->subWidget), "row-activated", G_CALLBACK(ListBox_activate), (gpointer)this);
|
||||
@@ -64,6 +81,11 @@ void ListBox::setHeaderVisible(bool visible) {
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), visible);
|
||||
}
|
||||
|
||||
void ListBox::setCheckable(bool checkable) {
|
||||
listBox->checkable = checkable;
|
||||
if(object->subWidget) gtk_tree_view_column_set_visible(listBox->column[0].column, checkable);
|
||||
}
|
||||
|
||||
void ListBox::setFont(Font &font) {
|
||||
Widget::setFont(font);
|
||||
unsigned columns = 1;
|
||||
@@ -89,17 +111,16 @@ void ListBox::resizeColumnsToContent() {
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(object->subWidget));
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
void ListBox::addItem(const string &text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
GtkTreeIter iter;
|
||||
gtk_list_store_append(listBox->store, &iter);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1);
|
||||
}
|
||||
unsigned index = 1;
|
||||
foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1);
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
void ListBox::setItem(unsigned row, const string &text) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreeIter iter;
|
||||
for(unsigned i = 0; i <= row; i++) {
|
||||
@@ -109,9 +130,28 @@ void ListBox::setItem(unsigned row, const char *text) {
|
||||
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1);
|
||||
}
|
||||
unsigned index = 1;
|
||||
foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1);
|
||||
}
|
||||
|
||||
bool ListBox::checked(unsigned row) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
|
||||
GtkTreeIter iter;
|
||||
bool state;
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_tree_model_get(model, &iter, 0, &state, -1);
|
||||
gtk_tree_path_free(path);
|
||||
return state;
|
||||
}
|
||||
|
||||
void ListBox::setChecked(unsigned row, bool checked) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
|
||||
GtkTreeIter iter;
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1);
|
||||
gtk_tree_path_free(path);
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
@@ -151,4 +191,5 @@ void ListBox::setSelection(unsigned row) {
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data;
|
||||
listBox->checkable = false;
|
||||
}
|
||||
|
@@ -1,14 +1,12 @@
|
||||
static void Action_setFont(GtkWidget *widget, gpointer font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, font);
|
||||
if(font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, (PangoFontDescription*)font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Action::setFont(Font &font) {
|
||||
Action_setFont(object->widget, font.font->font);
|
||||
}
|
||||
|
||||
bool Action::visible() {
|
||||
return gtk_widget_get_visible(object->widget);
|
||||
}
|
||||
@@ -25,25 +23,35 @@ void Action::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(object->widget, enabled);
|
||||
}
|
||||
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
Action::Action() {
|
||||
action = new Action::Data;
|
||||
action->font = 0;
|
||||
}
|
||||
|
||||
void Menu::create(Window &parent, const string &text) {
|
||||
action->font = parent.window->defaultFont;
|
||||
object->menu = gtk_menu_new();
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_bar_append(parent.object->menu, object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
void Menu::create(Menu &parent, const string &text) {
|
||||
action->font = parent.action->font;
|
||||
object->menu = gtk_menu_new();
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void MenuSeparator::create(Menu &parent) {
|
||||
action->font = parent.action->font;
|
||||
object->widget = gtk_separator_menu_item_new();
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
@@ -52,9 +60,11 @@ static void MenuItem_tick(MenuItem *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
void MenuItem::create(Menu &parent, const string &text) {
|
||||
action->font = parent.action->font;
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(MenuItem_tick), (gpointer)this);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
@@ -63,9 +73,11 @@ static void MenuCheckItem_tick(MenuCheckItem *self) {
|
||||
if(self->onTick && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
void MenuCheckItem::create(Menu &parent, const string &text) {
|
||||
action->font = parent.action->font;
|
||||
object->widget = gtk_check_menu_item_new_with_label(text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuCheckItem_tick), (gpointer)this);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
@@ -84,20 +96,24 @@ static void MenuRadioItem_tick(MenuRadioItem *self) {
|
||||
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
void MenuRadioItem::create(Menu &parent, const string &text) {
|
||||
first = this;
|
||||
action->font = parent.action->font;
|
||||
object->parentMenu = &parent;
|
||||
object->widget = gtk_radio_menu_item_new_with_label(0, text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
|
||||
first = parent.first;
|
||||
action->font = parent.action->font;
|
||||
object->parentMenu = parent.object->parentMenu;
|
||||
object->widget = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(first->object->widget), text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
|
||||
if(action->font) Action_setFont(object->widget, action->font->font->font);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(object->parentMenu->object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
@@ -8,56 +8,56 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", text
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", (const char*)text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", text
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", (const char*)text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", text
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", (const char*)text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", text
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", (const char*)text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
|
@@ -17,6 +17,14 @@ struct Font::Data {
|
||||
PangoFontDescription *font;
|
||||
};
|
||||
|
||||
struct Action::Data {
|
||||
Font *font;
|
||||
};
|
||||
|
||||
struct Widget::Data {
|
||||
Window *parent;
|
||||
};
|
||||
|
||||
struct Window::Data {
|
||||
Font *defaultFont;
|
||||
};
|
||||
@@ -27,6 +35,18 @@ struct Canvas::Data {
|
||||
unsigned pitch;
|
||||
};
|
||||
|
||||
struct HexEditor::Data {
|
||||
GtkWidget *container;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *scroll;
|
||||
|
||||
GtkTextMark *cursor;
|
||||
unsigned size;
|
||||
unsigned offset;
|
||||
unsigned columns;
|
||||
unsigned rows;
|
||||
};
|
||||
|
||||
struct ListBox::Data {
|
||||
GtkListStore *store;
|
||||
struct GtkColumn {
|
||||
@@ -35,16 +55,15 @@ struct ListBox::Data {
|
||||
GtkWidget *label;
|
||||
};
|
||||
linear_vector<GtkColumn> column;
|
||||
bool checkable;
|
||||
signed selection;
|
||||
};
|
||||
|
||||
struct OS::Data {
|
||||
};
|
||||
|
||||
void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
OS::initialize();
|
||||
object = new Object::Data;
|
||||
object->locked = false;
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
object->widget = gtk_progress_bar_new();
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progress = progress <= 100 ? progress : 0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)progress / 100.0);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
position = position <= 100 ? position : 0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)position / 100.0);
|
||||
}
|
||||
|
@@ -2,10 +2,11 @@ static void RadioBox_tick(RadioBox *self) {
|
||||
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
first = this;
|
||||
object->parentWindow = &parent;
|
||||
object->widget = gtk_radio_button_new_with_label(0, text);
|
||||
widget->parent = &parent;
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
@@ -13,7 +14,7 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
first = parent.first;
|
||||
object->parentWindow = parent.object->parentWindow;
|
||||
object->widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(parent.object->widget), text);
|
||||
|
@@ -1,11 +1,17 @@
|
||||
static void TextBox_activate(TextBox *self) {
|
||||
if(self->onActivate) self->onActivate();
|
||||
}
|
||||
|
||||
static void TextBox_change(TextBox *self) {
|
||||
if(self->object->locked == false && self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_entry_new();
|
||||
widget->parent = &parent;
|
||||
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(TextBox_activate), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(TextBox_change), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
@@ -20,7 +26,7 @@ string TextBox::text() {
|
||||
return gtk_entry_get_text(GTK_ENTRY(object->widget));
|
||||
}
|
||||
|
||||
void TextBox::setText(const char *text) {
|
||||
void TextBox::setText(const string &text) {
|
||||
object->locked = true;
|
||||
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
|
||||
object->locked = false;
|
||||
|
@@ -8,6 +8,7 @@ void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned wid
|
||||
object->position = 0;
|
||||
length += (length == 0);
|
||||
object->widget = gtk_vscale_new_with_range(0, length - 1, 1);
|
||||
widget->parent = &parent;
|
||||
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this);
|
||||
|
@@ -1,7 +1,16 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
object->widget = gtk_drawing_area_new();
|
||||
gtk_widget_set_double_buffered(object->widget, false);
|
||||
widget->parent = &parent;
|
||||
//gtk_widget_set_double_buffered(object->widget, false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
|
||||
GdkColor color;
|
||||
color.pixel = 0;
|
||||
color.red = 0;
|
||||
color.green = 0;
|
||||
color.blue = 0;
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
@@ -34,3 +34,14 @@ void Widget::setFocused() {
|
||||
if(visible() == false) setVisible(true);
|
||||
gtk_widget_grab_focus(object->widget);
|
||||
}
|
||||
|
||||
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
if(widget->parent == 0) return;
|
||||
gtk_fixed_move(GTK_FIXED(widget->parent->object->formContainer), object->widget, x, y);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
}
|
||||
|
||||
Widget::Widget() {
|
||||
widget = new Widget::Data;
|
||||
widget->parent = 0;
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ static gint Window_close(Window *window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
|
||||
@@ -47,6 +47,13 @@ void Window::setFocused() {
|
||||
gtk_window_present(GTK_WINDOW(object->widget));
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
gint x, y, width, height;
|
||||
gtk_window_get_position(GTK_WINDOW(object->widget), &x, &y);
|
||||
gtk_widget_get_size_request(object->formContainer, &width, &height);
|
||||
return Geometry(x, y, width, height);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
gtk_widget_set_size_request(object->formContainer, width, height);
|
||||
@@ -69,11 +76,11 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
void Window::setTitle(const string &text) {
|
||||
gtk_window_set_title(GTK_WINDOW(object->widget), text);
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
void Window::setStatusText(const string &text) {
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(object->status), 1);
|
||||
gtk_statusbar_push(GTK_STATUSBAR(object->status), 1, text);
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
button->setParent(parent.window->container);
|
||||
button->setGeometry(x, y, width, height);
|
||||
button->setText(text);
|
||||
button->setText(QString::fromUtf8(text));
|
||||
if(parent.window->defaultFont) button->setFont(*parent.window->defaultFont);
|
||||
button->show();
|
||||
button->connect(button, SIGNAL(released()), SLOT(onTick()));
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
checkBox->setParent(parent.window->container);
|
||||
checkBox->setGeometry(x, y, width, height);
|
||||
checkBox->setText(text);
|
||||
checkBox->setText(QString::fromUtf8(text));
|
||||
if(parent.window->defaultFont) checkBox->setFont(*parent.window->defaultFont);
|
||||
checkBox->show();
|
||||
checkBox->connect(checkBox, SIGNAL(stateChanged(int)), SLOT(onTick()));
|
||||
|
@@ -1,11 +1,11 @@
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
comboBox->setParent(parent.window->container);
|
||||
comboBox->setGeometry(x, y, width, height);
|
||||
|
||||
if(*text) {
|
||||
lstring list;
|
||||
list.split("\n", text);
|
||||
foreach(item, list) addItem((const char*)item);
|
||||
foreach(item, list) addItem(item);
|
||||
}
|
||||
|
||||
comboBox->connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange()));
|
||||
@@ -17,8 +17,8 @@ void ComboBox::reset() {
|
||||
while(comboBox->count()) comboBox->removeItem(0);
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
comboBox->addItem(text);
|
||||
void ComboBox::addItem(const string &text) {
|
||||
comboBox->addItem(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
unsigned ComboBox::selection() {
|
||||
@@ -27,7 +27,9 @@ unsigned ComboBox::selection() {
|
||||
}
|
||||
|
||||
void ComboBox::setSelection(unsigned row) {
|
||||
object->locked = true;
|
||||
comboBox->setCurrentIndex(row);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
ComboBox::ComboBox() {
|
||||
|
@@ -1,13 +1,14 @@
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
editBox->setParent(parent.window->container);
|
||||
editBox->setGeometry(x, y, width, height);
|
||||
editBox->setText(text);
|
||||
editBox->setPlainText(QString::fromUtf8(text));
|
||||
if(parent.window->defaultFont) editBox->setFont(*parent.window->defaultFont);
|
||||
editBox->show();
|
||||
editBox->connect(editBox, SIGNAL(textChanged()), SLOT(onChange()));
|
||||
}
|
||||
|
||||
void EditBox::setEditable(bool editable) {
|
||||
editBox->setReadOnly(editable == false);
|
||||
}
|
||||
|
||||
void EditBox::setWordWrap(bool wordWrap) {
|
||||
@@ -15,9 +16,18 @@ void EditBox::setWordWrap(bool wordWrap) {
|
||||
}
|
||||
|
||||
string EditBox::text() {
|
||||
return editBox->toPlainText().toUtf8().constData();
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
void EditBox::setText(const string &text) {
|
||||
editBox->setPlainText(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
void EditBox::setCursorPosition(unsigned position) {
|
||||
QTextCursor cursor = editBox->textCursor();
|
||||
unsigned lastchar = strlen(editBox->toPlainText().toUtf8().constData());
|
||||
cursor.setPosition(min(position, lastchar));
|
||||
editBox->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
EditBox::EditBox() {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
font->setFamily(name);
|
||||
bool Font::create(const string &name, unsigned size, Font::Style style) {
|
||||
font->setFamily(QString::fromUtf8(name));
|
||||
font->setPointSize(size);
|
||||
font->setBold((style & Style::Bold) == Style::Bold);
|
||||
font->setItalic((style & Style::Italic) == Style::Italic);
|
||||
|
@@ -1,13 +1,13 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
label->setParent(parent.window->container);
|
||||
label->setGeometry(x, y, width, height);
|
||||
label->setText(text);
|
||||
label->setText(QString::fromUtf8(text));
|
||||
if(parent.window->defaultFont) label->setFont(*parent.window->defaultFont);
|
||||
label->show();
|
||||
}
|
||||
|
||||
void Label::setText(const char *text) {
|
||||
label->setText(text);
|
||||
void Label::setText(const string &text) {
|
||||
label->setText(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
Label::Label() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
listBox->setParent(parent.window->container);
|
||||
listBox->setGeometry(x, y, width, height);
|
||||
listBox->setAllColumnsShowFocus(true);
|
||||
@@ -7,7 +7,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
QStringList labels;
|
||||
foreach(item, list) labels << (const char*)item;
|
||||
foreach(item, list) labels << QString::fromUtf8(item);
|
||||
listBox->setColumnCount(list.size());
|
||||
listBox->setHeaderLabels(labels);
|
||||
for(unsigned i = 0; i < list.size(); i++) listBox->resizeColumnToContents(i);
|
||||
@@ -16,6 +16,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
listBox->setAlternatingRowColors(list.size() >= 2);
|
||||
listBox->connect(listBox, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
|
||||
listBox->connect(listBox, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
|
||||
listBox->connect(listBox, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*)));
|
||||
if(parent.window->defaultFont) listBox->setFont(*parent.window->defaultFont);
|
||||
listBox->show();
|
||||
}
|
||||
@@ -24,6 +25,14 @@ void ListBox::setHeaderVisible(bool headerVisible) {
|
||||
listBox->setHeaderHidden(headerVisible == false);
|
||||
}
|
||||
|
||||
void ListBox::setCheckable(bool checkable) {
|
||||
listBox->checkable = checkable;
|
||||
if(listBox->checkable) {
|
||||
auto items = listBox->findItems("", Qt::MatchContains);
|
||||
for(unsigned i = 0; i < items.size(); i++) items[i]->setCheckState(0, Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::reset() {
|
||||
listBox->clear();
|
||||
}
|
||||
@@ -32,20 +41,37 @@ void ListBox::resizeColumnsToContent() {
|
||||
for(unsigned i = 0; i < listBox->columnCount(); i++) listBox->resizeColumnToContents(i);
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
void ListBox::addItem(const string &text) {
|
||||
object->locked = true;
|
||||
auto items = listBox->findItems("", Qt::MatchContains);
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(listBox);
|
||||
if(listBox->checkable) item->setCheckState(0, Qt::Unchecked);
|
||||
item->setData(0, Qt::UserRole, (unsigned)items.size());
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]);
|
||||
for(unsigned i = 0; i < list.size(); i++) item->setText(i, QString::fromUtf8(list[i]));
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
void ListBox::setItem(unsigned row, const string &text) {
|
||||
object->locked = true;
|
||||
QTreeWidgetItem *item = listBox->topLevelItem(row);
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]);
|
||||
for(unsigned i = 0; i < list.size(); i++) item->setText(i, QString::fromUtf8(list[i]));
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
bool ListBox::checked(unsigned row) {
|
||||
QTreeWidgetItem *item = listBox->topLevelItem(row);
|
||||
return (item ? item->checkState(0) == Qt::Checked : false);
|
||||
}
|
||||
|
||||
void ListBox::setChecked(unsigned row, bool checked) {
|
||||
object->locked = true;
|
||||
QTreeWidgetItem *item = listBox->topLevelItem(row);
|
||||
if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
|
@@ -1,10 +1,14 @@
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
menu->setTitle(text);
|
||||
void Menu::create(Window &parent, const string &text) {
|
||||
menu->parent = &parent;
|
||||
if(menu->parent->window->defaultFont) menu->setFont(*menu->parent->window->defaultFont);
|
||||
menu->setTitle(QString::fromUtf8(text));
|
||||
parent.window->menuBar->addMenu(menu);
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
menu->setTitle(text);
|
||||
void Menu::create(Menu &parent, const string &text) {
|
||||
menu->parent = parent.menu->parent;
|
||||
if(menu->parent->window->defaultFont) menu->setFont(*menu->parent->window->defaultFont);
|
||||
menu->setTitle(QString::fromUtf8(text));
|
||||
parent.menu->addMenu(menu);
|
||||
}
|
||||
|
||||
@@ -52,8 +56,8 @@ MenuSeparator::MenuSeparator() {
|
||||
menuSeparator = new MenuSeparator::Data(*this);
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
menuItem->setText(text);
|
||||
void MenuItem::create(Menu &parent, const string &text) {
|
||||
menuItem->setText(QString::fromUtf8(text));
|
||||
menuItem->connect(menuItem, SIGNAL(triggered()), SLOT(onTick()));
|
||||
parent.menu->addAction(menuItem);
|
||||
}
|
||||
@@ -78,8 +82,8 @@ MenuItem::MenuItem() {
|
||||
menuItem = new MenuItem::Data(*this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
menuCheckItem->setText(text);
|
||||
void MenuCheckItem::create(Menu &parent, const string &text) {
|
||||
menuCheckItem->setText(QString::fromUtf8(text));
|
||||
menuCheckItem->setCheckable(true);
|
||||
menuCheckItem->connect(menuCheckItem, SIGNAL(triggered()), SLOT(onTick()));
|
||||
parent.menu->addAction(menuCheckItem);
|
||||
@@ -113,22 +117,22 @@ MenuCheckItem::MenuCheckItem() {
|
||||
menuCheckItem = new MenuCheckItem::Data(*this);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
void MenuRadioItem::create(Menu &parent, const string &text) {
|
||||
menuRadioItem->parent = &parent;
|
||||
menuRadioItem->actionGroup = new QActionGroup(0);
|
||||
menuRadioItem->actionGroup->addAction(menuRadioItem);
|
||||
menuRadioItem->setText(text);
|
||||
menuRadioItem->setText(QString::fromUtf8(text));
|
||||
menuRadioItem->setCheckable(true);
|
||||
menuRadioItem->setChecked(true);
|
||||
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
|
||||
menuRadioItem->parent->menu->addAction(menuRadioItem);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
|
||||
menuRadioItem->parent = parent.menuRadioItem->parent;
|
||||
menuRadioItem->actionGroup = parent.menuRadioItem->actionGroup;
|
||||
menuRadioItem->actionGroup->addAction(menuRadioItem);
|
||||
menuRadioItem->setText(text);
|
||||
menuRadioItem->setText(QString::fromUtf8(text));
|
||||
menuRadioItem->setCheckable(true);
|
||||
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
|
||||
menuRadioItem->parent->menu->addAction(menuRadioItem);
|
||||
|
@@ -16,26 +16,30 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ",
|
||||
QString::fromUtf8(text), MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ",
|
||||
QString::fromUtf8(text), MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ",
|
||||
QString::fromUtf8(text), MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ",
|
||||
QString::fromUtf8(text), MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
@@ -2,5 +2,6 @@ void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
OS::initialize();
|
||||
object = new Object::Data(*this);
|
||||
}
|
||||
|
@@ -6,8 +6,8 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
|
||||
progressBar->show();
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progressBar->setValue(progress);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
progressBar->setValue(position);
|
||||
}
|
||||
|
||||
ProgressBar::ProgressBar() {
|
||||
|
@@ -27,12 +27,22 @@ namespace phoenix {
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
OS::Data *OS::os = 0;
|
||||
Window Window::None;
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
void OS::initialize() {
|
||||
static bool initialized = false;
|
||||
if(initialized == true) return;
|
||||
initialized = true;
|
||||
|
||||
os = new OS::Data;
|
||||
static int argc = 1;
|
||||
static char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
os->application = new QApplication(argc, argvp);
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
@@ -59,14 +69,17 @@ unsigned OS::desktopHeight() {
|
||||
return QApplication::desktop()->screenGeometry().height();
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
string OS::folderSelect(Window &parent, const string &path) {
|
||||
QString directory = QFileDialog::getExistingDirectory(
|
||||
&parent != &Window::None ? parent.window : 0, "Select Directory", path, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
|
||||
&parent != &Window::None ? parent.window : 0, "Select Directory",
|
||||
QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
|
||||
);
|
||||
return directory.toUtf8().constData();
|
||||
string name = directory.toUtf8().constData();
|
||||
if(name.endswith("/") == false) name.append("/");
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
|
||||
string filters;
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
@@ -83,12 +96,13 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
filters.rtrim(";;");
|
||||
|
||||
QString filename = QFileDialog::getOpenFileName(
|
||||
&parent != &Window::None ? parent.window : 0, "Open File", path, (const char*)filters
|
||||
&parent != &Window::None ? parent.window : 0, "Open File",
|
||||
QString::fromUtf8(path), QString::fromUtf8(filters)
|
||||
);
|
||||
return filename.toUtf8().constData();
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileSave(Window &parent, const string &filter, const string &path) {
|
||||
string filters;
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
@@ -105,20 +119,10 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
filters.rtrim(";;");
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(
|
||||
&parent != &Window::None ? parent.window : 0, "Save File", path, (const char*)filters
|
||||
&parent != &Window::None ? parent.window : 0, "Save File",
|
||||
QString::fromUtf8(path), QString::fromUtf8(filters)
|
||||
);
|
||||
return filename.toUtf8().constData();
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
os = new OS::Data(*this);
|
||||
static int argc = 1;
|
||||
static char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
os->application = new QApplication(argc, argvp);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -12,13 +12,20 @@ struct Object {
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
@@ -37,8 +44,8 @@ struct Action : Object {
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Window &parent, const nall::string &text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
@@ -63,7 +70,7 @@ struct MenuSeparator : Action {
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
@@ -76,7 +83,7 @@ struct MenuItem : Action {
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
@@ -91,8 +98,8 @@ struct MenuCheckItem : Action {
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
void create(MenuRadioItem &parent, const nall::string &text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
@@ -112,8 +119,8 @@ struct Widget : Object {
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
virtual bool focused();
|
||||
virtual void setFocused();
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -121,26 +128,28 @@ struct Widget : Object {
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setTitle(const nall::string &text);
|
||||
void setStatusText(const nall::string &text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
bool focused();
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
static Window None;
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
Button();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -161,7 +170,7 @@ struct Canvas : Widget {
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
CheckBox();
|
||||
@@ -172,9 +181,9 @@ struct CheckBox : Widget {
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned row);
|
||||
ComboBox();
|
||||
@@ -185,11 +194,12 @@ struct ComboBox : Widget {
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
void setCursorPosition(unsigned position);
|
||||
EditBox();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -208,8 +218,8 @@ struct HorizontalSlider : Widget {
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setText(const char *text);
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setText(const nall::string &text);
|
||||
Label();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -219,12 +229,16 @@ struct Label : Widget {
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
nall::function<void (unsigned)> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void setCheckable(bool checkable = true);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
void setItem(unsigned row, const nall::string &text);
|
||||
bool checked(unsigned row);
|
||||
void setChecked(unsigned row, bool checked = true);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
@@ -235,7 +249,7 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
void setPosition(unsigned position);
|
||||
ProgressBar();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -244,8 +258,8 @@ struct ProgressBar : Widget {
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
RadioBox();
|
||||
@@ -255,11 +269,12 @@ struct RadioBox : Widget {
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setEditable(bool editable = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
TextBox();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -298,30 +313,26 @@ struct MessageWindow : Object {
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
void run();
|
||||
void main();
|
||||
void quit();
|
||||
unsigned desktopWidth();
|
||||
unsigned desktopHeight();
|
||||
nall::string folderSelect(Window &parent, const char *path = "");
|
||||
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
|
||||
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
|
||||
static bool pending();
|
||||
static void run();
|
||||
static void main();
|
||||
static void quit();
|
||||
static unsigned desktopWidth();
|
||||
static unsigned desktopHeight();
|
||||
static nall::string folderSelect(Window &parent, const nall::string &path = "");
|
||||
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
private:
|
||||
OS();
|
||||
static Data *os;
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
** Meta object code from reading C++ file 'qt.moc.hpp'
|
||||
**
|
||||
** Created: Sat Sep 25 06:31:14 2010
|
||||
** Created: Mon Nov 1 06:26:59 2010
|
||||
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
@@ -641,7 +641,7 @@ static const uint qt_meta_data_ListBox__Data[] = {
|
||||
4, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
2, 14, // methods
|
||||
3, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
@@ -651,12 +651,14 @@ static const uint qt_meta_data_ListBox__Data[] = {
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
15, 14, 14, 14, 0x0a,
|
||||
28, 14, 14, 14, 0x0a,
|
||||
44, 39, 14, 14, 0x0a,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_ListBox__Data[] = {
|
||||
"ListBox::Data\0\0onActivate()\0onChange()\0"
|
||||
"item\0onTick(QTreeWidgetItem*)\0"
|
||||
};
|
||||
|
||||
const QMetaObject ListBox::Data::staticMetaObject = {
|
||||
@@ -690,9 +692,10 @@ int ListBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
switch (_id) {
|
||||
case 0: onActivate(); break;
|
||||
case 1: onChange(); break;
|
||||
case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
|
||||
default: ;
|
||||
}
|
||||
_id -= 2;
|
||||
_id -= 3;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
@@ -761,7 +764,7 @@ static const uint qt_meta_data_TextBox__Data[] = {
|
||||
4, // revision
|
||||
0, // classname
|
||||
0, 0, // classinfo
|
||||
1, 14, // methods
|
||||
2, 14, // methods
|
||||
0, 0, // properties
|
||||
0, 0, // enums/sets
|
||||
0, 0, // constructors
|
||||
@@ -770,12 +773,13 @@ static const uint qt_meta_data_TextBox__Data[] = {
|
||||
|
||||
// slots: signature, parameters, type, tag, flags
|
||||
15, 14, 14, 14, 0x0a,
|
||||
28, 14, 14, 14, 0x0a,
|
||||
|
||||
0 // eod
|
||||
};
|
||||
|
||||
static const char qt_meta_stringdata_TextBox__Data[] = {
|
||||
"TextBox::Data\0\0onChange()\0"
|
||||
"TextBox::Data\0\0onActivate()\0onChange()\0"
|
||||
};
|
||||
|
||||
const QMetaObject TextBox::Data::staticMetaObject = {
|
||||
@@ -807,10 +811,11 @@ int TextBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
||||
return _id;
|
||||
if (_c == QMetaObject::InvokeMetaMethod) {
|
||||
switch (_id) {
|
||||
case 0: onChange(); break;
|
||||
case 0: onActivate(); break;
|
||||
case 1: onChange(); break;
|
||||
default: ;
|
||||
}
|
||||
_id -= 1;
|
||||
_id -= 2;
|
||||
}
|
||||
return _id;
|
||||
}
|
||||
|
@@ -19,8 +19,9 @@ public:
|
||||
struct Menu::Data : public QMenu {
|
||||
public:
|
||||
Menu &self;
|
||||
Window *parent;
|
||||
|
||||
Data(Menu &self) : self(self) {
|
||||
Data(Menu &self) : self(self), parent(0) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -164,7 +165,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
if(self.object->locked == false && self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -213,8 +214,10 @@ struct ListBox::Data : public QTreeWidget {
|
||||
|
||||
public:
|
||||
ListBox &self;
|
||||
bool checkable;
|
||||
|
||||
Data(ListBox &self) : self(self) {
|
||||
checkable = false;
|
||||
}
|
||||
|
||||
public slots:
|
||||
@@ -225,6 +228,10 @@ public slots:
|
||||
void onChange() {
|
||||
if(self.object->locked == false && self.onChange) self.onChange();
|
||||
}
|
||||
|
||||
void onTick(QTreeWidgetItem *item) {
|
||||
if(self.object->locked == false && self.onTick) self.onTick(item->data(0, Qt::UserRole).toUInt());
|
||||
}
|
||||
};
|
||||
|
||||
struct ProgressBar::Data : public QProgressBar {
|
||||
@@ -262,6 +269,10 @@ public:
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onActivate() {
|
||||
if(self.onActivate) self.onActivate();
|
||||
}
|
||||
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
@@ -294,11 +305,7 @@ struct OS::Data : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OS &self;
|
||||
QApplication *application;
|
||||
|
||||
Data(OS &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
@@ -1,23 +1,23 @@
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
radioBox->parent = &parent;
|
||||
radioBox->buttonGroup = new QButtonGroup;
|
||||
radioBox->buttonGroup->addButton(radioBox);
|
||||
radioBox->setParent(radioBox->parent->window->container);
|
||||
radioBox->setGeometry(x, y, width, height);
|
||||
radioBox->setText(text);
|
||||
radioBox->setText(QString::fromUtf8(text));
|
||||
radioBox->setChecked(true);
|
||||
if(parent.window->defaultFont) radioBox->setFont(*parent.window->defaultFont);
|
||||
radioBox->show();
|
||||
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
radioBox->parent = parent.radioBox->parent;
|
||||
radioBox->buttonGroup = parent.radioBox->buttonGroup;
|
||||
radioBox->buttonGroup->addButton(radioBox);
|
||||
radioBox->setParent(radioBox->parent->window->container);
|
||||
radioBox->setGeometry(x, y, width, height);
|
||||
radioBox->setText(text);
|
||||
radioBox->setText(QString::fromUtf8(text));
|
||||
if(radioBox->parent->window->defaultFont) radioBox->setFont(*radioBox->parent->window->defaultFont);
|
||||
radioBox->show();
|
||||
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
|
||||
|
@@ -1,9 +1,10 @@
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
textBox->setParent(parent.window->container);
|
||||
textBox->setGeometry(x, y, width, height);
|
||||
textBox->setText(text);
|
||||
textBox->setText(QString::fromUtf8(text));
|
||||
if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont);
|
||||
textBox->show();
|
||||
textBox->connect(textBox, SIGNAL(returnPressed()), SLOT(onActivate()));
|
||||
textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
|
||||
}
|
||||
|
||||
@@ -15,8 +16,8 @@ string TextBox::text() {
|
||||
return textBox->text().toUtf8().constData();
|
||||
}
|
||||
|
||||
void TextBox::setText(const char *text) {
|
||||
textBox->setText(text);
|
||||
void TextBox::setText(const string &text) {
|
||||
textBox->setText(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
TextBox::TextBox() {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
viewport->setParent(parent.window->container);
|
||||
viewport->setGeometry(x, y, width, height);
|
||||
viewport->setAttribute(Qt::WA_PaintOnScreen, true);
|
||||
viewport->setStyleSheet("background: #000000");
|
||||
viewport->show();
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
window->setWindowTitle(text);
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
window->setWindowTitle(QString::fromUtf8(text));
|
||||
window->move(x, y);
|
||||
|
||||
window->layout = new QVBoxLayout(window);
|
||||
@@ -23,6 +23,10 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
|
||||
window->layout->addWidget(window->statusBar);
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
return Geometry(window->x(), window->y(), window->container->width(), window->container->height());
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
window->container->setFixedSize(width, height);
|
||||
window->move(x, y);
|
||||
@@ -44,12 +48,12 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
window->setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
window->setWindowTitle(text);
|
||||
void Window::setTitle(const string &text) {
|
||||
window->setWindowTitle(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
window->statusBar->showMessage(text, 0);
|
||||
void Window::setStatusText(const string &text) {
|
||||
window->statusBar->showMessage(QString::fromUtf8(text), 0);
|
||||
}
|
||||
|
||||
void Window::setMenuVisible(bool visible) {
|
||||
@@ -62,6 +66,10 @@ void Window::setStatusVisible(bool visible) {
|
||||
else window->statusBar->hide();
|
||||
}
|
||||
|
||||
bool Window::focused() {
|
||||
return window->isActiveWindow() && !window->isMinimized();
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data(*this);
|
||||
window->defaultFont = 0;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
@@ -6,5 +6,5 @@ void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
|
||||
@@ -6,7 +6,7 @@ void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
}
|
||||
|
||||
bool CheckBox::checked() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindowEx(
|
||||
0, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
@@ -7,7 +7,7 @@ void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
|
||||
);
|
||||
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
|
||||
//CreateWindow height parameter is the height of the expanded list box;
|
||||
//need additional code to override default ComboBox control height
|
||||
@@ -27,7 +27,7 @@ void ComboBox::reset() {
|
||||
SendMessage(widget->window, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
void ComboBox::addItem(const string &text) {
|
||||
SendMessage(widget->window, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
if(SendMessage(widget->window, CB_GETCOUNT, 0, 0) == 1) setSelection(0);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, L"EDIT", L"",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
|
||||
@@ -8,7 +8,7 @@ void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
);
|
||||
setText(text);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
}
|
||||
|
||||
string EditBox::getText() {
|
||||
@@ -21,7 +21,7 @@ string EditBox::getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
void EditBox::setText(const string &text) {
|
||||
string output = text;
|
||||
output.replace("\r", "");
|
||||
output.replace("\n", "\r\n");
|
||||
|
@@ -1,4 +1,4 @@
|
||||
static HFONT Font_createFont(const char *name, unsigned size, bool bold, bool italic) {
|
||||
static HFONT Font_createFont(const string &name, unsigned size, bool bold, bool italic) {
|
||||
return CreateFont(
|
||||
-(size * 96.0 / 72.0 + 0.5),
|
||||
0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -6,7 +6,7 @@ static HFONT Font_createFont(const char *name, unsigned size, bool bold, bool it
|
||||
);
|
||||
}
|
||||
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
bool Font::create(const string &name, unsigned size, Font::Style style) {
|
||||
font->font = Font_createFont(
|
||||
name, size,
|
||||
(style & Font::Style::Bold) == Font::Style::Bold,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindow(
|
||||
L"phoenix_label", L"",
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
@@ -6,12 +6,13 @@ void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsig
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
void Label::setText(const char *text) {
|
||||
void Label::setText(const string &text) {
|
||||
SetWindowText(widget->window, utf16_t(text));
|
||||
InvalidateRect(widget->window, 0, false);
|
||||
}
|
||||
|
||||
//all of this for want of a STATIC SS_VCENTER flag ...
|
||||
@@ -24,28 +25,14 @@ LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa
|
||||
Label &label = *label_ptr;
|
||||
|
||||
switch(msg) {
|
||||
case WM_ERASEBKGND: {
|
||||
if(window.window->brush == 0) break;
|
||||
RECT rc;
|
||||
GetClientRect(window.widget->window, &rc);
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(window.widget->window, &ps);
|
||||
FillRect(ps.hdc, &rc, window.window->brush);
|
||||
EndPaint(window.widget->window, &ps);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
SelectObject(ps.hdc, label.widget->font);
|
||||
if(window.window->brush) {
|
||||
SetBkColor(ps.hdc, window.window->brushColor);
|
||||
} else {
|
||||
SetBkColor(ps.hdc, GetSysColor(COLOR_3DFACE));
|
||||
}
|
||||
RECT rc;
|
||||
BeginPaint(hwnd, &ps);
|
||||
GetClientRect(hwnd, &rc);
|
||||
FillRect(ps.hdc, &rc, window.window->brush ? window.window->brush : GetSysColorBrush(COLOR_3DFACE));
|
||||
SetBkColor(ps.hdc, window.window->brush ? window.window->brushColor : GetSysColor(COLOR_3DFACE));
|
||||
SelectObject(ps.hdc, label.widget->font);
|
||||
unsigned length = GetWindowTextLength(hwnd);
|
||||
wchar_t text[length + 1];
|
||||
GetWindowText(hwnd, text, length + 1);
|
||||
@@ -57,7 +44,6 @@ LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa
|
||||
rc.bottom = rc.top + height;
|
||||
DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS);
|
||||
EndPaint(hwnd, &ps);
|
||||
InvalidateRect(hwnd, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
|
||||
@@ -7,7 +7,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT);
|
||||
|
||||
lstring list;
|
||||
@@ -34,6 +34,10 @@ void ListBox::setHeaderVisible(bool headerVisible) {
|
||||
);
|
||||
}
|
||||
|
||||
void ListBox::setCheckable(bool checkable) {
|
||||
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT | (checkable ? LVS_EX_CHECKBOXES : 0));
|
||||
}
|
||||
|
||||
void ListBox::reset() {
|
||||
ListView_DeleteAllItems(widget->window);
|
||||
}
|
||||
@@ -44,7 +48,7 @@ void ListBox::resizeColumnsToContent() {
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
void ListBox::addItem(const string &text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
LVITEM item;
|
||||
@@ -54,20 +58,28 @@ void ListBox::addItem(const char *text) {
|
||||
item.iSubItem = 0;
|
||||
utf16_t wtext(list[0]);
|
||||
item.pszText = wtext;
|
||||
object->locked = true;
|
||||
ListView_InsertItem(widget->window, &item);
|
||||
object->locked = false;
|
||||
for(unsigned i = 1; i < list.size(); i++) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
|
||||
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
|
||||
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
void ListBox::setItem(unsigned row, const string &text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
|
||||
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
|
||||
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
@@ -86,6 +98,16 @@ void ListBox::setSelection(unsigned row) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ListBox::checked(unsigned row) {
|
||||
return ListView_GetCheckState(widget->window, row);
|
||||
}
|
||||
|
||||
void ListBox::setChecked(unsigned row, bool checked) {
|
||||
object->locked = true;
|
||||
ListView_SetCheckState(widget->window, row, checked);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data;
|
||||
listBox->lostFocus = false;
|
||||
|
@@ -1,15 +1,15 @@
|
||||
Action::Action() {
|
||||
os.objects.append(this);
|
||||
OS::os->objects.append(this);
|
||||
action = new Action::Data;
|
||||
}
|
||||
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
void Menu::create(Window &parent, const string &text) {
|
||||
action->parentMenu = parent.window->menu;
|
||||
action->menu = CreatePopupMenu();
|
||||
AppendMenu(parent.window->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
void Menu::create(Menu &parent, const string &text) {
|
||||
action->parentMenu = parent.action->menu;
|
||||
action->menu = CreatePopupMenu();
|
||||
AppendMenu(parent.action->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
|
||||
@@ -46,7 +46,7 @@ void MenuSeparator::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
void MenuItem::create(Menu &parent, const string &text) {
|
||||
action->parent = &parent;
|
||||
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void MenuItem::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
void MenuCheckItem::create(Menu &parent, const string &text) {
|
||||
action->parent = &parent;
|
||||
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void MenuCheckItem::setChecked(bool checked) {
|
||||
CheckMenuItem(action->parent->action->menu, object->id, checked ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
void MenuRadioItem::create(Menu &parent, const string &text) {
|
||||
action->parent = &parent;
|
||||
action->radioParent = this;
|
||||
action->items.append(this);
|
||||
@@ -103,7 +103,7 @@ void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
setChecked();
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
|
||||
action->parent = parent.action->parent;
|
||||
action->radioParent = parent.action->radioParent;
|
||||
action->radioParent->action->items.append(this);
|
||||
|
@@ -8,7 +8,7 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONINFORMATION;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
@@ -16,7 +16,7 @@ MessageWindow::Response MessageWindow::information(Window &parent, const char *t
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONQUESTION;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
@@ -24,7 +24,7 @@ MessageWindow::Response MessageWindow::question(Window &parent, const char *text
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONWARNING;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
@@ -32,7 +32,7 @@ MessageWindow::Response MessageWindow::warning(Window &parent, const char *text,
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONERROR;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
|
@@ -70,6 +70,7 @@ struct VerticalSlider::Data {
|
||||
};
|
||||
|
||||
struct OS::Data {
|
||||
nall::array<Object*> objects;
|
||||
HFONT proportionalFont;
|
||||
HFONT monospaceFont;
|
||||
};
|
||||
@@ -78,6 +79,7 @@ void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
OS::initialize();
|
||||
static unsigned guid = 100;
|
||||
object = new Object::Data;
|
||||
object->id = guid++;
|
||||
|
@@ -9,10 +9,10 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
|
||||
SendMessage(widget->window, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
|
||||
}
|
||||
|
||||
unsigned ProgressBar::progress() {
|
||||
unsigned ProgressBar::position() {
|
||||
return SendMessage(widget->window, PBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
SendMessage(widget->window, PBM_SETPOS, (WPARAM)progress, 0);
|
||||
void ProgressBar::setPosition(unsigned position) {
|
||||
SendMessage(widget->window, PBM_SETPOS, (WPARAM)position, 0);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
radioBox->parentWindow = &parent;
|
||||
radioBox->parent = this;
|
||||
radioBox->parent->radioBox->items.append(this);
|
||||
@@ -9,11 +9,11 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
setChecked();
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
radioBox->parentWindow = parent.radioBox->parentWindow;
|
||||
radioBox->parent = parent.radioBox->parent;
|
||||
radioBox->parent->radioBox->items.append(this);
|
||||
@@ -24,7 +24,7 @@ void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width,
|
||||
GetParent(radioBox->parent->widget->window), (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : OS::os->proportionalFont), 0);
|
||||
}
|
||||
|
||||
bool RadioBox::checked() {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, L"EDIT", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
|
||||
@@ -6,7 +6,7 @@ void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
|
||||
}
|
||||
|
||||
string TextBox::text() {
|
||||
@@ -17,7 +17,7 @@ string TextBox::text() {
|
||||
return utf8_t(text);
|
||||
}
|
||||
|
||||
void TextBox::setText(const char *text) {
|
||||
void TextBox::setText(const string &text) {
|
||||
object->locked = true;
|
||||
SetWindowText(widget->window, utf16_t(text));
|
||||
object->locked = false;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
widget->window = CreateWindow(
|
||||
L"phoenix_window", L"",
|
||||
L"phoenix_viewport", L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_DISABLED,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
@@ -11,3 +11,7 @@ void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, un
|
||||
uintptr_t Viewport::handle() {
|
||||
return (uintptr_t)widget->window;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
@@ -28,9 +28,13 @@ void Widget::setFocused() {
|
||||
SetFocus(widget->window);
|
||||
}
|
||||
|
||||
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER);
|
||||
}
|
||||
|
||||
Widget::Widget() {
|
||||
os.objects.append(this);
|
||||
OS::os->objects.append(this);
|
||||
widget = new Widget::Data;
|
||||
widget->window = 0;
|
||||
widget->font = os.os->proportionalFont;
|
||||
widget->font = OS::os->proportionalFont;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
|
||||
widget->window = CreateWindowEx(
|
||||
0, L"phoenix_window", utf16_t(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
@@ -26,6 +26,18 @@ void Window::setFont(Font &font) {
|
||||
SendMessage(window->status, WM_SETFONT, (WPARAM)font.font->font, 0);
|
||||
}
|
||||
|
||||
Geometry Window::geometry() {
|
||||
RECT position, size;
|
||||
GetWindowRect(widget->window, &position);
|
||||
GetClientRect(widget->window, &size);
|
||||
if(GetWindowLongPtr(window->status, GWL_STYLE) & WS_VISIBLE) {
|
||||
RECT status;
|
||||
GetClientRect(window->status, &status);
|
||||
size.bottom -= status.bottom - status.top;
|
||||
}
|
||||
return Geometry(position.left, position.top, size.right, size.bottom);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
bool isVisible = visible();
|
||||
if(isVisible) setVisible(false);
|
||||
@@ -40,11 +52,11 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
window->brush = CreateSolidBrush(window->brushColor);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
void Window::setTitle(const string &text) {
|
||||
SetWindowText(widget->window, utf16_t(text));
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
void Window::setStatusText(const string &text) {
|
||||
SendMessage(window->status, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
}
|
||||
|
||||
|
@@ -29,14 +29,72 @@ namespace phoenix {
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
OS::Data *OS::os = 0;
|
||||
Window Window::None;
|
||||
|
||||
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
void OS::initialize() {
|
||||
static bool initialized = false;
|
||||
if(initialized == true) return;
|
||||
initialized = true;
|
||||
|
||||
InitCommonControls();
|
||||
CoInitialize(0);
|
||||
|
||||
os = new OS::Data;
|
||||
os->proportionalFont = Font_createFont("Tahoma", 8, false, false);
|
||||
os->monospaceFont = Font_createFont("Courier New", 8, false, false);
|
||||
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = OS_windowProc;
|
||||
wc.lpszClassName = L"phoenix_window";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Canvas_windowProc;
|
||||
wc.lpszClassName = L"phoenix_canvas";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Label_windowProc;
|
||||
wc.lpszClassName = L"phoenix_label";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Viewport_windowProc;
|
||||
wc.lpszClassName = L"phoenix_viewport";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
@@ -84,7 +142,7 @@ unsigned OS::desktopHeight() {
|
||||
return GetSystemMetrics(SM_CYSCREEN);
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
string OS::folderSelect(Window &parent, const string &path) {
|
||||
wchar_t wfilename[PATH_MAX + 1] = L"";
|
||||
BROWSEINFO bi;
|
||||
bi.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
|
||||
@@ -108,10 +166,13 @@ string OS::folderSelect(Window &parent, const char *path) {
|
||||
}
|
||||
}
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
string name = utf8_t(wfilename);
|
||||
name.transform("\\", "/");
|
||||
if(name.endswith("/") == false) name.append("/");
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
|
||||
string dir = path;
|
||||
dir.replace("/", "\\");
|
||||
|
||||
@@ -154,10 +215,12 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
|
||||
bool result = GetOpenFileName(&ofn);
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
string name = utf8_t(wfilename);
|
||||
name.transform("\\", "/");
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string OS::fileSave(Window &parent, const string &filter, const string &path) {
|
||||
string dir = path;
|
||||
dir.replace("/", "\\");
|
||||
|
||||
@@ -200,7 +263,9 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
|
||||
bool result = GetSaveFileName(&ofn);
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
string name = utf8_t(wfilename);
|
||||
name.transform("\\", "/");
|
||||
return name;
|
||||
}
|
||||
|
||||
static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
@@ -211,10 +276,17 @@ static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
info.cbSize = sizeof(GUITHREADINFO);
|
||||
GetGUIThreadInfo(GetCurrentThreadId(), &info);
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
|
||||
if(object_ptr && dynamic_cast<ListBox*>(object_ptr)) {
|
||||
ListBox &listBox = (ListBox&)*object_ptr;
|
||||
if(wparam == VK_RETURN) {
|
||||
if(listBox.onActivate) listBox.onActivate();
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<ListBox*>(object_ptr)) {
|
||||
ListBox &listBox = (ListBox&)*object_ptr;
|
||||
if(wparam == VK_RETURN) {
|
||||
if(listBox.onActivate) listBox.onActivate();
|
||||
}
|
||||
} else if(dynamic_cast<TextBox*>(object_ptr)) {
|
||||
TextBox &textBox = (TextBox&)*object_ptr;
|
||||
if(wparam == VK_RETURN) {
|
||||
if(textBox.onActivate) textBox.onActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +333,7 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.widget->window, id);
|
||||
if(control == 0) {
|
||||
Object *object_ptr = (Object*)os.findObject(id);
|
||||
Object *object_ptr = (Object*)OS::findObject(id);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<MenuItem*>(object_ptr)) {
|
||||
MenuItem &menuItem = (MenuItem&)*object_ptr;
|
||||
@@ -327,8 +399,12 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
|
||||
ListBox &listBox = (ListBox&)*object_ptr;
|
||||
LPNMHDR nmhdr = (LPNMHDR)lparam;
|
||||
LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam;
|
||||
|
||||
if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) {
|
||||
if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
|
||||
unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1;
|
||||
if(imagemask == 0 || imagemask == 1) {
|
||||
if(listBox.object->locked == false && listBox.onTick) listBox.onTick(nmlistview->iItem);
|
||||
} else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
|
||||
listBox.listBox->lostFocus = true;
|
||||
} else {
|
||||
if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) {
|
||||
@@ -385,54 +461,8 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
|
||||
}
|
||||
|
||||
Object* OS::findObject(unsigned id) {
|
||||
foreach(object, objects) { if(object->object->id == id) return object; }
|
||||
foreach(object, os->objects) { if(object->object->id == id) return object; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
InitCommonControls();
|
||||
CoInitialize(0);
|
||||
|
||||
os = new OS::Data;
|
||||
os->proportionalFont = Font_createFont("Tahoma", 8, false, false);
|
||||
os->monospaceFont = Font_createFont("Courier New", 8, false, false);
|
||||
|
||||
WNDCLASS wc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = OS_windowProc;
|
||||
wc.lpszClassName = L"phoenix_window";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Canvas_windowProc;
|
||||
wc.lpszClassName = L"phoenix_canvas";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
|
||||
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Label_windowProc;
|
||||
wc.lpszClassName = L"phoenix_label";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ struct Window;
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
Object& operator=(const Object&) = delete;
|
||||
Object(const Object&) = delete;
|
||||
//private:
|
||||
struct Data;
|
||||
Data *object;
|
||||
@@ -11,13 +13,20 @@ private:
|
||||
virtual void unused();
|
||||
};
|
||||
|
||||
struct Geometry {
|
||||
unsigned x, y;
|
||||
unsigned width, height;
|
||||
inline Geometry() : x(0), y(0), width(0), height(0) {}
|
||||
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
@@ -38,8 +47,8 @@ struct Action : Object {
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Window &parent, const nall::string &text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
@@ -52,14 +61,14 @@ struct MenuSeparator : Action {
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
@@ -68,8 +77,8 @@ struct MenuCheckItem : Action {
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
void create(Menu &parent, const nall::string &text);
|
||||
void create(MenuRadioItem &parent, const nall::string &text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
@@ -84,6 +93,7 @@ struct Widget : Object {
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
@@ -91,28 +101,28 @@ struct Widget : Object {
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setDefaultFont(Font &font);
|
||||
void setFont(Font &font);
|
||||
Geometry geometry();
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setTitle(const nall::string &text);
|
||||
void setStatusText(const nall::string &text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
//private:
|
||||
static Window None;
|
||||
void resize(unsigned width, unsigned height);
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
@@ -128,16 +138,16 @@ struct Canvas : Widget {
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned item);
|
||||
ComboBox();
|
||||
@@ -148,9 +158,9 @@ struct ComboBox : Widget {
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
nall::string getText();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
EditBox();
|
||||
@@ -171,19 +181,23 @@ struct HorizontalSlider : Widget {
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setText(const char *text);
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setText(const nall::string &text);
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
nall::function<void (unsigned)> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void setCheckable(bool checkable = true);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
void addItem(const nall::string &text);
|
||||
void setItem(unsigned row, const nall::string &text);
|
||||
bool checked(unsigned row);
|
||||
void setChecked(unsigned row, bool checked = true);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
@@ -194,14 +208,14 @@ struct ListBox : Widget {
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
unsigned progress();
|
||||
void setProgress(unsigned progress);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
RadioBox();
|
||||
@@ -211,10 +225,11 @@ struct RadioBox : Widget {
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
void setText(const nall::string &text);
|
||||
void setEditable(bool editable = true);
|
||||
};
|
||||
|
||||
@@ -246,33 +261,28 @@ struct MessageWindow : Object {
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
void run();
|
||||
void main();
|
||||
void quit();
|
||||
unsigned desktopWidth();
|
||||
unsigned desktopHeight();
|
||||
nall::string folderSelect(Window &parent, const char *path = "");
|
||||
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
|
||||
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
|
||||
static bool pending();
|
||||
static void run();
|
||||
static void main();
|
||||
static void quit();
|
||||
static unsigned desktopWidth();
|
||||
static unsigned desktopHeight();
|
||||
static nall::string folderSelect(Window &parent, const nall::string &path = "");
|
||||
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
static void initialize();
|
||||
struct Data;
|
||||
Data *os;
|
||||
Object* findObject(unsigned id);
|
||||
nall::array<Object*> objects;
|
||||
private:
|
||||
OS();
|
||||
static Data *os;
|
||||
static Object* findObject(unsigned id);
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user