Compare commits

...

21 Commits
v068 ... v069

Author SHA1 Message Date
Tim Allen
ccfff86140 Update to v069 release.
byuu says (since v068):

- added new effect toggle tool window, which allows toggling of BG/OAM
  graphics layers and DSP audio channels
- added an option to use the native OS file and folder open dialogs
  instead of my custom browser
- added a new state selection window
- added frame skipping support, which is only used during fast
  forwarding; as a result, fast forward is now ~80% faster
- removed unnecessary icons, added workaround for checkbox/radiobox menu
  icons on Linux/GNOME
- added RTS/CTS support to serial simulation
- all cores: OAM high table even address writes should update OAM latch
  data register [blargg]
- accuracy core: major improvements to mosaic emulation
- accuracy core: added additional hardware-based caching, resulting in
  a ~15% speed boost
- accuracy core: emulated CGRAM address invalidation for writes during
  active display
- performance core: added new S-PPU renderer, resulting in a ~10% speed
  bost
2010-10-20 22:51:18 +11:00
Tim Allen
4525d00eba Update to v068r25 release.
byuu says:

This is basically the v069 release candidate, heavy testing would really
be appreciated. I'd like for v070 to be the first official phoenix
release, but if a major bug slips past us that will ruin it.

The big change is that save state support was added to the
PPU-performance core.
2010-10-20 22:51:18 +11:00
Tim Allen
d0d8c2a921 Update to v068r24 release.
(there was no r23 release posted to the WIP thread)

byuu says:

Fixes OAM latchdata for all 3 cores and CGRAM address invalidation for
the accuracy core (the only one that really does it because it needs
cycle PPU timing.) Also removes the OAM/CGRAM read/write functions to
put them inside the actual MMIO functions. Easier to handle all the
special cases that way. VRAM is a bit more annoying since there's two
read and two write functions.

This should fix battletech/mechwarrior 3050 palette at least.
2010-10-20 22:51:18 +11:00
Tim Allen
8a91c95002 Update to v068r22 release.
byuu says:

Wanted to torture myself, so I implemented the hardest window of all,
the cheat code editor. I had to sacrifice checkboxes inside lists,
unfortunately, but it's a necessary evil. Maybe some day if we can port
checkboxes inside list items to Windows and GTK+, we can add it back. It
should be the only really apparent GUI sacrifice, though. You toggle
cheats by double-clicking them in the list. Easy to do, but not
apparent.

I also added in the focus policy.
2010-10-20 22:51:18 +11:00
Tim Allen
9484d1bc92 Update to v068r21 release.
byuu says:

Changelog:
- adds synchronize video
- adds synchronize audio
- adds mute audio
- adds advanced settings window with driver selection only
- adds the pretty section header thing I started going toward with Qt
- adds a configuration file, saves to bsnes-phoenix.cfg (I don't make
  the .bsnes folder yet)
- the status bar shows [A] for accuracy, [C] for compatibility and [P]
  for carburetor
2010-10-20 22:51:18 +11:00
Tim Allen
4163059b21 Update to v068r20 release.
byuu says:

Changelog:
- fixed window casting crash in phoenix
- added perfect forwarding to nall::string variadic templates to fix
  file load dialog crash in phoenix
- disabled copy constructors in utf8_t to prevent this problem from
  occurring again in the future
- separated canvas window proc by creating a separate class for it
  (ironically it was a desktop window causing the first crash)
- use processorArchitecture="*" to make compilation easier
- fixed status bar font assignment in phoenix/Windows
- added InitCommonControls + CoInitialize for XAudio2 on XP
- had to use DirectSound for audio; XAudio2 is crashing on exit which
  breaks the profiling (only a problem because you can't change the
  drivers without recompiling, there's really no reason to profile
  XAudio2 anyway)
2010-10-20 22:51:18 +11:00
Tim Allen
697f23d45c Update to v068r19 release.
byuu says:

This adds proper manifest files to get the nice XP/Vista controls. Need
to find a way to auto-detect MinGW 32 vs 64 since I can't use $shell or
`` on gcc -v on Windows. For now you have to edit the
ui-phoenix/Makefile by hand.

I've implemented the video settings window. I am going to be using
separate windows this time. As nice as having everything in one place
was, I didn't like being forced to stretch things to fill out the
one-size-fits-all tab window I was using before. That and I don't feel
like implementing tab support with phoenix anyway.

The menu gets a load cartridge command, and bsnes writes save RAM files
now. Loading by file dialog crashes on 64-bit. Something's fucked up
there, but I don't know what. Again, help would be great here :)
2010-10-20 22:48:46 +11:00
Tim Allen
b671e49644 Update to v068r18 release.
byuu says:

This WIP fixes the Mode7 repeat issue in the accuracy core.

More importantly, it's the first build to include phoenix. There is
a stub GUI that does basically nothing right now. It will give you
a window, a command to close the emulator, and an FPS meter so you can
tell how fast it is. To load a ROM, you have to drag the ROM on top of
the binary. I don't know if it will work if the filename+path has spaces
in it or not, so avoid that to be safe.

[...]

For some reason, the 64-bit binary sometimes crashes on start, maybe 1:6
times. So just keep trying. I don't know what's up with that, I'd
appreciate if someone here wanted to debug that for me though :D

One really good bit of news, there was that old hiro bug where keyboard
input would cause the main window to beep. I spied on the main event
loop and, as suspected, the status bar was getting focus and rejecting
key presses. What. The. Fuck. Why would a status bar ever need focus? So
I set WM_DISABLED on it, which luckily leaves the font color alone.
I also had to use WM_DISABLED on the Viewport widget that I use for
video output. These two combined let me have my main window with no
keyboard beeping AND allow tab+shift-tab to work as you'd expect on
other windows, so hooray.

Now, at the moment there's no Manifest included, because Microsoft for
some reason includes the processorArcitecture in the file. So I can't
use the same manifest for 32-bit and 64-bit mode, or the binary will
crash on one or the other. Fuck. So the status bar may look old-school
or something, whatever, it's only temporary.

Next up, my goal is to avoid the hiro icon corruption bullshit by making
phoenix itself try and use an internal resource icon. So just compile
your app with that resource icon and voila, perfect icon. Not in there
yet so you get the white box.

Input is hard-coded, up/down/left/right/z/x/a/s/d/c/apostrophe/return.

Lastly, compilation is ... in a serious state of flux. The code is set
to compile bsnes/phoenix-gtk right now. Try it at your own risk. Give me
a few WIPs to get everything nice and refined. Ubuntu users will need
gcc-4.5, which you can get by adding the Maverick Meerkat repository,
updating apt, installing the gcc-4.5 + g++-4.5 packages, and then
removing and re-updating your apt/sources.list file so you don't end up
fucking your whole system when you run apt again in the future.

For anyone who can work with all of that, great! Please post a framerate
comparison between 32-bit and 64-bit builds. Any game, any screen, so
long as the FPS is not fluctuating when you measure it (eg don't do it
during an attract sequence.)

If anyone complains about the 64-bit binary not working and it turns out
they are on 32-bit Windows, they are going to be removed from this WIP
forum :P
2010-10-20 22:47:14 +11:00
Tim Allen
92ab697f8c Update to v068r17 release.
byuu says:

This hopefully fixes vertical and horizontal mosaic with the accurate
S-PPU core.

It also adds frame-skipping support to the compatibility and performance
S-PPU cores. This is not visible to the user interface, because I feel
that virtually nobody is going to play with frame-skipping on when they
could use a faster emulation with it off. However, I did use it to
enhance the 'Fast Forward' key. When you press it, it will now turn off
video and audio sync, and set a frameskip of 9. This allows you to speed
things up an additional ~60% over your max theoretical speed without
frameskipping. ~35% with the compatible core, because the PPU is less of
a bottleneck for it. Slowdown was improved, it will turn on audio sync
if it is off until you release the key to ensure you actually get 30fps.

Eventually it'd probably be wise to set a cap on the fast forward speed,
but I hardly think it's an issue on today's computers.
2010-10-20 22:30:35 +11:00
Tim Allen
4147dc42d0 Update to v068r16 release.
byuu says:

Testing this one and all the new features would be appreciated.

New features?

http://img203.imageshack.us/img203/505/bsnes20100907.jpg

[For future reference, the above URL points to a screenshot of bsnes' Qt
GUI running with the following windows (apart from the main window) visible:
 - A new 'state selection' dialog wih buttons labelled 'Slot 1' through
   'Slot 10'.
 - The 'Tools' dialog open to a new 'Effect Toggle' tab, which has
   checkboxes for the various PPU backgrounds and sprites, and SPU
   channels.
 - The 'Configuration Settings' dialog open to the 'Advanced' tab, with
   a "Use Native OS File Dialogs" checkbox.
 - A 'Load Cartridge' dialog, which is the standard Windows file-open
   dialog.
It seems these are the new features referred to. -- Ed]
2010-10-20 22:30:35 +11:00
Tim Allen
05fca49b11 Update to v068r15 release.
byuu says:

This adds a new "Effect Toggle" window to the tools tab list. There's no
menu entry for it yet, oversight, but you can go to another tool and tab
to it.

The effect toggle window lets you toggle background/OAM layers on
a per-priority basis and DSP sound channels. This only works with the
compatibility and performance cores, because I'm not going to allow
accuracy-violating hacks like that into the core.

Non-essential icons have been removed, there's six of them left at the
moment. I am too much of a consistency guy to only have some scattered
around. I know other apps do that, but I'm not going to do that, and
I grow tired of trying to hammer in icons that don't really represent
the actions. Anyway, it still looks pretty good I think.
2010-10-20 22:30:35 +11:00
Tim Allen
3a81ac94a5 Update to v068r14 release.
byuu says:

Holy hell, that was a total brain twister. After hours of crazy bit
twiddling and debug printf's, I finally figured out how to allow both
lores and hires scrolling in the accurate PPU renderer. In the process,
I modified the main loop to run from -7 to 255, regardless of the hires
setting, and perform X adjustment inside the tile fetching. This fixed
a strange main/subscreen misalignment issue, so I was able to restore
the proper sub-then-main rendering for the final screen output stage.
Code looks a good bit cleaner this way overall.

I also added load state and save state menus to the tools menu, so you
can use the menubar to load and save to ten slots. I am thinking that
I should nuke the icons. As pretty as they are, it's getting tiresome
trying to find icons for everything, I have no pictures to represent
loading or saving a slot, nor to represent individual slots. I'll just
stick to radios and checkboxes.
2010-10-20 22:30:35 +11:00
Tim Allen
3f43747474 Update to v068r13 release.
byuu says:

Bug-fix night for the new PPUs.

Accuracy:

Fixed BG palette clamping, which fixes Taz-Mania.

Added blocking for CGRAM writes during active display, to match the
compatibility core. It really should override to the last fetched
palette color, I'll probably try that out soon enough.

Performance:

Mosaic should match the other renderers. Unfortunately, as suspected, it
murders speed. 290->275fps. It's now only 11fps faster, hardly worth it
at all. But the old rendering code is really awful, so maybe it's for
the best it gets refreshed.
It's really tough to understand why this is such a performance hit, it's
just a decrement+compare check four times per pixel. But yeah, it hits
it really, really hard.

Fixed a missing check in Mode4 offset-per-tile, fixes vertical alignment
of a test image in the SNES Test Program.
2010-10-20 22:30:35 +11:00
Tim Allen
5b4702afc4 Update to v068r12 release.
(there was no r11 release posted to the WIP thread)

byuu says:

This took ten hours of mind boggling insanity to pull off.

It upgrades the S-PPU dot-based renderer to fetch one tile, and then
output all of its pixels before fetching again. It sounds easy enough,
but it's insanely difficult. I ended up taking one small shortcut, in
that rather than fetch at -7, I fetch at the first instance where a tile
is needed to plot to x=0. So if you have {-3 to +4 } as a tile, it
fetches at -3. That won't work so well on hardware, if two BGs fetch at
the same X offset, they won't have time.

I have had no luck staggering the reads at BG1=-7, BG3=-5, etc. While
I can shift and fetch just fine, what happens is that when a new tile is
fetched in, that gives a new palette, priority, etc; and this ends up
happening between two tiles which results in the right-most edges of the
screen ending up with the wrong colors and such.

Offset-per-tile is cheap as always. Although looking at it, I'm not sure
how BG3 could pre-fetch, especially with the way one or two OPT modes
can fetch two tiles.

There's no magic in Hoffset caching yet, so the SMW1 pixel issue is
still there.

Mode 7 got a bugfix, it was off-by-one horizontally from the mosaic
code. After re-designing the BG mosaic, I ended up needing a separate
mosaic for Mode7, and in the process I fixed that bug. The obvious
change is that the Chrono Trigger Mode7->Mode2 transition doesn't cause
the pendulum to jump anymore.

Windows were simplified just a tad. The range testing is shared for all
modes now. Ironically, it's a bit slower, but I'll take less code over
more speed for the accuracy core.

Speaking of speed, because there's so much less calculations per pixel
for BGs, performance for the entire emulator has gone up by 30% in the
accuracy core. Pretty neat overall, I can maintain 60fps in all but,
yeah you can guess can't you?
2010-10-20 22:30:35 +11:00
Tim Allen
7df9157abd Update to v068r10 release.
(there was no r09 release posted to the WIP thread)

byuu says:

It is feature-complete, but horizontal mosaic is less accurate. I have
an idea for a mosaic color ring buffer to get it equally accurate, but
I haven't implemented it yet. For now it's just a simple x & ~(mosaic >>
1) trick that is passable.

Hires blending was left out, as it's more processor intensive and
blargg's NTSC does a better job with that anyway.

There's some OPT vertical positioning issues in the SNES Test Program's
character test; Goodbye, Anthrox has some sort of fast CPU DMA issue;
etc.

Total speedup is a mere 13.5%. Not quite the 50% I wanted in the best
case, but I'll take what I can get.

254->289fps in Zelda 3 on my E8400 now. There's another 15% hiding with
blargg's SMP and 5-10% with blargg's fast DSP, but they lose too much
accuracy. It'd put me at or below Snes9X accuracy, while still being 50%
slower.

SSE2 was performing worse this time, both on x86 and amd64, so I left
that optimization off.

So, barring a miracle, this is about the best it's going to get.
2010-10-20 22:30:35 +11:00
Tim Allen
f1009ec634 Update to v068r08 release.
byuu says:

This gets the basic new PPU skeleton up and running, still missing
a lot:
- Mode7
- direct color mode
- OAM color exemption (this one will impact performance negatively)
- vertical mosaic
- horizontal mosaic (this one may impact performance negatively)
- offset per tile
- interlace
- hires
- pseudo-hires

But it's correct enough to play most games okay.

So far, the new PPU is about 11% faster on my Atom, and 17% faster on my
E8400. I was hoping for more, but the window masking and sprite
calculation is just kicking my ass.

