Compare commits

...

17 Commits
v069 ... v071

Author SHA1 Message Date
Tim Allen
6c3aec7dc9 Update to v071 release.
byuu says (since v070):

- fixed a regression in the accuracy/compatibility CPU core with IRQ
  masking; fixes World Heroes 2
- fixed OAM address reset on $2100 writes for performance PPU core;
  fixes Mahjongg 2 and others
- DSP-1 always returns high 8-bits of status register; fixes Ace wo
  Nerae! freeze [Jonas Quinn]
- performance core can now take advantage of serial support
- pixel shaders now use a unified XML format; in the future they will
  support multi-pass shaders and textures
- major code restructuring
- first public release of phoenix GUI port
- mightymo's cheat code pack is now an external file for the phoenix
  port
- phoenix port stores cheat codes in XML format as well, unifying all
  file formats to the same markup language
2010-10-22 20:54:59 +11:00
Tim Allen
4016ae1d43 Update to v070r17 release.
byuu says:

- fixes DSP-1 status register for "Ace wo Nerae!"
- fixes IRQ masking for "World Heroes II"
- fixes compilation for the Qt port's debugger
2010-10-20 22:51:19 +11:00
Tim Allen
9e53c51b58 Update to v070r16 release.
(there was no r15 release posted to the WIP thread)

byuu says:

This mostly contains improvements for nall, like path unification.
This should fix FitzRoy's issue with .. on Windows.
2010-10-20 22:51:19 +11:00
Tim Allen
ce2b543679 Update to v070r14 release.
(there was no r13 release posted to the WIP thread)

byuu says:

- nall/string: trim and split functions now take the limit as a template
  parameter for clarity, trim_once variants are removed
  - quotable.trim<1>("\""); //remove quotes from string
  - cheatcode.split<3>(","); //split up to three times, third one is
    a description that may have commas
  - foobar.trim(" "); //remove any and all spaces
- nall/string: added wildcard() and iwildcard() functions for pattern
  matching
- nall/directory: accepts an optional pattern parameter to perform
  wildcard matching
  - lstring cartridges = directory::contents(path, "*.sfc");
  - some people may prefer directory::contents("/path/to/files/*.sfc"),
    but I like not having to build a string when you have the path
    separated already
- nall/qt: removed entirely, now resides in bsnes/ui-qt/template; I do
  intend to replace the check/radio actions with native Qt versions
  later
- bsnes/data: new folder, share the parts that both UIs use; bsnes.ico,
  bsnes.png, bsnes.Desktop, cheats.xml; simplify Makefile install target
- Makefile: install target now creates .bsnes folder and copies
  cheats.xml there for you
- Makefile: gconftool hack removed, not needed for phoenix, will work
  around with Qt later
- will probably make bsnes/Qt read the cheats.xml file externally as
  well, as that file makes each profile 1MB bigger when embedded
  - as such, will probably make bsnes also look in the binary directory
    for that file, so Windows users don't have to copy it to their
    userdata folder
2010-10-20 22:51:19 +11:00
Tim Allen
1a29b59225 Update to v070r12 release.
byuu says:

- removed support for images with copier headers
- phoenix/Windows: Label properly refreshes on text changes, fixes video
  settings sliders
- alt/ppu-performance: fixed mosaic Voffset bug, fixes Super Bowling et al
- alt/cpu: fixed CPU::joylatch() reporting, allows serial applications
  to work with performance profile
- hooked up SNES::cartridge.basename, allows MSU1 and serial support
  with the phoenix UI
- updated UPS patching code for bsnes/Qt, allowing it to compile again,
  hidden config option file.bypassPatchCrc32 was removed
2010-10-20 22:51:19 +11:00
Tim Allen
1926561ced Update to v070r11 release.
byuu says:

- phoenix/All: converted all instances of const char* to const
  nall::string&
  - above used to require: label.setText(string("FPS: ", fps)); but can
    now use: label.setText({"FPS", fps});
  - also avoids the need for the internal implementations to have to
    check for null string pointers
- phoenix/GTK+: no longer disabling double buffering on the viewport.
  Does not cause flickering, and fixes redraw issue on window resize
- phoenix/Qt: like phoenix/GTK+, it will use the default font on the
  menubar as well, so child menu items are consistently sized now
- Linux: file browser can list contents of / and won't let you go
  higher; Windows needs a similar guard for n:/ or \\
- UPS soft-patching support added
- external XML memory map loading support added
- cartridge folder support added: if folder ends in .sfc and there is
  ONE .sfc ROM inside it, it will load the folder as if it were a ROM
- input assignment refreshes text instead of reloading the list, this
  saves your position
  - auto-advance wasn't working very well, will try again later
- input clear all button removed since it's pretty fast now to do
  clear+down:repeat
2010-10-20 22:51:19 +11:00
Tim Allen
e2db2c24fc Update to v070r10 release.
byuu says:

- added workaround to phoenix/Windows to prevent horizontal scrollbar
  always being visible on single-column ListBoxes
- phoenix gains Window::geometry()
- added code to save and restore window positions, as in bsnes/Qt.
  Positions are saved to bsnes-phoenix-geometry.cfg this time
- resizing the main window will keep its position onscreen now

There's one issue with GTK+, if you close a window and then call
gtk_window_get_position(), it returns the previously set position rather
than where you actually placed the window. My easy fix of calling
gtk_window_get_position right before actually closing the window didn't
work, so for now you'll have to live with it.
2010-10-20 22:51:19 +11:00
Tim Allen
8a53e9ed22 Update to v070r09 release.
byuu says:

- removed native OS dialog option, I don't plan to add all the code
  required to make it optional everywhere
- cheat database supported, although it's external now. Either in the
  .bsnes folder or with the binary, named cheats.xml
- cheats.xml is external so that binaries can be much smaller, important
  for multiple profiles