The 11/17 figure is total emulator overhead, so that means raw PPU vs
PPU, the new one is at least 22-34% faster than the old one.

I don't really have any ideas for additional optimizations. I'm even
using little-endian word reads where applicable. But at any rate, I need
to get all the above implemented correctly before trying to push
optimizations even further.
2010-10-20 22:30:35 +11:00
Tim Allen
0bf6c40d1f Update to v068r07 release.
(there was no r06 release posted to the WIP thread)

byuu says:

New PPU renderer is coming along. Lots of new ideas, especially with
regards to the way the background renders in tiles rather than in
pixels. That skips the need for tile caching and compares, and it even
gets scrolling right.

The sprite item+tile lists are computing, but they are not rendering
yet.

It's a good deal faster for now, obviously, because 90% of the PPU
features are missing.
2010-10-20 22:30:35 +11:00
Tim Allen
2bafd18a5a Update to v068r05 release.
byuu says:

Started over again on the new S-PPU, heh. Three hours wasted last night
I guess.
I wanted to make the new one more like the accurate core in its
structure: multiple class instances for each background. It makes the
code easier to read, results in less structure insanity
(regs.main_enabled[bg] -> main_enabled), and will probably make it a tad
easier to parallelize if we want to go that route eg for the ARM.

Still very incomplete.
2010-10-20 22:30:35 +11:00
Tim Allen
c434e8a0d5 Update to v068r04 release.
(there was no r03 release posted to the WIP thread)

byuu says:

This should provide hardware-accurate mosaic support in the accurate
renderer, with the exception that I'm still not sure what mid-frame
vertical mosaic or mid-scanline horizontal mosaic writes do. Either the
code I have is correct, or it bypasses the mosaic adjust and gives the
exact H/V positions.

I've also renamed the fast folder to alternative (thinking about naming
it simply alt instead), and started on a brand new PPU renderer. So far
it's just a barebones setup with some MMIO support and VRAM/OAM/CGRAM
writing. I'm not even confident that I can get this to be faster than
the current scanline renderer, but it's the only avenue that we have
left for any kind of significant bsnes speedup, so I have to try. I'm
going to finish up the MMIO stuff first, that way we have a clean slate
with no actual rendering. And then from here we can try various
different approaches.
2010-10-20 22:30:35 +11:00
Tim Allen
39b1acb177 Update to v068r02 release.
byuu says:

This adds mosaic improvements to the S-PPU dot renderer. Specifically,
it eliminates the mosaic_table entirely, and performs mosaic adjustment
per pixel instead. It also moves from a mosaic countdown for mosaic Y to
a mosaic counter (incrementing).

In the process, I realized Sim Earth's map was broken, so I fixed that.
In doing so, I also fixed my old Mode7 demo that was always off-by-one,
causing different results on real hardware versus emulation. But then
I broke both Final Fantasy 5 and Air Strike Patrol effects that use
Mode7 but no mosaic.

I'm not really sure what's going on, but I think I am close. This is the
first time I can reproduce the Mode7 test ROM results without screwing
with M7Y which was obviously wrong. I think that somehow a mosaic >=
1 is glitching the Ycounter for the BG layers to tick one extra time.

There's a workaround that's not very nice to get everything going right
now. It could very well be that the workaround is hardware accurate, but
I can't help but feel there's a more eloquent way of doing this.
2010-10-20 22:30:35 +11:00
Tim Allen
920d139302 Update to v068r01 release.
byuu says:

This adds RTS/CTS support to the serial communications emulation. Okay,
well the PC acts as if it is always ready, because it always is even on
the real thing, but the PC-waiting-for-SNES side works.

Source only, hardware communication only works on OS X and Linux
(Windows serial communication is totally different, I don't feel like
writing a Windows version), more documentation will come later.
2010-10-20 22:30:34 +11:00
340 changed files with 10835 additions and 1087 deletions

View File

@@ -1,7 +1,7 @@
include nall/Makefile
snes := snes
profile := compatibility
ui := qt
ui := ui-qt
# compiler
c := $(compiler) -std=gnu99
@@ -24,7 +24,7 @@ else ifeq ($(platform),osx)
else ifeq ($(platform),win)
link += -mwindows
# link += -mconsole
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else
unknown_platform: help;
@@ -53,22 +53,23 @@ objects := $(patsubst %,obj/%.o,$(objects))
# targets
build: ui_build $(objects)
ifeq ($(platform),osx)
test -d ../bsnes-$(profile).app || mkdir -p ../bsnes-$(profile).app/Contents/MacOS
$(strip $(cpp) -o ../bsnes-$(profile).app/Contents/MacOS/bsnes-$(profile) $(objects) $(link))
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
else
$(strip $(cpp) -o out/bsnes-$(profile) $(objects) $(link))
$(strip $(cpp) -o out/bsnes $(objects) $(link))
endif
install:
ifeq ($(platform),x)
install -D -m 755 out/bsnes-$(profile) $(DESTDIR)$(prefix)/bin/bsnes-$(profile)
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
endif
uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/bin/bsnes-$(profile)
rm $(DESTDIR)$(prefix)/bin/bsnes
rm $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
rm $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
endif
@@ -87,6 +88,6 @@ clean: ui_clean
-@$(call delete,*.manifest)
archive-all:
tar -cjf bsnes-`date +%Y%m%d`.tar.bz2 launcher libco nall obj out qt ruby snes Makefile sync.sh cc.bat clean.bat
tar -cjf bsnes.tar.bz2 launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
help:;

View File

@@ -7,34 +7,6 @@
#include <nall/string.hpp>
using namespace nall;
#if !defined(PLATFORM_WIN)
char* userpath(char *path) {
*path = 0;
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) strcpy(path, userinfo->pw_dir);
return path;
}
#else
#include <nall/utf8.hpp>
#include <process.h>
#include <wchar.h>
#include <windows.h>
char* realpath(const char *filename, char *resolvedname) {
wchar_t fn[PATH_MAX] = L"";
_wfullpath(fn, nall::utf16_t(filename), PATH_MAX);
strcpy(resolvedname, nall::utf8_t(fn));
return resolvedname;
}
char* userpath(char *path) {
wchar_t fp[PATH_MAX] = L"";
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
strcpy(path, nall::utf8_t(fp));
return path;
}
#endif
int main(int argc, char **argv) {
char path[PATH_MAX], *unused;
#if !defined(PLATFORM_WIN)
@@ -74,7 +46,7 @@ int main(int argc, char **argv) {
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFOW));
if(!CreateProcessW(nall::utf16_t(fileName), GetCommandLineW(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
MessageBox(0, string("Error: unable to locate binary file: ", binaryName), "bsnes", MB_OK);
MessageBoxA(0, string("Error: unable to locate binary file: ", binaryName), "bsnes", MB_OK);
}
#endif

View File

@@ -29,10 +29,12 @@ ifeq ($(platform),)
endif
ifeq ($(compiler),)
ifeq ($(platform),osx)
compiler := gcc-mp-4.4
else
ifeq ($(platform),win)
compiler := gcc
else ifeq ($(platform),osx)
compiler := gcc-mp-4.5
else
compiler := gcc-4.5
endif
endif

129
bsnes/nall/directory.hpp Executable file
View File

@@ -0,0 +1,129 @@
#ifndef NALL_DIRECTORY_HPP
#define NALL_DIRECTORY_HPP
#include <nall/foreach.hpp>
#include <nall/sort.hpp>
#include <nall/string.hpp>
#if defined(_WIN32)
#include <nall/utf8.hpp>
#else
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#endif
namespace nall {
struct directory {
static lstring folders(const char *pathname);
static lstring files(const char *pathname);
static lstring contents(const char *pathname);
};
#if defined(_WIN32)
inline lstring directory::folders(const char *pathname) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
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), "/"));
}
}
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), "/"));
}
}
}
FindClose(handle);
}
sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const char *pathname) {
lstring list;
string path = pathname;
path.transform("/", "\\");
if(!strend(path, "\\")) path.append("\\");
path.append("*");
HANDLE handle;
WIN32_FIND_DATA data;
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
list.append(utf8_t(data.cFileName));
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
list.append(utf8_t(data.cFileName));
}
}
FindClose(handle);
}
sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const char *pathname) {
lstring folders = directory::folders(pathname);
lstring files = directory::files(pathname);
foreach(file, files) folders.append(file);
return folders;
}
#else
inline lstring directory::folders(const char *pathname) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
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, "/"));
}
closedir(dp);
}
sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const char *pathname) {
lstring list;
DIR *dp;
struct dirent *ep;
dp = opendir(pathname);
if(dp) {
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);
}
closedir(dp);
}
sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const char *pathname) {
lstring folders = directory::folders(pathname);
lstring files = directory::files(pathname);
foreach(file, files) folders.append(file);
return folders;
}
#endif
}
#endif

View File

@@ -1,7 +1,7 @@
#ifndef NALL_FUNCTION_HPP
#define NALL_FUNCTION_HPP
#include <malloc.h>
#include <stdlib.h>
#include <functional>
#include <type_traits>

View File

@@ -78,5 +78,45 @@
#define alwaysinline inline
#endif
//=========================
//file system functionality
//=========================
#if defined(_WIN32)
inline char* realpath(const char *filename, char *resolvedname) {
wchar_t fn[_MAX_PATH] = L"";
_wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
strcpy(resolvedname, nall::utf8_t(fn));
return resolvedname;
}
inline char* userpath(char *path) {
wchar_t fp[_MAX_PATH] = L"";
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
strcpy(path, nall::utf8_t(fp));
return path;
}
inline char* getcwd(char *path) {
wchar_t fp[_MAX_PATH] = L"";
_wgetcwd(fp, _MAX_PATH);
strcpy(path, nall::utf8_t(fp));
return path;
}
#else
//realpath() already exists
inline char* userpath(char *path) {
*path = 0;
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) strcpy(path, userinfo->pw_dir);
return path;
}
inline char *getcwd(char *path) {
return getcwd(path, PATH_MAX);
}
#endif
#endif

View File

@@ -23,7 +23,7 @@ namespace nall {
return ::write(port, (void*)data, length);
}
bool open(const char *portname, unsigned rate) {
bool open(const char *portname, unsigned rate, bool flowcontrol) {
close();
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
@@ -41,8 +41,13 @@ namespace nall {
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
attr.c_iflag |= (IGNBRK | IGNPAR);
attr.c_oflag &=~ (OPOST);
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB);
attr.c_cflag |= (CS8 | CREAD | CLOCAL);
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
attr.c_cflag |= (CS8 | CREAD);
if(flowcontrol == false) {
attr.c_cflag &= ~CRTSCTS;
} else {
attr.c_cflag |= CRTSCTS;
}
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }

View File

@@ -43,7 +43,7 @@ namespace nall {
inline string& operator=(const string&);
inline string& operator=(string&&);
template<typename... Args> inline string(Args... args);
template<typename... Args> inline string(Args&&... args);
inline string(const string&);
inline string(string&&);
inline ~string();
@@ -135,7 +135,7 @@ namespace nall {
inline string strdouble(double value);
//variadic.hpp
template<typename... Args> inline void print(Args... args);
template<typename... Args> inline void print(Args&&... args);
};
#endif

View File

@@ -72,16 +72,16 @@ static void istring(string &output) {
}
template<typename T, typename... Args>
static void istring(string &output, T value, Args... args) {
static void istring(string &output, const T &value, Args&&... args) {
output.append(value);
istring(output, args...);
istring(output, std::forward<Args>(args)...);
}
template<typename... Args> string::string(Args... args) {
template<typename... Args> string::string(Args&&... args) {
size = 64;
data = (char*)malloc(size + 1);
*data = 0;
istring(*this, args...);
istring(*this, std::forward<Args>(args)...);
}
string::string(const string &value) {

View File

@@ -3,8 +3,8 @@
namespace nall {
template<typename... Args> inline void print(Args... args) {
printf("%s", (const char*)string(args...));
template<typename... Args> inline void print(Args&&... args) {
printf("%s", (const char*)string(std::forward<Args>(args)...));
}
}

View File

@@ -6,9 +6,11 @@
#if defined(_WIN32)
#undef UNICODE
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#undef NOMINMAX
#define UNICODE
#define _WIN32_WINNT 0x0501
#define NOMINMAX
#include <windows.h>
#undef interface
@@ -62,9 +64,21 @@ namespace nall {
delete[] buffer;
}
utf8_t(const utf8_t&) = delete;
utf8_t& operator=(const utf8_t&) = delete;
private:
char *buffer;
};
inline void utf8_args(int &argc, char **&argv) {
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
argv = new char*[argc];
for(unsigned i = 0; i < argc; i++) {
argv[i] = new char[_MAX_PATH];
strcpy(argv[i], nall::utf8_t(wargv[i]));
}
}
}
#endif //if defined(_WIN32)

12
bsnes/phoenix/gtk/button.cpp Executable file
View File

@@ -0,0 +1,12 @@
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) {
object->widget = gtk_button_new_with_label(text);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}

58
bsnes/phoenix/gtk/canvas.cpp Executable file
View File

@@ -0,0 +1,58 @@
static void Canvas_expose(Canvas *self) {
uint32_t *rgb = self->canvas->bufferRGB;
uint32_t *bgr = self->canvas->bufferBGR;
for(unsigned y = self->object->widget->allocation.height; y; y--) {
for(unsigned x = self->object->widget->allocation.width; x; x--) {
uint32_t pixel = *rgb++;
*bgr++ = ((pixel << 16) & 0xff0000) | (pixel & 0x00ff00) | ((pixel >> 16) & 0x0000ff);
}
}
gdk_draw_rgb_32_image(
self->object->widget->window,
self->object->widget->style->fg_gc[GTK_WIDGET_STATE(self->object->widget)],
0, 0, self->object->widget->allocation.width, self->object->widget->allocation.height,
GDK_RGB_DITHER_NONE, (guchar*)self->canvas->bufferBGR, self->canvas->pitch
);
}
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
canvas->bufferRGB = new uint32_t[width * height]();
canvas->bufferBGR = new uint32_t[width * height]();
canvas->pitch = width * sizeof(uint32_t);
object->widget = gtk_drawing_area_new();
GdkColor color;
color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
gtk_widget_set_double_buffered(object->widget, false);
gtk_widget_add_events(object->widget, GDK_EXPOSURE_MASK);
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
uint32_t* Canvas::buffer() {
return canvas->bufferRGB;
}
void Canvas::redraw() {
GdkRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = object->widget->allocation.width;
rect.height = object->widget->allocation.height;
gdk_window_invalidate_rect(object->widget->window, &rect, true);
}
Canvas::Canvas() {
canvas = new Canvas::Data;
canvas->bufferRGB = 0;
canvas->bufferBGR = 0;
}
Canvas::~Canvas() {
if(canvas->bufferRGB) delete[] canvas->bufferRGB;
if(canvas->bufferBGR) delete[] canvas->bufferBGR;
}

22
bsnes/phoenix/gtk/checkbox.cpp Executable file
View File

@@ -0,0 +1,22 @@
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) {
object->widget = gtk_check_button_new_with_label(text);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
bool CheckBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object->widget));
}
void CheckBox::setChecked(bool checked) {
object->locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(object->widget), checked);
object->locked = false;
}

47
bsnes/phoenix/gtk/combobox.cpp Executable file
View File

@@ -0,0 +1,47 @@
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) {
object->widget = gtk_combo_box_new_text();
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);
if(*text) {
lstring list;
list.split("\n", text);
foreach(item, list) addItem(item);
}
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
void ComboBox::reset() {
object->locked = true;
for(signed i = counter - 1; i >= 0; i--) {
gtk_combo_box_remove_text(GTK_COMBO_BOX(object->widget), i);
}
object->locked = false;
counter = 0;
}
void ComboBox::addItem(const char *text) {
gtk_combo_box_append_text(GTK_COMBO_BOX(object->widget), text);
if(counter++ == 0) setSelection(0);
}
unsigned ComboBox::selection() {
return gtk_combo_box_get_active(GTK_COMBO_BOX(object->widget));
}
void ComboBox::setSelection(unsigned item) {
object->locked = true;
gtk_combo_box_set_active(GTK_COMBO_BOX(object->widget), item);
object->locked = false;
}
ComboBox::ComboBox() {
counter = 0;
}

48
bsnes/phoenix/gtk/editbox.cpp Executable file
View File

@@ -0,0 +1,48 @@
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) {
object->widget = gtk_scrolled_window_new(0, 0);
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);
object->subWidget = gtk_text_view_new();
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), GTK_WRAP_WORD_CHAR);
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(object->subWidget));
gtk_text_buffer_set_text(object->textBuffer, text, -1);
g_signal_connect_swapped(G_OBJECT(object->textBuffer), "changed", G_CALLBACK(EditBox_change), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->subWidget);
gtk_widget_show(object->widget);
}
void EditBox::setFocused() {
gtk_widget_grab_focus(object->subWidget);
}
void EditBox::setEditable(bool editable) {
gtk_text_view_set_editable(GTK_TEXT_VIEW(object->subWidget), editable);
}
void EditBox::setWordWrap(bool wordWrap) {
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE);
}
string EditBox::text() {
GtkTextIter start, end;
gtk_text_buffer_get_start_iter(object->textBuffer, &start);
gtk_text_buffer_get_end_iter(object->textBuffer, &end);
char *temp = gtk_text_buffer_get_text(object->textBuffer, &start, &end, true);
string text = temp;
g_free(temp);
return text;
}
void EditBox::setText(const char *text) {
object->locked = true;
gtk_text_buffer_set_text(object->textBuffer, text, -1);
object->locked = false;
}

18
bsnes/phoenix/gtk/font.cpp Executable file
View File

@@ -0,0 +1,18 @@
bool Font::create(const char *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);
pango_font_description_set_style(font->font, (style & Style::Italic) == Style::Italic ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL);
pango_font_description_set_weight(font->font, (style & Style::Bold) == Style::Bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
return true;
}
Font::Font() {
font = new Font::Data;
font->font = 0;
}
Font::~Font() {
if(font->font) pango_font_description_free(font->font);
delete font;
}

191
bsnes/phoenix/gtk/gtk.cpp Executable file
View File

@@ -0,0 +1,191 @@
#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>
#define None X11None
#define Window X11Window
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#undef None
#undef Window
using namespace nall;
namespace phoenix {
#include "object.cpp"
#include "font.cpp"
#include "menu.cpp"
#include "widget.cpp"
#include "window.cpp"
#include "button.cpp"
#include "canvas.cpp"
#include "checkbox.cpp"
#include "combobox.cpp"
#include "editbox.cpp"
#include "horizontalslider.cpp"
#include "label.cpp"
#include "listbox.cpp"
#include "progressbar.cpp"
#include "radiobox.cpp"
#include "textbox.cpp"
#include "verticalslider.cpp"
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
Window Window::None;
OS& OS::handle() {
static OS os;
return os;
}
bool OS::pending() {
return gtk_events_pending();
}
void OS::run() {
while(pending()) gtk_main_iteration_do(false);
}
void OS::main() {
gtk_main();
}
void OS::quit() {
gtk_main_quit();
}
unsigned OS::desktopWidth() {
return gdk_screen_get_width(gdk_screen_get_default());
}
unsigned OS::desktopHeight() {
return gdk_screen_get_height(gdk_screen_get_default());
}
string OS::folderSelect(Window &parent, const char *path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
"Select Folder",
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)0
);
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
return name;
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
"Open File",
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)0
);
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
lstring list;
list.split("\n", filter);
foreach(item, list) {
lstring part;
part.split("\t", item);
GtkFileFilter *filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, string(part[0], " (", part[1], ")"));
lstring patterns;
patterns.split(",", part[1]);
foreach(pattern, patterns) gtk_file_filter_add_pattern(filter, pattern);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
}
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
return name;
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
"Save File",
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)0
);
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
lstring list;
list.split("\n", filter);
foreach(item, list) {
lstring part;
part.split("\t", item);
GtkFileFilter *filter = gtk_file_filter_new();
gtk_file_filter_set_name(filter, string(part[0], " (", part[1], ")"));
lstring patterns;
patterns.split(",", part[1]);
foreach(pattern, patterns) gtk_file_filter_add_pattern(filter, pattern);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
}
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
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"
);
}
}

250
bsnes/phoenix/gtk/gtk.hpp Executable file
View File

@@ -0,0 +1,250 @@
namespace phoenix {
struct Window;
struct Object {
Object();
Object& operator=(const Object&) = delete;
Object(const Object&) = delete;
//private:
virtual void unused();
struct Data;
Data *object;
};
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);
Font();
~Font();
//private:
struct Data;
Data *font;
};
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
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);
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
};
struct MenuSeparator : Action {
void create(Menu &parent);
};
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
};
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *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);
bool checked();
void setChecked();
private:
MenuRadioItem *first;
};
struct Widget : Object {
virtual void setFont(Font &font);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
virtual bool focused();
virtual void setFocused();
};
struct Window : Widget {
static Window None;
nall::function<bool ()> onClose;
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
bool focused();
void setFocused();
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 setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
Window();
//private:
struct Data;
Data *window;
};
struct Button : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
};
struct Canvas : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
uint32_t* buffer();
void redraw();
Canvas();
~Canvas();
//private:
struct Data;
Data *canvas;
};
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *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 reset();
void addItem(const char *text);
unsigned selection();
void setSelection(unsigned item);
ComboBox();
private:
unsigned counter;
};
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setFocused();
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const char *text);
};
struct HorizontalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *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 = "");
void setFocused();
void setHeaderVisible(bool headerVisible = true);
void setFont(Font &font);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
//private:
struct Data;
Data *listBox;
};
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setProgress(unsigned progress);
};
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 = "");
bool checked();
void setChecked();
private:
RadioBox *first;
};
struct TextBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setEditable(bool editable = true);
nall::string text();
void setText(const char *text);
};
struct VerticalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
};
struct Viewport : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
uintptr_t handle();
};
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,
OkCancel,
YesNo,
};
enum class Response : unsigned {
Ok,
Cancel,
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);
};
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 = "");
//private:
static OS& handle();
struct Data;
Data *os;
private:
OS();
};
extern OS &os;
}

View File

@@ -0,0 +1,24 @@
static void HorizontalSlider_change(HorizontalSlider *self) {
if(self->object->position == self->position()) return;
self->object->position = self->position();
if(self->onChange) self->onChange();
}
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
object->position = 0;
length += (length == 0);
object->widget = gtk_hscale_new_with_range(0, length - 1, 1);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
unsigned HorizontalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(object->widget));
}
void HorizontalSlider::setPosition(unsigned position) {
gtk_range_set_value(GTK_RANGE(object->widget), position);
}

12
bsnes/phoenix/gtk/label.cpp Executable file
View File

@@ -0,0 +1,12 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_label_new(text);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
void Label::setText(const char *text) {
gtk_label_set_text(GTK_LABEL(object->widget), text);
}

154
bsnes/phoenix/gtk/listbox.cpp Executable file
View File

@@ -0,0 +1,154 @@
static void ListBox_change(ListBox *self) {
signed selection = -1;
if(auto position = self->selection()) selection = position();
if(selection == self->listBox->selection) return;
self->listBox->selection = selection;
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();
}
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
listBox->selection = -1;
object->widget = gtk_scrolled_window_new(0, 0);
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);
GType *v = (GType*)malloc(list.size() * sizeof(GType));
for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING;
listBox->store = gtk_list_store_newv(list.size(), v);
free(v);
object->subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(listBox->store));
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
);
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);
}
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);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->subWidget);
gtk_widget_show(object->widget);
}
void ListBox::setFocused() {
gtk_widget_grab_focus(object->subWidget);
}
void ListBox::setHeaderVisible(bool visible) {
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), visible);
}
void ListBox::setFont(Font &font) {
Widget::setFont(font);
unsigned columns = 1;
while(true) {
if(gtk_tree_view_get_column(GTK_TREE_VIEW(object->subWidget), columns) == 0) break;
columns++;
}
for(unsigned i = 0; i < columns; i++) {
gtk_widget_modify_font(listBox->column[i].label, font.font->font);
}
}
void ListBox::reset() {
listBox->selection = -1;
gtk_list_store_clear(GTK_LIST_STORE(listBox->store));
gtk_tree_view_set_model(GTK_TREE_VIEW(object->subWidget), GTK_TREE_MODEL(listBox->store));
//reset gtk_scrolled_window scrollbar position to 0,0 (top-left), as ListBox is now empty
gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(object->widget), 0);
gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(object->widget), 0);
}
void ListBox::resizeColumnsToContent() {
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(object->subWidget));
}
void ListBox::addItem(const char *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);
}
}
void ListBox::setItem(unsigned row, const char *text) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
GtkTreeIter iter;
for(unsigned i = 0; i <= row; i++) {
if(i == 0) gtk_tree_model_get_iter_first(model, &iter);
else gtk_tree_model_iter_next(model, &iter);
}
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);
}
}
optional<unsigned> ListBox::selection() {
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(object->subWidget));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
GtkTreeIter iter;
if(gtk_tree_model_get_iter_first(model, &iter) == false) return { false, 0 };
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return { true, 0 };
for(unsigned i = 1;; i++) {
if(gtk_tree_model_iter_next(model, &iter) == false) return { false, 0 };
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return { true, i };
}
return { false, 0 };
}
void ListBox::setSelection(unsigned row) {
signed current = -1;
if(auto position = selection()) current = position();
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(object->subWidget));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
gtk_tree_selection_unselect_all(selection);
GtkTreeIter iter;
if(gtk_tree_model_get_iter_first(model, &iter) == false) return;
if(row == 0) {
gtk_tree_selection_select_iter(selection, &iter);
return;
}
for(unsigned i = 1;; i++) {
if(gtk_tree_model_iter_next(model, &iter) == false) return;
if(row == i) {
gtk_tree_selection_select_iter(selection, &iter);
return;
}
}
}
ListBox::ListBox() {
listBox = new ListBox::Data;
}

113
bsnes/phoenix/gtk/menu.cpp Executable file
View File

@@ -0,0 +1,113 @@
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);
}
}
void Action::setFont(Font &font) {
Action_setFont(object->widget, font.font->font);
}
bool Action::visible() {
return gtk_widget_get_visible(object->widget);
}
void Action::setVisible(bool visible) {
gtk_widget_set_visible(object->widget, visible);
}
bool Action::enabled() {
return gtk_widget_get_sensitive(object->widget);
}
void Action::setEnabled(bool enabled) {
gtk_widget_set_sensitive(object->widget, enabled);
}
void Menu::create(Window &parent, const char *text) {
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);
gtk_menu_bar_append(parent.object->menu, object->widget);
gtk_widget_show(object->widget);
}
void Menu::create(Menu &parent, const char *text) {
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);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
void MenuSeparator::create(Menu &parent) {
object->widget = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
static void MenuItem_tick(MenuItem *self) {
if(self->onTick) self->onTick();
}
void MenuItem::create(Menu &parent, const char *text) {
object->widget = gtk_menu_item_new_with_label(text);
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(MenuItem_tick), (gpointer)this);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
static void MenuCheckItem_tick(MenuCheckItem *self) {
if(self->onTick && self->object->locked == false) self->onTick();
}
void MenuCheckItem::create(Menu &parent, const char *text) {
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);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
bool MenuCheckItem::checked() {
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(object->widget));
}
void MenuCheckItem::setChecked(bool state) {
object->locked = true;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(object->widget), state);
object->locked = false;
}
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) {
first = this;
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);
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) {
first = parent.first;
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);
gtk_menu_shell_append(GTK_MENU_SHELL(object->parentMenu->object->menu), object->widget);
gtk_widget_show(object->widget);
}
bool MenuRadioItem::checked() {
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(object->widget));
}
void MenuRadioItem::setChecked() {
object->locked = true;
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(object->widget), true);
object->locked = false;
}

View File

@@ -0,0 +1,65 @@
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, gint response) {
if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok;
if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel;
if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes;
if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *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
);
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) {
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
);
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) {
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
);
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) {
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
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
}

50
bsnes/phoenix/gtk/object.cpp Executable file
View File

@@ -0,0 +1,50 @@
struct Object::Data {
bool locked;
GtkWidget *widget;
GtkWidget *subWidget;
GtkWidget *menuContainer;
GtkWidget *formContainer;
GtkWidget *statusContainer;
GtkWidget *menu;
GtkWidget *status;
Menu *parentMenu;
Window *parentWindow;
GtkTextBuffer *textBuffer;
unsigned position;
};
struct Font::Data {
PangoFontDescription *font;
};
struct Window::Data {
Font *defaultFont;
};
struct Canvas::Data {
uint32_t *bufferRGB;
uint32_t *bufferBGR;
unsigned pitch;
};
struct ListBox::Data {
GtkListStore *store;
struct GtkColumn {
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkWidget *label;
};
linear_vector<GtkColumn> column;
signed selection;
};
struct OS::Data {
};
void Object::unused() {
}
Object::Object() {
object = new Object::Data;
object->locked = false;
}

View File

@@ -0,0 +1,11 @@
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_progress_bar_new();
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);
}

35
bsnes/phoenix/gtk/radiobox.cpp Executable file
View File

@@ -0,0 +1,35 @@
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) {
first = this;
object->parentWindow = &parent;
object->widget = gtk_radio_button_new_with_label(0, text);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *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);
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(object->parentWindow->window->defaultFont) setFont(*object->parentWindow->window->defaultFont);
gtk_fixed_put(GTK_FIXED(object->parentWindow->object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
bool RadioBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object->widget));
}
void RadioBox::setChecked() {
object->locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(object->widget), true);
object->locked = false;
}