- added "find codes" button to cheat editor (need to gray it out
  permanently if cheats.xml isn't found)
- added cheat database add window, works the same as bsnes/Qt, but it
  will also alert you if you run out of empty cheat slots upon import
- note: I should rename that ok button to "Import"
- hooked up callbacks for multitap/mouse/SS/justifier input
- added mapping for mouse axes and buttons
- used a simplified approach that only lets you map left/middle/right
  buttons, but doesn't need a separate popup window or fake controls
- moved capture mouse command to tools menu
- different from Qt where you'd click inside the main window, meant to
  be safer from accidental capture, escape still releases capture
- made a skeleton for GUI hotkey support, but the only hotkey is escape
2010-10-20 22:51:19 +11:00
Tim Allen
5286481d8d Update to v070r08 release.
byuu says:

- all three ports of phoenix gain the ability to use
  ListBox::setCheckable(), checked(row), setChecked(row, checked
  = true);
- cheat editor updated to take advantage of this

Some fun differences between the implementations. Windows was the least
flexible, it only lets you have a check at the start of each item.
Luckily that's all I need for my purposes so it'll work. It's also a lot
easier, as now I don't need a ton of extra code to try and set
per-column checkboxes. Now both Windows and Qt can put text into the
first item with the checkbox, but GTK+ cannot. Further, Qt needs this
because even if you hide the checkbox column, it still tries to search
for typed text from the checkbox column. GTK+ does this too, but unlike
GTK+, Qt lacks an API call to set the search column. Since my code
basically has to change this in real-time since you have to call the
setProperty functions after create(), this means I always set up the
checkbox columns regardless of whether or not they are used. For Qt,
I had to work around this and it'll be an annoying edge case if you try
and use setCheckable(true) and then setCheckable(false), because Qt has
no way to clear the checkboxes from an item once you've enabled them for
the first time. But without doing it this way, there's no way for eg the
ROM file loader to allow type-searching, so that's the way I do it.
Windows works the same, and GTK+ has a separate column (hidden from the
phoenix API standpoint) for the checkboxes, with no column header label
text.

All in all, a major hassle, but it was the only really major GUI hit
from leaving Qt, aside from the horror that's going to be the debugger,
which needs all kinds of highly specialized controls.
2010-10-20 22:51:19 +11:00
Tim Allen
440a59c879 Update to v070r07 release.
byuu says:

- added menu options to select controller port devices, they do actually
  work too
- however, input mapping can't map analog axes yet, and the mouse can't
  be captured yet, so it's of little use
- added clear and clear all buttons to the input mapper window, mainly
  because there was no reason not to (escape clears active input too)
- going to be adding a "special" button in the future that lets you map
  mouse axes and buttons
- fixed phoenix/Qt port, both the video rendering and Window::focused()
  commands work now

The way I've implemented mouse mapping has always been screwy. So the
special button is going to pop open another window. For digital mapping,
it'll let you choose a mouse button, and for analog mapping, it'll let
you choose an axis. May add in some manual joypad assignment stuff in
there for analog joypad buttons, those things are impossible to
auto-detect.
2010-10-20 22:51:19 +11:00
Tim Allen
96e9333ec2 Update to v070r06 release.
(there was no r05 release posted to the WIP thread)

byuu says:

- bsnes/phoenix uses XML for per-game cheat codes, markup is identical
  to the main database
- added clear and clear all buttons to the cheat code editor
- phoenix/GTK+ sets all child menu elements to match the parent menu font
- phoenix/Windows will draw a black canvas for the Viewport widget
  (phoenix/GTK+ still needs this)
2010-10-20 22:51:19 +11:00
Tim Allen
775c111fef Update to v070r04 release.
byuu says:

- fixed new config file input driver name (you'll have to delete your old config, or change to a different driver and back and restart)
- fixed slot loader windows' OK button placement
- fixed nall/directory.hpp when list size was zero
- rewrote nall/function.hpp, no longer requires <functional> or union tricks
- added state manager

The state manager is a little bit different this time. It's functionally
identical to bsnes/Qt, 100% of the way. But when you save slots, it
stores them in RAM. It only writes the BSA archive upon ROM unload
/ program exit. Yes, this means that technically if the emulator
crashes, you'll lose your states. But a) that very rarely happens, and
b) the old way was thrashing the disk like crazy, every letter you typed
dumped up to 8MB to disk. With this new method, I can simply store
a boolean valid flag before each slot, and pack the file better. Before,
a save on only slot 3 would be 3*state size (~1.2mb), it will now be
3bytes+state size (~400kb.) I have also added a proper signature because
of this, so it will detect when you load an archive for a previous
serializer version and ignore it. When you go to save (unload the game),
if there are no valid slots, the BSA archive gets unlinked (deleted.)

I am also planning a feature around the now-hidden "slot 0". My idea is
for it to be a fallback slot. How many times have you loaded a state
when you meant to save and said, "shit, now I lost some of my progress"?
The idea is that whenever you load a state, right before loading, it
will save to slot 0. When you unload the game, or exit the emulator, it
will also save to slot 0. You will be able to load from slot 0 from the
menu, but not save to it. It will appear at the bottom of the load list.
And lastly, I'll add an advanced option to auto-load slot 0 if it
exists, which will enable "close the emulator and restart where you left
off." functionality.
2010-10-20 22:51:19 +11:00
Tim Allen
3ffa44cef9 Add pixel shaders from the external tarball.
byuu has traditionally kept these shaders separately, but I don't see
why they shouldn't be stored alongside the code that uses them.

Unlike previous versions of pixel shaders, these are updated to use the
new file-format introduced in v070r03.
2010-10-20 22:51:19 +11:00
Tim Allen
f28d70f9e6 Update to v070r03 release.
byuu says:

- fixed a bug in xml_element::parse() with <![CDATA[...]]> tags
- merged FragmentShader and and VertexShader into Shader, which is an
  XML file that contains all relevant data
- updated Qt port to reflect the above
- added support for pixel shaders to the phoenix port
- updated all pixel shaders to use the new format
- ruby won't crash if you give an HLSL driver a GLSL shader or vice
  versa, but it will still crash on bad programs
- phoenix::Viewport has its own window class, that paints a black brush
  background

[The XML shader] format is subject to change, more specifically I may
change the <source> tag from HLSL shaders.
In the long-long term, it'd be nice to extend the format to allow
multiple shaders to be chained together and to encode base64 texture
files.
But for now, this is good enough.
2010-10-20 22:51:19 +11:00
Tim Allen
73fdbf893f Update to v070r02 release.
byuu says:

- added NTSC/PAL TV output mode selection
- added loading support for BSX Slotted, BSX, Sufami Turbo and Super
  Game Boy games
2010-10-20 22:51:18 +11:00
Tim Allen
da5263bfc3 Update to v070r01 release.
byuu says:

- phoenix supports onActivate, or return key pressed, on text boxes
- phoenix supports setGeometry() on all widgets
- input settings can now map analog axes and analog buttons
- analog button support is simplified over bsnes/Qt, and it supports the
  trigger inversion you see between Xbox 360 and Thrustmaster
  controllers
- load cartridge window lets you press enter in the path box to select
  the folder, but currently allows invalid folders (makes list empty)
- load cartridge won't reset your view if the folder doesn't change
  - this means the last ROM you loaded is highlighted the next time you
    go to load cartridge; you're welcome, FitzRoy :P
- removed quit system menu option
- added dummy controller port system menu options, there's no code
  behind them yet
- added power/reset menu options, dropped the power checkbox in favor of
  a standard power cycle option, removes unnecessary complexity
- added video mode scaling, 1x to 5x; and aspect ratio correction
- added video mode smooth toggle
- added audio settings panel with volume and input frequency adjustment
  - config file is where you can control output frequency and latency,
    they are too niche for a GUI
- fixed a realpath() crash on Linux when the bsnes binary was in /usr/bin
2010-10-20 22:51:18 +11:00
Tim Allen
449a3ad426 Update to v070 release.
byuu says:

This release represents the coup de grâce of bsnes/Qt.

Changelog:
- configuration file is now called bsnes-qt.cfg; the first run of this
  release will start with a clean state
- MSU1 now supports audio looping via new PCM file format
- disabled state load/save menu due to a serious bug in Qt 4.6.0 for
  Windows
- RawInput: all keyboards merged to KB0, it should no longer be required
  to reconfigure the keyboard out-of-the-box
- RawInput: fixed a bug where Xbox 360 controller states were being
  overwritten by DirectInput controllers
- RawInput: fixed a device sorting bug caused by moving ruby to Unicode
- Direct3D: fixed a pixel shader bug caused by moving ruby to Unicode
- Linux port: fixed sudo make install target
- Linux port: default to gcc/g++ instead of gcc-4.5/g++-4.5 for one last
  release
- updated to mightymo's 2010-09-20 cheat pack
2010-10-20 22:51:18 +11:00
180 changed files with 4560 additions and 1725 deletions

View File

@@ -1,7 +1,7 @@
include nall/Makefile
snes := snes
profile := compatibility
ui := ui-qt
profile := accuracy
ui := ui-phoenix
# compiler
c := $(compiler) -std=gnu99
@@ -62,9 +62,11 @@ endif
install:
ifeq ($(platform),x)
install -D -m 755 out/bsnes $(DESTDIR)$(prefix)/bin/bsnes
install -D -m 644 qt/data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
install -D -m 644 qt/data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
gconftool-2 --type bool --set /desktop/gnome/interface/menus_have_icons true
install -D -m 644 data/bsnes.png $(DESTDIR)$(prefix)/share/pixmaps/bsnes.png
install -D -m 644 data/bsnes.desktop $(DESTDIR)$(prefix)/share/applications/bsnes.desktop
test -d ~/.bsnes || mkdir ~/.bsnes
cp data/cheats.xml ~/.bsnes/cheats.xml
chmod 777 ~/.bsnes ~/.bsnes/cheats.xml
endif
uninstall:
@@ -88,6 +90,6 @@ clean: ui_clean
-@$(call delete,*.manifest)
archive-all:
tar -cjf bsnes.tar.bz2 launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
tar -cjf bsnes.tar.bz2 data launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
help:;

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="x86"/>
<assemblyIdentity type="win32" name="bsnes" version="1.0.0.0" processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -16,10 +16,10 @@ int main(int argc, char **argv) {
unused = realpath(nall::utf8_t(argw[0]), path);
#endif
string realPath = dir(path);
string basePath = string(dir(path), "bsnes.cfg");
string basePath = string(dir(path), "bsnes-qt.cfg");
unused = userpath(path);
if(!strend(path, "/") && !strend(path, "\\")) strcat(path, "/");
string userPath = string(path, ".bsnes/bsnes.cfg");
string userPath = string(path, ".bsnes/bsnes-qt.cfg");
configuration config;
string profile;

View File

@@ -102,7 +102,7 @@ namespace nall {
virtual bool save(const char *filename) const {
file fp;
if(fp.open(filename, file::mode_write)) {
if(fp.open(filename, file::mode::write)) {
for(unsigned i = 0; i < list.size(); i++) {
string output;
output << list[i].name << " = " << list[i].get();

View File

@@ -27,7 +27,7 @@ namespace nall {
bool import(const char *filename) {
string data;
if(data.readfile(filename) == false) return false;
data.ltrim_once("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
data.replace("\r", "");
lstring line;
@@ -43,8 +43,8 @@ namespace nall {
part[1].trim();
//remove quotes
part[0].trim_once("\"");
part[1].trim_once("\"");
part[0].trim<1>("\"");
part[1].trim<1>("\"");
unsigned n = index_input.size();
index_input[n] = part[0];

View File

@@ -16,13 +16,13 @@
namespace nall {
struct directory {
static lstring folders(const char *pathname);
static lstring files(const char *pathname);
static lstring contents(const char *pathname);
static lstring folders(const string &pathname, const string &pattern = "*");
static lstring files(const string &pathname, const string &pattern = "*");
static lstring contents(const string &pathname, const string &pattern = "*");
};
#if defined(_WIN32)
inline lstring directory::folders(const char *pathname) {
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
@@ -34,23 +34,25 @@ struct directory {
if(handle != INVALID_HANDLE_VALUE) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
list.append(string(utf8_t(data.cFileName), "/"));
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
list.append(string(utf8_t(data.cFileName), "/"));
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
}
}
}
FindClose(handle);
}
sort(&list[0], list.size());
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const char *pathname) {
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
string path = pathname;
path.transform("/", "\\");
@@ -61,27 +63,29 @@ struct directory {
handle = FindFirstFile(utf16_t(path), &data);
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
list.append(utf8_t(data.cFileName));
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
list.append(utf8_t(data.cFileName));
string name = utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
}
}
FindClose(handle);
}
sort(&list[0], list.size());
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const char *pathname) {
lstring folders = directory::folders(pathname);
lstring files = directory::files(pathname);
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
foreach(file, files) folders.append(file);
return folders;
}
#else
inline lstring directory::folders(const char *pathname) {
inline lstring directory::folders(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
@@ -90,16 +94,18 @@ struct directory {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) list.append(string(ep->d_name, "/"));
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
}
}
closedir(dp);
}
sort(&list[0], list.size());
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::files(const char *pathname) {
inline lstring directory::files(const string &pathname, const string &pattern) {
lstring list;
DIR *dp;
struct dirent *ep;
@@ -108,17 +114,19 @@ struct directory {
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if((ep->d_type & DT_DIR) == 0) list.append(ep->d_name);
if((ep->d_type & DT_DIR) == 0) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
sort(&list[0], list.size());
if(list.size() > 0) sort(&list[0], list.size());
return list;
}
inline lstring directory::contents(const char *pathname) {
lstring folders = directory::folders(pathname);
lstring files = directory::files(pathname);
inline lstring directory::contents(const string &pathname, const string &pattern) {
lstring folders = directory::folders(pathname); //pattern search of contents() should only filter files
lstring files = directory::files(pathname, pattern);
foreach(file, files) folders.append(file);
return folders;
}

View File

@@ -26,12 +26,12 @@ namespace nall {
class file {
public:
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };
enum SeekMode { seek_absolute, seek_relative };
enum class mode : unsigned { read, write, readwrite, writeread };
enum class index : unsigned { absolute, relative };
uint8_t read() {
if(!fp) return 0xff; //file not open
if(file_mode == mode_write) return 0xff; //reads not permitted
if(file_mode == mode::write) return 0xff; //reads not permitted
if(file_offset >= file_size) return 0xff; //cannot read past end of file
buffer_sync();
return buffer[(file_offset++) & buffer_mask];
@@ -59,8 +59,8 @@ namespace nall {
}
void write(uint8_t data) {
if(!fp) return; //file not open
if(file_mode == mode_read) return; //writes not permitted
if(!fp) return; //file not open
if(file_mode == mode::read) return; //writes not permitted
buffer_sync();
buffer[(file_offset++) & buffer_mask] = data;
buffer_dirty = true;
@@ -95,19 +95,19 @@ namespace nall {
fflush(fp);
}
void seek(int offset, SeekMode mode = seek_absolute) {
void seek(int offset, index index_ = index::absolute) {
if(!fp) return; //file not open
buffer_flush();
uintmax_t req_offset = file_offset;
switch(mode) {
case seek_absolute: req_offset = offset; break;
case seek_relative: req_offset += offset; break;
switch(index_) {
case index::absolute: req_offset = offset; break;
case index::relative: req_offset += offset; break;
}
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
if(req_offset > file_size) {
if(file_mode == mode_read) { //cannot seek past end of file
if(file_mode == mode::read) { //cannot seek past end of file
req_offset = file_size;
} else { //pad file to requested location
file_offset = file_size;
@@ -174,20 +174,20 @@ namespace nall {
return fp;
}
bool open(const char *fn, FileMode mode) {
bool open(const char *fn, mode mode_) {
if(fp) return false;
switch(file_mode = mode) {
switch(file_mode = mode_) {
#if !defined(_WIN32)
case mode_read: fp = fopen(fn, "rb"); break;
case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
case mode_readwrite: fp = fopen(fn, "rb+"); break;
case mode_writeread: fp = fopen(fn, "wb+"); break;
case mode::read: fp = fopen(fn, "rb"); break;
case mode::write: fp = fopen(fn, "wb+"); break; //need read permission for buffering
case mode::readwrite: fp = fopen(fn, "rb+"); break;
case mode::writeread: fp = fopen(fn, "wb+"); break;
#else
case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break;
case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode::read: fp = _wfopen(utf16_t(fn), L"rb"); break;
case mode::write: fp = _wfopen(utf16_t(fn), L"wb+"); break;
case mode::readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break;
case mode::writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break;
#endif
}
if(!fp) return false;
@@ -213,7 +213,7 @@ namespace nall {
fp = 0;
file_offset = 0;
file_size = 0;
file_mode = mode_read;
file_mode = mode::read;
}
~file() {
@@ -231,7 +231,7 @@ namespace nall {
FILE *fp;
unsigned file_offset;
unsigned file_size;
FileMode file_mode;
mode file_mode;
void buffer_sync() {
if(!fp) return; //file not open
@@ -245,14 +245,14 @@ namespace nall {
}
void buffer_flush() {
if(!fp) return; //file not open
if(file_mode == mode_read) return; //buffer cannot be written to
if(buffer_offset < 0) return; //buffer unused
if(buffer_dirty == false) return; //buffer unmodified since read
if(!fp) return; //file not open
if(file_mode == mode::read) return; //buffer cannot be written to
if(buffer_offset < 0) return; //buffer unused
if(buffer_dirty == false) return; //buffer unmodified since read
fseek(fp, buffer_offset, SEEK_SET);
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
buffer_offset = -1; //invalidate buffer
buffer_offset = -1; //invalidate buffer
buffer_dirty = false;
}
};

View File

@@ -19,14 +19,16 @@
namespace nall {
class filemap {
public:
enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread };
enum class mode : unsigned { read, write, readwrite, writeread };
bool open(const char *filename, filemode mode) { return p_open(filename, mode); }
bool opened() const { return p_opened(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); }
unsigned size() const { return p_size; }
uint8_t* handle() { return p_handle; }
const uint8_t* handle() const { return p_handle; }
uint8_t* data() { return p_handle; }
const uint8_t* data() const { return p_handle; }
filemap() : p_size(0), p_handle(0) { p_ctor(); }
filemap(const char *filename, mode mode_) : p_size(0), p_handle(0) { p_ctor(); p_open(filename, mode_); }
~filemap() { p_dtor(); }
private:
@@ -40,31 +42,35 @@ namespace nall {
HANDLE p_filehandle, p_maphandle;
bool p_open(const char *filename, filemode mode) {
bool p_opened() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
int desired_access, creation_disposition, flprotect, map_access;
switch(mode) {
switch(mode_) {
default: return false;
case mode_read:
case mode::read:
desired_access = GENERIC_READ;
creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READONLY;
map_access = FILE_MAP_READ;
break;
case mode_write:
case mode::write:
//write access requires read access
desired_access = GENERIC_WRITE;
creation_disposition = CREATE_ALWAYS;
flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS;
break;
case mode_readwrite:
case mode::readwrite:
desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = OPEN_EXISTING;
flprotect = PAGE_READWRITE;
map_access = FILE_MAP_ALL_ACCESS;
break;
case mode_writeread:
case mode::writeread:
desired_access = GENERIC_READ | GENERIC_WRITE;
creation_disposition = CREATE_NEW;
flprotect = PAGE_READWRITE;
@@ -122,30 +128,34 @@ namespace nall {
int p_fd;
bool p_open(const char *filename, filemode mode) {
bool p_opened() const {
return p_handle;
}
bool p_open(const char *filename, mode mode_) {
int open_flags, mmap_flags;
switch(mode) {
switch(mode_) {
default: return false;
case mode_read:
case mode::read:
open_flags = O_RDONLY;
mmap_flags = PROT_READ;
break;
case mode_write:
case mode::write:
open_flags = O_RDWR | O_CREAT; //mmap() requires read access
mmap_flags = PROT_WRITE;
break;
case mode_readwrite:
case mode::readwrite:
open_flags = O_RDWR;
mmap_flags = PROT_READ | PROT_WRITE;
break;
case mode_writeread:
case mode::writeread:
open_flags = O_RDWR | O_CREAT;
mmap_flags = PROT_READ | PROT_WRITE;
break;
}
p_fd = ::open(filename, open_flags);
p_fd = ::open(filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(p_fd < 0) return false;
struct stat p_stat;

View File

@@ -1,90 +1,59 @@
#ifndef NALL_FUNCTION_HPP
#define NALL_FUNCTION_HPP
#include <stdlib.h>
#include <functional>
#include <type_traits>
namespace nall {
template<typename T> class function;
template<typename R, typename... P>
class function<R (P...)> {
private:
struct base1 { virtual void func1(P...) {} };
struct base2 { virtual void func2(P...) {} };
struct derived : base1, virtual base2 {};
template<typename R, typename... P> class function<R (P...)> {
struct container {
virtual R operator()(P... p) const = 0;
virtual container* copy() const = 0;
virtual ~container() {}
} *callback;
struct data_t {
R (*callback)(const data_t&, P...);
union {
R (*callback_global)(P...);
struct {
R (derived::*callback_member)(P...);
void *object;
};
};
} data;
struct global : container {
R (*function)(P...);
R operator()(P... p) const { return function(std::forward<P>(p)...); }
container* copy() const { return new global(function); }
global(R (*function)(P...)) : function(function) {}
};
static R callback_global(const data_t &data, P... p) {
return data.callback_global(p...);
}
template<typename C> struct member : container {
R (C::*function)(P...);
C *object;
R operator()(P... p) const { return (object->*function)(std::forward<P>(p)...); }
container* copy() const { return new member(function, object); }
member(R (C::*function)(P...), C *object) : function(function), object(object) {}
};
template<typename C>
static R callback_member(const data_t &data, P... p) {
return (((C*)data.object)->*((R (C::*&)(P...))data.callback_member))(p...);
}
template<typename L> struct lambda : container {
L object;
R operator()(P... p) const { return object(std::forward<P>(p)...); }
container* copy() const { return new lambda(object); }
lambda(const L& object) : object(object) {}
};
public:
R operator()(P... p) const { return data.callback(data, p...); }
operator bool() const { return data.callback; }
void reset() { data.callback = 0; }
operator bool() const { return callback; }
R operator()(P... p) const { return (*callback)(std::forward<P>(p)...); }
void reset() { if(callback) { delete callback; callback = 0; } }
function& operator=(const function &source) {
if(this != &source) {
if(callback) { delete callback; callback = 0; }
if(source.callback) callback = source.callback->copy();
}
return *this;
}
function& operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; }
function(const function &source) { operator=(source); }
//no pointer
function() {
data.callback = 0;
}
//symbolic link pointer (nall/dl.hpp::sym, etc)
function(void *callback) {
data.callback = callback ? &callback_global : 0;
data.callback_global = (R (*)(P...))callback;
}
//global function pointer
function(R (*callback)(P...)) {
data.callback = &callback_global;
data.callback_global = callback;
}
//member function pointer
template<typename C>
function(R (C::*callback)(P...), C *object) {
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
data.callback = &callback_member<C>;
(R (C::*&)(P...))data.callback_member = callback;
data.object = object;
}
//const member function pointer
template<typename C>
function(R (C::*callback)(P...) const, C *object) {
static_assert(sizeof data.callback_member >= sizeof callback, "callback_member is too small");
data.callback = &callback_member<C>;
(R (C::*&)(P...))data.callback_member = (R (C::*&)(P...))callback;
data.object = object;
}
//lambda function pointer
template<typename T>
function(T callback) {
static_assert(std::is_same<R, typename std::result_of<T(P...)>::type>::value, "lambda mismatch");
data.callback = &callback_global;
data.callback_global = (R (*)(P...))callback;
}
function() : callback(0) {}
function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
function(R (*function)(P...)) { callback = new global(function); }
template<typename C> function(R (C::*function)(P...), C *object) { callback = new member<C>(function, object); }
template<typename C> function(R (C::*function)(P...) const, C *object) { callback = new member<C>((R (C::*)(P...))function, object); }
template<typename L> function(const L& object) { callback = new lambda<L>(object); }
~function() { if(callback) delete callback; }
};
}

View File

@@ -112,6 +112,7 @@ namespace nall {
imode = Size;
idata = 0;
isize = 0;
icapacity = 0;
}
serializer(unsigned capacity) {

View File

@@ -9,7 +9,7 @@ public:
inline snes_information(const uint8_t *data, unsigned size);
private:
//private:
inline void read_header(const uint8_t *data, unsigned size);
inline unsigned find_header(const uint8_t *data, unsigned size);
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);

View File

@@ -2,6 +2,7 @@
#define NALL_STRING_HPP
#include <initializer_list>
#include <nall/platform.hpp>
#include <nall/utility.hpp>
#include <nall/string/base.hpp>
@@ -13,6 +14,7 @@
#include <nall/string/filename.hpp>
#include <nall/string/match.hpp>
#include <nall/string/math.hpp>
#include <nall/string/platform.hpp>
#include <nall/string/strl.hpp>
#include <nall/string/strpos.hpp>
#include <nall/string/trim.hpp>
@@ -20,6 +22,7 @@
#include <nall/string/split.hpp>
#include <nall/string/utility.hpp>
#include <nall/string/variadic.hpp>
#include <nall/string/wrapper.hpp>
#include <nall/string/xml.hpp>
namespace nall {

View File

@@ -17,7 +17,6 @@ namespace nall {
class string {
public:
inline void reserve(unsigned);
inline unsigned length() const;
inline string& assign(const char*);
inline string& append(const char*);
@@ -26,6 +25,35 @@ namespace nall {
inline string& append(unsigned int value);
inline string& append(double value);
inline bool readfile(const char*);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
inline unsigned length() const;
inline bool equals(const char*) const;
inline bool iequals(const char*) const;
inline bool wildcard(const char*) const;
inline bool iwildcard(const char*) const;
inline bool beginswith(const char*) const;
inline bool ibeginswith(const char*) const;
inline bool endswith(const char*) const;
inline bool iendswith(const char*) const;
inline string& lower();
inline string& upper();
inline string& transform(const char *before, const char *after);
template<unsigned limit = 0> inline string& ltrim(const char *key = " ");
template<unsigned limit = 0> inline string& rtrim(const char *key = " ");
template<unsigned limit = 0> inline string& trim (const char *key = " ");
inline optional<unsigned> position(const char *key) const;
inline optional<unsigned> qposition(const char *key) const;
template<typename T> inline string& operator= (T value);
template<typename T> inline string& operator<<(T value);
@@ -48,20 +76,6 @@ namespace nall {
inline string(string&&);
inline ~string();
inline bool readfile(const char*);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
inline string& lower();
inline string& upper();
inline string& transform(const char *before, const char *after);
inline string& ltrim(const char *key = " ");
inline string& rtrim(const char *key = " ");
inline string& trim (const char *key = " ");
inline string& ltrim_once(const char *key = " ");
inline string& rtrim_once(const char *key = " ");
inline string& trim_once (const char *key = " ");
protected:
char *data;
unsigned size;
@@ -76,9 +90,9 @@ namespace nall {
public:
template<typename T> inline lstring& operator<<(T value);
inline optional<unsigned> find(const char*);
inline void split (const char*, const char*, unsigned = 0);
inline void qsplit(const char*, const char*, unsigned = 0);
inline optional<unsigned> find(const char*) const;
template<unsigned limit = 0> inline void split (const char*, const char*);
template<unsigned limit = 0> inline void qsplit(const char*, const char*);
lstring();
lstring(std::initializer_list<string>);
@@ -87,7 +101,9 @@ namespace nall {
//compare.hpp
inline char chrlower(char c);
inline char chrupper(char c);
inline int stricmp(const char *dest, const char *src);
inline int stricmp(const char *str1, const char *str2);
inline bool wildcard(const char *str, const char *pattern);
inline bool iwildcard(const char *str, const char *pattern);
inline bool strbegin (const char *str, const char *key);
inline bool stribegin(const char *str, const char *key);
inline bool strend (const char *str, const char *key);
@@ -110,23 +126,28 @@ namespace nall {
inline bool strint (const char *str, int &result);
inline bool strmath(const char *str, int &result);
//platform.hpp
inline string realpath(const char *name);
inline string userpath();
inline string currentpath();
//strl.hpp
inline unsigned strlcpy(char *dest, const char *src, unsigned length);
inline unsigned strlcat(char *dest, const char *src, unsigned length);
//strpos.hpp
inline optional<unsigned> strpos(const char *str, const char *key);
inline optional<unsigned> qstrpos(const char *str, const char *key);
//trim.hpp
inline char* ltrim(char *str, const char *key = " ");
inline char* rtrim(char *str, const char *key = " ");
inline char* trim (char *str, const char *key = " ");
inline char* ltrim_once(char *str, const char *key = " ");
inline char* rtrim_once(char *str, const char *key = " ");
inline char* trim_once (char *str, const char *key = " ");
template<unsigned limit = 0> inline char* ltrim(char *str, const char *key = " ");
template<unsigned limit = 0> inline char* rtrim(char *str, const char *key = " ");
template<unsigned limit = 0> inline char* trim (char *str, const char *key = " ");
//utility.hpp
inline unsigned strlcpy(string &dest, const char *src, unsigned length);
inline unsigned strlcat(string &dest, const char *src, unsigned length);
inline string substr(const char *src, unsigned start = 0, unsigned length = 0);
inline string& strtr(string &dest, const char *before, const char *after);
template<unsigned length = 0, char padding = '0'> inline string strhex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strsigned(intmax_t value);
template<unsigned length = 0, char padding = '0'> inline string strunsigned(uintmax_t value);

View File

@@ -11,14 +11,52 @@ char chrupper(char c) {
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
int stricmp(const char *dest, const char *src) {
while(*dest) {
if(chrlower(*dest) != chrlower(*src)) break;
dest++;
src++;
int stricmp(const char *str1, const char *str2) {
while(*str1) {
if(chrlower(*str1) != chrlower(*str2)) break;
str1++, str2++;
}
return (int)chrlower(*str1) - (int)chrlower(*str2);
}
return (int)chrlower(*dest) - (int)chrlower(*src);
bool wildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && *s != *p) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || *p == *s) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool iwildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool strbegin(const char *str, const char *key) {

View File

@@ -40,10 +40,6 @@ char* strtr(char *dest, const char *before, const char *after) {
return dest;
}
string& string::lower() { nall::strlower(data); return *this; }
string& string::upper() { nall::strupper(data); return *this; }
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
uintmax_t strhex(const char *str) {
if(!str) return 0;
uintmax_t result = 0;

View File

@@ -11,10 +11,6 @@ void string::reserve(unsigned size_) {
}
}
unsigned string::length() const {
return strlen(data);
}
string& string::assign(const char *s) {
unsigned length = strlen(s);
reserve(length);
@@ -122,7 +118,7 @@ bool string::readfile(const char *filename) {
return true;
}
optional<unsigned> lstring::find(const char *key) {
optional<unsigned> lstring::find(const char *key) const {
for(unsigned i = 0; i < size(); i++) {
if(operator[](i) == key) return { true, i };
}

View File

@@ -3,7 +3,9 @@
namespace nall {
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
// "foo/bar.c" -> "foo/"
// "foo/" -> "foo/"
// "bar.c" -> "./"
inline string dir(char const *name) {
string result = name;
for(signed i = strlen(result); i >= 0; i--) {

41
bsnes/nall/string/platform.hpp Executable file
View File

@@ -0,0 +1,41 @@
#ifndef NALL_STRING_PLATFORM_HPP
#define NALL_STRING_PLATFORM_HPP
namespace nall {
string realpath(const char *name) {
char path[PATH_MAX];
if(::realpath(name, path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
string userpath() {
char path[PATH_MAX];
if(::userpath(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
string currentpath() {
char path[PATH_MAX];
if(::getcwd(path)) {
string result(path);
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
return "";
}
}
#endif

View File

@@ -3,7 +3,8 @@
namespace nall {
void lstring::split(const char *key, const char *src, unsigned limit) {
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
unsigned limit = Limit;
reset();
int ssl = strlen(src), ksl = strlen(key);
@@ -21,7 +22,8 @@ void lstring::split(const char *key, const char *src, unsigned limit) {
operator[](split_count++) = src + lp;
}
void lstring::qsplit(const char *key, const char *src, unsigned limit) {
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
unsigned limit = Limit;
reset();
int ssl = strlen(src), ksl = strlen(key);

View File

@@ -7,7 +7,7 @@
namespace nall {
inline optional<unsigned> strpos(const char *str, const char *key) {
optional<unsigned> strpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 };
@@ -18,7 +18,7 @@ inline optional<unsigned> strpos(const char *str, const char *key) {
return { false, 0 };
}
inline optional<unsigned> qstrpos(const char *str, const char *key) {
optional<unsigned> qstrpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 };

View File

@@ -3,7 +3,9 @@
namespace nall {
char* ltrim(char *str, const char *key) {
//limit defaults to zero, which will underflow on first compare; equivalent to no limit
template<unsigned Limit> char* ltrim(char *str, const char *key) {
unsigned limit = Limit;
if(!key || !*key) return str;
while(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
@@ -12,50 +14,25 @@ char* ltrim(char *str, const char *key) {
if(!*dest) break;
dest++;
}
if(--limit == 0) break;
}
return str;
}
char* rtrim(char *str, const char *key) {
template<unsigned Limit> char* rtrim(char *str, const char *key) {
unsigned limit = Limit;
if(!key || !*key) return str;
while(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
return str;
}
char* trim(char *str, const char *key) {
return ltrim(rtrim(str, key), key);
}
char* ltrim_once(char *str, const char *key) {
if(!key || !*key) return str;
if(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
while(strend(str, key)) {
str[strlen(str) - strlen(key)] = 0;
if(--limit == 0) break;
}
return str;
}
char* rtrim_once(char *str, const char *key) {
if(!key || !*key) return str;
if(strend(str, key)) str[strlen(str) - strlen(key)] = 0;
return str;
template<unsigned limit> char* trim(char *str, const char *key) {
return ltrim<limit>(rtrim<limit>(str, key), key);
}
char* trim_once(char *str, const char *key) {
return ltrim_once(rtrim_once(str, key), key);
}
string& string::ltrim(const char *key) { nall::ltrim(data, key); return *this; }
string& string::rtrim(const char *key) { nall::rtrim(data, key); return *this; }
string& string::trim (const char *key) { nall::trim (data, key); return *this; }
string& string::ltrim_once(const char *key) { nall::ltrim_once(data, key); return *this; }
string& string::rtrim_once(const char *key) { nall::rtrim_once(data, key); return *this; }
string& string::trim_once (const char *key) { nall::trim_once (data, key); return *this; }
}
#endif

33
bsnes/nall/string/wrapper.hpp Executable file
View File

@@ -0,0 +1,33 @@
#ifndef NALL_STRING_WRAPPER_HPP
#define NALL_STRING_WRAPPER_HPP
namespace nall {
unsigned string::length() const { return strlen(data); }
bool string::equals(const char *str) const { return !strcmp(data, str); }
bool string::iequals(const char *str) const { return !stricmp(data, str); }
bool string::wildcard(const char *str) const { return nall::wildcard(data, str); }
bool string::iwildcard(const char *str) const { return nall::iwildcard(data, str); }
bool string::beginswith(const char *str) const { return strbegin(data, str); }
bool string::ibeginswith(const char *str) const { return stribegin(data, str); }
bool string::endswith(const char *str) const { return strend(data, str); }
bool string::iendswith(const char *str) const { return striend(data, str); }
string& string::lower() { nall::strlower(data); return *this; }
string& string::upper() { nall::strupper(data); return *this; }
string& string::transform(const char *before, const char *after) { nall::strtr(data, before, after); return *this; }
template<unsigned limit> string& string::ltrim(const char *key) { nall::ltrim<limit>(data, key); return *this; }
template<unsigned limit> string& string::rtrim(const char *key) { nall::rtrim<limit>(data, key); return *this; }
template<unsigned limit> string& string::trim (const char *key) { nall::trim <limit>(data, key); return *this; }
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
}
#endif

View File

@@ -75,11 +75,12 @@ inline string xml_element::parse() const {
if(strbegin(source, "<![CDATA[")) {
if(auto pos = strpos(source, "]]>")) {
string cdata = substr(source, 9, pos() - 9);
data << cdata;
offset += strlen(cdata);
source += offset + 3;
if(pos() - 9 > 0) {
string cdata = substr(source, 9, pos() - 9);
data << cdata;
offset += strlen(cdata);
}
source += 9 + offset + 3;
continue;
} else {
return "";
@@ -138,8 +139,8 @@ inline bool xml_element::parse_head(string data) {
xml_attribute attr;
attr.name = side[0];
attr.content = side[1];
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim_once("\"");
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim_once("'");
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
else throw "...";
attribute.append(attr);
}
@@ -185,10 +186,10 @@ inline bool xml_element::parse_body(const char *&data) {
if(strend(tag, "?") == true) {
self_terminating = true;
tag.rtrim_once("?");
tag.rtrim<1>("?");
} else if(strend(tag, "/") == true) {
self_terminating = true;
tag.rtrim_once("/");
tag.rtrim<1>("/");
}
parse_head(tag);

View File

@@ -1,190 +1,221 @@
#ifndef NALL_UPS_HPP
#define NALL_UPS_HPP
#include <stdio.h>
#include <nall/algorithm.hpp>
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/stdint.hpp>
namespace nall {
class ups {
public:
enum result {
ok,
patch_unreadable,
patch_unwritable,
patch_invalid,
input_invalid,
output_invalid,
patch_crc32_invalid,
input_crc32_invalid,
output_crc32_invalid,
};
ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) {
if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable;
struct ups {
enum class result : unsigned {
unknown,
success,
patch_unwritable,
patch_invalid,
source_invalid,
target_invalid,
target_too_small,
patch_checksum_invalid,
source_checksum_invalid,
target_checksum_invalid,
};
crc32 = ~0;
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
function<void (unsigned offset, unsigned length)> progress;
//header
write('U');
write('P');
write('S');
write('1');
encptr(x_size);
encptr(y_size);
result create(
const uint8_t *sourcedata, unsigned sourcelength,
const uint8_t *targetdata, unsigned targetlength,
const char *patchfilename
) {
source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata;
source_length = sourcelength, target_length = targetlength;
source_offset = target_offset = 0;
source_checksum = target_checksum = patch_checksum = ~0;
//body
unsigned max_size = max(x_size, y_size);
unsigned relative = 0;
for(unsigned i = 0; i < max_size;) {
uint8_t x = i < x_size ? x_data[i] : 0x00;
uint8_t y = i < y_size ? y_data[i] : 0x00;
if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable;
if(x == y) {
i++;
continue;
}
patch_write('U');
patch_write('P');
patch_write('S');
patch_write('1');
encode(source_length);
encode(target_length);
encptr(i++ - relative);
write(x ^ y);
unsigned output_length = source_length > target_length ? source_length : target_length;
unsigned relative = 0;
for(unsigned offset = 0; offset < output_length;) {
uint8_t x = source_read();
uint8_t y = target_read();
while(true) {
if(i >= max_size) {
write(0x00);
break;
}
x = i < x_size ? x_data[i] : 0x00;
y = i < y_size ? y_data[i] : 0x00;
i++;
write(x ^ y);
if(x == y) break;
}
relative = i;
if(x == y) {
offset++;
continue;
}
//footer
for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3));
for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3));
uint32_t p_crc32 = ~crc32;
for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3));
encode(offset++ - relative);
patch_write(x ^ y);
fp.close();
return ok;
}
ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) {
if(p_size < 18) return patch_invalid;
p_buffer = p_data;
crc32 = ~0;
//header
if(read() != 'U') return patch_invalid;
if(read() != 'P') return patch_invalid;
if(read() != 'S') return patch_invalid;
if(read() != '1') return patch_invalid;
unsigned px_size = decptr();
unsigned py_size = decptr();
//mirror
if(x_size != px_size && x_size != py_size) return input_invalid;
y_size = (x_size == px_size) ? py_size : px_size;
y_data = new uint8_t[y_size]();
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;
//body
unsigned relative = 0;
while(p_buffer < p_data + p_size - 12) {
relative += decptr();
while(true) {
uint8_t x = read();
if(x && relative < y_size) {
uint8_t y = relative < x_size ? x_data[relative] : 0x00;
y_data[relative] = x ^ y;
}
relative++;
if(!x) break;
}
}
//footer
unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0;
for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3);
for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3);
uint32_t p_crc32 = ~crc32;
for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3);
uint32_t x_crc32 = crc32_calculate(x_data, x_size);
uint32_t y_crc32 = crc32_calculate(y_data, y_size);
if(px_size != py_size) {
if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid;
if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid;
if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid;
if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid;
} else {
if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid;
if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid;
if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid;
if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid;
}
if(p_crc32 != pp_crc32) return patch_crc32_invalid;
return ok;
}
private:
file fp;
uint32_t crc32;
const uint8_t *p_buffer;
uint8_t read() {
uint8_t n = *p_buffer++;
crc32 = crc32_adjust(crc32, n);
return n;
}
void write(uint8_t n) {
fp.write(n);
crc32 = crc32_adjust(crc32, n);
}
void encptr(uint64_t offset) {
while(true) {
uint64_t x = offset & 0x7f;
offset >>= 7;
if(offset == 0) {
write(0x80 | x);
if(offset >= output_length) {
patch_write(0x00);
break;
}
write(x);
offset--;
x = source_read();
y = target_read();
offset++;
patch_write(x ^ y);
if(x == y) break;
}
relative = offset;
}
source_checksum = ~source_checksum;
target_checksum = ~target_checksum;
for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8));
for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8));
uint32_t patch_result_checksum = ~patch_checksum;
for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8));
patch_file.close();
return result::success;
}
result apply(
const uint8_t *patchdata, unsigned patchlength,
const uint8_t *sourcedata, unsigned sourcelength,
uint8_t *targetdata, unsigned &targetlength
) {
patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata;
patch_length = patchlength, source_length = sourcelength, target_length = targetlength;
patch_offset = source_offset = target_offset = 0;
patch_checksum = source_checksum = target_checksum = ~0;
if(patch_length < 18) return result::patch_invalid;
if(patch_read() != 'U') return result::patch_invalid;
if(patch_read() != 'P') return result::patch_invalid;
if(patch_read() != 'S') return result::patch_invalid;
if(patch_read() != '1') return result::patch_invalid;
unsigned source_read_length = decode();
unsigned target_read_length = decode();
if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid;
targetlength = (source_length == source_read_length ? target_read_length : source_read_length);
if(target_length < targetlength) return result::target_too_small;
target_length = targetlength;
while(patch_offset < patch_length - 12) {
unsigned length = decode();
while(length--) target_write(source_read());
while(true) {
uint8_t patch_xor = patch_read();
target_write(patch_xor ^ source_read());
if(patch_xor == 0) break;
}
}
uint64_t decptr() {
uint64_t offset = 0, shift = 1;
while(true) {
uint8_t x = read();
offset += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
offset += shift;
}
return offset;
uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0;
for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8);
for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8);
uint32_t patch_result_checksum = ~patch_checksum;
source_checksum = ~source_checksum;
target_checksum = ~target_checksum;
for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8);
if(patch_result_checksum != patch_read_checksum) return result::patch_invalid;
if(source_checksum == source_read_checksum && source_length == source_read_length) {
if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success;
return result::target_invalid;
} else if(source_checksum == target_read_checksum && source_length == target_read_length) {
if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success;
return result::target_invalid;
} else {
return result::source_invalid;
}
};
}
private:
uint8_t *patch_data, *source_data, *target_data;
unsigned patch_length, source_length, target_length;
unsigned patch_offset, source_offset, target_offset;
unsigned patch_checksum, source_checksum, target_checksum;
file patch_file;
uint8_t patch_read() {
if(patch_offset < patch_length) {
uint8_t n = patch_data[patch_offset++];
patch_checksum = crc32_adjust(patch_checksum, n);
return n;
}
return 0x00;
}
uint8_t source_read() {
if(source_offset < source_length) {
uint8_t n = source_data[source_offset++];
source_checksum = crc32_adjust(source_checksum, n);
return n;
}
return 0x00;
}
uint8_t target_read() {
uint8_t result = 0x00;
if(target_offset < target_length) {
result = target_data[target_offset];
target_checksum = crc32_adjust(target_checksum, result);
}
if(((target_offset++ & 255) == 0) && progress) {
progress(target_offset, source_length > target_length ? source_length : target_length);
}
return result;
}
void patch_write(uint8_t n) {
patch_file.write(n);
patch_checksum = crc32_adjust(patch_checksum, n);
}
void target_write(uint8_t n) {
if(target_offset < target_length) {
target_data[target_offset] = n;
target_checksum = crc32_adjust(target_checksum, n);
}
if(((target_offset++ & 255) == 0) && progress) {
progress(target_offset, source_length > target_length ? source_length : target_length);
}
}
void encode(uint64_t offset) {
while(true) {
uint64_t x = offset & 0x7f;
offset >>= 7;
if(offset == 0) {
patch_write(0x80 | x);
break;
}
patch_write(x);
offset--;
}
}
uint64_t decode() {
uint64_t offset = 0, shift = 1;
while(true) {
uint8_t x = patch_read();
offset += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
offset += shift;
}
return offset;
}
};
}
#endif

View File

@@ -2,8 +2,9 @@ static void Button_tick(Button *self) {
if(self->onTick) self->onTick();
}
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_button_new_with_label(text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@@ -22,6 +22,7 @@ void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi
canvas->pitch = width * sizeof(uint32_t);
object->widget = gtk_drawing_area_new();
widget->parent = &parent;
GdkColor color;
color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);

View File

@@ -2,8 +2,9 @@ static void CheckBox_tick(CheckBox *self) {
if(self->onTick && self->object->locked == false) self->onTick();
}
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_check_button_new_with_label(text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);

View File

@@ -2,8 +2,9 @@ void ComboBox_change(ComboBox *self) {
if(self->object->locked == false && self->onChange) self->onChange();
}
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_combo_box_new_text();
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);
@@ -27,7 +28,7 @@ void ComboBox::reset() {
counter = 0;
}
void ComboBox::addItem(const char *text) {
void ComboBox::addItem(const string &text) {
gtk_combo_box_append_text(GTK_COMBO_BOX(object->widget), text);
if(counter++ == 0) setSelection(0);
}

View File

@@ -2,8 +2,9 @@ static void EditBox_change(EditBox *self) {
if(self->object->locked == false && self->onChange) self->onChange();
}
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_scrolled_window_new(0, 0);
widget->parent = &parent;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
gtk_widget_set_size_request(object->widget, width, height);
@@ -41,7 +42,7 @@ string EditBox::text() {
return text;
}
void EditBox::setText(const char *text) {
void EditBox::setText(const string &text) {
object->locked = true;
gtk_text_buffer_set_text(object->textBuffer, text, -1);
object->locked = false;

View File

@@ -1,4 +1,4 @@
bool Font::create(const char *name, unsigned size, Font::Style style) {
bool Font::create(const string &name, unsigned size, Font::Style style) {
font->font = pango_font_description_new();
pango_font_description_set_family(font->font, name);
pango_font_description_set_size(font->font, size * PANGO_SCALE);

View File

@@ -37,12 +37,30 @@ namespace phoenix {
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
Window Window::None;
OS& OS::handle() {
static OS os;
return os;
void OS::initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
int argc = 1;
char *argv[2];
argv[0] = new char[8];
argv[1] = 0;
strcpy(argv[0], "phoenix");
char **argvp = argv;
gtk_init(&argc, &argvp);
gtk_rc_parse_string(
"style \"phoenix-gtk\"\n"
"{\n"
" GtkComboBox::appears-as-list = 1\n"
" GtkTreeView::vertical-separator = 0\n"
"}\n"
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
);
}
bool OS::pending() {
@@ -69,7 +87,7 @@ unsigned OS::desktopHeight() {
return gdk_screen_get_height(gdk_screen_get_default());
}
string OS::folderSelect(Window &parent, const char *path) {
string OS::folderSelect(Window &parent, const string &path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
@@ -90,10 +108,11 @@ string OS::folderSelect(Window &parent, const char *path) {
}
gtk_widget_destroy(dialog);
if(name.endswith("/") == false) name.append("/");
return name;
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
@@ -130,7 +149,7 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
return name;
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string OS::fileSave(Window &parent, const string &filter, const string &path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
@@ -167,25 +186,4 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
return name;
}
OS::OS() {
os = new OS::Data;
int argc = 1;
char *argv[2];
argv[0] = new char[8];
argv[1] = 0;
strcpy(argv[0], "phoenix");
char **argvp = argv;
gtk_init(&argc, &argvp);
gtk_rc_parse_string(
"style \"phoenix-gtk\"\n"
"{\n"
" GtkComboBox::appears-as-list = 1\n"
" GtkTreeView::vertical-separator = 0\n"
"}\n"
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
);
}
}

View File

@@ -12,13 +12,20 @@ struct Object {
Data *object;
};
struct Geometry {
unsigned x, y;
unsigned width, height;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
};
struct Font : Object {
enum class Style : unsigned {
None = 0,
Bold = 1,
Italic = 2,
};
bool create(const char *name, unsigned size, Font::Style style = Style::None);
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
Font();
~Font();
//private:
@@ -30,16 +37,19 @@ inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
struct Action : Object {
void setFont(Font &font);
bool visible();
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
Action();
//private:
struct Data;
Data *action;
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
void create(Window &parent, const nall::string &text);
void create(Menu &parent, const nall::string &text);
};
struct MenuSeparator : Action {
@@ -48,20 +58,20 @@ struct MenuSeparator : Action {
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
};
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
bool checked();
void setChecked(bool checked = true);
};
struct MenuRadioItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(MenuRadioItem &parent, const char *text);
void create(Menu &parent, const nall::string &text);
void create(MenuRadioItem &parent, const nall::string &text);
bool checked();
void setChecked();
private:
@@ -76,31 +86,37 @@ struct Widget : Object {
void setEnabled(bool enabled = true);
virtual bool focused();
virtual void setFocused();
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
Widget();
//private:
struct Data;
Data *widget;
};
struct Window : Widget {
static Window None;
nall::function<bool ()> onClose;
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool focused();
void setFocused();
Geometry geometry();
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
void setDefaultFont(Font &font);
void setFont(Font &font);
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setTitle(const char *text);
void setStatusText(const char *text);
void setTitle(const nall::string &text);
void setStatusText(const nall::string &text);
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
Window();
//private:
struct Data;
Data *window;
static Window None;
};
struct Button : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
};
struct Canvas : Widget {
@@ -116,16 +132,16 @@ struct Canvas : Widget {
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked(bool checked = true);
};
struct ComboBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void reset();
void addItem(const char *text);
void addItem(const nall::string &text);
unsigned selection();
void setSelection(unsigned item);
ComboBox();
@@ -135,12 +151,12 @@ private:
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setFocused();
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const char *text);
void setText(const nall::string &text);
};
struct HorizontalSlider : Widget {
@@ -151,21 +167,25 @@ struct HorizontalSlider : Widget {
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *text);
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setText(const nall::string &text);
};
struct ListBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::function<void (unsigned)> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setFocused();
void setHeaderVisible(bool headerVisible = true);
void setCheckable(bool checkable = true);
void setFont(Font &font);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
void addItem(const nall::string &text);
void setItem(unsigned row, const nall::string &text);
bool checked(unsigned row);
void setChecked(unsigned row, bool checked = true);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
@@ -176,13 +196,13 @@ struct ListBox : Widget {
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setProgress(unsigned progress);
void setPosition(unsigned position);
};
struct RadioBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked();
private:
@@ -190,11 +210,12 @@ private:
};
struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setEditable(bool editable = true);
nall::string text();
void setText(const char *text);
void setText(const nall::string &text);
};
struct VerticalSlider : Widget {
@@ -221,30 +242,24 @@ struct MessageWindow : Object {
Yes,
No,
};
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
};
struct OS : Object {
bool pending();
void run();
void main();
void quit();
unsigned desktopWidth();
unsigned desktopHeight();
nall::string folderSelect(Window &parent, const char *path = "");
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
static bool pending();
static void run();
static void main();
static void quit();
static unsigned desktopWidth();
static unsigned desktopHeight();
static nall::string folderSelect(Window &parent, const nall::string &path = "");
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
//private:
static OS& handle();
struct Data;
Data *os;
private:
OS();
static void initialize();
};
extern OS &os;
}

View File

@@ -8,6 +8,7 @@ void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned w
object->position = 0;
length += (length == 0);
object->widget = gtk_hscale_new_with_range(0, length - 1, 1);
widget->parent = &parent;
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this);

View File

@@ -1,5 +1,6 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_label_new(text);
widget->parent = &parent;
gtk_misc_set_alignment(GTK_MISC(object->widget), 0.0, 0.5);
gtk_widget_set_size_request(object->widget, width, height);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
@@ -7,6 +8,6 @@ void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsig
gtk_widget_show(object->widget);
}
void Label::setText(const char *text) {
void Label::setText(const string &text) {
gtk_label_set_text(GTK_LABEL(object->widget), text);
}

View File

@@ -1,3 +1,10 @@
static void ListBox_activate(ListBox *self) {
signed selection = -1;
if(auto position = self->selection()) selection = position();
self->listBox->selection = selection;
if(self->onActivate) self->onActivate();
}
static void ListBox_change(ListBox *self) {
signed selection = -1;
if(auto position = self->selection()) selection = position();
@@ -6,25 +13,25 @@ static void ListBox_change(ListBox *self) {
if(self->onChange) self->onChange();
}
static void ListBox_activate(ListBox *self) {
signed selection = -1;
if(auto position = self->selection()) selection = position();
self->listBox->selection = selection;
if(self->onActivate) self->onActivate();
static void ListBox_tick(GtkCellRendererToggle *cell, gchar *path_string, ListBox *self) {
unsigned index = strunsigned(path_string);
self->setChecked(index, !self->checked(index));
if(self->onTick) self->onTick(index);
}
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
listBox->selection = -1;
object->widget = gtk_scrolled_window_new(0, 0);
widget->parent = &parent;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
gtk_widget_set_size_request(object->widget, width, height);
lstring list;
list.split("\t", text);
list.split("\t", string("\t", text));
GType *v = (GType*)malloc(list.size() * sizeof(GType));
for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING;
for(unsigned i = 0; i < list.size(); i++) v[i] = (i == 0 ? G_TYPE_BOOLEAN : G_TYPE_STRING);
listBox->store = gtk_list_store_newv(list.size(), v);
free(v);
@@ -32,20 +39,30 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
g_object_unref(G_OBJECT(listBox->store));
//alternate color of each row if there is more than one column
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 2);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false);
for(unsigned i = 0; i < list.size(); i++) {
listBox->column[i].renderer = gtk_cell_renderer_text_new();
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
list[i], listBox->column[i].renderer, "text", i, (void*)0
);
if(i == 0) {
listBox->column[i].renderer = gtk_cell_renderer_toggle_new();
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
"", listBox->column[i].renderer, "active", i, (void*)0
);
gtk_tree_view_column_set_resizable(listBox->column[i].column, false);
gtk_tree_view_column_set_visible(listBox->column[i].column, listBox->checkable);
g_signal_connect(listBox->column[i].renderer, "toggled", G_CALLBACK(ListBox_tick), (gpointer)this);
} else {
listBox->column[i].renderer = gtk_cell_renderer_text_new();
listBox->column[i].column = gtk_tree_view_column_new_with_attributes(
"", listBox->column[i].renderer, "text", i, (void*)0
);
gtk_tree_view_column_set_resizable(listBox->column[i].column, true);
}
listBox->column[i].label = gtk_label_new(list[i]);
gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(listBox->column[i].column), listBox->column[i].label);
gtk_tree_view_append_column(GTK_TREE_VIEW(object->subWidget), listBox->column[i].column);
gtk_widget_show(listBox->column[i].label);
}
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false);
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 3); //>= 2 + one for the checkbox column
gtk_tree_view_set_search_column(GTK_TREE_VIEW(object->subWidget), 1);
g_signal_connect_swapped(G_OBJECT(object->subWidget), "cursor-changed", G_CALLBACK(ListBox_change), (gpointer)this);
g_signal_connect_swapped(G_OBJECT(object->subWidget), "row-activated", G_CALLBACK(ListBox_activate), (gpointer)this);
@@ -64,6 +81,11 @@ void ListBox::setHeaderVisible(bool visible) {
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), visible);
}
void ListBox::setCheckable(bool checkable) {
listBox->checkable = checkable;
if(object->subWidget) gtk_tree_view_column_set_visible(listBox->column[0].column, checkable);
}
void ListBox::setFont(Font &font) {
Widget::setFont(font);
unsigned columns = 1;
@@ -89,17 +111,16 @@ void ListBox::resizeColumnsToContent() {
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(object->subWidget));
}
void ListBox::addItem(const char *text) {
void ListBox::addItem(const string &text) {
lstring list;
list.split("\t", text);
GtkTreeIter iter;
gtk_list_store_append(listBox->store, &iter);
for(unsigned i = 0; i < list.size(); i++) {
gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1);
}
unsigned index = 1;
foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1);
}
void ListBox::setItem(unsigned row, const char *text) {
void ListBox::setItem(unsigned row, const string &text) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
GtkTreeIter iter;
for(unsigned i = 0; i <= row; i++) {
@@ -109,9 +130,28 @@ void ListBox::setItem(unsigned row, const char *text) {
lstring list;
list.split("\t", text);
for(unsigned i = 0; i < list.size(); i++) {
gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1);
}
unsigned index = 1;
foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1);
}
bool ListBox::checked(unsigned row) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
GtkTreeIter iter;
bool state;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, 0, &state, -1);
gtk_tree_path_free(path);
return state;
}
void ListBox::setChecked(unsigned row, bool checked) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
GtkTreeIter iter;
gtk_tree_model_get_iter(model, &iter, path);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1);
gtk_tree_path_free(path);
}
optional<unsigned> ListBox::selection() {
@@ -151,4 +191,5 @@ void ListBox::setSelection(unsigned row) {
ListBox::ListBox() {
listBox = new ListBox::Data;
listBox->checkable = false;
}

View File

@@ -1,14 +1,12 @@
static void Action_setFont(GtkWidget *widget, gpointer font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, font);
if(font) {
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) {
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, (PangoFontDescription*)font);
}
}
}
void Action::setFont(Font &font) {
Action_setFont(object->widget, font.font->font);
}
bool Action::visible() {
return gtk_widget_get_visible(object->widget);
}
@@ -25,25 +23,35 @@ void Action::setEnabled(bool enabled) {
gtk_widget_set_sensitive(object->widget, enabled);
}
void Menu::create(Window &parent, const char *text) {
Action::Action() {
action = new Action::Data;
action->font = 0;
}
void Menu::create(Window &parent, const string &text) {
action->font = parent.window->defaultFont;
object->menu = gtk_menu_new();
object->widget = gtk_menu_item_new_with_label(text);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_bar_append(parent.object->menu, object->widget);
gtk_widget_show(object->widget);
}
void Menu::create(Menu &parent, const char *text) {
void Menu::create(Menu &parent, const string &text) {
action->font = parent.action->font;
object->menu = gtk_menu_new();
object->widget = gtk_menu_item_new_with_label(text);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
void MenuSeparator::create(Menu &parent) {
action->font = parent.action->font;
object->widget = gtk_separator_menu_item_new();
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@@ -52,9 +60,11 @@ static void MenuItem_tick(MenuItem *self) {
if(self->onTick) self->onTick();
}
void MenuItem::create(Menu &parent, const char *text) {
void MenuItem::create(Menu &parent, const string &text) {
action->font = parent.action->font;
object->widget = gtk_menu_item_new_with_label(text);
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(MenuItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@@ -63,9 +73,11 @@ static void MenuCheckItem_tick(MenuCheckItem *self) {
if(self->onTick && self->object->locked == false) self->onTick();
}
void MenuCheckItem::create(Menu &parent, const char *text) {
void MenuCheckItem::create(Menu &parent, const string &text) {
action->font = parent.action->font;
object->widget = gtk_check_menu_item_new_with_label(text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuCheckItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
@@ -84,20 +96,24 @@ static void MenuRadioItem_tick(MenuRadioItem *self) {
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
}
void MenuRadioItem::create(Menu &parent, const char *text) {
void MenuRadioItem::create(Menu &parent, const string &text) {
first = this;
action->font = parent.action->font;
object->parentMenu = &parent;
object->widget = gtk_radio_menu_item_new_with_label(0, text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
gtk_widget_show(object->widget);
}
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
first = parent.first;
action->font = parent.action->font;
object->parentMenu = parent.object->parentMenu;
object->widget = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(first->object->widget), text);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
if(action->font) Action_setFont(object->widget, action->font->font->font);
gtk_menu_shell_append(GTK_MENU_SHELL(object->parentMenu->object->menu), object->widget);
gtk_widget_show(object->widget);
}

View File

@@ -8,56 +8,56 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", text
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
}
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", text
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
}
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", text
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
}
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", text
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);

View File

@@ -17,6 +17,14 @@ struct Font::Data {
PangoFontDescription *font;
};
struct Action::Data {
Font *font;
};
struct Widget::Data {
Window *parent;
};
struct Window::Data {
Font *defaultFont;
};
@@ -35,16 +43,15 @@ struct ListBox::Data {
GtkWidget *label;
};
linear_vector<GtkColumn> column;
bool checkable;
signed selection;
};
struct OS::Data {
};
void Object::unused() {
}
Object::Object() {
OS::initialize();
object = new Object::Data;
object->locked = false;
}

View File

@@ -1,11 +1,12 @@
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_progress_bar_new();
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}
void ProgressBar::setProgress(unsigned progress) {
progress = progress <= 100 ? progress : 0;
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)progress / 100.0);
void ProgressBar::setPosition(unsigned position) {
position = position <= 100 ? position : 0;
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)position / 100.0);
}

View File

@@ -2,10 +2,11 @@ static void RadioBox_tick(RadioBox *self) {
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
}
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
first = this;
object->parentWindow = &parent;
object->widget = gtk_radio_button_new_with_label(0, text);
widget->parent = &parent;
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
@@ -13,7 +14,7 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
gtk_widget_show(object->widget);
}
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
first = parent.first;
object->parentWindow = parent.object->parentWindow;
object->widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(parent.object->widget), text);

View File

@@ -1,11 +1,17 @@
static void TextBox_activate(TextBox *self) {
if(self->onActivate) self->onActivate();
}
static void TextBox_change(TextBox *self) {
if(self->object->locked == false && self->onChange) self->onChange();
}
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_entry_new();
widget->parent = &parent;
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(TextBox_activate), (gpointer)this);
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(TextBox_change), (gpointer)this);
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
@@ -20,7 +26,7 @@ string TextBox::text() {
return gtk_entry_get_text(GTK_ENTRY(object->widget));
}
void TextBox::setText(const char *text) {
void TextBox::setText(const string &text) {
object->locked = true;
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
object->locked = false;

View File

@@ -8,6 +8,7 @@ void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned wid
object->position = 0;
length += (length == 0);
object->widget = gtk_vscale_new_with_range(0, length - 1, 1);
widget->parent = &parent;
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
gtk_widget_set_size_request(object->widget, width, height);
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this);

View File

@@ -1,7 +1,16 @@
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
object->widget = gtk_drawing_area_new();
gtk_widget_set_double_buffered(object->widget, false);
widget->parent = &parent;
//gtk_widget_set_double_buffered(object->widget, false);
gtk_widget_set_size_request(object->widget, width, height);
GdkColor color;
color.pixel = 0;
color.red = 0;
color.green = 0;
color.blue = 0;
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
gtk_widget_show(object->widget);
}

View File

@@ -34,3 +34,14 @@ void Widget::setFocused() {
if(visible() == false) setVisible(true);
gtk_widget_grab_focus(object->widget);
}
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
if(widget->parent == 0) return;
gtk_fixed_move(GTK_FIXED(widget->parent->object->formContainer), object->widget, x, y);
gtk_widget_set_size_request(object->widget, width, height);
}
Widget::Widget() {
widget = new Widget::Data;
widget->parent = 0;
}

View File

@@ -7,7 +7,7 @@ static gint Window_close(Window *window) {
return true;
}
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_move(GTK_WINDOW(object->widget), x, y);
@@ -47,6 +47,13 @@ void Window::setFocused() {
gtk_window_present(GTK_WINDOW(object->widget));
}
Geometry Window::geometry() {
gint x, y, width, height;
gtk_window_get_position(GTK_WINDOW(object->widget), &x, &y);
gtk_widget_get_size_request(object->formContainer, &width, &height);
return Geometry(x, y, width, height);
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
gtk_window_move(GTK_WINDOW(object->widget), x, y);
gtk_widget_set_size_request(object->formContainer, width, height);
@@ -69,11 +76,11 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
}
void Window::setTitle(const char *text) {
void Window::setTitle(const string &text) {
gtk_window_set_title(GTK_WINDOW(object->widget), text);
}
void Window::setStatusText(const char *text) {
void Window::setStatusText(const string &text) {
gtk_statusbar_pop(GTK_STATUSBAR(object->status), 1);
gtk_statusbar_push(GTK_STATUSBAR(object->status), 1, text);
}

View File

@@ -1,7 +1,7 @@
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
button->setParent(parent.window->container);
button->setGeometry(x, y, width, height);
button->setText(text);
button->setText(QString::fromUtf8(text));
if(parent.window->defaultFont) button->setFont(*parent.window->defaultFont);
button->show();
button->connect(button, SIGNAL(released()), SLOT(onTick()));

View File

@@ -1,7 +1,7 @@
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
checkBox->setParent(parent.window->container);
checkBox->setGeometry(x, y, width, height);
checkBox->setText(text);
checkBox->setText(QString::fromUtf8(text));
if(parent.window->defaultFont) checkBox->setFont(*parent.window->defaultFont);
checkBox->show();
checkBox->connect(checkBox, SIGNAL(stateChanged(int)), SLOT(onTick()));

View File

@@ -1,11 +1,11 @@
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
comboBox->setParent(parent.window->container);
comboBox->setGeometry(x, y, width, height);
if(*text) {
lstring list;
list.split("\n", text);
foreach(item, list) addItem((const char*)item);
foreach(item, list) addItem(item);
}
comboBox->connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange()));
@@ -17,8 +17,8 @@ void ComboBox::reset() {
while(comboBox->count()) comboBox->removeItem(0);
}
void ComboBox::addItem(const char *text) {
comboBox->addItem(text);
void ComboBox::addItem(const string &text) {
comboBox->addItem(QString::fromUtf8(text));
}
unsigned ComboBox::selection() {
@@ -27,7 +27,9 @@ unsigned ComboBox::selection() {
}
void ComboBox::setSelection(unsigned row) {
object->locked = true;
comboBox->setCurrentIndex(row);
object->locked = false;
}
ComboBox::ComboBox() {

View File

@@ -1,13 +1,14 @@
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
editBox->setParent(parent.window->container);
editBox->setGeometry(x, y, width, height);
editBox->setText(text);
editBox->setPlainText(QString::fromUtf8(text));
if(parent.window->defaultFont) editBox->setFont(*parent.window->defaultFont);
editBox->show();
editBox->connect(editBox, SIGNAL(textChanged()), SLOT(onChange()));
}
void EditBox::setEditable(bool editable) {
editBox->setReadOnly(editable == false);
}
void EditBox::setWordWrap(bool wordWrap) {
@@ -15,9 +16,11 @@ void EditBox::setWordWrap(bool wordWrap) {
}
string EditBox::text() {
return editBox->toPlainText().toUtf8().constData();
}
void EditBox::setText(const char *text) {
void EditBox::setText(const string &text) {
editBox->setPlainText(QString::fromUtf8(text));
}
EditBox::EditBox() {

View File

@@ -1,5 +1,5 @@
bool Font::create(const char *name, unsigned size, Font::Style style) {
font->setFamily(name);
bool Font::create(const string &name, unsigned size, Font::Style style) {
font->setFamily(QString::fromUtf8(name));
font->setPointSize(size);
font->setBold((style & Style::Bold) == Style::Bold);
font->setItalic((style & Style::Italic) == Style::Italic);

View File

@@ -1,13 +1,13 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
label->setParent(parent.window->container);
label->setGeometry(x, y, width, height);
label->setText(text);
label->setText(QString::fromUtf8(text));
if(parent.window->defaultFont) label->setFont(*parent.window->defaultFont);
label->show();
}
void Label::setText(const char *text) {
label->setText(text);
void Label::setText(const string &text) {
label->setText(QString::fromUtf8(text));
}
Label::Label() {

View File

@@ -1,4 +1,4 @@
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
listBox->setParent(parent.window->container);
listBox->setGeometry(x, y, width, height);
listBox->setAllColumnsShowFocus(true);
@@ -7,7 +7,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
lstring list;
list.split("\t", text);
QStringList labels;
foreach(item, list) labels << (const char*)item;
foreach(item, list) labels << QString::fromUtf8(item);
listBox->setColumnCount(list.size());
listBox->setHeaderLabels(labels);
for(unsigned i = 0; i < list.size(); i++) listBox->resizeColumnToContents(i);
@@ -16,6 +16,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
listBox->setAlternatingRowColors(list.size() >= 2);
listBox->connect(listBox, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
listBox->connect(listBox, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
listBox->connect(listBox, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*)));
if(parent.window->defaultFont) listBox->setFont(*parent.window->defaultFont);
listBox->show();
}
@@ -24,6 +25,14 @@ void ListBox::setHeaderVisible(bool headerVisible) {
listBox->setHeaderHidden(headerVisible == false);
}
void ListBox::setCheckable(bool checkable) {
listBox->checkable = checkable;
if(listBox->checkable) {
auto items = listBox->findItems("", Qt::MatchContains);
for(unsigned i = 0; i < items.size(); i++) items[i]->setCheckState(0, Qt::Unchecked);
}
}
void ListBox::reset() {
listBox->clear();
}
@@ -32,20 +41,37 @@ void ListBox::resizeColumnsToContent() {
for(unsigned i = 0; i < listBox->columnCount(); i++) listBox->resizeColumnToContents(i);
}
void ListBox::addItem(const char *text) {
void ListBox::addItem(const string &text) {
object->locked = true;
auto items = listBox->findItems("", Qt::MatchContains);
QTreeWidgetItem *item = new QTreeWidgetItem(listBox);
if(listBox->checkable) item->setCheckState(0, Qt::Unchecked);
item->setData(0, Qt::UserRole, (unsigned)items.size());
lstring list;
list.split("\t", text);
for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]);
for(unsigned i = 0; i < list.size(); i++) item->setText(i, QString::fromUtf8(list[i]));
object->locked = false;
}
void ListBox::setItem(unsigned row, const char *text) {
void ListBox::setItem(unsigned row, const string &text) {
object->locked = true;
QTreeWidgetItem *item = listBox->topLevelItem(row);
lstring list;
list.split("\t", text);
for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]);
for(unsigned i = 0; i < list.size(); i++) item->setText(i, QString::fromUtf8(list[i]));
object->locked = false;
}
bool ListBox::checked(unsigned row) {
QTreeWidgetItem *item = listBox->topLevelItem(row);
return (item ? item->checkState(0) == Qt::Checked : false);
}
void ListBox::setChecked(unsigned row, bool checked) {
object->locked = true;
QTreeWidgetItem *item = listBox->topLevelItem(row);
if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked);
object->locked = false;
}
optional<unsigned> ListBox::selection() {

View File

@@ -1,10 +1,14 @@
void Menu::create(Window &parent, const char *text) {
menu->setTitle(text);
void Menu::create(Window &parent, const string &text) {
menu->parent = &parent;
if(menu->parent->window->defaultFont) menu->setFont(*menu->parent->window->defaultFont);
menu->setTitle(QString::fromUtf8(text));
parent.window->menuBar->addMenu(menu);
}
void Menu::create(Menu &parent, const char *text) {
menu->setTitle(text);
void Menu::create(Menu &parent, const string &text) {
menu->parent = parent.menu->parent;
if(menu->parent->window->defaultFont) menu->setFont(*menu->parent->window->defaultFont);
menu->setTitle(QString::fromUtf8(text));
parent.menu->addMenu(menu);
}
@@ -52,8 +56,8 @@ MenuSeparator::MenuSeparator() {
menuSeparator = new MenuSeparator::Data(*this);
}
void MenuItem::create(Menu &parent, const char *text) {
menuItem->setText(text);
void MenuItem::create(Menu &parent, const string &text) {
menuItem->setText(QString::fromUtf8(text));
menuItem->connect(menuItem, SIGNAL(triggered()), SLOT(onTick()));
parent.menu->addAction(menuItem);
}
@@ -78,8 +82,8 @@ MenuItem::MenuItem() {
menuItem = new MenuItem::Data(*this);
}
void MenuCheckItem::create(Menu &parent, const char *text) {
menuCheckItem->setText(text);
void MenuCheckItem::create(Menu &parent, const string &text) {
menuCheckItem->setText(QString::fromUtf8(text));
menuCheckItem->setCheckable(true);
menuCheckItem->connect(menuCheckItem, SIGNAL(triggered()), SLOT(onTick()));
parent.menu->addAction(menuCheckItem);
@@ -113,22 +117,22 @@ MenuCheckItem::MenuCheckItem() {
menuCheckItem = new MenuCheckItem::Data(*this);
}
void MenuRadioItem::create(Menu &parent, const char *text) {
void MenuRadioItem::create(Menu &parent, const string &text) {
menuRadioItem->parent = &parent;
menuRadioItem->actionGroup = new QActionGroup(0);
menuRadioItem->actionGroup->addAction(menuRadioItem);
menuRadioItem->setText(text);
menuRadioItem->setText(QString::fromUtf8(text));
menuRadioItem->setCheckable(true);
menuRadioItem->setChecked(true);
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
menuRadioItem->parent->menu->addAction(menuRadioItem);
}
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
menuRadioItem->parent = parent.menuRadioItem->parent;
menuRadioItem->actionGroup = parent.menuRadioItem->actionGroup;
menuRadioItem->actionGroup->addAction(menuRadioItem);
menuRadioItem->setText(text);
menuRadioItem->setText(QString::fromUtf8(text));
menuRadioItem->setCheckable(true);
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
menuRadioItem->parent->menu->addAction(menuRadioItem);

View File

@@ -16,26 +16,30 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
);
}
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return MessageWindow_response(
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
);
}

View File

@@ -2,5 +2,6 @@ void Object::unused() {
}
Object::Object() {
OS::initialize();
object = new Object::Data(*this);
}

View File

@@ -6,8 +6,8 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
progressBar->show();
}
void ProgressBar::setProgress(unsigned progress) {
progressBar->setValue(progress);
void ProgressBar::setPosition(unsigned position) {
progressBar->setValue(position);
}
ProgressBar::ProgressBar() {

View File

@@ -27,12 +27,22 @@ namespace phoenix {
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
OS::Data *OS::os = 0;
Window Window::None;
OS& OS::handle() {
static OS os;
return os;
void OS::initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
os = new OS::Data;
static int argc = 1;
static char *argv[2];
argv[0] = new char[8];
argv[1] = 0;
strcpy(argv[0], "phoenix");
char **argvp = argv;
os->application = new QApplication(argc, argvp);
}
bool OS::pending() {
@@ -59,14 +69,17 @@ unsigned OS::desktopHeight() {
return QApplication::desktop()->screenGeometry().height();
}
string OS::folderSelect(Window &parent, const char *path) {
string OS::folderSelect(Window &parent, const string &path) {
QString directory = QFileDialog::getExistingDirectory(
&parent != &Window::None ? parent.window : 0, "Select Directory", path, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
&parent != &Window::None ? parent.window : 0, "Select Directory",
QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
);
return directory.toUtf8().constData();
string name = directory.toUtf8().constData();
if(name.endswith("/") == false) name.append("/");
return name;
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
string filters;
lstring list;
list.split("\n", filter);
@@ -83,12 +96,13 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
filters.rtrim(";;");
QString filename = QFileDialog::getOpenFileName(
&parent != &Window::None ? parent.window : 0, "Open File", path, (const char*)filters
&parent != &Window::None ? parent.window : 0, "Open File",
QString::fromUtf8(path), QString::fromUtf8(filters)
);
return filename.toUtf8().constData();
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string OS::fileSave(Window &parent, const string &filter, const string &path) {
string filters;
lstring list;
list.split("\n", filter);
@@ -105,20 +119,10 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
filters.rtrim(";;");
QString filename = QFileDialog::getSaveFileName(
&parent != &Window::None ? parent.window : 0, "Save File", path, (const char*)filters
&parent != &Window::None ? parent.window : 0, "Save File",
QString::fromUtf8(path), QString::fromUtf8(filters)
);
return filename.toUtf8().constData();
}
OS::OS() {
os = new OS::Data(*this);
static int argc = 1;
static char *argv[2];
argv[0] = new char[8];
argv[1] = 0;
strcpy(argv[0], "phoenix");
char **argvp = argv;
os->application = new QApplication(argc, argvp);
}
}

View File

@@ -12,13 +12,20 @@ struct Object {
Data *object;
};
struct Geometry {
unsigned x, y;
unsigned width, height;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
};
struct Font : Object {
enum class Style : unsigned {
None = 0,
Bold = 1,
Italic = 2,
};
bool create(const char *name, unsigned size, Font::Style style = Style::None);
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
Font();
~Font();
//private:
@@ -37,8 +44,8 @@ struct Action : Object {
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
void create(Window &parent, const nall::string &text);
void create(Menu &parent, const nall::string &text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
@@ -63,7 +70,7 @@ struct MenuSeparator : Action {
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
@@ -76,7 +83,7 @@ struct MenuItem : Action {
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
@@ -91,8 +98,8 @@ struct MenuCheckItem : Action {
struct MenuRadioItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(MenuRadioItem &parent, const char *text);
void create(Menu &parent, const nall::string &text);
void create(MenuRadioItem &parent, const nall::string &text);
bool visible();
void setVisible(bool visible = true);
bool enabled();
@@ -112,8 +119,8 @@ struct Widget : Object {
void setVisible(bool visible = true);
bool enabled();
void setEnabled(bool enabled = true);
bool focused();
void setFocused();
virtual bool focused();
virtual void setFocused();
Widget();
//private:
struct Data;
@@ -121,26 +128,28 @@ struct Widget : Object {
};
struct Window : Widget {
static Window None;
nall::function<bool ()> onClose;
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
Geometry geometry();
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
void setDefaultFont(Font &font);
void setFont(Font &font);
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setTitle(const char *text);
void setStatusText(const char *text);
void setTitle(const nall::string &text);
void setStatusText(const nall::string &text);
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
bool focused();
Window();
//private:
struct Data;
Data *window;
static Window None;
};
struct Button : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
Button();
//private:
struct Data;
@@ -161,7 +170,7 @@ struct Canvas : Widget {
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked(bool checked = true);
CheckBox();
@@ -172,9 +181,9 @@ struct CheckBox : Widget {
struct ComboBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void reset();
void addItem(const char *text);
void addItem(const nall::string &text);
unsigned selection();
void setSelection(unsigned row);
ComboBox();
@@ -185,11 +194,11 @@ struct ComboBox : Widget {
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
nall::string text();
void setText(const char *text);
void setText(const nall::string &text);
EditBox();
//private:
struct Data;
@@ -208,8 +217,8 @@ struct HorizontalSlider : Widget {
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *text);
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setText(const nall::string &text);
Label();
//private:
struct Data;
@@ -219,12 +228,16 @@ struct Label : Widget {
struct ListBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::function<void (unsigned)> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setHeaderVisible(bool headerVisible = true);
void setCheckable(bool checkable = true);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
void addItem(const nall::string &text);
void setItem(unsigned row, const nall::string &text);
bool checked(unsigned row);
void setChecked(unsigned row, bool checked = true);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
@@ -235,7 +248,7 @@ struct ListBox : Widget {
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
void setProgress(unsigned progress);
void setPosition(unsigned position);
ProgressBar();
//private:
struct Data;
@@ -244,8 +257,8 @@ struct ProgressBar : Widget {
struct RadioBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked();
RadioBox();
@@ -255,11 +268,12 @@ struct RadioBox : Widget {
};
struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setEditable(bool editable = true);
nall::string text();
void setText(const char *text);
void setText(const nall::string &text);
TextBox();
//private:
struct Data;
@@ -298,30 +312,26 @@ struct MessageWindow : Object {
Yes,
No,
};
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
};
struct OS : Object {
bool pending();
void run();
void main();
void quit();
unsigned desktopWidth();
unsigned desktopHeight();
nall::string folderSelect(Window &parent, const char *path = "");
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
static bool pending();
static void run();
static void main();
static void quit();
static unsigned desktopWidth();
static unsigned desktopHeight();
static nall::string folderSelect(Window &parent, const nall::string &path = "");
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
//private:
static OS& handle();
struct Data;
Data *os;
private:
OS();
static Data *os;
static void initialize();
};
extern OS &os;
}

View File

@@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Sat Sep 25 06:31:14 2010
** Created: Mon Oct 11 13:03:04 2010
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
**
** WARNING! All changes made in this file will be lost!
@@ -641,7 +641,7 @@ static const uint qt_meta_data_ListBox__Data[] = {
4, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
3, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
@@ -651,12 +651,14 @@ static const uint qt_meta_data_ListBox__Data[] = {
// slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a,
28, 14, 14, 14, 0x0a,
44, 39, 14, 14, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_ListBox__Data[] = {
"ListBox::Data\0\0onActivate()\0onChange()\0"
"item\0onTick(QTreeWidgetItem*)\0"
};
const QMetaObject ListBox::Data::staticMetaObject = {
@@ -690,9 +692,10 @@ int ListBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
switch (_id) {
case 0: onActivate(); break;
case 1: onChange(); break;
case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
default: ;
}
_id -= 2;
_id -= 3;
}
return _id;
}
@@ -761,7 +764,7 @@ static const uint qt_meta_data_TextBox__Data[] = {
4, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
2, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
@@ -770,12 +773,13 @@ static const uint qt_meta_data_TextBox__Data[] = {
// slots: signature, parameters, type, tag, flags
15, 14, 14, 14, 0x0a,
28, 14, 14, 14, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_TextBox__Data[] = {
"TextBox::Data\0\0onChange()\0"
"TextBox::Data\0\0onActivate()\0onChange()\0"
};
const QMetaObject TextBox::Data::staticMetaObject = {
@@ -807,10 +811,11 @@ int TextBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
case 0: onActivate(); break;
case 1: onChange(); break;
default: ;
}
_id -= 1;
_id -= 2;
}
return _id;
}

View File

@@ -19,8 +19,9 @@ public:
struct Menu::Data : public QMenu {
public:
Menu &self;
Window *parent;
Data(Menu &self) : self(self) {
Data(Menu &self) : self(self), parent(0) {
}
};
@@ -164,7 +165,7 @@ public:
public slots:
void onChange() {
if(self.onChange) self.onChange();
if(self.object->locked == false && self.onChange) self.onChange();
}
};
@@ -213,8 +214,10 @@ struct ListBox::Data : public QTreeWidget {
public:
ListBox &self;
bool checkable;
Data(ListBox &self) : self(self) {
checkable = false;
}
public slots:
@@ -225,6 +228,10 @@ public slots:
void onChange() {
if(self.object->locked == false && self.onChange) self.onChange();
}
void onTick(QTreeWidgetItem *item) {
if(self.object->locked == false && self.onTick) self.onTick(item->data(0, Qt::UserRole).toUInt());
}
};
struct ProgressBar::Data : public QProgressBar {
@@ -262,6 +269,10 @@ public:
}
public slots:
void onActivate() {
if(self.onActivate) self.onActivate();
}
void onChange() {
if(self.onChange) self.onChange();
}
@@ -294,11 +305,7 @@ struct OS::Data : public QObject {
Q_OBJECT
public:
OS &self;
QApplication *application;
Data(OS &self) : self(self) {
}
public slots:
};

View File

@@ -1,23 +1,23 @@
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
radioBox->parent = &parent;
radioBox->buttonGroup = new QButtonGroup;
radioBox->buttonGroup->addButton(radioBox);
radioBox->setParent(radioBox->parent->window->container);
radioBox->setGeometry(x, y, width, height);
radioBox->setText(text);
radioBox->setText(QString::fromUtf8(text));
radioBox->setChecked(true);
if(parent.window->defaultFont) radioBox->setFont(*parent.window->defaultFont);
radioBox->show();
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
}
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
radioBox->parent = parent.radioBox->parent;
radioBox->buttonGroup = parent.radioBox->buttonGroup;
radioBox->buttonGroup->addButton(radioBox);
radioBox->setParent(radioBox->parent->window->container);
radioBox->setGeometry(x, y, width, height);
radioBox->setText(text);
radioBox->setText(QString::fromUtf8(text));
if(radioBox->parent->window->defaultFont) radioBox->setFont(*radioBox->parent->window->defaultFont);
radioBox->show();
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));

View File

@@ -1,9 +1,10 @@
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
textBox->setParent(parent.window->container);
textBox->setGeometry(x, y, width, height);
textBox->setText(text);
textBox->setText(QString::fromUtf8(text));
if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont);
textBox->show();
textBox->connect(textBox, SIGNAL(returnPressed()), SLOT(onActivate()));
textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
}
@@ -15,8 +16,8 @@ string TextBox::text() {
return textBox->text().toUtf8().constData();
}
void TextBox::setText(const char *text) {
textBox->setText(text);
void TextBox::setText(const string &text) {
textBox->setText(QString::fromUtf8(text));
}
TextBox::TextBox() {

View File

@@ -1,6 +1,8 @@
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
viewport->setParent(parent.window->container);
viewport->setGeometry(x, y, width, height);
viewport->setAttribute(Qt::WA_PaintOnScreen, true);
viewport->setStyleSheet("background: #000000");
viewport->show();
}

View File

@@ -1,5 +1,5 @@
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
window->setWindowTitle(text);
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
window->setWindowTitle(QString::fromUtf8(text));
window->move(x, y);
window->layout = new QVBoxLayout(window);
@@ -23,6 +23,10 @@ void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, con
window->layout->addWidget(window->statusBar);
}
Geometry Window::geometry() {
return Geometry(window->x(), window->y(), window->container->width(), window->container->height());
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
window->container->setFixedSize(width, height);
window->move(x, y);
@@ -44,12 +48,12 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
window->setAutoFillBackground(true);
}
void Window::setTitle(const char *text) {
window->setWindowTitle(text);
void Window::setTitle(const string &text) {
window->setWindowTitle(QString::fromUtf8(text));
}
void Window::setStatusText(const char *text) {
window->statusBar->showMessage(text, 0);
void Window::setStatusText(const string &text) {
window->statusBar->showMessage(QString::fromUtf8(text), 0);
}
void Window::setMenuVisible(bool visible) {
@@ -62,6 +66,10 @@ void Window::setStatusVisible(bool visible) {
else window->statusBar->hide();
}
bool Window::focused() {
return window->isActiveWindow() && !window->isMinimized();
}
Window::Window() {
window = new Window::Data(*this);
window->defaultFont = 0;

View File

@@ -1,4 +1,4 @@
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
@@ -6,5 +6,5 @@ void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
}

View File

@@ -1,4 +1,4 @@
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindow(
L"BUTTON", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
@@ -6,7 +6,7 @@ void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
}
bool CheckBox::checked() {

View File

@@ -1,4 +1,4 @@
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindowEx(
0, L"COMBOBOX", L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
@@ -7,7 +7,7 @@ void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
//CreateWindow height parameter is the height of the expanded list box;
//need additional code to override default ComboBox control height
@@ -27,7 +27,7 @@ void ComboBox::reset() {
SendMessage(widget->window, CB_RESETCONTENT, 0, 0);
}
void ComboBox::addItem(const char *text) {
void ComboBox::addItem(const string &text) {
SendMessage(widget->window, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text));
if(SendMessage(widget->window, CB_GETCOUNT, 0, 0) == 1) setSelection(0);
}

View File

@@ -1,4 +1,4 @@
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
@@ -8,7 +8,7 @@ void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
);
setText(text);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
}
string EditBox::getText() {
@@ -21,7 +21,7 @@ string EditBox::getText() {
return text;
}
void EditBox::setText(const char *text) {
void EditBox::setText(const string &text) {
string output = text;
output.replace("\r", "");
output.replace("\n", "\r\n");

View File

@@ -1,4 +1,4 @@
static HFONT Font_createFont(const char *name, unsigned size, bool bold, bool italic) {
static HFONT Font_createFont(const string &name, unsigned size, bool bold, bool italic) {
return CreateFont(
-(size * 96.0 / 72.0 + 0.5),
0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0,
@@ -6,7 +6,7 @@ static HFONT Font_createFont(const char *name, unsigned size, bool bold, bool it
);
}
bool Font::create(const char *name, unsigned size, Font::Style style) {
bool Font::create(const string &name, unsigned size, Font::Style style) {
font->font = Font_createFont(
name, size,
(style & Font::Style::Bold) == Font::Style::Bold,

View File

@@ -1,4 +1,4 @@
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindow(
L"phoenix_label", L"",
WS_CHILD | WS_VISIBLE,
@@ -6,12 +6,13 @@ void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsig
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
setText(text);
}
void Label::setText(const char *text) {
void Label::setText(const string &text) {
SetWindowText(widget->window, utf16_t(text));
InvalidateRect(widget->window, 0, false);
}
//all of this for want of a STATIC SS_VCENTER flag ...
@@ -24,28 +25,14 @@ LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa
Label &label = *label_ptr;
switch(msg) {
case WM_ERASEBKGND: {
if(window.window->brush == 0) break;
RECT rc;
GetClientRect(window.widget->window, &rc);
PAINTSTRUCT ps;
BeginPaint(window.widget->window, &ps);
FillRect(ps.hdc, &rc, window.window->brush);
EndPaint(window.widget->window, &ps);
return TRUE;
}
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
SelectObject(ps.hdc, label.widget->font);
if(window.window->brush) {
SetBkColor(ps.hdc, window.window->brushColor);
} else {
SetBkColor(ps.hdc, GetSysColor(COLOR_3DFACE));
}
RECT rc;
BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
FillRect(ps.hdc, &rc, window.window->brush ? window.window->brush : GetSysColorBrush(COLOR_3DFACE));
SetBkColor(ps.hdc, window.window->brush ? window.window->brushColor : GetSysColor(COLOR_3DFACE));
SelectObject(ps.hdc, label.widget->font);
unsigned length = GetWindowTextLength(hwnd);
wchar_t text[length + 1];
GetWindowText(hwnd, text, length + 1);
@@ -57,7 +44,6 @@ LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa
rc.bottom = rc.top + height;
DrawText(ps.hdc, text, -1, &rc, DT_LEFT | DT_END_ELLIPSIS);
EndPaint(hwnd, &ps);
InvalidateRect(hwnd, 0, false);
}
}

View File

@@ -1,4 +1,4 @@
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
@@ -7,7 +7,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT);
lstring list;
@@ -34,6 +34,10 @@ void ListBox::setHeaderVisible(bool headerVisible) {
);
}
void ListBox::setCheckable(bool checkable) {
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT | (checkable ? LVS_EX_CHECKBOXES : 0));
}
void ListBox::reset() {
ListView_DeleteAllItems(widget->window);
}
@@ -44,7 +48,7 @@ void ListBox::resizeColumnsToContent() {
}
}
void ListBox::addItem(const char *text) {
void ListBox::addItem(const string &text) {
lstring list;
list.split("\t", text);
LVITEM item;
@@ -54,20 +58,28 @@ void ListBox::addItem(const char *text) {
item.iSubItem = 0;
utf16_t wtext(list[0]);
item.pszText = wtext;
object->locked = true;
ListView_InsertItem(widget->window, &item);
object->locked = false;
for(unsigned i = 1; i < list.size(); i++) {
utf16_t wtext(list[i]);
ListView_SetItemText(widget->window, row, i, wtext);
}
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
}
void ListBox::setItem(unsigned row, const char *text) {
void ListBox::setItem(unsigned row, const string &text) {
lstring list;
list.split("\t", text);
for(unsigned i = 0; i < list.size(); i++) {
utf16_t wtext(list[i]);
ListView_SetItemText(widget->window, row, i, wtext);
}
//workaround: when there is only one column, the horizontal scrollbar will always appear without this
if(listBox->columns == 1) ListView_SetColumnWidth(widget->window, 0, LVSCW_AUTOSIZE_USEHEADER);
}
optional<unsigned> ListBox::selection() {
@@ -86,6 +98,16 @@ void ListBox::setSelection(unsigned row) {
}
}
bool ListBox::checked(unsigned row) {
return ListView_GetCheckState(widget->window, row);
}
void ListBox::setChecked(unsigned row, bool checked) {
object->locked = true;
ListView_SetCheckState(widget->window, row, checked);
object->locked = false;
}
ListBox::ListBox() {
listBox = new ListBox::Data;
listBox->lostFocus = false;

View File

@@ -1,15 +1,15 @@
Action::Action() {
os.objects.append(this);
OS::os->objects.append(this);
action = new Action::Data;
}
void Menu::create(Window &parent, const char *text) {
void Menu::create(Window &parent, const string &text) {
action->parentMenu = parent.window->menu;
action->menu = CreatePopupMenu();
AppendMenu(parent.window->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
}
void Menu::create(Menu &parent, const char *text) {
void Menu::create(Menu &parent, const string &text) {
action->parentMenu = parent.action->menu;
action->menu = CreatePopupMenu();
AppendMenu(parent.action->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
@@ -46,7 +46,7 @@ void MenuSeparator::setEnabled(bool enabled) {
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
}
void MenuItem::create(Menu &parent, const char *text) {
void MenuItem::create(Menu &parent, const string &text) {
action->parent = &parent;
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
}
@@ -64,7 +64,7 @@ void MenuItem::setEnabled(bool enabled) {
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
}
void MenuCheckItem::create(Menu &parent, const char *text) {
void MenuCheckItem::create(Menu &parent, const string &text) {
action->parent = &parent;
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
}
@@ -95,7 +95,7 @@ void MenuCheckItem::setChecked(bool checked) {
CheckMenuItem(action->parent->action->menu, object->id, checked ? MF_CHECKED : MF_UNCHECKED);
}
void MenuRadioItem::create(Menu &parent, const char *text) {
void MenuRadioItem::create(Menu &parent, const string &text) {
action->parent = &parent;
action->radioParent = this;
action->items.append(this);
@@ -103,7 +103,7 @@ void MenuRadioItem::create(Menu &parent, const char *text) {
setChecked();
}
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
void MenuRadioItem::create(MenuRadioItem &parent, const string &text) {
action->parent = parent.action->parent;
action->radioParent = parent.action->radioParent;
action->radioParent->action->items.append(this);

View File

@@ -8,7 +8,7 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
return MessageWindow::Response::Ok;
}
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONINFORMATION;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
@@ -16,7 +16,7 @@ MessageWindow::Response MessageWindow::information(Window &parent, const char *t
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
}
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONQUESTION;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
@@ -24,7 +24,7 @@ MessageWindow::Response MessageWindow::question(Window &parent, const char *text
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
}
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONWARNING;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
@@ -32,7 +32,7 @@ MessageWindow::Response MessageWindow::warning(Window &parent, const char *text,
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
}
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONERROR;
if(buttons == Buttons::Ok) flags |= MB_OK;
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;

View File

@@ -70,6 +70,7 @@ struct VerticalSlider::Data {
};
struct OS::Data {
nall::array<Object*> objects;
HFONT proportionalFont;
HFONT monospaceFont;
};
@@ -78,6 +79,7 @@ void Object::unused() {
}
Object::Object() {
OS::initialize();
static unsigned guid = 100;
object = new Object::Data;
object->id = guid++;

View File

@@ -9,10 +9,10 @@ void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width,
SendMessage(widget->window, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
}
unsigned ProgressBar::progress() {
unsigned ProgressBar::position() {
return SendMessage(widget->window, PBM_GETPOS, 0, 0);
}
void ProgressBar::setProgress(unsigned progress) {
SendMessage(widget->window, PBM_SETPOS, (WPARAM)progress, 0);
void ProgressBar::setPosition(unsigned position) {
SendMessage(widget->window, PBM_SETPOS, (WPARAM)position, 0);
}

View File

@@ -1,4 +1,4 @@
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
radioBox->parentWindow = &parent;
radioBox->parent = this;
radioBox->parent->radioBox->items.append(this);
@@ -9,11 +9,11 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
setChecked();
}
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
radioBox->parentWindow = parent.radioBox->parentWindow;
radioBox->parent = parent.radioBox->parent;
radioBox->parent->radioBox->items.append(this);
@@ -24,7 +24,7 @@ void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width,
GetParent(radioBox->parent->widget->window), (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : OS::os->proportionalFont), 0);
}
bool RadioBox::checked() {

View File

@@ -1,4 +1,4 @@
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", utf16_t(text),
WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
@@ -6,7 +6,7 @@ void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
);
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0);
SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0);
}
string TextBox::text() {
@@ -17,7 +17,7 @@ string TextBox::text() {
return utf8_t(text);
}
void TextBox::setText(const char *text) {
void TextBox::setText(const string &text) {
object->locked = true;
SetWindowText(widget->window, utf16_t(text));
object->locked = false;

View File

@@ -1,6 +1,6 @@
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
widget->window = CreateWindow(
L"phoenix_window", L"",
L"phoenix_viewport", L"",
WS_CHILD | WS_VISIBLE | WS_DISABLED,
x, y, width, height,
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
@@ -11,3 +11,7 @@ void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, un
uintptr_t Viewport::handle() {
return (uintptr_t)widget->window;
}
static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@@ -28,9 +28,13 @@ void Widget::setFocused() {
SetFocus(widget->window);
}
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER);
}
Widget::Widget() {
os.objects.append(this);
OS::os->objects.append(this);
widget = new Widget::Data;
widget->window = 0;
widget->font = os.os->proportionalFont;
widget->font = OS::os->proportionalFont;
}

View File

@@ -1,4 +1,4 @@
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const string &text) {
widget->window = CreateWindowEx(
0, L"phoenix_window", utf16_t(text),
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
@@ -26,6 +26,18 @@ void Window::setFont(Font &font) {
SendMessage(window->status, WM_SETFONT, (WPARAM)font.font->font, 0);
}
Geometry Window::geometry() {
RECT position, size;
GetWindowRect(widget->window, &position);
GetClientRect(widget->window, &size);
if(GetWindowLongPtr(window->status, GWL_STYLE) & WS_VISIBLE) {
RECT status;
GetClientRect(window->status, &status);
size.bottom -= status.bottom - status.top;
}
return Geometry(position.left, position.top, size.right, size.bottom);
}
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
bool isVisible = visible();
if(isVisible) setVisible(false);
@@ -40,11 +52,11 @@ void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
window->brush = CreateSolidBrush(window->brushColor);
}
void Window::setTitle(const char *text) {
void Window::setTitle(const string &text) {
SetWindowText(widget->window, utf16_t(text));
}
void Window::setStatusText(const char *text) {
void Window::setStatusText(const string &text) {
SendMessage(window->status, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
}

View File

@@ -29,14 +29,72 @@ namespace phoenix {
#include "viewport.cpp"
#include "messagewindow.cpp"
OS &os = OS::handle();
OS::Data *OS::os = 0;
Window Window::None;
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
OS& OS::handle() {
static OS os;
return os;
void OS::initialize() {
static bool initialized = false;
if(initialized == true) return;
initialized = true;
InitCommonControls();
CoInitialize(0);
os = new OS::Data;
os->proportionalFont = Font_createFont("Tahoma", 8, false, false);
os->monospaceFont = Font_createFont("Courier New", 8, false, false);
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = OS_windowProc;
wc.lpszClassName = L"phoenix_window";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Canvas_windowProc;
wc.lpszClassName = L"phoenix_canvas";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Label_windowProc;
wc.lpszClassName = L"phoenix_label";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Viewport_windowProc;
wc.lpszClassName = L"phoenix_viewport";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
}
bool OS::pending() {
@@ -84,7 +142,7 @@ unsigned OS::desktopHeight() {
return GetSystemMetrics(SM_CYSCREEN);
}
string OS::folderSelect(Window &parent, const char *path) {
string OS::folderSelect(Window &parent, const string &path) {
wchar_t wfilename[PATH_MAX + 1] = L"";
BROWSEINFO bi;
bi.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
@@ -108,10 +166,13 @@ string OS::folderSelect(Window &parent, const char *path) {
}
}
if(result == false) return "";
return utf8_t(wfilename);
string name = utf8_t(wfilename);
name.transform("\\", "/");
if(name.endswith("/") == false) name.append("/");
return name;
}
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
string OS::fileOpen(Window &parent, const string &filter, const string &path) {
string dir = path;
dir.replace("/", "\\");
@@ -154,10 +215,12 @@ string OS::fileOpen(Window &parent, const char *filter, const char *path) {
bool result = GetOpenFileName(&ofn);
if(result == false) return "";
return utf8_t(wfilename);
string name = utf8_t(wfilename);
name.transform("\\", "/");
return name;
}
string OS::fileSave(Window &parent, const char *filter, const char *path) {
string OS::fileSave(Window &parent, const string &filter, const string &path) {
string dir = path;
dir.replace("/", "\\");
@@ -200,7 +263,9 @@ string OS::fileSave(Window &parent, const char *filter, const char *path) {
bool result = GetSaveFileName(&ofn);
if(result == false) return "";
return utf8_t(wfilename);
string name = utf8_t(wfilename);
name.transform("\\", "/");
return name;
}
static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
@@ -211,10 +276,17 @@ static void OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
info.cbSize = sizeof(GUITHREADINFO);
GetGUIThreadInfo(GetCurrentThreadId(), &info);
Object *object_ptr = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
if(object_ptr && dynamic_cast<ListBox*>(object_ptr)) {
ListBox &listBox = (ListBox&)*object_ptr;
if(wparam == VK_RETURN) {
if(listBox.onActivate) listBox.onActivate();
if(object_ptr) {
if(dynamic_cast<ListBox*>(object_ptr)) {
ListBox &listBox = (ListBox&)*object_ptr;
if(wparam == VK_RETURN) {
if(listBox.onActivate) listBox.onActivate();
}
} else if(dynamic_cast<TextBox*>(object_ptr)) {
TextBox &textBox = (TextBox&)*object_ptr;
if(wparam == VK_RETURN) {
if(textBox.onActivate) textBox.onActivate();
}
}
}
}
@@ -261,7 +333,7 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
unsigned id = LOWORD(wparam);
HWND control = GetDlgItem(window.widget->window, id);
if(control == 0) {
Object *object_ptr = (Object*)os.findObject(id);
Object *object_ptr = (Object*)OS::findObject(id);
if(object_ptr) {
if(dynamic_cast<MenuItem*>(object_ptr)) {
MenuItem &menuItem = (MenuItem&)*object_ptr;
@@ -327,8 +399,12 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
ListBox &listBox = (ListBox&)*object_ptr;
LPNMHDR nmhdr = (LPNMHDR)lparam;
LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam;
if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) {
if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1;
if(imagemask == 0 || imagemask == 1) {
if(listBox.object->locked == false && listBox.onTick) listBox.onTick(nmlistview->iItem);
} else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
listBox.listBox->lostFocus = true;
} else {
if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) {
@@ -385,54 +461,8 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
}
Object* OS::findObject(unsigned id) {
foreach(object, objects) { if(object->object->id == id) return object; }
foreach(object, os->objects) { if(object->object->id == id) return object; }
return 0;
}
OS::OS() {
InitCommonControls();
CoInitialize(0);
os = new OS::Data;
os->proportionalFont = Font_createFont("Tahoma", 8, false, false);
os->monospaceFont = Font_createFont("Courier New", 8, false, false);
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = OS_windowProc;
wc.lpszClassName = L"phoenix_window";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Canvas_windowProc;
wc.lpszClassName = L"phoenix_canvas";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Label_windowProc;
wc.lpszClassName = L"phoenix_label";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
}
}

View File

@@ -4,6 +4,8 @@ struct Window;
struct Object {
Object();
Object& operator=(const Object&) = delete;
Object(const Object&) = delete;
//private:
struct Data;
Data *object;
@@ -11,13 +13,20 @@ private:
virtual void unused();
};
struct Geometry {
unsigned x, y;
unsigned width, height;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(unsigned x, unsigned y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
};
struct Font : Object {
enum class Style : unsigned {
None = 0,
Bold = 1,
Italic = 2,
};
bool create(const char *name, unsigned size, Font::Style style = Style::None);
bool create(const nall::string &name, unsigned size, Font::Style style = Style::None);
Font();
~Font();
//private:
@@ -38,8 +47,8 @@ struct Action : Object {
};
struct Menu : Action {
void create(Window &parent, const char *text);
void create(Menu &parent, const char *text);
void create(Window &parent, const nall::string &text);
void create(Menu &parent, const nall::string &text);
bool enabled();
void setEnabled(bool enabled = true);
};
@@ -52,14 +61,14 @@ struct MenuSeparator : Action {
struct MenuItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
bool enabled();
void setEnabled(bool enabled = true);
};
struct MenuCheckItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(Menu &parent, const nall::string &text);
bool enabled();
void setEnabled(bool enabled = true);
bool checked();
@@ -68,8 +77,8 @@ struct MenuCheckItem : Action {
struct MenuRadioItem : Action {
nall::function<void ()> onTick;
void create(Menu &parent, const char *text);
void create(MenuRadioItem &parent, const char *text);
void create(Menu &parent, const nall::string &text);
void create(MenuRadioItem &parent, const nall::string &text);
bool enabled();
void setEnabled(bool enabled = true);
bool checked();
@@ -84,6 +93,7 @@ struct Widget : Object {
void setEnabled(bool enabled = true);
bool focused();
void setFocused();
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
Widget();
//private:
struct Data;
@@ -91,28 +101,28 @@ struct Widget : Object {
};
struct Window : Widget {
static Window None;
nall::function<bool ()> onClose;
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setDefaultFont(Font &font);
void setFont(Font &font);
Geometry geometry();
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setTitle(const char *text);
void setStatusText(const char *text);
void setTitle(const nall::string &text);
void setStatusText(const nall::string &text);
void setMenuVisible(bool visible = true);
void setStatusVisible(bool visible = true);
Window();
//private:
struct Data;
Data *window;
//private:
static Window None;
void resize(unsigned width, unsigned height);
};
struct Button : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
};
struct Canvas : Widget {
@@ -128,16 +138,16 @@ struct Canvas : Widget {
struct CheckBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked(bool checked = true);
};
struct ComboBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void reset();
void addItem(const char *text);
void addItem(const nall::string &text);
unsigned selection();
void setSelection(unsigned item);
ComboBox();
@@ -148,9 +158,9 @@ struct ComboBox : Widget {
struct EditBox : Widget {
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
nall::string getText();
void setText(const char *text);
void setText(const nall::string &text);
void setEditable(bool editable = true);
void setWordWrap(bool wordWrap = true);
EditBox();
@@ -171,19 +181,23 @@ struct HorizontalSlider : Widget {
};
struct Label : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void setText(const char *text);
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setText(const nall::string &text);
};
struct ListBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
nall::function<void (unsigned)> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void setHeaderVisible(bool headerVisible = true);
void setCheckable(bool checkable = true);
void reset();
void resizeColumnsToContent();
void addItem(const char *text);
void setItem(unsigned row, const char *text);
void addItem(const nall::string &text);
void setItem(unsigned row, const nall::string &text);
bool checked(unsigned row);
void setChecked(unsigned row, bool checked = true);
nall::optional<unsigned> selection();
void setSelection(unsigned row);
ListBox();
@@ -194,14 +208,14 @@ struct ListBox : Widget {
struct ProgressBar : Widget {
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
unsigned progress();
void setProgress(unsigned progress);
unsigned position();
void setPosition(unsigned position);
};
struct RadioBox : Widget {
nall::function<void ()> onTick;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
bool checked();
void setChecked();
RadioBox();
@@ -211,10 +225,11 @@ struct RadioBox : Widget {
};
struct TextBox : Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const nall::string &text = "");
nall::string text();
void setText(const char *text);
void setText(const nall::string &text);
void setEditable(bool editable = true);
};
@@ -246,33 +261,28 @@ struct MessageWindow : Object {
Yes,
No,
};
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
};
struct OS : Object {
bool pending();
void run();
void main();
void quit();
unsigned desktopWidth();
unsigned desktopHeight();
nall::string folderSelect(Window &parent, const char *path = "");
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
static bool pending();
static void run();
static void main();
static void quit();
static unsigned desktopWidth();
static unsigned desktopHeight();
static nall::string folderSelect(Window &parent, const nall::string &path = "");
static nall::string fileOpen(Window &parent, const nall::string &filter, const nall::string &path = "");
static nall::string fileSave(Window &parent, const nall::string &filter, const nall::string &path = "");
//private:
static OS& handle();
static void initialize();
struct Data;
Data *os;
Object* findObject(unsigned id);
nall::array<Object*> objects;
private:
OS();
static Data *os;
static Object* findObject(unsigned id);
friend class Object;
};
extern OS &os;
};

View File

@@ -277,8 +277,8 @@ public:
//this is used to sort device IDs
struct DevicePool {
HANDLE handle;
char name[4096];
bool operator<(const DevicePool &pool) const { return strcmp(name, pool.name) < 0; }
wchar_t name[4096];
bool operator<(const DevicePool &pool) const { return wcscmp(name, pool.name) < 0; }
};
int main() {
@@ -342,8 +342,12 @@ public:
//per MSDN: XInput devices have "IG_" in their device strings,
//which is how they should be identified.
const char *p = strstr(pool[i].name, "IG_");
lgamepad[n].isXInputDevice = (bool)p;
string p = utf8_t(pool[i].name);
if(auto position = strpos(p, "IG_")) {
lgamepad[n].isXInputDevice = true;
} else {
lgamepad[n].isXInputDevice = false;
}
}
}
}
@@ -693,7 +697,9 @@ public:
//=========
for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)Keyboard::Count); i++) {
for(unsigned n = 0; n < nall::Keyboard::Size; n++) {
table[keyboard(i).key(n)] = rawinput.lkeyboard[i].state[n];
//using keyboard(0)|= instead of keyboard(i)= merges all keyboards to KB0
//this is done to favor ease of mapping over flexibility (eg share laptop+USB keyboard mapping)
table[keyboard(0).key(n)] |= rawinput.lkeyboard[i].state[n];
}
}
@@ -723,15 +729,17 @@ public:
for(unsigned i = 0; i < xinput.lgamepad.size(); i++) {
if(joy >= Joypad::Count) break;
table[joypad(i).hat(0)] = xinput.lgamepad[i].hat;
table[joypad(joy).hat(0)] = xinput.lgamepad[i].hat;
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = xinput.lgamepad[i].axis[axis];
table[joypad(joy).axis(axis)] = xinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(10U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).button(button)] = xinput.lgamepad[i].button[button];
table[joypad(joy).button(button)] = xinput.lgamepad[i].button[button];
}
joy++;
}
//=======================
@@ -742,16 +750,18 @@ public:
if(joy >= Joypad::Count) break;
for(unsigned hat = 0; hat < min(4U, (unsigned)Joypad::Hats); hat++) {
table[joypad(i).hat(hat)] = dinput.lgamepad[i].hat[hat];
table[joypad(joy).hat(hat)] = dinput.lgamepad[i].hat[hat];
}
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = dinput.lgamepad[i].axis[axis];
table[joypad(joy).axis(axis)] = dinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(128U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).button(button)] = dinput.lgamepad[i].button[button];
table[joypad(joy).button(button)] = dinput.lgamepad[i].button[button];
}
joy++;
}
return true;

View File

@@ -14,6 +14,7 @@ InputInterface input;
const char *Video::Handle = "Handle";
const char *Video::Synchronize = "Synchronize";
const char *Video::Filter = "Filter";
const char *Video::Shader = "Shader";
const char *Video::FragmentShader = "FragmentShader";
const char *Video::VertexShader = "VertexShader";

View File

@@ -3,6 +3,7 @@ public:
static const char *Handle;
static const char *Synchronize;
static const char *Filter;
static const char *Shader;
static const char *FragmentShader;
static const char *VertexShader;

View File

@@ -24,7 +24,7 @@ public:
LPDIRECT3DTEXTURE9 texture;
LPDIRECT3DSURFACE9 surface;
LPD3DXEFFECT effect;
string shaderSource;
string shader_source_xml;
bool lost;
unsigned iwidth, iheight;
@@ -64,7 +64,7 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::FragmentShader) return true;
if(name == Video::Shader) return true;
return false;
}
@@ -92,8 +92,8 @@ public:
return true;
}
if(name == Video::FragmentShader) {
set_fragment_shader(any_cast<const char*>(value));
if(name == Video::Shader) {
set_shader(any_cast<const char*>(value));
return true;
}
@@ -268,7 +268,7 @@ public:
//failure to do so causes scaling issues on some video drivers.
if(state.width != rd.right || state.height != rd.bottom) {
init();
set_fragment_shader(shaderSource);
set_shader(shader_source_xml);
return;
}
@@ -327,7 +327,7 @@ public:
if(device->Present(0, 0, 0, 0) == D3DERR_DEVICELOST) lost = true;
}
void set_fragment_shader(const char *source) {
void set_shader(const char *source) {
if(!caps.shader) return;
if(effect) {
@@ -336,11 +336,27 @@ public:
}
if(!source || !*source) {
shaderSource = "";
shader_source_xml = "";
return;
}
shader_source_xml = source;
shaderSource = source;
bool is_hlsl = false;
string shader_source;
xml_element document = xml_parse(shader_source_xml);
foreach(head, document.element) {
if(head.name == "shader") {
foreach(attribute, head.attribute) {
if(attribute.name == "language" && attribute.content == "HLSL") is_hlsl = true;
}
foreach(element, head.element) {
if(element.name == "source") {
if(is_hlsl) shader_source = element.parse();
}
}
}
}
if(shader_source == "") return;
HMODULE d3dx;
for(unsigned i = 0; i < 256; i++) {
@@ -349,14 +365,14 @@ public:
d3dx = LoadLibraryW(utf16_t(t));
if(d3dx) break;
}
if(!d3dx) d3dx = LoadLibrary(L"d3dx9.dll");
if(!d3dx) d3dx = LoadLibraryW(L"d3dx9.dll");
if(!d3dx) return;
EffectProc effectProc = (EffectProc)GetProcAddress(d3dx, "D3DXCreateEffect");
TextureProc textureProc = (TextureProc)GetProcAddress(d3dx, "D3DXCreateTextureFromFileA");
LPD3DXBUFFER pBufferErrors = NULL;
effectProc(device, utf16_t(shaderSource), lstrlen(utf16_t(source)), NULL, NULL, 0, NULL, &effect, &pBufferErrors);
effectProc(device, shader_source, lstrlenA(shader_source), NULL, NULL, 0, NULL, &effect, &pBufferErrors);
D3DXHANDLE hTech;
effect->FindNextValidTechnique(NULL, &hTech);

View File

@@ -2,7 +2,7 @@
video.glx
author: byuu
license: public domain
last updated: 2010-01-05
last updated: 2010-09-28
Design notes:
SGI's GLX is the X11/Xlib interface to OpenGL.
@@ -62,6 +62,7 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::Shader) return true;
if(name == Video::FragmentShader) return true;
if(name == Video::VertexShader) return true;
return false;
@@ -93,6 +94,11 @@ public:
return true;
}
if(name == Video::Shader) {
OpenGL::set_shader(any_cast<const char*>(value));
return true;
}
if(name == Video::FragmentShader) {
OpenGL::set_fragment_shader(any_cast<const char*>(value));
return true;

View File

@@ -122,7 +122,7 @@ public:
}
}
void set_fragment_shader(const char *source) {
void set_shader(const char *source) {
if(!shader_support) return;
if(fragmentshader) {
@@ -131,19 +131,6 @@ public:
fragmentshader = 0;
}
if(source) {
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &source, 0);
glCompileShader(fragmentshader);
glAttachShader(glprogram, fragmentshader);
}
glLinkProgram(glprogram);
}
void set_vertex_shader(const char *source) {
if(!shader_support) return;
if(vertexshader) {
glDetachShader(glprogram, vertexshader);
glDeleteShader(vertexshader);
@@ -151,15 +138,49 @@ public:
}
if(source) {
vertexshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader, 1, &source, 0);
glCompileShader(vertexshader);
glAttachShader(glprogram, vertexshader);
bool is_glsl = false;
string fragment_source;
string vertex_source;
xml_element document = xml_parse(source);
foreach(head, document.element) {
if(head.name == "shader") {
foreach(attribute, head.attribute) {
if(attribute.name == "language" && attribute.content == "GLSL") is_glsl = true;
}
foreach(element, head.element) {
if(element.name == "fragment") {
fragment_source = element.parse();
} else if(element.name == "vertex") {
vertex_source = element.parse();
}
}
}
}
if(is_glsl) {
if(fragment_source != "") set_fragment_shader(fragment_source);
if(vertex_source != "") set_vertex_shader(vertex_source);
}
}
glLinkProgram(glprogram);
}
void set_fragment_shader(const char *source) {
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &source, 0);
glCompileShader(fragmentshader);
glAttachShader(glprogram, fragmentshader);
}
void set_vertex_shader(const char *source) {
vertexshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader, 1, &source, 0);
glCompileShader(vertexshader);
glAttachShader(glprogram, vertexshader);
}
void init() {
//disable unused features
glDisable(GL_ALPHA_TEST);

View File

@@ -29,8 +29,7 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::FragmentShader) return true;
if(name == Video::VertexShader) return true;
if(name == Video::Shader) return true;
return false;
}
@@ -59,13 +58,8 @@ public:
return true;
}
if(name == Video::FragmentShader) {
OpenGL::set_fragment_shader(any_cast<const char*>(value));
return true;
}
if(name == Video::VertexShader) {
OpenGL::set_vertex_shader(any_cast<const char*>(value));
if(name == Video::Shader) {
OpenGL::set_shader(any_cast<const char*>(value));
return true;
}

View File

@@ -5,7 +5,7 @@ uint8 CPU::pio() {
}
bool CPU::joylatch() {
return 0;
return status.joypad_strobe_latch;
}
bool CPU::interrupt_pending() {

View File

@@ -75,7 +75,7 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
} break;
case 2: { //palette color 0 outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
if((px | py) & ~1023) {
palette = 0;
} else {
px &= 1023;
@@ -87,7 +87,7 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
}
} break;
case 3: { //character 0 repetition outside of screen area
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
if((px | py) & ~1023) {
tile = 0;
} else {
px &= 1023;

View File

@@ -43,10 +43,10 @@ void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset,
void PPU::Background::scanline() {
if(self.vcounter() == 1) {
mosaic_vcounter = regs.mosaic + 1;
y = 1;
mosaic_voffset = 1;
} else if(--mosaic_vcounter == 0) {
mosaic_vcounter = regs.mosaic + 1;
y += regs.mosaic + 1;
mosaic_voffset += regs.mosaic + 1;
}
if(self.regs.display_disable) return;
@@ -93,7 +93,7 @@ void PPU::Background::render() {
hscroll = regs.hoffset;
vscroll = regs.voffset;
unsigned y = Background::y;
unsigned y = (regs.mosaic == 0 ? self.vcounter() : mosaic_voffset);
if(hires) {
hscroll <<= 1;
if(self.regs.interlace) y = (y << 1) + self.field();

View File

@@ -31,7 +31,6 @@ class Background {
const unsigned id;
unsigned opt_valid_bit;
unsigned y;
bool hires;
signed width;
@@ -48,6 +47,7 @@ class Background {
unsigned vscroll;
unsigned mosaic_vcounter;
unsigned mosaic_voffset;
LayerWindow window;

View File

@@ -49,7 +49,7 @@ void PPU::Background::render_mode7() {
}
case 2: {
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
if((px | py) & ~1023) {
palette = 0;
} else {
px &= 1023;
@@ -63,7 +63,7 @@ void PPU::Background::render_mode7() {
}
case 3: {
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
if((px | py) & ~1023) {
tile = 0;
} else {
px &= 1023;

View File

@@ -283,7 +283,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
switch(addr & 0xffff) {
case 0x2100: { //INIDISP
if(regs.display_disable && vcounter() == display.height) oam.address_reset();
if(regs.display_disable && cpu.vcounter() == display.height) oam.address_reset();
regs.display_disable = data & 0x80;
regs.display_brightness = data & 0x0f;
return;

View File

@@ -115,7 +115,6 @@ void PPU::Background::serialize(serializer &s) {
s.integer(regs.main_enable);
s.integer(regs.sub_enable);
s.integer(y);
s.integer(hires);
s.integer(width);
@@ -132,6 +131,7 @@ void PPU::Background::serialize(serializer &s) {
s.integer(vscroll);
s.integer(mosaic_vcounter);
s.integer(mosaic_voffset);
window.serialize(s);
}

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