27
bsnes/phoenix/gtk/textbox.cpp Executable file
View File

@@ -0,0 +1,27 @@
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) {
object->widget = gtk_entry_new();
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), "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);
gtk_widget_show(object->widget);
}
void TextBox::setEditable(bool editable) {
gtk_entry_set_editable(GTK_ENTRY(object->widget), editable);
}
string TextBox::text() {
return gtk_entry_get_text(GTK_ENTRY(object->widget));
}
void TextBox::setText(const char *text) {
object->locked = true;
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
object->locked = false;
}

View File

@@ -0,0 +1,24 @@
static void VerticalSlider_change(VerticalSlider *self) {
if(self->object->position == self->position()) return;
self->object->position = self->position();
if(self->onChange) self->onChange();
}
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
object->position = 0;
length += (length == 0);
object->widget = gtk_vscale_new_with_range(0, length - 1, 1);
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);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
unsigned VerticalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(object->widget));
}
void VerticalSlider::setPosition(unsigned position) {
gtk_range_set_value(GTK_RANGE(object->widget), position);
}

11
bsnes/phoenix/gtk/viewport.cpp Executable file
View File

@@ -0,0 +1,11 @@
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);
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);
}
uintptr_t Viewport::handle() {
return GDK_WINDOW_XID(object->widget->window);
}

36
bsnes/phoenix/gtk/widget.cpp Executable file
View File

@@ -0,0 +1,36 @@
static void Widget_setFont(GtkWidget *widget, gpointer font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Widget_setFont, font);
}
}
void Widget::setFont(Font &font) {
Widget_setFont(object->widget, font.font->font);
}
bool Widget::visible() {
return gtk_widget_get_visible(object->widget);
}
void Widget::setVisible(bool visible) {
if(visible) gtk_widget_show(object->widget);
else gtk_widget_hide(object->widget);
}
bool Widget::enabled() {
return gtk_widget_get_sensitive(object->widget);
}
void Widget::setEnabled(bool enabled) {
gtk_widget_set_sensitive(object->widget, enabled);
}
bool Widget::focused() {
return gtk_widget_is_focus(object->widget);
}
void Widget::setFocused() {
if(visible() == false) setVisible(true);
gtk_widget_grab_focus(object->widget);
}

92
bsnes/phoenix/gtk/window.cpp Executable file
View File

@@ -0,0 +1,92 @@
static gint Window_close(Window *window) {
if(window->onClose) {
if(window->onClose()) window->setVisible(false);
return true;
}
window->setVisible(false);
return true;
}
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_move(GTK_WINDOW(object->widget), x, y);
gtk_window_set_title(GTK_WINDOW(object->widget), text);
gtk_window_set_resizable(GTK_WINDOW(object->widget), false);
gtk_widget_set_app_paintable(object->widget, true);
g_signal_connect_swapped(G_OBJECT(object->widget), "delete_event", G_CALLBACK(Window_close), (gpointer)this);
object->menuContainer = gtk_vbox_new(false, 0);
gtk_container_add(GTK_CONTAINER(object->widget), object->menuContainer);
gtk_widget_show(object->menuContainer);
object->menu = gtk_menu_bar_new();
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->menu, false, false, 0);
object->formContainer = gtk_fixed_new();
gtk_widget_set_size_request(object->formContainer, width, height);
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->formContainer, true, true, 0);
gtk_widget_show(object->formContainer);
object->statusContainer = gtk_event_box_new();
object->status = gtk_statusbar_new();
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(object->status), false);
gtk_container_add(GTK_CONTAINER(object->statusContainer), object->status);
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->statusContainer, false, false, 0);
gtk_widget_show(object->statusContainer);
gtk_widget_realize(object->widget);
}
bool Window::focused() {
return gtk_window_is_active(GTK_WINDOW(object->widget));
}
void Window::setFocused() {
gtk_window_present(GTK_WINDOW(object->widget));
}
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);
}
void Window::setDefaultFont(Font &font) {
window->defaultFont = &font;
}
void Window::setFont(Font &font) {
Widget_setFont(object->status, font.font->font);
}
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
GdkColor color;
color.pixel = (red << 16) | (green << 8) | (blue << 0);
color.red = (red << 8) | (red << 0);
color.green = (green << 8) | (green << 0);
color.blue = (blue << 8) | (blue << 0);
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
}
void Window::setTitle(const char *text) {
gtk_window_set_title(GTK_WINDOW(object->widget), text);
}
void Window::setStatusText(const char *text) {
gtk_statusbar_pop(GTK_STATUSBAR(object->status), 1);
gtk_statusbar_push(GTK_STATUSBAR(object->status), 1, text);
}
void Window::setMenuVisible(bool visible) {
gtk_widget_set_visible(object->menu, visible);
}
void Window::setStatusVisible(bool visible) {
gtk_widget_set_visible(object->status, visible);
}
Window::Window() {
window = new Window::Data;
window->defaultFont = 0;
}

17
bsnes/phoenix/phoenix.cpp Executable file
View File

@@ -0,0 +1,17 @@
#if defined(PHOENIX_WINDOWS)
#define UNICODE
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0600
#define NOMINMAX
#endif
#include "phoenix.hpp"
#if defined(PHOENIX_WINDOWS)
#include "windows/windows.cpp"
#elif defined(PHOENIX_GTK)
#include "gtk/gtk.cpp"
#elif defined(PHOENIX_QT)
#include "qt/qt.cpp"
#endif

15
bsnes/phoenix/phoenix.hpp Executable file
View File

@@ -0,0 +1,15 @@
#include <nall/array.hpp>
#include <nall/foreach.hpp>
#include <nall/function.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/vector.hpp>
#if defined(PHOENIX_WINDOWS)
#include "windows/windows.hpp"
#elif defined(PHOENIX_GTK)
#include "gtk/gtk.hpp"
#elif defined(PHOENIX_QT)
#include "qt/qt.hpp"
#endif

13
bsnes/phoenix/qt/button.cpp Executable file
View File

@@ -0,0 +1,13 @@
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
button->setParent(parent.window->container);
button->setGeometry(x, y, width, height);
button->setText(text);
if(parent.window->defaultFont) button->setFont(*parent.window->defaultFont);
button->show();
button->connect(button, SIGNAL(released()), SLOT(onTick()));
}
Button::Button() {
button = new Button::Data(*this);
widget->widget = button;
}

39
bsnes/phoenix/qt/canvas.cpp Executable file
View File

@@ -0,0 +1,39 @@
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
canvas->image = new QImage(width, height, QImage::Format_RGB32);
canvas->image->fill(0);
canvas->setParent(parent.window->container);
canvas->setGeometry(x, y, width, height);
canvas->show();
}
void Canvas::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
delete canvas->image;
canvas->image = new QImage(width, height, QImage::Format_RGB32);
canvas->image->fill(0);
canvas->setGeometry(x, y, width, height);
canvas->update();
}
uint32_t* Canvas::buffer() {
return (uint32_t*)canvas->image->bits();
}
void Canvas::redraw() {
canvas->update();
}
Canvas::Canvas() {
canvas = new Canvas::Data(*this);
canvas->image = 0;
widget->widget = canvas;
}
Canvas::~Canvas() {
if(canvas->image) delete canvas->image;
delete canvas;
}
void Canvas::Data::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.drawImage(0, 0, *image);
}

21
bsnes/phoenix/qt/checkbox.cpp Executable file
View File

@@ -0,0 +1,21 @@
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
checkBox->setParent(parent.window->container);
checkBox->setGeometry(x, y, width, height);
checkBox->setText(text);
if(parent.window->defaultFont) checkBox->setFont(*parent.window->defaultFont);
checkBox->show();
checkBox->connect(checkBox, SIGNAL(stateChanged(int)), SLOT(onTick()));
}
bool CheckBox::checked() {
return checkBox->isChecked();
}
void CheckBox::setChecked(bool checked) {
checkBox->setChecked(checked);
}
CheckBox::CheckBox() {
checkBox = new CheckBox::Data(*this);
widget->widget = checkBox;
}

36
bsnes/phoenix/qt/combobox.cpp Executable file
View File

@@ -0,0 +1,36 @@
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *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);
}
comboBox->connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange()));
if(parent.window->defaultFont) comboBox->setFont(*parent.window->defaultFont);
comboBox->show();
}
void ComboBox::reset() {
while(comboBox->count()) comboBox->removeItem(0);
}
void ComboBox::addItem(const char *text) {
comboBox->addItem(text);
}
unsigned ComboBox::selection() {
signed index = comboBox->currentIndex();
return (index >= 0 ? index : 0);
}
void ComboBox::setSelection(unsigned row) {
comboBox->setCurrentIndex(row);
}
ComboBox::ComboBox() {
comboBox = new ComboBox::Data(*this);
widget->widget = comboBox;
}

26
bsnes/phoenix/qt/editbox.cpp Executable file
View File

@@ -0,0 +1,26 @@
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
editBox->setParent(parent.window->container);
editBox->setGeometry(x, y, width, height);
editBox->setText(text);
if(parent.window->defaultFont) editBox->setFont(*parent.window->defaultFont);
editBox->show();
editBox->connect(editBox, SIGNAL(textChanged()), SLOT(onChange()));
}
void EditBox::setEditable(bool editable) {
}
void EditBox::setWordWrap(bool wordWrap) {
editBox->setWordWrapMode(wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap);
}
string EditBox::text() {
}
void EditBox::setText(const char *text) {
}
EditBox::EditBox() {
editBox = new EditBox::Data(*this);
widget->widget = editBox;
}

14
bsnes/phoenix/qt/font.cpp Executable file
View File

@@ -0,0 +1,14 @@
bool Font::create(const char *name, unsigned size, Font::Style style) {
font->setFamily(name);
font->setPointSize(size);
font->setBold((style & Style::Bold) == Style::Bold);
font->setItalic((style & Style::Italic) == Style::Italic);
}
Font::Font() {
font = new Font::Data(*this);
}
Font::~Font() {
delete font;
}

View File

@@ -0,0 +1,22 @@
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
length += (length == 0);
horizontalSlider->setParent(parent.window->container);
horizontalSlider->setGeometry(x, y, width, height);
horizontalSlider->setRange(0, length - 1);
horizontalSlider->setPageStep(length >> 3);
horizontalSlider->connect(horizontalSlider, SIGNAL(valueChanged(int)), SLOT(onChange()));
horizontalSlider->show();
}
unsigned HorizontalSlider::position() {
return horizontalSlider->value();
}
void HorizontalSlider::setPosition(unsigned position) {
horizontalSlider->setValue(position);
}
HorizontalSlider::HorizontalSlider() {
horizontalSlider = new HorizontalSlider::Data(*this);
widget->widget = horizontalSlider;
}

16
bsnes/phoenix/qt/label.cpp Executable file
View File

@@ -0,0 +1,16 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
label->setParent(parent.window->container);
label->setGeometry(x, y, width, height);
label->setText(text);
if(parent.window->defaultFont) label->setFont(*parent.window->defaultFont);
label->show();
}
void Label::setText(const char *text) {
label->setText(text);
}
Label::Label() {
label = new Label::Data(*this);
widget->widget = label;
}

76
bsnes/phoenix/qt/listbox.cpp Executable file
View File

@@ -0,0 +1,76 @@
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
listBox->setParent(parent.window->container);
listBox->setGeometry(x, y, width, height);
listBox->setAllColumnsShowFocus(true);
listBox->setRootIsDecorated(false);
lstring list;
list.split("\t", text);
QStringList labels;
foreach(item, list) labels << (const char*)item;
listBox->setColumnCount(list.size());
listBox->setHeaderLabels(labels);
for(unsigned i = 0; i < list.size(); i++) listBox->resizeColumnToContents(i);
listBox->setHeaderHidden(true);
listBox->setAlternatingRowColors(list.size() >= 2);
listBox->connect(listBox, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
listBox->connect(listBox, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
if(parent.window->defaultFont) listBox->setFont(*parent.window->defaultFont);
listBox->show();
}
void ListBox::setHeaderVisible(bool headerVisible) {
listBox->setHeaderHidden(headerVisible == false);
}
void ListBox::reset() {
listBox->clear();
}
void ListBox::resizeColumnsToContent() {
for(unsigned i = 0; i < listBox->columnCount(); i++) listBox->resizeColumnToContents(i);
}
void ListBox::addItem(const char *text) {
auto items = listBox->findItems("", Qt::MatchContains);
QTreeWidgetItem *item = new QTreeWidgetItem(listBox);
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]);
}
void ListBox::setItem(unsigned row, const char *text) {
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]);
}
optional<unsigned> ListBox::selection() {
QTreeWidgetItem *item = listBox->currentItem();
if(item == 0) return { false, 0 };
if(item->isSelected() == false) return { false, 0 };
unsigned row = item->data(0, Qt::UserRole).toUInt();
return { true, row };
}
void ListBox::setSelection(unsigned row) {
object->locked = true;
QTreeWidgetItem *item = listBox->currentItem();
if(item) item->setSelected(false);
auto items = listBox->findItems("", Qt::MatchContains);
for(unsigned i = 0; i < items.size(); i++) {
if(items[i]->data(0, Qt::UserRole).toUInt() == row) {
listBox->setCurrentItem(items[i]);
break;
}
}
object->locked = false;
}
ListBox::ListBox() {
listBox = new ListBox::Data(*this);
widget->widget = listBox;
}

165
bsnes/phoenix/qt/menu.cpp Executable file
View File

@@ -0,0 +1,165 @@
void Menu::create(Window &parent, const char *text) {
menu->setTitle(text);
parent.window->menuBar->addMenu(menu);
}
void Menu::create(Menu &parent, const char *text) {
menu->setTitle(text);
parent.menu->addMenu(menu);
}
bool Menu::visible() {
return menu->isVisible();
}
void Menu::setVisible(bool visible) {
menu->setVisible(visible);
}
bool Menu::enabled() {
return menu->isEnabled();
}
void Menu::setEnabled(bool enabled) {
menu->setEnabled(enabled);
}
Menu::Menu() {
menu = new Menu::Data(*this);
}
void MenuSeparator::create(Menu &parent) {
menuSeparator->action = parent.menu->addSeparator();
}
bool MenuSeparator::visible() {
return menuSeparator->action->isVisible();
}
void MenuSeparator::setVisible(bool visible) {
menuSeparator->action->setVisible(visible);
}
bool MenuSeparator::enabled() {
return menuSeparator->action->isEnabled();
}
void MenuSeparator::setEnabled(bool enabled) {
menuSeparator->action->setEnabled(enabled);
}
MenuSeparator::MenuSeparator() {
menuSeparator = new MenuSeparator::Data(*this);
}
void MenuItem::create(Menu &parent, const char *text) {
menuItem->setText(text);
menuItem->connect(menuItem, SIGNAL(triggered()), SLOT(onTick()));
parent.menu->addAction(menuItem);
}
bool MenuItem::visible() {
return menuItem->isVisible();
}
void MenuItem::setVisible(bool visible) {
menuItem->setVisible(visible);
}
bool MenuItem::enabled() {
return menuItem->isEnabled();
}
void MenuItem::setEnabled(bool enabled) {
menuItem->setEnabled(enabled);
}
MenuItem::MenuItem() {
menuItem = new MenuItem::Data(*this);
}
void MenuCheckItem::create(Menu &parent, const char *text) {
menuCheckItem->setText(text);
menuCheckItem->setCheckable(true);
menuCheckItem->connect(menuCheckItem, SIGNAL(triggered()), SLOT(onTick()));
parent.menu->addAction(menuCheckItem);
}
bool MenuCheckItem::visible() {
return menuCheckItem->isVisible();
}
void MenuCheckItem::setVisible(bool visible) {
menuCheckItem->setVisible(visible);
}
bool MenuCheckItem::enabled() {
return menuCheckItem->isEnabled();
}
void MenuCheckItem::setEnabled(bool enabled) {
menuCheckItem->setEnabled(enabled);
}
bool MenuCheckItem::checked() {
return menuCheckItem->isChecked();
}
void MenuCheckItem::setChecked(bool checked) {
menuCheckItem->setChecked(checked);
}
MenuCheckItem::MenuCheckItem() {
menuCheckItem = new MenuCheckItem::Data(*this);
}
void MenuRadioItem::create(Menu &parent, const char *text) {
menuRadioItem->parent = &parent;
menuRadioItem->actionGroup = new QActionGroup(0);
menuRadioItem->actionGroup->addAction(menuRadioItem);
menuRadioItem->setText(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) {
menuRadioItem->parent = parent.menuRadioItem->parent;
menuRadioItem->actionGroup = parent.menuRadioItem->actionGroup;
menuRadioItem->actionGroup->addAction(menuRadioItem);
menuRadioItem->setText(text);
menuRadioItem->setCheckable(true);
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
menuRadioItem->parent->menu->addAction(menuRadioItem);
}
bool MenuRadioItem::visible() {
return menuRadioItem->isVisible();
}
void MenuRadioItem::setVisible(bool visible) {
menuRadioItem->setVisible(visible);
}
bool MenuRadioItem::enabled() {
return menuRadioItem->isEnabled();
}
void MenuRadioItem::setEnabled(bool enabled) {
menuRadioItem->setEnabled(enabled);
}
bool MenuRadioItem::checked() {
return menuRadioItem->isChecked();
}
void MenuRadioItem::setChecked() {
object->locked = true;
menuRadioItem->setChecked(true);
object->locked = false;
}
MenuRadioItem::MenuRadioItem() {
menuRadioItem = new MenuRadioItem::Data(*this);
}

View File

@@ -0,0 +1,41 @@
static QMessageBox::StandardButtons MessageWindow_buttons(MessageWindow::Buttons buttons) {
QMessageBox::StandardButtons standardButtons = QMessageBox::NoButton;
if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok;
if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No;
return standardButtons;
}
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, QMessageBox::StandardButton response) {
if(response == QMessageBox::Ok) return MessageWindow::Response::Ok;
if(response == QMessageBox::Cancel) return MessageWindow::Response::Cancel;
if(response == QMessageBox::Yes) return MessageWindow::Response::Yes;
if(response == QMessageBox::No) return MessageWindow::Response::No;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
);
}

6
bsnes/phoenix/qt/object.cpp Executable file
View File

@@ -0,0 +1,6 @@
void Object::unused() {
}
Object::Object() {
object = new Object::Data(*this);
}

View File

@@ -0,0 +1,16 @@
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
progressBar->setParent(parent.window->container);
progressBar->setGeometry(x, y, width, height);
progressBar->setRange(0, 100);
progressBar->setTextVisible(false);
progressBar->show();
}
void ProgressBar::setProgress(unsigned progress) {
progressBar->setValue(progress);
}
ProgressBar::ProgressBar() {
progressBar = new ProgressBar::Data(*this);
widget->widget = progressBar;
}

124
bsnes/phoenix/qt/qt.cpp Executable file
View File

@@ -0,0 +1,124 @@
#include <QApplication>
#include <QtGui>
using namespace nall;
namespace phoenix {
#include "qt.moc.hpp"
#include "qt.moc"
#include "object.cpp"
#include "font.cpp"
#include "menu.cpp"
#include "widget.cpp"
#include "window.cpp"
#include "button.cpp"
#include "canvas.cpp"
#include "checkbox.cpp"
#include "combobox.cpp"
#include "editbox.cpp"
#include "horizontalslider.cpp"
#include "label.cpp"
#include "listbox.cpp"
#include "progressbar.cpp"
#include "radiobox.cpp"
#include "textbox.cpp"
#include "verticalslider.cpp"
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
Window Window::None;
OS& OS::handle() {
static OS os;
return os;
}
bool OS::pending() {
return QApplication::hasPendingEvents();
}
void OS::run() {
QApplication::processEvents();
}
void OS::main() {
QApplication::exec();
}
void OS::quit() {
QApplication::quit();
}
unsigned OS::desktopWidth() {
return QApplication::desktop()->screenGeometry().width();
}
unsigned OS::desktopHeight() {
return QApplication::desktop()->screenGeometry().height();
}
string OS::folderSelect(Window &parent, const char *path) {
QString directory = QFileDialog::getExistingDirectory(
&parent != &Window::None ? parent.window : 0, "Select Directory", path, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
);
return directory.toUtf8().constData();
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string filters;
lstring list;
list.split("\n", filter);
foreach(item, list) {
lstring part;
part.split("\t", item);
if(part.size() != 2) continue;
part[1].replace(",", " ");
filters.append(part[0]);
filters.append(" (");
filters.append(part[1]);
filters.append(");;");
}
filters.rtrim(";;");
QString filename = QFileDialog::getOpenFileName(
&parent != &Window::None ? parent.window : 0, "Open File", path, (const char*)filters
);
return filename.toUtf8().constData();
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string filters;
lstring list;
list.split("\n", filter);
foreach(item, list) {
lstring part;
part.split("\t", item);
if(part.size() != 2) continue;
part[1].replace(",", " ");
filters.append(part[0]);
filters.append(" (");
filters.append(part[1]);
filters.append(");;");
}
filters.rtrim(";;");
QString filename = QFileDialog::getSaveFileName(
&parent != &Window::None ? parent.window : 0, "Save File", path, (const char*)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);
}
}

327
bsnes/phoenix/qt/qt.hpp Executable file
View File

@@ -0,0 +1,327 @@
namespace phoenix {
struct Window;
struct Object {
Object();
Object& operator=(const Object&) = delete;
Object(const Object&) = delete;
//private:
virtual void unused();
struct Data;
Data *object;
};
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);
Font();
~Font();
//private:
struct Data;
Data *font;
};
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
struct Action : Object {
virtual bool visible() = 0;
virtual void setVisible(bool visible = true) = 0;
virtual bool enabled() = 0;
virtual void setEnabled(bool enabled = true) = 0;
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
Menu();
//private:
struct Data;
Data *menu;
};
struct MenuSeparator : Action {
void create(Menu &parent);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
MenuSeparator();
//private:
struct Data;
Data *menuSeparator;
};
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
MenuItem();
//private:
struct Data;
Data *menuItem;
};
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
bool checked();
void setChecked(bool checked = true);
MenuCheckItem();
//private:
struct Data;
Data *menuCheckItem;
};
struct MenuRadioItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(MenuRadioItem &parent, const char *text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
bool checked();
void setChecked();
MenuRadioItem();
//private:
struct Data;
Data *menuRadioItem;
};
struct Widget : Object {
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
virtual void setFont(Font &font);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
bool focused();
void setFocused();
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 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 setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
Window();
//private:
struct Data;
Data *window;
};
struct Button : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
Button();
//private:
struct Data;
Data *button;
};
struct Canvas : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
uint32_t* buffer();
void redraw();
Canvas();
~Canvas();
//private:
struct Data;
Data *canvas;
};
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
bool checked();
void setChecked(bool checked = true);
CheckBox();
//private:
struct Data;
Data *checkBox;
};
struct ComboBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void reset();
void addItem(const char *text);
unsigned selection();
void setSelection(unsigned row);
ComboBox();
//private:
struct Data;
Data *comboBox;
};
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const char *text);
EditBox();
//private:
struct Data;
Data *editBox;
};
struct HorizontalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
HorizontalSlider();
//private:
struct Data;
Data *horizontalSlider;
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *text);
Label();
//private:
struct Data;
Data *label;
};
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 = "");
void setHeaderVisible(bool headerVisible = true);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
//private:
struct Data;
Data *listBox;
};
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setProgress(unsigned progress);
ProgressBar();
//private:
struct Data;
Data *progressBar;
};
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 = "");
bool checked();
void setChecked();
RadioBox();
//private:
struct Data;
Data *radioBox;
};
struct TextBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setEditable(bool editable = true);
nall::string text();
void setText(const char *text);
TextBox();
//private:
struct Data;
Data *textBox;
};
struct VerticalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
VerticalSlider();
//private:
struct Data;
Data *verticalSlider;
};
struct Viewport : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
uintptr_t handle();
Viewport();
//private:
struct Data;
Data *viewport;
};
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,
OkCancel,
YesNo,
};
enum class Response : unsigned {
Ok,
Cancel,
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);
};
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 = "");
//private:
static OS& handle();
struct Data;
Data *os;
private:
OS();
};
extern OS &os;
}

925
bsnes/phoenix/qt/qt.moc Executable file
View File

@@ -0,0 +1,925 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Sat Sep 25 06:31:14 2010
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'qt.moc.hpp' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 62
#error "This file was generated using the moc from 4.6.2. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_MenuItem__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
16, 15, 15, 15, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_MenuItem__Data[] = {
"MenuItem::Data\0\0onTick()\0"
};
const QMetaObject MenuItem::Data::staticMetaObject = {
{ &QAction::staticMetaObject, qt_meta_stringdata_MenuItem__Data,
qt_meta_data_MenuItem__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &MenuItem::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *MenuItem::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *MenuItem::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_MenuItem__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QAction::qt_metacast(_clname);
}
int MenuItem::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QAction::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_MenuCheckItem__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
21, 20, 20, 20, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_MenuCheckItem__Data[] = {
"MenuCheckItem::Data\0\0onTick()\0"
};
const QMetaObject MenuCheckItem::Data::staticMetaObject = {
{ &QAction::staticMetaObject, qt_meta_stringdata_MenuCheckItem__Data,
qt_meta_data_MenuCheckItem__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &MenuCheckItem::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *MenuCheckItem::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *MenuCheckItem::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_MenuCheckItem__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QAction::qt_metacast(_clname);
}
int MenuCheckItem::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QAction::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_MenuRadioItem__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
21, 20, 20, 20, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_MenuRadioItem__Data[] = {
"MenuRadioItem::Data\0\0onTick()\0"
};
const QMetaObject MenuRadioItem::Data::staticMetaObject = {
{ &QAction::staticMetaObject, qt_meta_stringdata_MenuRadioItem__Data,
qt_meta_data_MenuRadioItem__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &MenuRadioItem::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *MenuRadioItem::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *MenuRadioItem::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_MenuRadioItem__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QAction::qt_metacast(_clname);
}
int MenuRadioItem::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QAction::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_Window__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_Window__Data[] = {
"Window::Data\0"
};
const QMetaObject Window::Data::staticMetaObject = {
{ &QWidget::staticMetaObject, qt_meta_stringdata_Window__Data,
qt_meta_data_Window__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &Window::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *Window::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *Window::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Window__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QWidget::qt_metacast(_clname);
}
int Window::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_Button__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
14, 13, 13, 13, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_Button__Data[] = {
"Button::Data\0\0onTick()\0"
};
const QMetaObject Button::Data::staticMetaObject = {
{ &QPushButton::staticMetaObject, qt_meta_stringdata_Button__Data,
qt_meta_data_Button__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &Button::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *Button::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *Button::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Button__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QPushButton::qt_metacast(_clname);
}
int Button::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QPushButton::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_Canvas__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_Canvas__Data[] = {
"Canvas::Data\0"
};
const QMetaObject Canvas::Data::staticMetaObject = {
{ &QWidget::staticMetaObject, qt_meta_stringdata_Canvas__Data,
qt_meta_data_Canvas__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &Canvas::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *Canvas::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *Canvas::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Canvas__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QWidget::qt_metacast(_clname);
}
int Canvas::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_CheckBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
16, 15, 15, 15, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_CheckBox__Data[] = {
"CheckBox::Data\0\0onTick()\0"
};
const QMetaObject CheckBox::Data::staticMetaObject = {
{ &QCheckBox::staticMetaObject, qt_meta_stringdata_CheckBox__Data,
qt_meta_data_CheckBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &CheckBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *CheckBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *CheckBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_CheckBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QCheckBox::qt_metacast(_clname);
}
int CheckBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QCheckBox::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_ComboBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
16, 15, 15, 15, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_ComboBox__Data[] = {
"ComboBox::Data\0\0onChange()\0"
};
const QMetaObject ComboBox::Data::staticMetaObject = {
{ &QComboBox::staticMetaObject, qt_meta_stringdata_ComboBox__Data,
qt_meta_data_ComboBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &ComboBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *ComboBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *ComboBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_ComboBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QComboBox::qt_metacast(_clname);
}
int ComboBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QComboBox::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_EditBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_EditBox__Data[] = {
"EditBox::Data\0\0onChange()\0"
};
const QMetaObject EditBox::Data::staticMetaObject = {
{ &QTextEdit::staticMetaObject, qt_meta_stringdata_EditBox__Data,
qt_meta_data_EditBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &EditBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *EditBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *EditBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_EditBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QTextEdit::qt_metacast(_clname);
}
int EditBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QTextEdit::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_HorizontalSlider__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
24, 23, 23, 23, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_HorizontalSlider__Data[] = {
"HorizontalSlider::Data\0\0onChange()\0"
};
const QMetaObject HorizontalSlider::Data::staticMetaObject = {
{ &QSlider::staticMetaObject, qt_meta_stringdata_HorizontalSlider__Data,
qt_meta_data_HorizontalSlider__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &HorizontalSlider::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *HorizontalSlider::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *HorizontalSlider::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_HorizontalSlider__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QSlider::qt_metacast(_clname);
}
int HorizontalSlider::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QSlider::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_Label__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_Label__Data[] = {
"Label::Data\0"
};
const QMetaObject Label::Data::staticMetaObject = {
{ &QLabel::staticMetaObject, qt_meta_stringdata_Label__Data,
qt_meta_data_Label__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &Label::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *Label::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *Label::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_Label__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QLabel::qt_metacast(_clname);
}
int Label::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QLabel::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_ListBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a,
28, 14, 14, 14, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_ListBox__Data[] = {
"ListBox::Data\0\0onActivate()\0onChange()\0"
};
const QMetaObject ListBox::Data::staticMetaObject = {
{ &QTreeWidget::staticMetaObject, qt_meta_stringdata_ListBox__Data,
qt_meta_data_ListBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &ListBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *ListBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *ListBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_ListBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QTreeWidget::qt_metacast(_clname);
}
int ListBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QTreeWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
case 1: onChange(); break;
default: ;
}
_id -= 2;
}
return _id;
}
static const uint qt_meta_data_RadioBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
16, 15, 15, 15, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_RadioBox__Data[] = {
"RadioBox::Data\0\0onTick()\0"
};
const QMetaObject RadioBox::Data::staticMetaObject = {
{ &QRadioButton::staticMetaObject, qt_meta_stringdata_RadioBox__Data,
qt_meta_data_RadioBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &RadioBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *RadioBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *RadioBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_RadioBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QRadioButton::qt_metacast(_clname);
}
int RadioBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QRadioButton::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTick(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_TextBox__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_TextBox__Data[] = {
"TextBox::Data\0\0onChange()\0"
};
const QMetaObject TextBox::Data::staticMetaObject = {
{ &QLineEdit::staticMetaObject, qt_meta_stringdata_TextBox__Data,
qt_meta_data_TextBox__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &TextBox::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *TextBox::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *TextBox::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_TextBox__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QLineEdit::qt_metacast(_clname);
}
int TextBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QLineEdit::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_VerticalSlider__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
22, 21, 21, 21, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_VerticalSlider__Data[] = {
"VerticalSlider::Data\0\0onChange()\0"
};
const QMetaObject VerticalSlider::Data::staticMetaObject = {
{ &QSlider::staticMetaObject, qt_meta_stringdata_VerticalSlider__Data,
qt_meta_data_VerticalSlider__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &VerticalSlider::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *VerticalSlider::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *VerticalSlider::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_VerticalSlider__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QSlider::qt_metacast(_clname);
}
int VerticalSlider::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QSlider::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_OS__Data[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_OS__Data[] = {
"OS::Data\0"
};
const QMetaObject OS::Data::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_OS__Data,
qt_meta_data_OS__Data, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &OS::Data::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *OS::Data::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *OS::Data::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_OS__Data))
return static_cast<void*>(const_cast< Data*>(this));
return QObject::qt_metacast(_clname);
}
int OS::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
QT_END_MOC_NAMESPACE

304
bsnes/phoenix/qt/qt.moc.hpp Executable file
View File

@@ -0,0 +1,304 @@
struct Object::Data {
public:
Object &self;
bool locked;
Data(Object &self) : self(self) {
locked = false;
}
};
struct Font::Data : public QFont {
public:
Font &self;
Data(Font &self) : self(self) {
}
};
struct Menu::Data : public QMenu {
public:
Menu &self;
Data(Menu &self) : self(self) {
}
};
struct MenuSeparator::Data {
public:
MenuSeparator &self;
QAction *action;
Data(MenuSeparator &self) : self(self) {
}
};
struct MenuItem::Data : public QAction {
Q_OBJECT
public:
MenuItem &self;
Data(MenuItem &self) : self(self), QAction(0) {
}
public slots:
void onTick() {
if(self.onTick) self.onTick();
}
};
struct MenuCheckItem::Data : public QAction {
Q_OBJECT
public:
MenuCheckItem &self;
Data(MenuCheckItem &self) : self(self), QAction(0) {
}
public slots:
void onTick() {
if(self.onTick) self.onTick();
}
};
struct MenuRadioItem::Data : public QAction {
Q_OBJECT
public:
MenuRadioItem &self;
Menu *parent;
QActionGroup *actionGroup;
Data(MenuRadioItem &self) : self(self), QAction(0) {
}
public slots:
void onTick() {
if(self.object->locked == false && self.onTick && self.checked()) self.onTick();
}
};
struct Widget::Data {
public:
Widget &self;
QWidget *widget;
Data(Widget &self) : self(self) {
}
};
struct Window::Data : public QWidget {
Q_OBJECT
public:
Window &self;
QFont *defaultFont;
QVBoxLayout *layout;
QMenuBar *menuBar;
QWidget *container;
QStatusBar *statusBar;
void closeEvent(QCloseEvent *event) {
if(self.onClose) {
bool result = self.onClose();
if(result == false) event->ignore();
}
}
Data(Window &self) : self(self) {
}
};
struct Button::Data : public QPushButton {
Q_OBJECT
public:
Button &self;
Data(Button &self) : self(self) {
}
public slots:
void onTick() {
if(self.onTick) self.onTick();
}
};
struct Canvas::Data : public QWidget {
Q_OBJECT
public:
Canvas &self;
QImage *image;
void paintEvent(QPaintEvent*);
Data(Canvas &self) : self(self) {
}
};
struct CheckBox::Data : public QCheckBox {
Q_OBJECT
public:
CheckBox &self;
Data(CheckBox &self) : self(self) {
}
public slots:
void onTick() {
if(self.onTick) self.onTick();
}
};
struct ComboBox::Data : public QComboBox {
Q_OBJECT
public:
ComboBox &self;
Data(ComboBox &self) : self(self) {
}
public slots:
void onChange() {
if(self.onChange) self.onChange();
}
};
struct EditBox::Data : public QTextEdit {
Q_OBJECT
public:
EditBox &self;
Data(EditBox &self) : self(self) {
}
public slots:
void onChange() {
if(self.onChange) self.onChange();
}
};
struct HorizontalSlider::Data : public QSlider {
Q_OBJECT
public:
HorizontalSlider &self;
Data(HorizontalSlider &self) : self(self), QSlider(Qt::Horizontal) {
}
public slots:
void onChange() {
if(self.onChange) self.onChange();
}
};
struct Label::Data : public QLabel {
Q_OBJECT
public:
Label &self;
Data(Label &self) : self(self) {
}
};
struct ListBox::Data : public QTreeWidget {
Q_OBJECT
public:
ListBox &self;
Data(ListBox &self) : self(self) {
}
public slots:
void onActivate() {
if(self.object->locked == false && self.onActivate) self.onActivate();
}
void onChange() {
if(self.object->locked == false && self.onChange) self.onChange();
}
};
struct ProgressBar::Data : public QProgressBar {
public:
ProgressBar &self;
Data(ProgressBar &self) : self(self) {
}
};
struct RadioBox::Data : public QRadioButton {
Q_OBJECT
public:
RadioBox &self;
Window *parent;
QButtonGroup *buttonGroup;
Data(RadioBox &self) : self(self) {
}
public slots:
void onTick() {
if(self.onTick && self.checked()) self.onTick();
}
};
struct TextBox::Data : public QLineEdit {
Q_OBJECT
public:
TextBox &self;
Data(TextBox &self) : self(self) {
}
public slots:
void onChange() {
if(self.onChange) self.onChange();
}
};
struct VerticalSlider::Data : public QSlider {
Q_OBJECT
public:
VerticalSlider &self;
Data(VerticalSlider &self) : self(self), QSlider(Qt::Vertical) {
}
public slots:
void onChange() {
if(self.onChange) self.onChange();
}
};
struct Viewport::Data : public QWidget {
public:
Viewport &self;
Data(Viewport &self) : self(self) {
}
};
struct OS::Data : public QObject {
Q_OBJECT
public:
OS &self;
QApplication *application;
Data(OS &self) : self(self) {
}
public slots:
};

37
bsnes/phoenix/qt/radiobox.cpp Executable file
View File

@@ -0,0 +1,37 @@
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *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->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) {
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);
if(radioBox->parent->window->defaultFont) radioBox->setFont(*radioBox->parent->window->defaultFont);
radioBox->show();
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
}
bool RadioBox::checked() {
return radioBox->isChecked();
}
void RadioBox::setChecked() {
radioBox->setChecked(true);
}
RadioBox::RadioBox() {
radioBox = new RadioBox::Data(*this);
widget->widget = radioBox;
}

25
bsnes/phoenix/qt/textbox.cpp Executable file
View File

@@ -0,0 +1,25 @@
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
textBox->setParent(parent.window->container);
textBox->setGeometry(x, y, width, height);
textBox->setText(text);
if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont);
textBox->show();
textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
}
void TextBox::setEditable(bool editable) {
textBox->setReadOnly(editable == false);
}
string TextBox::text() {
return textBox->text().toUtf8().constData();
}
void TextBox::setText(const char *text) {
textBox->setText(text);
}
TextBox::TextBox() {
textBox = new TextBox::Data(*this);
widget->widget = textBox;
}

View File

@@ -0,0 +1,24 @@
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
length += (length == 0);
verticalSlider->setParent(parent.window->container);
verticalSlider->setGeometry(x, y, width, height);
verticalSlider->setInvertedAppearance(true);
verticalSlider->setInvertedControls(true);
verticalSlider->setRange(0, length - 1);
verticalSlider->setPageStep(length >> 3);
verticalSlider->connect(verticalSlider, SIGNAL(valueChanged(int)), SLOT(onChange()));
verticalSlider->show();
}
unsigned VerticalSlider::position() {
return verticalSlider->value();
}
void VerticalSlider::setPosition(unsigned position) {
verticalSlider->setValue(position);
}
VerticalSlider::VerticalSlider() {
verticalSlider = new VerticalSlider::Data(*this);
widget->widget = verticalSlider;
}

14
bsnes/phoenix/qt/viewport.cpp Executable file
View File

@@ -0,0 +1,14 @@
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->show();
}
uintptr_t Viewport::handle() {
return (uintptr_t)viewport->winId();
}
Viewport::Viewport() {
viewport = new Viewport::Data(*this);
widget->widget = viewport;
}

35
bsnes/phoenix/qt/widget.cpp Executable file
View File

@@ -0,0 +1,35 @@
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
widget->widget->setGeometry(x, y, width, height);
}
void Widget::setFont(Font &font) {
widget->widget->setFont(*font.font);
}
bool Widget::visible() {
return widget->widget->isVisible();
}
void Widget::setVisible(bool visible) {
widget->widget->setVisible(visible);
}
bool Widget::enabled() {
return widget->widget->isEnabled();
}
void Widget::setEnabled(bool enabled) {
widget->widget->setEnabled(enabled);
}
bool Widget::focused() {
return widget->widget->hasFocus();
}
void Widget::setFocused() {
widget->widget->setFocus(Qt::OtherFocusReason);
}
Widget::Widget() {
widget = new Widget::Data(*this);
}

69
bsnes/phoenix/qt/window.cpp Executable file
View File

@@ -0,0 +1,69 @@
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
window->setWindowTitle(text);
window->move(x, y);
window->layout = new QVBoxLayout(window);
window->layout->setMargin(0);
window->layout->setSpacing(0);
window->layout->setSizeConstraint(QLayout::SetFixedSize);
window->setLayout(window->layout);
window->menuBar = new QMenuBar(window);
window->menuBar->setVisible(false);
window->layout->addWidget(window->menuBar);
window->container = new QWidget(window);
window->container->setFixedSize(width, height);
window->container->setVisible(true);
window->layout->addWidget(window->container);
window->statusBar = new QStatusBar(window);
window->statusBar->setSizeGripEnabled(false);
window->statusBar->setVisible(false);
window->layout->addWidget(window->statusBar);
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
window->container->setFixedSize(width, height);
window->move(x, y);
}
void Window::setDefaultFont(Font &font) {
window->defaultFont = font.font;
window->menuBar->setFont(*font.font);
}
void Window::setFont(Font &font) {
window->statusBar->setFont(*font.font);
}
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
QPalette palette;
palette.setColor(QPalette::Window, QColor(red, green, blue));
window->setPalette(palette);
window->setAutoFillBackground(true);
}
void Window::setTitle(const char *text) {
window->setWindowTitle(text);
}
void Window::setStatusText(const char *text) {
window->statusBar->showMessage(text, 0);
}
void Window::setMenuVisible(bool visible) {
if(visible) window->menuBar->show();
else window->menuBar->hide();
}
void Window::setStatusVisible(bool visible) {
if(visible) window->statusBar->show();
else window->statusBar->hide();
}
Window::Window() {
window = new Window::Data(*this);
window->defaultFont = 0;
widget->widget = window;
}

View File

@@ -0,0 +1,10 @@
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
x, y, width, height,
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);
}

View File

@@ -0,0 +1,60 @@
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
canvas->buffer = new uint32_t[width * height]();
canvas->pitch = width * sizeof(uint32_t);
canvas->width = width;
canvas->height = height;
memset(&canvas->bmi, 0, sizeof(BITMAPINFO));
canvas->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
canvas->bmi.bmiHeader.biPlanes = 1;
canvas->bmi.bmiHeader.biBitCount = 32;
canvas->bmi.bmiHeader.biCompression = BI_RGB;
canvas->bmi.bmiHeader.biWidth = width;
canvas->bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside down; negative height flips bitmap
canvas->bmi.bmiHeader.biSizeImage = canvas->pitch * canvas->height;
widget->window = CreateWindow(
L"phoenix_canvas", L"",
WS_CHILD | WS_VISIBLE,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
}
uint32_t* Canvas::buffer() {
return canvas->buffer;
}
void Canvas::redraw() {
PAINTSTRUCT ps;
BeginPaint(widget->window, &ps);
SetDIBitsToDevice(ps.hdc, 0, 0, canvas->width, canvas->height, 0, 0, 0, canvas->height, (void*)canvas->buffer, &canvas->bmi, DIB_RGB_COLORS);
EndPaint(widget->window, &ps);
InvalidateRect(widget->window, 0, false);
}
Canvas::Canvas() {
canvas = new Canvas::Data;
canvas->buffer = 0;
}
Canvas::~Canvas() {
delete[] canvas->buffer;
delete canvas;
}
static LRESULT CALLBACK Canvas_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch(msg) {
case WM_PAINT: {
Object *object_ptr = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(object_ptr) {
if(dynamic_cast<Canvas*>(object_ptr)) {
Canvas &canvas = (Canvas&)*object_ptr;
canvas.redraw();
}
}
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@@ -0,0 +1,18 @@
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
x, y, width, height,
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);
}
bool CheckBox::checked() {
return SendMessage(widget->window, BM_GETCHECK, 0, 0);
}
void CheckBox::setChecked(bool checked) {
SendMessage(widget->window, BM_SETCHECK, (WPARAM)checked, 0);
}

View File

@@ -0,0 +1,46 @@
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindowEx(
0, L"COMBOBOX", L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
x, y, width, 200,
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);
//CreateWindow height parameter is the height of the expanded list box;
//need additional code to override default ComboBox control height
RECT rc;
GetWindowRect(widget->window, &rc);
unsigned adjustedHeight = height - ((rc.bottom - rc.top) - SendMessage(widget->window, CB_GETITEMHEIGHT, (WPARAM)-1, 0));
SendMessage(widget->window, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight);
if(*text) {
lstring list;
list.split("\n", text);
foreach(item, list) addItem(item);
}
}
void ComboBox::reset() {
SendMessage(widget->window, CB_RESETCONTENT, 0, 0);
}
void ComboBox::addItem(const char *text) {
SendMessage(widget->window, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text));
if(SendMessage(widget->window, CB_GETCOUNT, 0, 0) == 1) setSelection(0);
}
unsigned ComboBox::selection() {
return SendMessage(widget->window, CB_GETCURSEL, 0, 0);
}
void ComboBox::setSelection(unsigned row) {
SendMessage(widget->window, CB_SETCURSEL, comboBox->selection = row, 0);
}
ComboBox::ComboBox() {
comboBox = new ComboBox::Data;
comboBox->selection = 0;
}

View File

@@ -0,0 +1,53 @@
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
(editBox->wordWrap == false ? ES_AUTOHSCROLL : 0),
editBox->x = x, editBox->y = y, editBox->width = width, editBox->height = height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
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);
}
string EditBox::getText() {
unsigned length = GetWindowTextLength(widget->window);
wchar_t buffer[length + 1];
GetWindowText(widget->window, buffer, length + 1);
buffer[length] = 0;
string text = utf8_t(buffer);
text.replace("\r", "");
return text;
}
void EditBox::setText(const char *text) {
string output = text;
output.replace("\r", "");
output.replace("\n", "\r\n");
object->locked = true;
SetWindowText(widget->window, utf16_t(output));
object->locked = false;
}
void EditBox::setEditable(bool editable) {
SendMessage(widget->window, EM_SETREADONLY, editable == false, (LPARAM)0);
}
void EditBox::setWordWrap(bool wordWrap) {
editBox->wordWrap = wordWrap;
if(widget->window == 0) return;
//ES_AUTOSCROLL options cannot be changed after control has been created;
//so destroy the control and recreate it with desired options
HWND hparent = GetParent(widget->window);
Window *parent = (Window*)GetWindowLongPtr(hparent, GWLP_USERDATA);
string text = getText();
DestroyWindow(widget->window);
create(*parent, editBox->x, editBox->y, editBox->width, editBox->height, text);
}
EditBox::EditBox() {
editBox = new EditBox::Data;
editBox->wordWrap = true;
}

26
bsnes/phoenix/windows/font.cpp Executable file
View File

@@ -0,0 +1,26 @@
static HFONT Font_createFont(const char *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,
utf16_t(name)
);
}
bool Font::create(const char *name, unsigned size, Font::Style style) {
font->font = Font_createFont(
name, size,
(style & Font::Style::Bold) == Font::Style::Bold,
(style & Font::Style::Italic) == Font::Style::Italic
);
return font->font;
}
Font::Font() {
font = new Font::Data;
font->font = 0;
}
Font::~Font() {
if(font->font) DeleteObject(font->font);
delete font;
}

View File

@@ -0,0 +1,25 @@
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
length += (length == 0);
widget->window = CreateWindow(
TRACKBAR_CLASS, L"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1));
SendMessage(widget->window, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3));
setPosition(0);
}
unsigned HorizontalSlider::position() {
return SendMessage(widget->window, TBM_GETPOS, 0, 0);
}
void HorizontalSlider::setPosition(unsigned position) {
SendMessage(widget->window, TBM_SETPOS, (WPARAM)true, (LPARAM)(horizontalSlider->position = position));
}
HorizontalSlider::HorizontalSlider() {
horizontalSlider = new HorizontalSlider::Data;
}

65
bsnes/phoenix/windows/label.cpp Executable file
View File

@@ -0,0 +1,65 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindow(
L"phoenix_label", L"",
WS_CHILD | WS_VISIBLE,
x, y, width, height,
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);
setText(text);
}
void Label::setText(const char *text) {
SetWindowText(widget->window, utf16_t(text));
}
//all of this for want of a STATIC SS_VCENTER flag ...
LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
Window *window_ptr = (Window*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
if(!window_ptr) return DefWindowProc(hwnd, msg, wparam, lparam);
Label *label_ptr = (Label*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!label_ptr) return DefWindowProc(hwnd, msg, wparam, lparam);
Window &window = *window_ptr;
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;
GetClientRect(hwnd, &rc);
unsigned length = GetWindowTextLength(hwnd);
wchar_t text[length + 1];
GetWindowText(hwnd, text, length + 1);
text[length] = 0;
DrawText(ps.hdc, text, -1, &rc, DT_CALCRECT | DT_END_ELLIPSIS);
unsigned height = rc.bottom;
GetClientRect(hwnd, &rc);
rc.top = (rc.bottom - height) / 2;
rc.bottom = rc.top + height;
DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS);
EndPaint(hwnd, &ps);
InvalidateRect(hwnd, 0, false);
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@@ -0,0 +1,92 @@
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER,
x, y, width, height,
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);
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT);
lstring list;
list.split("\t", text);
listBox->columns = list.size();
for(unsigned i = 0; i < list.size(); i++) {
LVCOLUMN column;
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
column.fmt = LVCFMT_LEFT;
column.iSubItem = list.size();
utf16_t text(list[i]);
column.pszText = text;
ListView_InsertColumn(widget->window, i, &column);
}
resizeColumnsToContent();
}
void ListBox::setHeaderVisible(bool headerVisible) {
SetWindowLong(
widget->window,
GWL_STYLE,
(GetWindowLong(widget->window, GWL_STYLE) & ~LVS_NOCOLUMNHEADER) |
(headerVisible == false ? LVS_NOCOLUMNHEADER : 0)
);
}
void ListBox::reset() {
ListView_DeleteAllItems(widget->window);
}
void ListBox::resizeColumnsToContent() {
for(unsigned i = 0; i < listBox->columns; i++) {
ListView_SetColumnWidth(widget->window, i, LVSCW_AUTOSIZE_USEHEADER);
}
}
void ListBox::addItem(const char *text) {
lstring list;
list.split("\t", text);
LVITEM item;
unsigned row = ListView_GetItemCount(widget->window);
item.mask = LVIF_TEXT;
item.iItem = row;
item.iSubItem = 0;
utf16_t wtext(list[0]);
item.pszText = wtext;
ListView_InsertItem(widget->window, &item);
for(unsigned i = 1; i < list.size(); i++) {
utf16_t wtext(list[i]);
ListView_SetItemText(widget->window, row, i, wtext);
}
}
void ListBox::setItem(unsigned row, const char *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);
}
}
optional<unsigned> ListBox::selection() {
unsigned count = ListView_GetItemCount(widget->window);
for(unsigned i = 0; i < count; i++) {
if(ListView_GetItemState(widget->window, i, LVIS_SELECTED)) return { true, i };
}
return { false, 0 };
}
void ListBox::setSelection(unsigned row) {
unsigned count = ListView_GetItemCount(widget->window);
for(unsigned i = 0; i < count; i++) {
ListView_SetItemState(widget->window, i, LVIS_FOCUSED, (i == row ? LVIS_FOCUSED : 0));
ListView_SetItemState(widget->window, i, LVIS_SELECTED, (i == row ? LVIS_SELECTED : 0));
}
}
ListBox::ListBox() {
listBox = new ListBox::Data;
listBox->lostFocus = false;
}

144
bsnes/phoenix/windows/menu.cpp Executable file
View File

@@ -0,0 +1,144 @@
Action::Action() {
os.objects.append(this);
action = new Action::Data;
}
void Menu::create(Window &parent, const char *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) {
action->parentMenu = parent.action->menu;
action->menu = CreatePopupMenu();
AppendMenu(parent.action->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
}
bool Menu::enabled() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parentMenu, (UINT_PTR)action->menu, false, &info);
return (info.fState & MFS_GRAYED) == 0;
}
void Menu::setEnabled(bool enabled) {
EnableMenuItem(action->parentMenu, (UINT_PTR)action->menu, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
}
void MenuSeparator::create(Menu &parent) {
action->parent = &parent;
AppendMenu(parent.action->menu, MF_SEPARATOR, object->id, L"");
}
bool MenuSeparator::enabled() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return (info.fState & MFS_GRAYED) == 0;
}
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) {
action->parent = &parent;
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
}
bool MenuItem::enabled() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return (info.fState & MFS_GRAYED) == 0;
}
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) {
action->parent = &parent;
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
}
bool MenuCheckItem::enabled() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return (info.fState & MFS_GRAYED) == 0;
}
void MenuCheckItem::setEnabled(bool enabled) {
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
}
bool MenuCheckItem::checked() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return info.fState & MFS_CHECKED;
}
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) {
action->parent = &parent;
action->radioParent = this;
action->items.append(this);
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
setChecked();
}
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
action->parent = parent.action->parent;
action->radioParent = parent.action->radioParent;
action->radioParent->action->items.append(this);
AppendMenu(action->parent->action->menu, MF_STRING, object->id, utf16_t(text));
}
bool MenuRadioItem::enabled() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return (info.fState & MFS_GRAYED) == 0;
}
void MenuRadioItem::setEnabled(bool enabled) {
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
}
bool MenuRadioItem::checked() {
MENUITEMINFO info;
memset(&info, 0, sizeof(MENUITEMINFO));
info.cbSize = sizeof(MENUITEMINFO);
info.fMask = MIIM_STATE;
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
return info.fState & MFS_CHECKED;
}
void MenuRadioItem::setChecked() {
MenuRadioItem *parent = action->radioParent;
foreach(item, parent->action->items) {
CheckMenuRadioItem(
action->parent->action->menu,
item->object->id, item->object->id, item->object->id + (item != this),
MF_BYCOMMAND
);
}
}

View File

@@ -0,0 +1,41 @@
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, UINT response) {
if(response == IDOK) return MessageWindow::Response::Ok;
if(response == IDCANCEL) return MessageWindow::Response::Cancel;
if(response == IDYES) return MessageWindow::Response::Yes;
if(response == IDNO) return MessageWindow::Response::No;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONINFORMATION;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
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) {
UINT flags = MB_ICONQUESTION;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
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) {
UINT flags = MB_ICONWARNING;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
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) {
UINT flags = MB_ICONERROR;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
}

View File

@@ -0,0 +1,85 @@
struct Object::Data {
unsigned id;
bool locked;
};
struct Font::Data {
HFONT font;
};
struct Action::Data {
Menu *parent;
HMENU parentMenu;
HMENU menu;
MenuRadioItem *radioParent;
array<MenuRadioItem*> items;
};
struct Widget::Data {
HWND window;
HFONT font;
};
struct Window::Data {
HFONT defaultFont;
HBRUSH brush;
COLORREF brushColor;
HMENU menu;
HWND status;
unsigned width;
unsigned height;
};
struct Canvas::Data {
uint32_t *buffer;
BITMAPINFO bmi;
unsigned pitch;
unsigned width;
unsigned height;
};
struct ComboBox::Data {
unsigned selection;
};
struct EditBox::Data {
bool wordWrap;
unsigned x;
unsigned y;
unsigned width;
unsigned height;
};
struct HorizontalSlider::Data {
unsigned position;
};
struct ListBox::Data {
unsigned columns;
bool lostFocus;
};
struct RadioBox::Data {
Window *parentWindow;
RadioBox *parent;
array<RadioBox*> items;
};
struct VerticalSlider::Data {
unsigned position;
};
struct OS::Data {
HFONT proportionalFont;
HFONT monospaceFont;
};
void Object::unused() {
}
Object::Object() {
static unsigned guid = 100;
object = new Object::Data;
object->id = guid++;
object->locked = false;
}

View File

@@ -0,0 +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="phoenix" version="1.0.0.0" processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -0,0 +1 @@
1 24 "phoenix.Manifest"

View File

@@ -0,0 +1,18 @@
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
widget->window = CreateWindow(
PROGRESS_CLASS, L"",
WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SendMessage(widget->window, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
SendMessage(widget->window, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
}
unsigned ProgressBar::progress() {
return SendMessage(widget->window, PBM_GETPOS, 0, 0);
}
void ProgressBar::setProgress(unsigned progress) {
SendMessage(widget->window, PBM_SETPOS, (WPARAM)progress, 0);
}

View File

@@ -0,0 +1,42 @@
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
radioBox->parentWindow = &parent;
radioBox->parent = this;
radioBox->parent->radioBox->items.append(this);
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
x, y, width, height,
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);
setChecked();
}
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
radioBox->parentWindow = parent.radioBox->parentWindow;
radioBox->parent = parent.radioBox->parent;
radioBox->parent->radioBox->items.append(this);
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
x, y, width, height,
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);
}
bool RadioBox::checked() {
return SendMessage(widget->window, BM_GETCHECK, 0, 0);
}
void RadioBox::setChecked() {
foreach(item, radioBox->parent->radioBox->items) {
SendMessage(item->widget->window, BM_SETCHECK, (WPARAM)(item == this), 0);
}
}
RadioBox::RadioBox() {
radioBox = new RadioBox::Data;
}

View File

@@ -0,0 +1,28 @@
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
x, y, width, height,
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);
}
string TextBox::text() {
unsigned length = GetWindowTextLength(widget->window);
wchar_t text[length + 1];
GetWindowText(widget->window, text, length + 1);
text[length] = 0;
return utf8_t(text);
}
void TextBox::setText(const char *text) {
object->locked = true;
SetWindowText(widget->window, utf16_t(text));
object->locked = false;
}
void TextBox::setEditable(bool editable) {
SendMessage(widget->window, EM_SETREADONLY, editable == false, 0);
}

View File

@@ -0,0 +1,25 @@
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
length += (length == 0);
widget->window = CreateWindow(
TRACKBAR_CLASS, L"",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1));
SendMessage(widget->window, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3));
setPosition(0);
}
unsigned VerticalSlider::position() {
return SendMessage(widget->window, TBM_GETPOS, 0, 0);
}
void VerticalSlider::setPosition(unsigned position) {
SendMessage(widget->window, TBM_SETPOS, (WPARAM)true, (LPARAM)(verticalSlider->position = position));
}
VerticalSlider::VerticalSlider() {
verticalSlider = new VerticalSlider::Data;
}

View File

@@ -0,0 +1,13 @@
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
widget->window = CreateWindow(
L"phoenix_window", L"",
WS_CHILD | WS_VISIBLE | WS_DISABLED,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
}
uintptr_t Viewport::handle() {
return (uintptr_t)widget->window;
}

View File

@@ -0,0 +1,36 @@
void Widget::setFont(Font &font) {
widget->font = font.font->font;
SendMessage(widget->window, WM_SETFONT, (WPARAM)font.font->font, 0);
}
bool Widget::visible() {
return GetWindowLong(widget->window, GWL_STYLE) & WS_VISIBLE;
}
void Widget::setVisible(bool visible) {
ShowWindow(widget->window, visible ? SW_SHOWNORMAL : SW_HIDE);
}
bool Widget::enabled() {
return IsWindowEnabled(widget->window);
}
void Widget::setEnabled(bool enabled) {
EnableWindow(widget->window, enabled);
}
bool Widget::focused() {
return (GetForegroundWindow() == widget->window);
}
void Widget::setFocused() {
if(visible() == false) setVisible(true);
SetFocus(widget->window);
}
Widget::Widget() {
os.objects.append(this);
widget = new Widget::Data;
widget->window = 0;
widget->font = os.os->proportionalFont;
}

View File

@@ -0,0 +1,84 @@
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
widget->window = CreateWindowEx(
0, L"phoenix_window", utf16_t(text),
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
x, y, width, height,
0, 0, GetModuleHandle(0), 0
);
window->menu = CreateMenu();
window->status = CreateWindowEx(
0, STATUSCLASSNAME, L"",
WS_CHILD,
0, 0, 0, 0,
widget->window, 0, GetModuleHandle(0), 0
);
//StatusBar will be capable of receiving tab focus if it is not disabled
SetWindowLongPtr(window->status, GWL_STYLE, GetWindowLong(window->status, GWL_STYLE) | WS_DISABLED);
resize(width, height);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
}
void Window::setDefaultFont(Font &font) {
window->defaultFont = font.font->font;
}
void Window::setFont(Font &font) {
SendMessage(window->status, WM_SETFONT, (WPARAM)font.font->font, 0);
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
bool isVisible = visible();
if(isVisible) setVisible(false);
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER | SWP_FRAMECHANGED);
resize(width, height);
if(isVisible) setVisible(true);
}
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
if(window->brush) DeleteObject(window->brush);
window->brushColor = RGB(red, green, blue);
window->brush = CreateSolidBrush(window->brushColor);
}
void Window::setTitle(const char *text) {
SetWindowText(widget->window, utf16_t(text));
}
void Window::setStatusText(const char *text) {
SendMessage(window->status, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
}
void Window::setMenuVisible(bool visible) {
SetMenu(widget->window, visible ? window->menu : 0);
resize(window->width, window->height);
}
void Window::setStatusVisible(bool visible) {
ShowWindow(window->status, visible ? SW_SHOWNORMAL : SW_HIDE);
resize(window->width, window->height);
}
Window::Window() {
window = new Window::Data;
window->defaultFont = 0;
window->brush = 0;
}
void Window::resize(unsigned width, unsigned height) {
window->width = width;
window->height = height;
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
RECT rc;
GetClientRect(widget->window, &rc);
width += width - (rc.right - rc.left);
height += height - (rc.bottom - rc.top);
if(GetWindowLongPtr(window->status, GWL_STYLE) & WS_VISIBLE) {
GetClientRect(window->status, &rc);
height += rc.bottom - rc.top;
}
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
SetWindowPos(window->status, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
}

438
bsnes/phoenix/windows/windows.cpp Executable file
View File

@@ -0,0 +1,438 @@
#include <windows.h>
#include <commctrl.h>
#include <io.h>
#include <direct.h>
#include <shlobj.h>
#include <nall/platform.hpp>
#include <nall/utf8.hpp>
using namespace nall;
namespace phoenix {
#include "object.cpp"
#include "font.cpp"
#include "menu.cpp"
#include "widget.cpp"
#include "window.cpp"
#include "button.cpp"
#include "canvas.cpp"
#include "checkbox.cpp"
#include "combobox.cpp"
#include "editbox.cpp"
#include "horizontalslider.cpp"
#include "label.cpp"
#include "listbox.cpp"
#include "progressbar.cpp"
#include "radiobox.cpp"
#include "textbox.cpp"
#include "verticalslider.cpp"
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
Window Window::None;
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
OS& OS::handle() {
static OS os;
return os;
}
bool OS::pending() {
MSG msg;
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
}
void OS::run() {
while(pending()) {
MSG msg;
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
void OS::main() {
MSG msg;
while(GetMessage(&msg, 0, 0, 0)) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
void OS::quit() {
PostQuitMessage(0);
}
unsigned OS::desktopWidth() {
return GetSystemMetrics(SM_CXSCREEN);
}
unsigned OS::desktopHeight() {
return GetSystemMetrics(SM_CYSCREEN);
}
string OS::folderSelect(Window &parent, const char *path) {
wchar_t wfilename[PATH_MAX + 1] = L"";
BROWSEINFO bi;
bi.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
bi.pidlRoot = NULL;
bi.pszDisplayName = wfilename;
bi.lpszTitle = L"";
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
bi.lpfn = NULL;
bi.lParam = 0;
bi.iImage = 0;
bool result = false;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if(pidl) {
if(SHGetPathFromIDList(pidl, wfilename)) {
result = true;
IMalloc *imalloc = 0;
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
imalloc->Free(pidl);
imalloc->Release();
}
}
}
if(result == false) return "";
return utf8_t(wfilename);
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string dir = path;
dir.replace("/", "\\");
string filterInfo;
lstring type;
type.split("\n", filter);
for(unsigned i = 0; i < type.size(); i++) {
lstring part;
part.split("\t", type[i]);
if(part.size() != 2) continue;
filterInfo.append(part[0]);
filterInfo.append(" (");
filterInfo.append(part[1]);
filterInfo.append(")\t");
part[1].replace(",", ";");
filterInfo.append(part[1]);
filterInfo.append("\t");
}
utf16_t wfilter(filterInfo);
utf16_t wdir(dir);
wchar_t wfilename[PATH_MAX] = L"";
wchar_t *p = wfilter;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
ofn.lpstrFilter = wfilter;
ofn.lpstrInitialDir = wdir;
ofn.lpstrFile = wfilename;
ofn.nMaxFile = PATH_MAX;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"";
bool result = GetOpenFileName(&ofn);
if(result == false) return "";
return utf8_t(wfilename);
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string dir = path;
dir.replace("/", "\\");
string filterInfo;
lstring type;
type.split("\n", filter);
for(unsigned i = 0; i < type.size(); i++) {
lstring part;
part.split("\t", type[i]);
if(part.size() != 2) continue;
filterInfo.append(part[0]);
filterInfo.append(" (");
filterInfo.append(part[1]);
filterInfo.append(")\t");
part[1].replace(",", ";");
filterInfo.append(part[1]);
filterInfo.append("\t");
}
utf16_t wfilter(filterInfo);
utf16_t wdir(dir);
wchar_t wfilename[PATH_MAX] = L"";
wchar_t *p = wfilter;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
ofn.lpstrFilter = wfilter;
ofn.lpstrInitialDir = wdir;
ofn.lpstrFile = wfilename;
ofn.nMaxFile = PATH_MAX;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"";
bool result = GetSaveFileName(&ofn);
if(result == false) return "";
return utf8_t(wfilename);
}
static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch(msg) {
case WM_KEYDOWN: {
GUITHREADINFO info;
memset(&info, 0, sizeof(GUITHREADINFO));
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();
}
}
}
}
}
static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
Object *object_ptr = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(!object_ptr || !dynamic_cast<Window*>(object_ptr)) return DefWindowProc(hwnd, msg, wparam, lparam);
Window &window = (Window&)*object_ptr;
switch(msg) {
case WM_CLOSE: {
if(window.onClose) {
if(window.onClose()) window.setVisible(false);
} else {
window.setVisible(false);
}
return TRUE;
}
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_CTLCOLORBTN:
case WM_CTLCOLORSTATIC: {
Object *object_ptr = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
if(object_ptr && window.window->brush) {
HDC hdc = (HDC)wparam;
SetBkColor((HDC)wparam, window.window->brushColor);
return (INT_PTR)window.window->brush;
}
}
case WM_COMMAND: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(window.widget->window, id);
if(control == 0) {
Object *object_ptr = (Object*)os.findObject(id);
if(object_ptr) {
if(dynamic_cast<MenuItem*>(object_ptr)) {
MenuItem &menuItem = (MenuItem&)*object_ptr;
if(menuItem.onTick) menuItem.onTick();
} else if(dynamic_cast<MenuCheckItem*>(object_ptr)) {
MenuCheckItem &menuCheckItem = (MenuCheckItem&)*object_ptr;
menuCheckItem.setChecked(!menuCheckItem.checked());
if(menuCheckItem.onTick) menuCheckItem.onTick();
} else if(dynamic_cast<MenuRadioItem*>(object_ptr)) {
MenuRadioItem &menuRadioItem = (MenuRadioItem&)*object_ptr;
if(menuRadioItem.checked() == false) {
menuRadioItem.setChecked();
if(menuRadioItem.onTick) menuRadioItem.onTick();
}
}
}
} else {
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object_ptr) {
if(dynamic_cast<Button*>(object_ptr)) {
Button &button = (Button&)*object_ptr;
if(button.onTick) button.onTick();
} else if(dynamic_cast<CheckBox*>(object_ptr)) {
CheckBox &checkBox = (CheckBox&)*object_ptr;
checkBox.setChecked(!checkBox.checked());
if(checkBox.onTick) checkBox.onTick();
} else if(dynamic_cast<ComboBox*>(object_ptr)) {
ComboBox &comboBox = (ComboBox&)*object_ptr;
if(HIWORD(wparam) == CBN_SELCHANGE) {
if(comboBox.comboBox->selection != comboBox.selection()) {
comboBox.comboBox->selection = comboBox.selection();
if(comboBox.onChange) comboBox.onChange();
}
}
} else if(dynamic_cast<EditBox*>(object_ptr)) {
EditBox &editBox = (EditBox&)*object_ptr;
if(HIWORD(wparam) == EN_CHANGE) {
if(editBox.object->locked == false && editBox.onChange) editBox.onChange();
}
} else if(dynamic_cast<RadioBox*>(object_ptr)) {
RadioBox &radioBox = (RadioBox&)*object_ptr;
if(radioBox.checked() == false) {
radioBox.setChecked();
if(radioBox.onTick) radioBox.onTick();
}
} else if(dynamic_cast<TextBox*>(object_ptr)) {
TextBox &textBox = (TextBox&)*object_ptr;
if(HIWORD(wparam) == EN_CHANGE) {
if(textBox.object->locked == false && textBox.onChange) textBox.onChange();
}
}
}
}
}
case WM_NOTIFY: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(window.widget->window, id);
if(control) {
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object_ptr) {
if(dynamic_cast<ListBox*>(object_ptr)) {
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)) {
listBox.listBox->lostFocus = true;
} else {
if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) {
if(listBox.onChange) listBox.onChange();
} else if(listBox.listBox->lostFocus == false && listBox.selection() == false) {
if(listBox.onChange) listBox.onChange();
}
listBox.listBox->lostFocus = false;
}
} else if(nmhdr->code == LVN_ITEMACTIVATE) {
if(listBox.onActivate) listBox.onActivate();
}
}
}
}
}
case WM_HSCROLL: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(window.widget->window, id);
if(control) {
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object_ptr) {
if(dynamic_cast<HorizontalSlider*>(object_ptr)) {
HorizontalSlider &horizontalSlider = (HorizontalSlider&)*object_ptr;
if(horizontalSlider.horizontalSlider->position != horizontalSlider.position()) {
horizontalSlider.horizontalSlider->position = horizontalSlider.position();
if(horizontalSlider.onChange) horizontalSlider.onChange();
}
}
}
}
}
case WM_VSCROLL: {
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(window.widget->window, id);
if(control) {
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
if(object_ptr) {
if(dynamic_cast<VerticalSlider*>(object_ptr)) {
VerticalSlider &verticalSlider = (VerticalSlider&)*object_ptr;
if(verticalSlider.verticalSlider->position != verticalSlider.position()) {
verticalSlider.verticalSlider->position = verticalSlider.position();
if(verticalSlider.onChange) verticalSlider.onChange();
}
}
}
}
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
Object* OS::findObject(unsigned id) {
foreach(object, 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);
}
}

278
bsnes/phoenix/windows/windows.hpp Executable file
View File

@@ -0,0 +1,278 @@
namespace phoenix {
struct Window;
struct Object {
Object();
//private:
struct Data;
Data *object;
private:
virtual void unused();
};
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);
Font();
~Font();
//private:
struct Data;
Data *font;
};
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
struct Action : Object {
virtual bool enabled() = 0;
virtual void setEnabled(bool enabled = true) = 0;
Action();
//private:
struct Data;
Data *action;
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
bool enabled();
void setEnabled(bool enabled = true);
};
struct MenuSeparator : Action {
void create(Menu &parent);
bool enabled();
void setEnabled(bool enabled = true);
};
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
bool enabled();
void setEnabled(bool enabled = true);
};
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
bool enabled();
void setEnabled(bool enabled = true);
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);
bool enabled();
void setEnabled(bool enabled = true);
bool checked();
void setChecked();
};
struct Widget : Object {
virtual void setFont(Font &font);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
bool focused();
void setFocused();
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 setDefaultFont(Font &font);
void setFont(Font &font);
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 setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
Window();
//private:
struct Data;
Data *window;
//private:
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 = "");
};
struct Canvas : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
uint32_t* buffer();
void redraw();
Canvas();
~Canvas();
//private:
struct Data;
Data *canvas;
};
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *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 reset();
void addItem(const char *text);
unsigned selection();
void setSelection(unsigned item);
ComboBox();
//private:
struct Data;
Data *comboBox;
};
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::string getText();
void setText(const char *text);
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
EditBox();
//private:
struct Data;
Data *editBox;
};
struct HorizontalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
HorizontalSlider();
//private:
struct Data;
Data *horizontalSlider;
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *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 = "");
void setHeaderVisible(bool headerVisible = true);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
//private:
struct Data;
Data *listBox;
};
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
unsigned progress();
void setProgress(unsigned progress);
};
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 = "");
bool checked();
void setChecked();
RadioBox();
//private:
struct Data;
Data *radioBox;
};
struct TextBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::string text();
void setText(const char *text);
void setEditable(bool editable = true);
};
struct VerticalSlider : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
unsigned position();
void setPosition(unsigned position);
VerticalSlider();
//private:
struct Data;
Data *verticalSlider;
};
struct Viewport : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
uintptr_t handle();
};
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,
OkCancel,
YesNo,
};
enum class Response : unsigned {
Ok,
Cancel,
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);
};
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 = "");
//private:
static OS& handle();
struct Data;
Data *os;
Object* findObject(unsigned id);
nall::array<Object*> objects;
private:
OS();
friend class Object;
};
extern OS &os;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 B

Some files were not shown because too many files have changed in this diff Show More