Compare commits

...

30 Commits
v077 ... v081

Author SHA1 Message Date
Tim Allen
064ca4c626 Update to v081 release.
byuu says:

This release polishes up the GUI, adds some more features, and fixes
a few minor issues.

Changelog (since v080):
- rewrote S-DD1 module to decompress individual bytes at a time
- simplified SPC7110 deinterleaving code
- OBC1 should not clear RAM on reset [Jonas Quinn]
- fixed enum-cast compilation errors with the latest GCC 4.6.x releases
- added bsnes logo to about screen
- make phoenix=gtk will now build the GTK+ port on Linux
- added settings.startFullScreen to the config file for front-end users
- added advanced settings option to disable window compositor (only
  works on Windows and Xfce)
- merged settings windows into the panel approach used by bsnes/Qt in
  the past
- fixed a crashing bug on input settings window
- fixed GTK+ auto-geometry sizing
- added screenshot capture capability
- added exit emulator hotkey (defaults to being unmapped)
- Xorg keyboard polling now uses cached Display variable [Bisqwit]
- cheat code database updated [mightymo]
2011-08-12 22:33:07 +10:00
Tim Allen
10906d8418 Update to v080r08 release.
byuu says, in a post between the v080r07 release and the v080r08
release:

phoenix/Windows:

The slider and scrollbar setParent calls setLength+setPosition, but
setLength sets position = 0 (due to new length possibly invalidating
previous position.)
Cache position first to fix this, can now reparent widgets with proper
slider/scroll positions.

ListView had a workaround where the horizontal scrollbar was always
appearing on single-column lists. The workaround was forcing the config
settings list in bsnes to only select the text portions of each item in
the list, instead of the entire lines. The workaround was needed because
without setting a single header text, the header text count was equal to
zero, causing autoSizeColumns to have no effect. Made the constructor
call setHeaderText("") to guarantee size() >= 1 always. Removes the need
for the workaround, and gives a good file browser and configuration
setting window.

phoenix/Qt:

Worked around Qt bugs #258,674+258,675: if you click a list item with
your mouse, currentItem()->isSelected() returns false. It does not
return true until you select an item with a keyboard key. I forced it to
set the selected item upon currentItemChanged() message. It was also not
sending a changed message upon clearing the selection and then selecting
the same item again. I had to do something undocumented:
setCurrentItem(nullptr) so that currentItemChanged works again.

phoenix/All:

Fonts are now initialized to the platform default settings, Tahoma or
Sans 8-point. This lets geometry on widgets not attached to windows work
better. Makes the ../... buttons smaller pretty much everywhere.

byuu says, announcing the v080r08 release:

Fixed all of the above phoenix issues, and improved the auto-disabling
of buttons on the input setting and state manager windows.
Also manually initiailized lastConfigure for Valgrind in GTK+. Windows
and GTK+ ports look a lot nicer now.
2011-08-08 22:04:47 +10:00
Tim Allen
e88ab60663 Update to v080r07 release.
byuu says:

- fixed a long-standing crash: when you have a device index above the
  range permitted by another port, the app would crash (eg Controller
  Port 2 -> Mouse, then switch to Hotkeys)
- Qt bug workaround: have to use currentItemChanged signal instead of
  itemSelectionChanged signal for QTreeWidget, otherwise scrolling with
  mouse gives you the previous item with currentItem() ...
- added support for toggling the Xfce compositor
- added support for detecting if the compositor is enabled in the first
  place on Windows, so that it won't get turned on when you had it off
  permanently
- added advanced setting to toggle behavior (never disable, disable only
  in fullscreen mode, disable whenever emulator is open)
- worked around GTK+ ../... button height issue
- worked around Windows slider position issue when attaching to a new
  window (need to research this one more)
- fixed up input settings window more: closing window ends assignment,
  custom mapping buttons hidden by default

Some of those bugs have been there since the phoenix port began, good
times.
2011-08-08 22:02:51 +10:00
Tim Allen
564e38ea9f Update to v080r06 release.
byuu says:

Ran out of time, so this is incomplete, but ...

Windows will disable the compositor in fullscreen mode, and enable it
when switching back to windowed mode. Should help with Vsync issues, but
of course only in fullscreen mode.

I've also merged the four settings windows back into a panel with a list
view (since I have no tab control widget.) The input settings window is
a bit incomplete, need to break assignment on window close, hide the
capture buttons on first showing, etc. Will probably try and finish that
up tonight.
2011-08-08 22:01:09 +10:00
Tim Allen
0c3f0834ab Update to v080r05 release.
byuu says:

Includes updated versions of nall and phoenix, which mostly improves the
GTK+ version. However, it appears to be crashing at the moment after
loading a game. Unfortunately it works when gdb is used, so I can't
easily debug it :/

You can now build with make phoenix=gtk if you want the GTK+ version on
Linux (the Qt version is leagues better even on Gnome, please use it if
at all possible.)

There's also settings.startFullScreen, config-file only, to allow for
front-end use. Forgot to add the reset/power hotkeys.

I also fixed compilation of ui-gameboy on GCC 4.6. I hope that's the
last switch(enum) error, those are damn annoying. Can't wait to switch
to GCC 4.6 on Windows.
2011-08-07 00:03:52 +10:00
Tim Allen
f38af85e0a Update to v080r04 release.
byuu says:

Adds nall/inflate.hpp and nall/unzip.hpp. Updates nall/resource.hpp to
encode and decode using ZIP/deflate files, rather than a much simpler
(and less powerful) LZSS implementation. Cuts the bsnes-logo.hpp file
from 270KB to 130KB, and the binary overhead from 80KB to 35KB.
2011-07-24 23:51:01 +10:00
Tim Allen
8276700381 Update to v080r03 release.
byuu says:

Wow, nothing in 19 days. Anyway, I wanted to get Nick's logo back in on
the about screen. Adds 80kb to both the binary and source archive, but
eh. Gotta have some style. Nothing else new.
2011-07-23 20:14:47 +10:00
Tim Allen
ec69109c0b Update to v080r02 release.
byuu says:

- added qstrlower and qstrupper; mainly for the sake of others wanting
  to patch bass
- added: string sha256(const uint8_t *data, unsigned size); for easier
  hash generation
- cleaned up the NEC DSP and Hitachi DSP XML mapping code; they are
  consistent now as well
- "necdsp" in paths.cfg is now "firmware", since it also affects the
  Hitachi DSP
- XML mapping was using program= for DSP-n/ST-001n and data= for Cx4;
  they both use firmware= now instead
- fixed icd2/interface casting issue for GCC 4.6.0 (thanks for the
  reminder, vEX)
- removed the last parts of code that used string << foo; and removed
  that from nall/string entirely
  - I need to do this for the debugger as well, I'll make sure that it
    compiles before v081 though
- converted all string(...) syntax to { ... } syntax that I could
  (obviously it won't cast to a function that takes const char* instead
  of const string&)

Probably some other tiny things. Just basic maintenance here.
2011-07-07 22:59:26 +10:00
Tim Allen
8ae6444af7 Update to v080r01 release.
byuu says:

There was one unfortunate aspect of the S-DD1 module: you had to give it
the DMA length and a target buffer, and it would do the entire
decompression at once. Real hardware would work by streaming the data
byte by byte. So with that, I went ahead and rewrote the code to handle
byte-based streaming.

This WIP is an important milestone for me personally. Up until now,
bsnes has always had code that was directly copy-pasted from other
authors. With all of the DSP and Cx4 chips rewritten in LLE, and the
SPC7110 algorithm already ported over from C, and archive decompression
code removed for a long time, the S-DD1 was the only module left like
this. It's obviously not that big of a deal. The code is basically still
a copy of the original. S-DD1 decomp from Andreas Naive, SPC7110 decomp
from neviksti, and S-DSP from blargg. And the rest of the emulator is of
course only possible because of code and research before it, although
everything else has no resemblance at all to code before it. The main
advantage, really, is absolute code consistency. I always use the same
variant of K&R, for instance. I dunno, I guess I just never really liked
the "Build-a-Bear Workshop" style of emulators, like is so prominent in
the Genesis scene: "My new Genesis emu (uses Starscream/Musashi 68K
core, Marat Fayzullin's Z80 core, YM2612 core from Game_Music_Emu, VDP
core from Gens, SVP core from picodrive)", sorry, but you wrote
a front-end, not an emulator :/

I also updated the SPC7110 decompression module: I merged the class
inside the SPC7110 class (not sure why it was separate before), and
replaced the morton lookup tables with for-loops. The morton tables were
added to be a tiny bit faster when I was more interested in speed than
code clarity. It may be a tiny bit slower (or faster due to less L2
cache usage), but you won't even notice an FPS drop, and it cuts out
a good chunk of code and some tables. Lastly, I added pinput_poll() to
video_refresh(). Forgot to remove Interface::input_poll() from the C++
side, will have to do that later.
2011-06-28 21:36:00 +10:00
Tim Allen
5fc86eae6d Update to v080 release.
byuu says:

This release adds low-level emulation of the Hitachi HG51B169 DSP, which
was used in Mega Man X2 and Mega Man X3 as the Cx4 chip. It also fixes
a regression in both the sound core and cheat engine.

You will now need the HG51B169 data ROM to play MMX2/MMX3.

Once again, Cx4 LLE could not have been possible without the help of Dr.
Decapitator, Jonas Quinn, Overload and Segher. Be sure to thank them,
please!

Changelog:
* added Cx4 low-level emulation; removed Cx4 high-level emulation code
* fixed S-SMP synchronization to S-CPU on CPUIO writes
* controllers now have their own threads and classes
* serial controller is now emulated as an actual controller, rather than
  as a coprocessor
* added link coprocessor module for special chip research and homebrew
* fixed cheat codes that target mask ROM addresses [Cydrak]
* fixed compilation error with the latest GCC 4.6.0 beta releases
* added flexibility to XML memory mapping file format
* updated to mightymo's latest cheat pack (2011-06-20)
2011-06-26 22:51:37 +10:00
Tim Allen
927c97eb06 Update to v079r06 release.
byuu says:

It does add some more code to the CPU::step() function, so performance
probably went down actually, by about 1%. Removing the input.tick() call
didn't compensate as much as I'd hoped.
Hooked up Super Scope and Justifier support. The good news is that the
Justifier alignment doesn't get fucked up anymore when you go
off-screen. Never could fix that in the old version.
The bad news is that it takes a major speed hit for the time being.
I need to figure out how to run the CPU and input threads out of order.
Every time I try, the input gets thrown off by most of a scanline.
Right now, I'm forced to sync constantly to get the latching position
really accurate. But worst case, I can cut the syncs down by skipping
large chunks around the cursor position, +/-40 clock cycles. So it's
only temporarily slow.
Lastly, killed the old Input class, merged Controllers class into it.
I actually like Controllers as a name better, but it doesn't jive with
video/audio/input, so oh well.
2011-06-25 22:56:32 +10:00
Tim Allen
cf09d41669 Update to v079r05 release.
byuu says:

- Fixed GCC-4.6 casting errors in ui/input/input.cpp.
- Fixed some of the opcode mnemonics specified in the HG51B169 core (was
  unable to speed up the code)
- Started on a new core input system: snes/controller. More on that
  here:

    http://board.byuu.org/viewtopic.php?f=16&t=1761

- Have not yet attempted to add threading support to the controllers, so
  serial is still there as a coprocessor.
- I'm going to move the Controllers {} class back to Input {} once all
  individual controllers have been ported over.

Note: Super Scope and Justifier do not have counter latching support
yet, so you can't really use them. The gamepad, multitap and mouse all
work great; and the SS/Justifier cursors work at least. I also colored
the SS cursor red, so that all three (SS, Justifier, chained secondary
Justifier) all have unique R/G/B colors now. Should prevent confusion
between the SS and one Justifier.
2011-06-24 20:43:29 +10:00
Tim Allen
724747ac9e Update to v079r04 release.
byuu says:

Back from vacation. We were successful in emulating the Cx4 using LLE
during my vacation. We finished on June 15th. And now that I'm back,
I've rewritten the code and merged it into bsnes official. With that,
the very last HLE emulation code in bsnes has now been purged.

[...]

The emulation is as minimal as possible. If I don't see an opcode or
feature actually used, I don't implement it. The one exception being
that I do support the vector override functionality. And there are also
dummy handlers for ld ?,$2e + loop, so that the chip won't stall out.
But things like "byte 4" on rdram/wrram, the two-bit destination
selections for all but ld, etc are treated as invalid opcodes, since we
aren't 100% sure if they are there and work as we hypothesize. I also
only map in known registers into the 256-entry register list. This
leaves 90% of the map empty.

The chip runs at 20MHz, and it will disable the ROM while running. DMA
does transfer one byte at a time against the clock and also locks out
the ROM. rdbus won't fetch from IRAM, only from ROM. DMA transfer only
reads from ROM, and only writes to RAM. Unless someone verifies that
they can do more, I'll leave it that way. I don't yet actually buffer
the program ROM into the internal program RAM just yet, but that is on
the to-do list. We aren't entirely sure how that works either, but my
plan is to just lock the Cx4 CPU and load in 512-bytes.

There's still a few unknown registers in $7f40-5f that I don't do
anything with yet. The secondary chip disable is going to be the
weirdest one, since MMX3 only has one chip. I'd really rather not have
to specify the ROM mapping as two separate chips on MMX2 and as one on
MMX3 just to support this, so I don't know yet.

Save state support is of course there already.

Speed hit is 118fps HLE -> 109fps LLE in most scenes. Not bad, honestly.
2011-06-22 23:27:55 +10:00
Tim Allen
e1e275eb38 Update to v079r03 release.
byuu says:

This fixes the S-SMP synchronization on CPUIO writes that was broken by
improvements in v078.01. Terranigma will work now. Also adds the 'link'
coprocessor module that was added in v079.01, and improved in v079.02.
2011-06-13 22:26:48 +10:00
Tim Allen
e30fcade43 Update to v079r02 release.
byuu says:

Added "unsigned link_run();" which acts as its own thread synchronized
against the S-CPU. Specify the frequency in the configuration file.
I intend to prototype the Cx4 LLE openly using the link module, and that
required timing support, so there we go.

It's very basic, and it synchronizes the CPU to the coprocessors and
vice versa after every call to link_run(). Meaning performance won't be
super exceptional at full 21MHz or higher, but then this is for
prototyping only. I didn't want to expose cothreading, yielding, calls
back into bsnes' core, calls to sync up the S-CPU, etc.
2011-06-13 22:22:06 +10:00
Tim Allen
42dbf73d18 Update to v079r01 release.
This version adds a "link" SNES coprocessor module, which just loads
a shared library. It was posted outside the v079 WIP thread, in this
thread:

    http://board.byuu.org/viewtopic.php?f=16&t=1700
2011-06-13 22:13:30 +10:00
Tim Allen
2a90e12999 Update to v079 release.
byuu says:

This release includes Nintendo Super System DIP switch emulation and
improved PPU rendering accuracy, among other things.

Changelog:
- added Nintendo Super System DIP switch emulation [requires XML setting
  maps]
- emulated Super Game Boy $6001 VRAM offset selection port [ikari_01]
- fixed randomness initialization of S-SMP port registers [fixes
  DBZ:Hyper Dimension and Ninja Warriors]
- mosaic V-countdown caches BGOFS registers (fixes Super Turrican
  2 effect) [reported by zal16]
- non-mosaic BGOFS registers are always cached at H=60 (fixes NHL '94
  and Super Mario World flickering)
- fixed 2xSaI family of renderers on 64-bit systems
- cleaned up SMP source code
- phoenix: fixed a bug when closing bsnes while minimized

Please note that the mosaic BGOFS fix is only for the accuracy profile.
Unfortunately the older scanline-based compatibility renderer's code is
nearly unmaintainable at this point, so I haven't yet been able to
backport the fixes.

Also, I have written a new cycle-accurate SMP core that does not use
libco. The aim is to implement it into Snes9X v1.54. But it would of
course be prudent to test the new core first.

[...then in the next post...]

Decided to keep that Super Mario World part a surprise, so ... surprise!

Realized while working on the Super Turrican 2 mosaic fix, and from
looking at NHL '94 and Dai Kaijuu Monogatari 2's behavior, that BGOFS
registers must be cached between H=0 and H=88 for the entire scanline
... they can't work otherwise, and it'd be stupid for the PPU to re-add
the offset to the position on every pixel anyway. I chose H=60 for now.
Once I am set up with the RGB monitor and the North American cartridge
dumping is completed, I'll set it on getting exact timings for all these
things. It'll probably require a smallish speed hit to allow exact-cycle
timing events for everything in the PPU.
2011-06-05 13:45:04 +10:00
Tim Allen
d129b72ced Update to v078r07 release.
byuu says:

Would appreciate testing on any games with mosaic, especially Mode7
mosaic.I have tested Super Turrican 2, Sim Earth, Contra III and SNES
Test Program.

This only applies to BG modes 0-6, and technically should not affect
Mode7 at all. I am not sure if Mode7 needs the same change made or not,
but given the way it fetches that could prove quite challenging. I also
simplified the background renderer a good bit. See eg the pixel copy
stuff in Background::run().

I've only fixed this in the accuracy renderer. I'm sorry, but the
compatibility renderer is a fucking mess. I haven't really touched it in
four or five years now.

Will probably just revert to the accuracy/SMP in the performance profile
for the next release since it's not being used otherwise. People can
toggle it on if they want to try it out.
2011-06-05 13:25:24 +10:00
Tim Allen
bc0b86891a Update to v078r06 release.
byuu says:

This adds ikari_01's emulation of the ICD2 (Super Game Boy) $6001 register.

It basically removes a really ugly hack where I was intercepting the DMA
transfer destination address to determine while Game Boy tile row to
transfer.  This should make implementing SGB emulation in other
emulators easier, as said hooks were very emulator-specific.
2011-05-08 23:46:37 +10:00
Tim Allen
52443936e6 Update to v078r05 release.
byuu says:

This WIP adds Nintendo Super System emulation, at least of its DIP
switches.  This is done via XML mapping, like so:

    <?xml version="1.0" encoding="UTF-8"?>
    <cartridge region="NTSC">
      <name>ActRaiser</name>
      <rom>
	<map mode="linear" address="00-7f:8000-ffff"/>
	<map mode="linear" address="80-ff:8000-ffff"/>
      </rom>
      <nss>
	<setting name="Difficulty">
	  <option value="0000" name="Easy"/>
	  <option value="0001" name="Normal"/>
	  <option value="0002" name="Hard"/>
	  <option value="0003" name="Expert"/>
	</setting>
	<setting name="Lives">
	  <option value="0000" name="5 lives"/>
	  <option value="0004" name="4 lives"/>
	  <option value="0008" name="3 lives"/>
	  <option value="000c" name="2 lives"/>
	</setting>
      </nss>
    </cartridge>

The value field is a 16-bit value. All selected options are ORed
together to produce the final DIP switch values.  The number of options
per setting is unlimited, but there are only sixteen settings allowed
(you can't have more settings than you have switches, that's just
stupid.)

In the example above, d0-d1 controls difficulty, and d2-d3 controls # of
lives. d4-d15 appear to be unused, as far as I can tell.
2011-05-07 00:16:46 +10:00
Tim Allen
6694a1c986 Update to v078r04 release.
byuu says:

Changelog:
- file and slot load dialogs should now have perfectly square buttons
  that are based on the platform's default button height.
- cleaned up bsnes/Accuracy SMP source code (removed old !! stuff, stage
  3 timer is now uint4, memory access switch/case cleaned up,
  sSMPTimer->Timer, etc.)
- cleaned up bsnes/Accuracy memory access functions (read/writestack ->
  read/writesp, read/writeaddr -> read/write)
- minor optimization to bsnes/Performance SMP core in cycle-mode
2011-05-05 21:40:22 +10:00
Tim Allen
7ffaeb2ac1 Update to v078r03 release.
byuu says:

I apparently wasted two days writing that SMP core for nothing.  I had
a perfectly well-written and well-tested core in bsnes v045.  The old
opcode.b files that were a cycle-based markup language.

So I took that core, and wrote new parsers to generate both opcode-based
(one switch) and cycle-based (two switch) cores. Throw in a
little #define magic around CYCLE_ACCURATE, and it is compile-time
toggleable.

EWJ2's bug was due to not resetting the timer variables, and Bahamut
Lagoon's was due to dividing timer frequencies by 3, but failing to
remove the 0->1 transition phase (should have done the latter and
divided by two.)

Anyway, all fixed up.
2011-05-05 21:37:46 +10:00
Tim Allen
67e6a6e742 Update to v078r02 release.
byuu says:

New S-SMP core is feature-complete, but still buggy.  It's good enough
for perfect audio in Zelda 3 and Super Mario World, but there are plenty
of issues.  No audio in Bahamut Lagoon, deadlock in Earthworm Jim 2,
etc.

With this core, bsnes/Performance runs about 3-5% faster than with the
old one. That won't seem like much, because the S-SMP is the least
demanding portion of the SNES.  blargg's SMP core netted me a 5-8%
speedup the last time I tried it, so I'm sure there's still room to
speed things up.

The core is opcode-based, but has dummy op_io() calls (they compile to
nothing), so it is trivial to make it cycle-based if desired.  I'm not
convinced that is necessary, but we shall see once we get the opcode
bugs ironed out.
2011-05-03 19:58:12 +10:00
Tim Allen
9a3650c6ab Update to v078r01 release.
byuu says:

Started on a new SMP core for bsnes/Performance. I wanted to start
clean, and only copied over the debugger+disassembler portions from the
existing version.  I figured that if I took the existing one and tried
trimming it down, that it'd end up with too much old baggage.  But so
far, the opcodes are looking mostly the same anyway, only I'm
using #defines and a switch table in place of the template function
trickery.

I have enough written now that I can run Zelda 3 at least (although it
gets stuck in a loop immediately after.) No real point in comparing
speed yet, because it'll definitely go down as it becomes more complete.
2011-05-02 23:53:16 +10:00
Tim Allen
0a3d6e4c53 Update to v078 release.
byuu says:

Finally, a new release. I have been very busy finishing up SNES box,
cartridge and PCB scanning plus cataloguing the data, however this
release still has some significant improvements.

Most notably would be randomization on startup. This will help match the
behavior of real hardware and uninitialized memory + registers. It
should help catch homebrew software that forgets to initialize things
properly. Of course, I was not able to test the complete library, so it
is possible that if I've randomized anything that should be constant,
that this could cause a regression. You can disable this randomization
for netplay or to work around any incompatibilities by editing bsnes.cfg
and setting snes.random to false.

The GUI also received some updates. Widget sizes are now computed based
on font sizes, giving it a perfectly native look (because it is native.)
I've also added a hotkey remapping screen to the input settings. Not
only can you remap inputs to controllers now, but those who did not know
the hotkey bindings can now quickly see which ones exist and what they
are mapped to.

Changelog (since v077):

- memory and most registers are now randomly initialized on power-up
- fixed auto joypad polling issue in Super Star Wars
- fixed .nec and .rtc file extensions (they were missing the dot) [krom]
- PPU/accuracy now clears overscan region on any frame when it is
  disabled
- PPU/compatibility no longer auto-blends hires pixels (use NTSC filter
  for this)
- added hotkey remapping dialog to input settings window
- added a few new hotkeys, including quick-reset
- phoenix API now auto-sizes widgets based on font sizes
- file dialog once again remembers previously selected file when
  possible
2011-04-30 23:12:15 +10:00
Tim Allen
378b78dad7 Update to v077r05 release.
byuu says:

Changelog:
- fixed .nec and both .rtc file extensions (thanks krom)
- randomized most S-PPU registers, should trip up some broken homebrew
  that does not initialize all registers
- randomization is now seeded with time(0) rather than 'byuu'
- SNES::interface.video_refresh() now always receives
  {256,512}x{240,480}
- PPU/accuracy scanline 0 does not render the screen back color anymore,
  fixes strange coloring look on first scanline in PAL TV mode in
  non-overscan games
- disabled hires blending in PPU/compatibility; all three cores act the
  same now
2011-04-27 18:57:31 +10:00
Tim Allen
721e0b1762 Update to v077r04 release.
byuu says:

Changelog:
- setGeometry is called after append(layout) now. This fixes the window
  sizing on Qt.
- removed enum Style {} code, as it's no longer necessary.
- removed Filter, Shader path selection code from the file load dialog,
  since that is menu-driven now.
- improved the file load dialog to remember last selected file when mode
  doesn't change (had to split a switch statement into two switches.)
- added Hotkeys port onto input settings window, allowing one to
  dynamically see and remap GUI shortcuts
- added power cycle / reset shortcuts

Still very minimal with the hotkeys, so I packed them all into one group
for now. A few more I'd like to add, but I don't want to get ridiculous
like with the Qt GUI.
2011-03-26 22:31:07 +11:00
Tim Allen
2bf3dbf375 Update to v077r03 release.
byuu says:

Fixed up the geometry calculation code. There is now minimumGeometry()
[returns minimum size needed to display a layout, treats MaximumSize as
MinimumSize], and minimumLayoutGeometry() [like minimumGeometry(), but
it will return MaximumSize if a single container item has that
attribute. Used mostly internally for layout sizing.]

It looks great on Windows, but it looks visually off on Qt. Not exactly
sure what's up there. When I make a test application, everything looks
great. Going to have to clone a bsnes window that's having a problem (eg
bsnes main debugger checkbox window), and see what's up.
2011-03-23 19:04:37 +11:00
Tim Allen
396003e7f6 Update to v077r02 release.
byuu says:

Wouldn't recommend using this, but it has bsnes ported to the new auto-size calculating phoenix API.

Known issues:
- minimumWidth/Height on layouts isn't working right, windows that use
  it are usually too small
- Windows gives 0,0 size for empty text string sizes, which messes up
  a lot of default sizes for LineEdit controls
2011-03-22 23:56:49 +11:00
Tim Allen
a92a554d7b Update to v077r01 release.
byuu says:

Changelog:
- fixed auto joypad polling bug (fixes Super Star Wars start button
  input)
- added pseudo-random class; so far it is RAM only [WRAM, APURAM, VRAM,
  OAM, CGRAM]
- added new system configuration options to bsnes.cfg

The pseudo-random class is optional. For right now, I am defaulting it
to enabled. bsnes.cfg::snes.random = true.
You can of course turn it off if you want. This will break Death Brade
and Unnamed Euro Racer, no questions about it.
So I don't know if I want to leave this on or off by default. Leaving it
on will thwart emulator detection code and help to keep code that relies
on uninitialized memory from working, but leaving it off will increase
compatibility.
2011-03-21 00:57:55 +11:00
436 changed files with 23749 additions and 7085 deletions

View File

@@ -3,9 +3,9 @@ snes := snes
gameboy := gameboy
profile := accuracy
ui := ui
# phoenix := gtk
# debugger
options :=
# options += debugger
# compiler
c := $(compiler) -std=gnu99

1228
bsnes/data/bsnes-logo.hpp Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,7 @@ void APU::Wave::power() {
frequency = 0;
counter = 0;
random_cyclic r;
random_lfsr r;
foreach(n, pattern) n = r() & 15;
output = 0;

View File

@@ -1,5 +1,6 @@
class Interface {
public:
virtual void lcd_scanline() {}
virtual void joyp_write(bool p15, bool p14) {}
virtual void video_refresh(const uint8_t *data) {}

View File

@@ -75,6 +75,7 @@ void LCD::render() {
uint8_t *output = screen + status.ly * 160;
for(unsigned n = 0; n < 160; n++) output[n] = (3 - line[n]) * 0x55;
system.interface->lcd_scanline();
}
uint16 LCD::read_tile(bool select, unsigned x, unsigned y) {

View File

@@ -54,6 +54,10 @@ namespace nall {
operator[](buffersize) = data;
}
void remove() {
if(size > 0) resize(size - 1); //remove last element only
}
template<typename U> void insert(unsigned index, const U list) {
unsigned listsize = container_size(list);
resize(buffersize + listsize);
@@ -133,6 +137,12 @@ namespace nall {
if(index >= buffersize) throw "array[] out of bounds";
return pool[index];
}
//iteration
T* begin() { return &pool[0]; }
T* end() { return &pool[buffersize]; }
const T* begin() const { return &pool[0]; }
const T* end() const { return &pool[buffersize]; }
};
template<typename T> struct has_size<array<T>> { enum { value = true }; };

View File

@@ -72,6 +72,7 @@ namespace nall {
private:
static char enc(uint8_t n) {
//base64 for URL encodings
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
return lookup_table[n & 63];
}

101
bsnes/nall/bmp.hpp Executable file
View File

@@ -0,0 +1,101 @@
#ifndef NALL_BMP_HPP
#define NALL_BMP_HPP
#include <nall/file.hpp>
//BMP reader / writer
//author: byuu
//note: only 24-bit RGB and 32-bit ARGB uncompressed images supported
namespace nall {
struct bmp {
inline static bool read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height);
inline static bool write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha = false);
};
bool bmp::read(const string &filename, uint32_t *&data, unsigned &width, unsigned &height) {
file fp;
if(fp.open(filename, file::mode::read) == false) return false;
if(fp.size() < 0x36) return false;
if(fp.readm(2) != 0x424d) return false;
fp.seek(0x000a);
unsigned offset = fp.readl(4);
unsigned dibsize = fp.readl(4);
if(dibsize != 40) return false;
signed headerWidth = fp.readl(4);
if(headerWidth < 0) return false;
signed headerHeight = fp.readl(4);
fp.readl(2);
unsigned bitsPerPixel = fp.readl(2);
if(bitsPerPixel != 24 && bitsPerPixel != 32) return false;
unsigned compression = fp.readl(4);
if(compression != 0) return false;
fp.seek(offset);
bool noFlip = headerHeight < 0;
width = headerWidth, height = abs(headerHeight);
data = new uint32_t[width * height];
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
for(unsigned y = 0; y < height; y++) {
uint32_t *p = noFlip ? data + y * width : data + (height - 1 - y) * width;
for(unsigned x = 0; x < width; x++, p++) {
*p = fp.readl(bytesPerPixel);
if(bytesPerPixel == 3) *p |= 255 << 24;
}
if(paddingLength) fp.readl(paddingLength);
}
fp.close();
return true;
}
bool bmp::write(const string &filename, const uint32_t *data, unsigned width, unsigned height, unsigned pitch, bool alpha) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
unsigned bitsPerPixel = alpha ? 32 : 24;
unsigned bytesPerPixel = bitsPerPixel / 8;
unsigned alignedWidth = width * bytesPerPixel;
unsigned paddingLength = 0;
unsigned imageSize = alignedWidth * height;
unsigned fileSize = 0x36 + imageSize;
while(alignedWidth % 4) alignedWidth++, paddingLength++;
fp.writem(0x424d, 2); //signature
fp.writel(fileSize, 4); //file size
fp.writel(0, 2); //reserved
fp.writel(0, 2); //reserved
fp.writel(0x36, 4); //offset
fp.writel(40, 4); //DIB size
fp.writel(width, 4); //width
fp.writel(-height, 4); //height
fp.writel(1, 2); //color planes
fp.writel(bitsPerPixel, 2); //bits per pixel
fp.writel(0, 4); //compression method (BI_RGB)
fp.writel(imageSize, 4); //image data size
fp.writel(3780, 4); //horizontal resolution
fp.writel(3780, 4); //vertical resolution
fp.writel(0, 4); //palette size
fp.writel(0, 4); //important color count
for(unsigned y = 0; y < height; y++) {
const uint32_t *p = (const uint32_t*)((const uint8_t*)data + y * pitch);
for(unsigned x = 0; x < width; x++) fp.writel(*p++, bytesPerPixel);
if(paddingLength) fp.writel(0, paddingLength);
}
fp.close();
return true;
}
}
#endif

79
bsnes/nall/compositor.hpp Executable file
View File

@@ -0,0 +1,79 @@
#ifndef NALL_COMPOSITOR_HPP
#define NALL_COMPOSITOR_HPP
#include <nall/detect.hpp>
namespace nall {
struct compositor {
inline static bool enabled();
inline static bool enable(bool status);
};
#if defined(PLATFORM_X)
bool compositor::enabled() {
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
if(fp == 0) return false;
char buffer[512];
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
if(!memcmp(buffer, "true", 4)) return true;
return false;
}
bool compositor::enable(bool status) {
FILE *fp;
if(status) {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
} else {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
}
if(fp == 0) return false;
pclose(fp);
return true;
}
#elif defined(PLATFORM_WIN)
bool compositor::enabled() {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
if(pDwmIsCompositionEnabled == 0) return false;
BOOL result;
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
return result;
}
bool compositor::enable(bool status) {
HMODULE module = GetModuleHandleW(L"dwmapi");
if(module == 0) module = LoadLibraryW(L"dwmapi");
if(module == 0) return false;
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
if(pDwmEnableComposition == 0) return false;
if(pDwmEnableComposition(status) != S_OK) return false;
return true;
}
#else
bool compositor::enabled() {
return false;
}
bool compositor::enable(bool) {
return false;
}
#endif
}
#endif

View File

@@ -34,11 +34,11 @@ namespace nall {
string get() const {
switch(type) {
case boolean_t: return string() << *(bool*)data;
case signed_t: return string() << *(signed*)data;
case unsigned_t: return string() << *(unsigned*)data;
case double_t: return string() << *(double*)data;
case string_t: return string() << "\"" << *(string*)data << "\"";
case boolean_t: return { *(bool*)data };
case signed_t: return { *(signed*)data };
case unsigned_t: return { *(unsigned*)data };
case double_t: return { *(double*)data };
case string_t: return { "\"", *(string*)data, "\"" };
}
return "???";
}
@@ -105,9 +105,9 @@ namespace nall {
if(fp.open(filename, file::mode::write)) {
for(unsigned i = 0; i < list.size(); i++) {
string output;
output << list[i].name << " = " << list[i].get();
if(list[i].desc != "") output << " # " << list[i].desc;
output << "\r\n";
output.append(list[i].name, " = ", list[i].get());
if(list[i].desc != "") output.append(" # ", list[i].desc);
output.append("\r\n");
fp.print(output);
}

View File

@@ -1,75 +0,0 @@
#ifndef NALL_DICTIONARY_HPP
#define NALL_DICTIONARY_HPP
#include <nall/array.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
namespace nall {
class dictionary {
public:
string operator[](const char *input) {
for(unsigned i = 0; i < index_input.size(); i++) {
if(index_input[i] == input) return index_output[i];
}
//no match, use input; remove input identifier, if one exists
if(strbegin(input, "{{")) {
if(auto pos = strpos(input, "}}")) {
string temp = substr(input, pos() + 2);
return temp;
}
}
return input;
}
bool import(const char *filename) {
string data;
if(data.readfile(filename) == false) return false;
data.ltrim<1>("\xef\xbb\xbf"); //remove UTF-8 marker, if it exists
data.replace("\r", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
//format: "Input" = "Output"
part.qsplit("=", line[i]);
if(part.size() != 2) continue;
//remove whitespace
part[0].trim();
part[1].trim();
//remove quotes
part[0].trim<1>("\"");
part[1].trim<1>("\"");
unsigned n = index_input.size();
index_input[n] = part[0];
index_output[n] = part[1];
}
return true;
}
void reset() {
index_input.reset();
index_output.reset();
}
~dictionary() {
reset();
}
dictionary& operator=(const dictionary&) = delete;
dictionary(const dictionary&) = delete;
protected:
lstring index_input;
lstring index_output;
};
}
#endif

View File

@@ -6,7 +6,7 @@
#include <nall/string.hpp>
#if defined(_WIN32)
#include <nall/utf8.hpp>
#include <nall/windows/utf8.hpp>
#else
#include <dirent.h>
#include <stdio.h>
@@ -42,20 +42,21 @@ struct directory {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
if(wildcard(name, pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(string(name, "/"));
if(wildcard(name, pattern)) list.append(name);
}
}
}
FindClose(handle);
}
if(list.size() > 0) sort(&list[0], list.size());
foreach(name, list) name.append("/"); //must append after sorting
return list;
}
@@ -109,14 +110,14 @@ struct directory {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(string(ep->d_name, "/"));
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
}
if(list.size() > 0) sort(&list[0], list.size());
foreach(name, list) name.append("/"); //must append after sorting
return list;
}
inline lstring directory::files(const string &pathname, const string &pattern) {

View File

@@ -12,7 +12,7 @@
#include <dlfcn.h>
#elif defined(PLATFORM_WIN)
#include <windows.h>
#include <nall/utf8.hpp>
#include <nall/windows/utf8.hpp>
#endif
namespace nall {

View File

@@ -1,22 +1,14 @@
#ifndef NALL_FILE_HPP
#define NALL_FILE_HPP
#include <stdio.h>
#include <string.h>
#if !defined(_WIN32)
#include <unistd.h>
#else
#include <io.h>
#endif
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utf8.hpp>
#include <nall/utility.hpp>
#include <nall/windows/utf8.hpp>
namespace nall {
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
#if !defined(_WIN32)
return fopen(utf8_filename, mode);
#else
@@ -28,6 +20,25 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
enum class index : unsigned { absolute, relative };
enum class time : unsigned { create, modify, access };
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
file fp;
if(fp.open(filename, mode::read) == false) return false;
size = fp.size();
data = new uint8_t[size];
fp.read(data, size);
fp.close();
return true;
}
static bool write(const string &filename, const uint8_t *data, unsigned size) {
file fp;
if(fp.open(filename, mode::write) == false) return false;
fp.write(data, size);
fp.close();
return true;
}
uint8_t read() {
if(!fp) return 0xff; //file not open
@@ -142,52 +153,60 @@ namespace nall {
return file_offset >= file_size;
}
static bool exists(const char *fn) {
static bool exists(const string &filename) {
#if !defined(_WIN32)
FILE *fp = fopen(fn, "rb");
struct stat64 data;
return stat64(filename, &data) == 0;
#else
FILE *fp = _wfopen(utf16_t(fn), L"rb");
struct __stat64 data;
return _wstat64(utf16_t(filename), &data) == 0;
#endif
if(fp) {
fclose(fp);
return true;
}
return false;
}
static unsigned size(const char *fn) {
static uintmax_t size(const string &filename) {
#if !defined(_WIN32)
FILE *fp = fopen(fn, "rb");
struct stat64 data;
stat64(filename, &data);
#else
FILE *fp = _wfopen(utf16_t(fn), L"rb");
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
unsigned filesize = 0;
if(fp) {
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fclose(fp);
return S_ISREG(data.st_mode) ? data.st_size : 0u;
}
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
#if !defined(_WIN32)
struct stat64 data;
stat64(filename, &data);
#else
struct __stat64 data;
_wstat64(utf16_t(filename), &data);
#endif
switch(mode) { default:
case file::time::create: return data.st_ctime;
case file::time::modify: return data.st_mtime;
case file::time::access: return data.st_atime;
}
return filesize;
}
bool open() {
return fp;
}
bool open(const char *fn, mode mode_) {
bool open(const string &filename, mode mode_) {
if(fp) return false;
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(filename, "rb" ); break;
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
case mode::readwrite: fp = fopen(filename, "rb+"); break;
case mode::writeread: fp = fopen(filename, "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(filename), L"rb" ); break;
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
#endif
}
if(!fp) return false;

View File

@@ -2,7 +2,7 @@
#define NALL_FILEMAP_HPP
#include <nall/stdint.hpp>
#include <nall/utf8.hpp>
#include <nall/windows/utf8.hpp>
#include <stdio.h>
#include <stdlib.h>
@@ -21,7 +21,7 @@ namespace nall {
public:
enum class mode : unsigned { read, write, readwrite, writeread };
bool opened() const { return p_opened(); }
bool open() const { return p_open(); }
bool open(const char *filename, mode mode_) { return p_open(filename, mode_); }
void close() { return p_close(); }
unsigned size() const { return p_size; }
@@ -42,7 +42,7 @@ namespace nall {
HANDLE p_filehandle, p_maphandle;
bool p_opened() const {
bool p_open() const {
return p_handle;
}
@@ -128,7 +128,7 @@ namespace nall {
int p_fd;
bool p_opened() const {
bool p_open() const {
return p_handle;
}

View File

@@ -86,17 +86,17 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
xml << "<cartridge mapper='" << info.mapper << "'";
if(info.rtc) xml << " rtc='true'";
if(info.rumble) xml << " rumble='true'";
xml << ">\n";
xml.append("<cartridge mapper='", info.mapper, "'");
if(info.rtc) xml.append(" rtc='true'");
if(info.rumble) xml.append(" rumble='true'");
xml.append(">\n");
xml << " <rom size='" << hex(romsize) << "'/>\n"; //TODO: trust/check info.romsize?
xml.append(" <rom size='", hex(romsize), "'/>\n"); //TODO: trust/check info.romsize?
if(info.ramsize > 0)
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
xml.append(" <ram size='", hex(info.ramsize), "' battery='", info.battery, "'/>\n");
xml << "</cartridge>\n";
xml.append("</cartridge>\n");
xml.transform("'", "\"");
}

87
bsnes/nall/gzip.hpp Executable file
View File

@@ -0,0 +1,87 @@
#ifndef NALL_GZIP_HPP
#define NALL_GZIP_HPP
#include <nall/file.hpp>
#include <nall/inflate.hpp>
namespace nall {
struct gzip {
string filename;
uint8_t *data;
unsigned size;
bool decompress(const string &filename);
bool decompress(const uint8_t *data, unsigned size);
gzip();
~gzip();
};
bool gzip::decompress(const string &filename) {
uint8_t *data;
unsigned size;
if(file::read(filename, data, size) == false) return false;
bool result = decompress(data, size);
delete[] data;
return result;
}
bool gzip::decompress(const uint8_t *data, unsigned size) {
if(size < 18) return false;
if(data[0] != 0x1f) return false;
if(data[1] != 0x8b) return false;
unsigned cm = data[2];
unsigned flg = data[3];
unsigned mtime = data[4];
mtime |= data[5] << 8;
mtime |= data[6] << 16;
mtime |= data[7] << 24;
unsigned xfl = data[8];
unsigned os = data[9];
unsigned p = 10;
unsigned isize = data[size - 4];
isize |= data[size - 3] << 8;
isize |= data[size - 2] << 16;
isize |= data[size - 1] << 24;
filename = "";
if(flg & 0x04) { //FEXTRA
unsigned xlen = data[p + 0];
xlen |= data[p + 1] << 8;
p += 2 + xlen;
}
if(flg & 0x08) { //FNAME
char buffer[PATH_MAX];
for(unsigned n = 0; n < PATH_MAX; n++, p++) {
buffer[n] = data[p];
if(data[p] == 0) break;
}
if(data[p++]) return false;
filename = buffer;
}
if(flg & 0x10) { //FCOMMENT
while(data[p++]);
}
if(flg & 0x02) { //FHCRC
p += 2;
}
this->size = isize;
this->data = new uint8_t[this->size];
return inflate(this->data, this->size, data + p, size - p - 8);
}
gzip::gzip() : data(0) {
}
gzip::~gzip() {
if(data) delete[] data;
}
}
#endif

176
bsnes/nall/http.hpp Executable file
View File

@@ -0,0 +1,176 @@
#ifndef NALL_HTTP_HPP
#define NALL_HTTP_HPP
#if !defined(_WIN32)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#else
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <nall/platform.hpp>
#include <nall/string.hpp>
namespace nall {
struct http {
string hostname;
addrinfo *serverinfo;
int serversocket;
string header;
inline void download(const string &path, uint8_t *&data, unsigned &size) {
data = 0;
size = 0;
send({
"GET ", path, " HTTP/1.1\r\n"
"Host: ", hostname, "\r\n"
"Connection: close\r\n"
"\r\n"
});
header = downloadHeader();
downloadContent(data, size);
}
inline bool connect(string host, unsigned port) {
hostname = host;
addrinfo hints;
memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(hostname, string(port), &hints, &serverinfo);
if(status != 0) return false;
serversocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
if(serversocket == -1) return false;
int result = ::connect(serversocket, serverinfo->ai_addr, serverinfo->ai_addrlen);
if(result == -1) return false;
return true;
}
inline bool send(const string &data) {
return send((const uint8_t*)(const char*)data, data.length());
}
inline bool send(const uint8_t *data, unsigned size) {
while(size) {
int length = ::send(serversocket, (const char*)data, size, 0);
if(length == -1) return false;
data += length;
size -= length;
}
return true;
}
inline string downloadHeader() {
string output;
do {
char buffer[2];
int length = recv(serversocket, buffer, 1, 0);
if(length <= 0) return output;
buffer[1] = 0;
output.append(buffer);
} while(output.endswith("\r\n\r\n") == false);
return output;
}
inline string downloadChunkLength() {
string output;
do {
char buffer[2];
int length = recv(serversocket, buffer, 1, 0);
if(length <= 0) return output;
buffer[1] = 0;
output.append(buffer);
} while(output.endswith("\r\n") == false);
return output;
}
inline void downloadContent(uint8_t *&data, unsigned &size) {
unsigned capacity = 0;
if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) {
while(true) {
unsigned length = hex(downloadChunkLength());
if(length == 0) break;
capacity += length;
data = (uint8_t*)realloc(data, capacity);
char buffer[length];
while(length) {
int packetlength = recv(serversocket, buffer, length, 0);
if(packetlength <= 0) break;
memcpy(data + size, buffer, packetlength);
size += packetlength;
length -= packetlength;
}
}
} else if(auto position = header.iposition("\r\nContent-Length: ")) {
unsigned length = decimal((const char*)header + position() + 16);
while(length) {
char buffer[256];
int packetlength = recv(serversocket, buffer, min(256, length), 0);
if(packetlength <= 0) break;
capacity += packetlength;
data = (uint8_t*)realloc(data, capacity);
memcpy(data + size, buffer, packetlength);
size += packetlength;
length -= packetlength;
}
} else {
while(true) {
char buffer[256];
int packetlength = recv(serversocket, buffer, 256, 0);
if(packetlength <= 0) break;
capacity += packetlength;
data = (uint8_t*)realloc(data, capacity);
memcpy(data + size, buffer, packetlength);
size += packetlength;
}
}
data = (uint8_t*)realloc(data, capacity + 1);
data[capacity] = 0;
}
inline void disconnect() {
close(serversocket);
freeaddrinfo(serverinfo);
serverinfo = 0;
serversocket = -1;
}
#ifdef _WIN32
inline int close(int sock) {
return closesocket(sock);
}
inline http() {
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock == INVALID_SOCKET && WSAGetLastError() == WSANOTINITIALISED) {
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
WSACleanup();
return;
}
} else {
close(sock);
}
}
#endif
};
}
#endif

358
bsnes/nall/inflate.hpp Executable file
View File

@@ -0,0 +1,358 @@
#ifndef NALL_INFLATE_HPP
#define NALL_INFLATE_HPP
#include <setjmp.h>
namespace nall {
namespace puff {
inline int puff(
unsigned char *dest, unsigned long *destlen,
unsigned char *source, unsigned long *sourcelen
);
}
inline bool inflate(
uint8_t *target, unsigned targetLength,
const uint8_t *source, unsigned sourceLength
) {
unsigned long tl = targetLength, sl = sourceLength;
int result = puff::puff((unsigned char*)target, &tl, (unsigned char*)source, &sl);
return result == 0;
}
namespace puff {
//zlib/contrib/puff.c
//version 2.1*
//author: Mark Adler
//license: zlib
//ported by: byuu
//* I have corrected a bug in fixed(), where it was accessing uninitialized
// memory: calling construct() with lencode prior to initializing lencode.count
enum {
MAXBITS = 15,
MAXLCODES = 286,
MAXDCODES = 30,
FIXLCODES = 288,
MAXCODES = MAXLCODES + MAXDCODES,
};
struct state {
unsigned char *out;
unsigned long outlen;
unsigned long outcnt;
unsigned char *in;
unsigned long inlen;
unsigned long incnt;
int bitbuf;
int bitcnt;
jmp_buf env;
};
struct huffman {
short *count;
short *symbol;
};
inline int bits(state *s, int need) {
long val;
val = s->bitbuf;
while(s->bitcnt < need) {
if(s->incnt == s->inlen) longjmp(s->env, 1);
val |= (long)(s->in[s->incnt++]) << s->bitcnt;
s->bitcnt += 8;
}
s->bitbuf = (int)(val >> need);
s->bitcnt -= need;
return (int)(val & ((1L << need) - 1));
}
inline int stored(state *s) {
unsigned len;
s->bitbuf = 0;
s->bitcnt = 0;
if(s->incnt + 4 > s->inlen) return 2;
len = s->in[s->incnt++];
len |= s->in[s->incnt++] << 8;
if(s->in[s->incnt++] != (~len & 0xff) ||
s->in[s->incnt++] != ((~len >> 8) & 0xff)
) return 2;
if(s->incnt + len > s->inlen) return 2;
if(s->out != 0) {
if(s->outcnt + len > s->outlen) return 1;
while(len--) s->out[s->outcnt++] = s->in[s->incnt++];
} else {
s->outcnt += len;
s->incnt += len;
}
return 0;
}
inline int decode(state *s, huffman *h) {
int len, code, first, count, index, bitbuf, left;
short *next;
bitbuf = s->bitbuf;
left = s->bitcnt;
code = first = index = 0;
len = 1;
next = h->count + 1;
while(true) {
while(left--) {
code |= bitbuf & 1;
bitbuf >>= 1;
count = *next++;
if(code - count < first) {
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7;
return h->symbol[index + (code - first)];
}
index += count;
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS + 1) - len;
if(left == 0) break;
if(s->incnt == s->inlen) longjmp(s->env, 1);
bitbuf = s->in[s->incnt++];
if(left > 8) left = 8;
}
return -10;
}
inline int construct(huffman *h, short *length, int n) {
int symbol, len, left;
short offs[MAXBITS + 1];
for(len = 0; len <= MAXBITS; len++) h->count[len] = 0;
for(symbol = 0; symbol < n; symbol++) h->count[length[symbol]]++;
if(h->count[0] == n) return 0;
left = 1;
for(len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= h->count[len];
if(left < 0) return left;
}
offs[1] = 0;
for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len];
for(symbol = 0; symbol < n; symbol++) {
if(length[symbol] != 0) h->symbol[offs[length[symbol]]++] = symbol;
}
return left;
}
inline int codes(state *s, huffman *lencode, huffman *distcode) {
int symbol, len;
unsigned dist;
static const short lens[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
};
static const short lext[29] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
};
static const short dists[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577
};
static const short dext[30] = {
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13
};
do {
symbol = decode(s, lencode);
if(symbol < 0) return symbol;
if(symbol < 256) {
if(s->out != 0) {
if(s->outcnt == s->outlen) return 1;
s->out[s->outcnt] = symbol;
}
s->outcnt++;
} else if(symbol > 256) {
symbol -= 257;
if(symbol >= 29) return -10;
len = lens[symbol] + bits(s, lext[symbol]);
symbol = decode(s, distcode);
if(symbol < 0) return symbol;
dist = dists[symbol] + bits(s, dext[symbol]);
#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
if(dist > s->outcnt) return -11;
#endif
if(s->out != 0) {
if(s->outcnt + len > s->outlen) return 1;
while(len--) {
s->out[s->outcnt] =
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOO_FAR
dist > s->outcnt ? 0 :
#endif
s->out[s->outcnt - dist];
s->outcnt++;
}
} else {
s->outcnt += len;
}
}
} while(symbol != 256);
return 0;
}
inline int fixed(state *s) {
static int virgin = 1;
static short lencnt[MAXBITS + 1], lensym[FIXLCODES];
static short distcnt[MAXBITS + 1], distsym[MAXDCODES];
static huffman lencode, distcode;
if(virgin) {
int symbol = 0;
short lengths[FIXLCODES];
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
for(; symbol < 144; symbol++) lengths[symbol] = 8;
for(; symbol < 256; symbol++) lengths[symbol] = 9;
for(; symbol < 280; symbol++) lengths[symbol] = 7;
for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
construct(&lencode, lengths, FIXLCODES);
for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
construct(&distcode, lengths, MAXDCODES);
virgin = 0;
}
return codes(s, &lencode, &distcode);
}
inline int dynamic(state *s) {
int nlen, ndist, ncode, index, err;
short lengths[MAXCODES];
short lencnt[MAXBITS + 1], lensym[MAXLCODES];
short distcnt[MAXBITS + 1], distsym[MAXDCODES];
huffman lencode, distcode;
static const short order[19] = {
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
lencode.count = lencnt;
lencode.symbol = lensym;
distcode.count = distcnt;
distcode.symbol = distsym;
nlen = bits(s, 5) + 257;
ndist = bits(s, 5) + 1;
ncode = bits(s, 4) + 4;
if(nlen > MAXLCODES || ndist > MAXDCODES) return -3;
for(index = 0; index < ncode; index++) lengths[order[index]] = bits(s, 3);
for(; index < 19; index++) lengths[order[index]] = 0;
err = construct(&lencode, lengths, 19);
if(err != 0) return -4;
index = 0;
while(index < nlen + ndist) {
int symbol, len;
symbol = decode(s, &lencode);
if(symbol < 16) {
lengths[index++] = symbol;
} else {
len = 0;
if(symbol == 16) {
if(index == 0) return -5;
len = lengths[index - 1];
symbol = 3 + bits(s, 2);
} else if(symbol == 17) {
symbol = 3 + bits(s, 3);
} else {
symbol = 11 + bits(s, 7);
}
if(index + symbol > nlen + ndist) return -6;
while(symbol--) lengths[index++] = len;
}
}
if(lengths[256] == 0) return -9;
err = construct(&lencode, lengths, nlen);
if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) return -7;
err = construct(&distcode, lengths + nlen, ndist);
if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) return -8;
return codes(s, &lencode, &distcode);
}
inline int puff(
unsigned char *dest, unsigned long *destlen,
unsigned char *source, unsigned long *sourcelen
) {
state s;
int last, type, err;
s.out = dest;
s.outlen = *destlen;
s.outcnt = 0;
s.in = source;
s.inlen = *sourcelen;
s.incnt = 0;
s.bitbuf = 0;
s.bitcnt = 0;
if(setjmp(s.env) != 0) {
err = 2;
} else {
do {
last = bits(&s, 1);
type = bits(&s, 2);
err = type == 0 ? stored(&s)
: type == 1 ? fixed(&s)
: type == 2 ? dynamic(&s)
: -1;
if(err != 0) break;
} while(!last);
}
if(err <= 0) {
*destlen = s.outcnt;
*sourcelen = s.incnt;
}
return err;
}
}
}
#endif

View File

@@ -110,7 +110,7 @@ struct Keyboard {
break;
}
}
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
return { "KB", ID, "::", KeyboardScancodeName[index] };
}
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
@@ -207,7 +207,7 @@ struct Mouse {
break;
}
}
return string() << "MS" << ID << "::" << MouseScancodeName[index];
return { "MS", ID, "::", MouseScancodeName[index] };
}
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
@@ -330,7 +330,7 @@ struct Joypad {
index = code - (Base + Size * i);
}
}
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
return { "JP", ID, "::", JoypadScancodeName[index] };
}
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }

View File

@@ -2,14 +2,13 @@
#define NALL_LZSS_HPP
#include <nall/array.hpp>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
namespace nall {
class lzss {
public:
static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) {
output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9];
output = new uint8_t[inlength * 9 / 8 + 9]();
unsigned i = 0, o = 0;
while(i < inlength) {
@@ -52,7 +51,7 @@ namespace nall {
}
static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) {
output = new(zeromemory) uint8_t[length];
output = new uint8_t[length]();
unsigned i = 0, o = 0;
while(o < length) {

View File

@@ -1,7 +1,12 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
#include <nall/utf8.hpp>
#if defined(_WIN32)
//minimum version needed for _wstat64, etc
#undef __MSVCRT_VERSION__
#define __MSVCRT_VERSION__ 0x0601
#include <nall/windows/utf8.hpp>
#endif
//=========================
//standard platform headers
@@ -18,16 +23,19 @@
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(_WIN32)
#include <io.h>
#include <direct.h>
#include <shlobj.h>
#include <wchar.h>
#undef interface
#define dllexport __declspec(dllexport)
#else
#include <unistd.h>
#include <pwd.h>
#include <sys/stat.h>
#define dllexport
#endif
@@ -53,11 +61,11 @@
#if defined(_WIN32)
#define getcwd _getcwd
#define ftruncate _chsize
#define putenv _putenv
#define mkdir(n, m) _wmkdir(nall::utf16_t(n))
#define putenv _putenv
#define rmdir _rmdir
#define vsnprintf _vsnprintf
#define usleep(n) Sleep(n / 1000)
#define vsnprintf _vsnprintf
#endif
//================

423
bsnes/nall/png.hpp Executable file
View File

@@ -0,0 +1,423 @@
#ifndef NALL_PNG_HPP
#define NALL_PNG_HPP
//PNG image decoder
//author: byuu
#include <nall/inflate.hpp>
#include <nall/string.hpp>
namespace nall {
struct png {
uint32_t *data;
unsigned size;
struct Info {
unsigned width;
unsigned height;
unsigned bitDepth;
unsigned colorType;
unsigned compressionMethod;
unsigned filterType;
unsigned interlaceMethod;
unsigned bytesPerPixel;
unsigned pitch;
uint8_t palette[256][3];
} info;
uint8_t *rawData;
unsigned rawSize;
inline bool decode(const string &filename);
inline bool decode(const uint8_t *sourceData, unsigned sourceSize);
inline void transform();
inline void alphaTransform(uint32_t rgb = 0xffffff);
inline png();
inline ~png();
protected:
enum class FourCC : unsigned {
IHDR = 0x49484452,
PLTE = 0x504c5445,
IDAT = 0x49444154,
IEND = 0x49454e44,
};
static const unsigned interlace[7][4];
unsigned bitpos;
inline unsigned inflateSize();
inline bool deinterlace(const uint8_t *&inputData, unsigned pass);
inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height);
inline unsigned read(const uint8_t *data, unsigned length);
inline unsigned decode(const uint8_t *&data);
inline unsigned readbits(const uint8_t *&data);
inline unsigned scale(unsigned n);
};
bool png::decode(const string &filename) {
uint8_t *data;
unsigned size;
if(file::read(filename, data, size) == false) return false;
bool result = decode(data, size);
delete[] data;
return result;
}
bool png::decode(const uint8_t *sourceData, unsigned sourceSize) {
if(sourceSize < 8) return false;
if(read(sourceData + 0, 4) != 0x89504e47) return false;
if(read(sourceData + 4, 4) != 0x0d0a1a0a) return false;
uint8_t *compressedData = 0;
unsigned compressedSize = 0;
unsigned offset = 8;
while(offset < sourceSize) {
unsigned length = read(sourceData + offset + 0, 4);
unsigned fourCC = read(sourceData + offset + 4, 4);
unsigned checksum = read(sourceData + offset + 8 + length, 4);
if(fourCC == (unsigned)FourCC::IHDR) {
info.width = read(sourceData + offset + 8, 4);
info.height = read(sourceData + offset + 12, 4);
info.bitDepth = read(sourceData + offset + 16, 1);
info.colorType = read(sourceData + offset + 17, 1);
info.compressionMethod = read(sourceData + offset + 18, 1);
info.filterType = read(sourceData + offset + 19, 1);
info.interlaceMethod = read(sourceData + offset + 20, 1);
if(info.bitDepth == 0 || info.bitDepth > 16) return false;
if(info.bitDepth & (info.bitDepth - 1)) return false; //not a power of two
if(info.compressionMethod != 0) return false;
if(info.filterType != 0) return false;
if(info.interlaceMethod != 0 && info.interlaceMethod != 1) return false;
switch(info.colorType) {
case 0: info.bytesPerPixel = info.bitDepth * 1; break; //L
case 2: info.bytesPerPixel = info.bitDepth * 3; break; //R,G,B
case 3: info.bytesPerPixel = info.bitDepth * 1; break; //P
case 4: info.bytesPerPixel = info.bitDepth * 2; break; //L,A
case 6: info.bytesPerPixel = info.bitDepth * 4; break; //R,G,B,A
default: return false;
}
if(info.colorType == 2 || info.colorType == 4 || info.colorType == 6)
if(info.bitDepth != 8 && info.bitDepth != 16) return false;
if(info.colorType == 3 && info.bitDepth == 16) return false;
info.bytesPerPixel = (info.bytesPerPixel + 7) / 8;
info.pitch = (int)info.width * info.bytesPerPixel;
}
if(fourCC == (unsigned)FourCC::PLTE) {
if(length % 3) return false;
for(unsigned n = 0, p = offset + 8; n < length / 3; n++) {
info.palette[n][0] = sourceData[p++];
info.palette[n][1] = sourceData[p++];
info.palette[n][2] = sourceData[p++];
}
}
if(fourCC == (unsigned)FourCC::IDAT) {
compressedData = (uint8_t*)realloc(compressedData, compressedSize + length);
memcpy(compressedData + compressedSize, sourceData + offset + 8, length);
compressedSize += length;
}
if(fourCC == (unsigned)FourCC::IEND) {
break;
}
offset += 4 + 4 + length + 4;
}
unsigned interlacedSize = inflateSize();
uint8_t *interlacedData = new uint8_t[interlacedSize];
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
delete[] compressedData;
if(result == false) {
delete[] interlacedData;
return false;
}
rawSize = info.width * info.height * info.bytesPerPixel;
rawData = new uint8_t[rawSize];
if(info.interlaceMethod == 0) {
if(filter(rawData, interlacedData, info.width, info.height) == false) {
delete[] interlacedData;
delete[] rawData;
rawData = 0;
return false;
}
} else {
const uint8_t *passData = interlacedData;
for(unsigned pass = 0; pass < 7; pass++) {
if(deinterlace(passData, pass) == false) {
delete[] interlacedData;
delete[] rawData;
rawData = 0;
return false;
}
}
}
delete[] interlacedData;
return true;
}
const unsigned png::interlace[7][4] = {
//x-distance, y-distance, x-origin, y-origin
{ 8, 8, 0, 0 },
{ 8, 8, 4, 0 },
{ 4, 8, 0, 4 },
{ 4, 4, 2, 0 },
{ 2, 4, 0, 2 },
{ 2, 2, 1, 0 },
{ 1, 2, 0, 1 },
};
unsigned png::inflateSize() {
if(info.interlaceMethod == 0) {
return info.width * info.height * info.bytesPerPixel + info.height;
}
unsigned size = 0;
for(unsigned pass = 0; pass < 7; pass++) {
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
unsigned width = (info.width + (xd - xo - 1)) / xd;
unsigned height = (info.height + (yd - yo - 1)) / yd;
if(width == 0 || height == 0) continue;
size += width * height * info.bytesPerPixel + height;
}
return size;
}
bool png::deinterlace(const uint8_t *&inputData, unsigned pass) {
unsigned xd = interlace[pass][0], yd = interlace[pass][1];
unsigned xo = interlace[pass][2], yo = interlace[pass][3];
unsigned width = (info.width + (xd - xo - 1)) / xd;
unsigned height = (info.height + (yd - yo - 1)) / yd;
if(width == 0 || height == 0) return true;
unsigned outputSize = width * height * info.bytesPerPixel;
uint8_t *outputData = new uint8_t[outputSize];
bool result = filter(outputData, inputData, width, height);
const uint8_t *rd = outputData;
for(unsigned y = yo; y < info.height; y += yd) {
uint8_t *wr = rawData + y * info.pitch;
for(unsigned x = xo; x < info.width; x += xd) {
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
wr[x * info.bytesPerPixel + b] = *rd++;
}
}
}
inputData += outputSize + height;
delete[] outputData;
return result;
}
bool png::filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height) {
uint8_t *wr = outputData;
const uint8_t *rd = inputData;
int bpp = info.bytesPerPixel, pitch = width * bpp;
for(int y = 0; y < height; y++) {
uint8_t filter = *rd++;
switch(filter) {
case 0x00: //None
for(int x = 0; x < pitch; x++) {
wr[x] = rd[x];
}
break;
case 0x01: //Subtract
for(int x = 0; x < pitch; x++) {
wr[x] = rd[x] + (x - bpp < 0 ? 0 : wr[x - bpp]);
}
break;
case 0x02: //Above
for(int x = 0; x < pitch; x++) {
wr[x] = rd[x] + (y - 1 < 0 ? 0 : wr[x - pitch]);
}
break;
case 0x03: //Average
for(int x = 0; x < pitch; x++) {
short a = x - bpp < 0 ? 0 : wr[x - bpp];
short b = y - 1 < 0 ? 0 : wr[x - pitch];
wr[x] = rd[x] + (uint8_t)((a + b) / 2);
}
break;
case 0x04: //Paeth
for(int x = 0; x < pitch; x++) {
short a = x - bpp < 0 ? 0 : wr[x - bpp];
short b = y - 1 < 0 ? 0 : wr[x - pitch];
short c = x - bpp < 0 || y - 1 < 0 ? 0 : wr[x - pitch - bpp];
short p = a + b - c;
short pa = p > a ? p - a : a - p;
short pb = p > b ? p - b : b - p;
short pc = p > c ? p - c : c - p;
uint8_t paeth = (uint8_t)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
wr[x] = rd[x] + paeth;
}
break;
default: //Invalid
return false;
}
rd += pitch;
wr += pitch;
}
return true;
}
unsigned png::read(const uint8_t *data, unsigned length) {
unsigned result = 0;
while(length--) result = (result << 8) | (*data++);
return result;
}
unsigned png::decode(const uint8_t *&data) {
unsigned p, r, g, b, a;
switch(info.colorType) {
case 0: //L
r = g = b = scale(readbits(data));
a = 0xff;
break;
case 2: //R,G,B
r = scale(readbits(data));
g = scale(readbits(data));
b = scale(readbits(data));
a = 0xff;
break;
case 3: //P
p = readbits(data);
r = info.palette[p][0];
g = info.palette[p][1];
b = info.palette[p][2];
a = 0xff;
break;
case 4: //L,A
r = g = b = scale(readbits(data));
a = scale(readbits(data));
break;
case 6: //R,G,B,A
r = scale(readbits(data));
g = scale(readbits(data));
b = scale(readbits(data));
a = scale(readbits(data));
break;
}
return (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
unsigned png::readbits(const uint8_t *&data) {
unsigned result = 0;
switch(info.bitDepth) {
case 1:
result = (*data >> bitpos) & 1;
bitpos++;
if(bitpos == 8) { data++; bitpos = 0; }
break;
case 2:
result = (*data >> bitpos) & 3;
bitpos += 2;
if(bitpos == 8) { data++; bitpos = 0; }
break;
case 4:
result = (*data >> bitpos) & 15;
bitpos += 4;
if(bitpos == 8) { data++; bitpos = 0; }
break;
case 8:
result = *data++;
break;
case 16:
result = (data[0] << 8) | (data[1] << 0);
data += 2;
break;
}
return result;
}
unsigned png::scale(unsigned n) {
switch(info.bitDepth) {
case 1: return n ? 0xff : 0x00;
case 2: return n * 0x55;
case 4: return n * 0x11;
case 8: return n;
case 16: return n >> 8;
}
return 0;
}
void png::transform() {
if(data) delete[] data;
data = new uint32_t[info.width * info.height];
bitpos = 0;
const uint8_t *rd = rawData;
for(unsigned y = 0; y < info.height; y++) {
uint32_t *wr = data + y * info.width;
for(unsigned x = 0; x < info.width; x++) {
wr[x] = decode(rd);
}
}
}
void png::alphaTransform(uint32_t rgb) {
transform();
uint8_t ir = rgb >> 16;
uint8_t ig = rgb >> 8;
uint8_t ib = rgb >> 0;
uint32_t *p = data;
for(unsigned y = 0; y < info.height; y++) {
for(unsigned x = 0; x < info.width; x++) {
uint32_t pixel = *p;
uint8_t a = pixel >> 24;
uint8_t r = pixel >> 16;
uint8_t g = pixel >> 8;
uint8_t b = pixel >> 0;
r = (r * a) + (ir * (255 - a)) >> 8;
g = (g * a) + (ig * (255 - a)) >> 8;
b = (b * a) + (ib * (255 - a)) >> 8;
*p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
}
png::png() : data(0), rawData(0) {
}
png::~png() {
if(data) delete[] data;
if(rawData) delete[] rawData;
}
}
#endif

View File

@@ -8,12 +8,20 @@ namespace nall {
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
}
struct random_cyclic {
unsigned seed;
inline unsigned operator()() {
return seed = (seed >> 1) ^ (((seed & 1) - 1) & 0xedb88320);
struct random_lfsr {
inline void seed(unsigned seed__) {
seed_ = seed__;
}
random_cyclic() : seed(0) {}
inline unsigned operator()() {
return seed_ = (seed_ >> 1) ^ (((seed_ & 1) - 1) & 0xedb88320);
}
random_lfsr() : seed_(0) {
}
private:
unsigned seed_;
};
}

61
bsnes/nall/resource.hpp Executable file
View File

@@ -0,0 +1,61 @@
#ifndef NALL_RESOURCE_HPP
#define NALL_RESOURCE_HPP
#include <nall/file.hpp>
#include <nall/zip.hpp>
namespace nall {
struct resource {
//create resource with "zip -9 resource.zip resource"
static bool encode(const char *outputFilename, const char *inputFilename) {
file fp;
if(fp.open(inputFilename, file::mode::read) == false) return false;
unsigned size = fp.size();
uint8_t *data = new uint8_t[size];
fp.read(data, size);
fp.close();
fp.open(outputFilename, file::mode::write);
fp.print("static const uint8_t data[", size, "] = {\n");
uint8_t *p = data;
while(size) {
fp.print(" ");
for(unsigned n = 0; n < 32 && size; n++, size--) {
fp.print((unsigned)*p++, ",");
}
fp.print("\n");
}
fp.print("};\n");
fp.close();
delete[] data;
}
uint8_t *data;
unsigned size;
//extract first file from ZIP archive
bool decode(const uint8_t *cdata, unsigned csize) {
if(data) delete[] data;
zip archive;
if(archive.open(cdata, csize) == false) return false;
if(archive.file.size() == 0) return false;
bool result = archive.extract(archive.file[0], data, size);
archive.close();
return result;
}
resource() : data(0), size(0) {
}
~resource() {
if(data) delete[] data;
}
};
}
#endif

View File

@@ -3,6 +3,8 @@
//author: vladitx
#include <nall/stdint.hpp>
namespace nall {
#define PTR(t, a) ((t*)(a))
@@ -49,7 +51,7 @@ namespace nall {
uint64_t len;
};
void sha256_init(sha256_ctx *p) {
inline void sha256_init(sha256_ctx *p) {
memset(p, 0, sizeof(sha256_ctx));
memcpy(p->h, T_H, sizeof(T_H));
}
@@ -90,7 +92,7 @@ namespace nall {
p->inlen = 0;
}
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
inline void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
unsigned l;
p->len += len;
@@ -107,7 +109,7 @@ namespace nall {
}
}
void sha256_final(sha256_ctx *p) {
inline void sha256_final(sha256_ctx *p) {
uint64_t len;
p->in[p->inlen++] = 0x80;
@@ -124,7 +126,7 @@ namespace nall {
sha256_block(p);
}
void sha256_hash(sha256_ctx *p, uint8_t *s) {
inline void sha256_hash(sha256_ctx *p, uint8_t *s) {
uint32_t *t = (uint32_t*)s;
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
}

View File

@@ -111,422 +111,426 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
if(type == TypeBsx) {
xml << "<cartridge/>";
xml.append("<cartridge/>");
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeSufamiTurbo) {
xml << "<cartridge/>";
xml.append("<cartridge/>");
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeGameBoy) {
xml << "<cartridge rtc='" << gameboy_has_rtc(data, size) << "'>\n";
xml.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'>\n");
if(gameboy_ram_size(data, size) > 0) {
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
xml.append(" <ram size='0x", hex(gameboy_ram_size(data, size)), "'/>\n");
}
xml << "</cartridge>\n";
xml.append("</cartridge>\n");
xmlMemoryMap = xml.transform("'", "\"");
return;
}
xml << "<cartridge";
xml.append("<cartridge");
if(region == NTSC) {
xml << " region='NTSC'";
xml.append(" region='NTSC'");
} else {
xml << " region='PAL'";
xml.append(" region='PAL'");
}
xml << ">\n";
xml.append(">\n");
if(type == TypeSuperGameBoy1Bios) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <icd2 revision='1'>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </icd2>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <icd2 revision='1'>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </icd2>\n");
} else if(type == TypeSuperGameBoy2Bios) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <icd2 revision='2'>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </icd2>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <icd2 revision='2'>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </icd2>\n");
} else if(has_cx4) {
xml.append(" <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </hitachidsp>\n");
} else if(has_spc7110) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-cf:0000-ffff'/>\n";
xml << " </rom>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-0f:8000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-cf:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml << " <spc7110>\n";
xml << " <mcu>\n";
xml << " <map address='d0-ff:0000-ffff' offset='100000' size='" << hex(size - 0x100000) << "'/>\n";
xml << " </mcu>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00:6000-7fff'/>\n";
xml << " <map mode='linear' address='30:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:4800-483f'/>\n";
xml << " <map address='80-bf:4800-483f'/>\n";
xml << " </mmio>\n";
xml.append(" <spc7110>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n");
xml.append(" </mcu>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='00:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='30:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:4800-483f'/>\n");
xml.append(" <map address='80-bf:4800-483f'/>\n");
xml.append(" </mmio>\n");
if(has_spc7110rtc) {
xml << " <rtc>\n";
xml << " <map address='00-3f:4840-4842'/>\n";
xml << " <map address='80-bf:4840-4842'/>\n";
xml << " </rtc>\n";
xml.append(" <rtc>\n");
xml.append(" <map address='00-3f:4840-4842'/>\n");
xml.append(" <map address='80-bf:4840-4842'/>\n");
xml.append(" </rtc>\n");
}
xml << " <dcu>\n";
xml << " <map address='50:0000-ffff'/>\n";
xml << " </dcu>\n";
xml << " </spc7110>\n";
xml.append(" <dcu>\n");
xml.append(" <map address='50:0000-ffff'/>\n");
xml.append(" </dcu>\n");
xml.append(" </spc7110>\n");
} else if(mapper == LoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
xml << " </rom>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-ffff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-ffff'/>\n");
}
xml << " </ram>\n";
xml.append(" </ram>\n");
}
} else if(mapper == HiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-ff:0000-ffff'/>\n");
xml.append(" </rom>\n");
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
}
xml << " </ram>\n";
xml.append(" </ram>\n");
}
} else if(mapper == ExLoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
xml.append(" </rom>\n");
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " </ram>\n";
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" </ram>\n");
}
} else if(mapper == ExHiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-3f:8000-ffff' offset='400000'/>\n";
xml << " <map mode='linear' address='40-7f:0000-ffff' offset='400000'/>\n";
xml << " <map mode='shadow' address='80-bf:8000-ffff' offset='000000'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff' offset='000000'/>\n";
xml << " </rom>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n");
xml.append(" <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n");
xml.append(" </rom>\n");
if(ram_size > 0) {
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
} else {
xml << " <map mode='linear' address='70-7f:0000-ffff'/>\n";
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
}
xml << " </ram>\n";
xml.append(" </ram>\n");
}
} else if(mapper == SuperFXROM) {
xml << " <superfx revision='2'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff' size='2000'/>\n";
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff' size='2000'/>\n";
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
xml << " </ram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:3000-32ff'/>\n";
xml << " <map address='80-bf:3000-32ff'/>\n";
xml << " </mmio>\n";
xml << " </superfx>\n";
xml.append(" <superfx revision='2'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n");
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n");
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:3000-32ff'/>\n");
xml.append(" <map address='80-bf:3000-32ff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </superfx>\n");
} else if(mapper == SA1ROM) {
xml << " <sa1>\n";
xml << " <mcu>\n";
xml << " <rom>\n";
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " </mcu>\n";
xml << " <iram size='800'>\n";
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
xml << " </iram>\n";
xml << " <bwram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
xml << " </bwram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2200-23ff'/>\n";
xml << " <map address='80-bf:2200-23ff'/>\n";
xml << " </mmio>\n";
xml << " </sa1>\n";
xml.append(" <sa1>\n");
xml.append(" <mcu>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='direct' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='direct' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='direct' address='c0-ff:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram>\n");
xml.append(" <map mode='direct' address='00-3f:6000-7fff'/>\n");
xml.append(" <map mode='direct' address='80-bf:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" </mcu>\n");
xml.append(" <iram size='0x800'>\n");
xml.append(" <map mode='linear' address='00-3f:3000-37ff'/>\n");
xml.append(" <map mode='linear' address='80-bf:3000-37ff'/>\n");
xml.append(" </iram>\n");
xml.append(" <bwram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='40-4f:0000-ffff'/>\n");
xml.append(" </bwram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:2200-23ff'/>\n");
xml.append(" <map address='80-bf:2200-23ff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </sa1>\n");
} else if(mapper == BSCLoROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-1f:8000-ffff' offset='000000'/>\n";
xml << " <map mode='linear' address='20-3f:8000-ffff' offset='100000'/>\n";
xml << " <map mode='linear' address='80-9f:8000-ffff' offset='200000'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff' offset='100000'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='70-7f:0000-7fff'/>\n";
xml << " <map mode='linear' address='f0-ff:0000-7fff'/>\n";
xml << " </ram>\n";
xml << " <bsx>\n";
xml << " <slot>\n";
xml << " <map mode='linear' address='c0-ef:0000-ffff'/>\n";
xml << " </slot>\n";
xml << " </bsx>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n");
xml.append(" <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n");
xml.append(" <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n");
xml.append(" <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <bsx>\n");
xml.append(" <slot>\n");
xml.append(" <map mode='linear' address='c0-ef:0000-ffff'/>\n");
xml.append(" </slot>\n");
xml.append(" </bsx>\n");
} else if(mapper == BSCHiROM) {
xml << " <rom>\n";
xml << " <map mode='shadow' address='00-1f:8000-ffff'/>\n";
xml << " <map mode='linear' address='40-5f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='80-9f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='20-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='a0-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " <bsx>\n";
xml << " <slot>\n";
xml << " <map mode='shadow' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='60-7f:0000-ffff'/>\n";
xml << " <map mode='shadow' address='a0-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-ff:0000-ffff'/>\n";
xml << " </slot>\n";
xml << " </bsx>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-1f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-9f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <bsx>\n");
xml.append(" <slot>\n");
xml.append(" <map mode='shadow' address='20-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='a0-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
xml.append(" </slot>\n");
xml.append(" </bsx>\n");
} else if(mapper == BSXROM) {
xml << " <bsx>\n";
xml << " <mcu>\n";
xml << " <map address='00-3f:8000-ffff'/>\n";
xml << " <map address='80-bf:8000-ffff'/>\n";
xml << " <map address='40-7f:0000-ffff'/>\n";
xml << " <map address='c0-ff:0000-ffff'/>\n";
xml << " <map address='20-3f:6000-7fff'/>\n";
xml << " </mcu>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:5000-5fff'/>\n";
xml << " <map address='80-bf:5000-5fff'/>\n";
xml << " </mmio>\n";
xml << " </bsx>\n";
xml.append(" <bsx>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='00-3f:8000-ffff'/>\n");
xml.append(" <map address='80-bf:8000-ffff'/>\n");
xml.append(" <map address='40-7f:0000-ffff'/>\n");
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
xml.append(" <map address='20-3f:6000-7fff'/>\n");
xml.append(" </mcu>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:5000-5fff'/>\n");
xml.append(" <map address='80-bf:5000-5fff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </bsx>\n");
} else if(mapper == STROM) {
xml << " <rom>\n";
xml << " <map mode='linear' address='00-1f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-9f:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <sufamiturbo>\n";
xml << " <slot id='A'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='20-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='a0-bf:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='60-63:8000-ffff'/>\n";
xml << " <map mode='linear' address='e0-e3:8000-ffff'/>\n";
xml << " </ram>\n";
xml << " </slot>\n";
xml << " <slot id='B'>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='40-5f:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-df:8000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram size='20000'>\n";
xml << " <map mode='linear' address='70-73:8000-ffff'/>\n";
xml << " <map mode='linear' address='f0-f3:8000-ffff'/>\n";
xml << " </ram>\n";
xml << " </slot>\n";
xml << " </sufamiturbo>\n";
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-1f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-9f:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <sufamiturbo>\n");
xml.append(" <slot id='A'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='20-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x20000'>\n");
xml.append(" <map mode='linear' address='60-63:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='e0-e3:8000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" </slot>\n");
xml.append(" <slot id='B'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='40-5f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x20000'>\n");
xml.append(" <map mode='linear' address='70-73:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='f0-f3:8000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" </slot>\n");
xml.append(" </sufamiturbo>\n");
}
if(has_srtc) {
xml << " <srtc>\n";
xml << " <map address='00-3f:2800-2801'/>\n";
xml << " <map address='80-bf:2800-2801'/>\n";
xml << " </srtc>\n";
xml.append(" <srtc>\n");
xml.append(" <map address='00-3f:2800-2801'/>\n");
xml.append(" <map address='80-bf:2800-2801'/>\n");
xml.append(" </srtc>\n");
}
if(has_sdd1) {
xml << " <sdd1>\n";
xml << " <mcu>\n";
xml << " <map address='c0-ff:0000-ffff'/>\n";
xml << " </mcu>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:4800-4807'/>\n";
xml << " <map address='80-bf:4800-4807'/>\n";
xml << " </mmio>\n";
xml << " </sdd1>\n";
}
if(has_cx4) {
xml << " <cx4>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </cx4>\n";
xml.append(" <sdd1>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
xml.append(" </mcu>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:4800-4807'/>\n");
xml.append(" <map address='80-bf:4800-4807'/>\n");
xml.append(" </mmio>\n");
xml.append(" </sdd1>\n");
}
if(has_dsp1) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
if(dsp1_mapper == DSP1LoROM1MB) {
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
} else if(dsp1_mapper == DSP1LoROM2MB) {
xml << " <dr>\n";
xml << " <map address='60-6f:0000-3fff'/>\n";
xml << " <map address='e0-ef:0000-3fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60-6f:4000-7fff'/>\n";
xml << " <map address='e0-ef:4000-7fff'/>\n";
xml << " </sr>\n";
xml.append(" <dr>\n");
xml.append(" <map address='60-6f:0000-3fff'/>\n");
xml.append(" <map address='e0-ef:0000-3fff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60-6f:4000-7fff'/>\n");
xml.append(" <map address='e0-ef:4000-7fff'/>\n");
xml.append(" </sr>\n");
} else if(dsp1_mapper == DSP1HiROM) {
xml << " <dr>\n";
xml << " <map address='00-1f:6000-6fff'/>\n";
xml << " <map address='80-9f:6000-6fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='00-1f:7000-7fff'/>\n";
xml << " <map address='80-9f:7000-7fff'/>\n";
xml << " </sr>\n";
xml.append(" <dr>\n");
xml.append(" <map address='00-1f:6000-6fff'/>\n");
xml.append(" <map address='80-9f:6000-6fff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='00-1f:7000-7fff'/>\n");
xml.append(" <map address='80-9f:7000-7fff'/>\n");
xml.append(" </sr>\n");
}
xml << " </necdsp>\n";
xml.append(" </necdsp>\n");
}
if(has_dsp2) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
}
if(has_dsp3) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
}
if(has_dsp4) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
xml << " <dr>\n";
xml << " <map address='30-3f:8000-bfff'/>\n";
xml << " <map address='b0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='30-3f:c000-ffff'/>\n";
xml << " <map address='b0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='30-3f:8000-bfff'/>\n");
xml.append(" <map address='b0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='30-3f:c000-ffff'/>\n");
xml.append(" <map address='b0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
}
if(has_obc1) {
xml << " <obc1>\n";
xml << " <map address='00-3f:6000-7fff'/>\n";
xml << " <map address='80-bf:6000-7fff'/>\n";
xml << " </obc1>\n";
xml.append(" <obc1>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </obc1>\n");
}
if(has_st010) {
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
xml.append(" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='60:0000'/>\n");
xml.append(" <map address='e0:0000'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60:0001'/>\n");
xml.append(" <map address='e0:0001'/>\n");
xml.append(" </sr>\n");
xml.append(" <dp>\n");
xml.append(" <map address='68-6f:0000-0fff'/>\n");
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
xml.append(" </dp>\n");
xml.append(" </necdsp>\n");
}
if(has_st011) {
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
xml.append(" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='60:0000'/>\n");
xml.append(" <map address='e0:0000'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60:0001'/>\n");
xml.append(" <map address='e0:0001'/>\n");
xml.append(" </sr>\n");
xml.append(" <dp>\n");
xml.append(" <map address='68-6f:0000-0fff'/>\n");
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
xml.append(" </dp>\n");
xml.append(" </necdsp>\n");
}
if(has_st018) {
xml << " <setarisc program='ST-0018'>\n";
xml << " <map address='00-3f:3800-38ff'/>\n";
xml << " <map address='80-bf:3800-38ff'/>\n";
xml << " </setarisc>\n";
xml.append(" <setarisc firmware='ST-0018'>\n");
xml.append(" <map address='00-3f:3800-38ff'/>\n");
xml.append(" <map address='80-bf:3800-38ff'/>\n");
xml.append(" </setarisc>\n");
}
xml << "</cartridge>\n";
xml.append("</cartridge>\n");
xmlMemoryMap = xml.transform("'", "\"");
}

29
bsnes/nall/stack.hpp Executable file
View File

@@ -0,0 +1,29 @@
#ifndef NALL_STACK_HPP
#define NALL_STACK_HPP
#include <nall/concept.hpp>
#include <nall/vector.hpp>
namespace nall {
template<typename T> struct stack : public linear_vector<T> {
void push(const T &value) {
linear_vector<T>::append(value);
}
T pull() {
if(linear_vector<T>::size() == 0) throw;
T value = linear_vector<T>::operator[](linear_vector<T>::size() - 1);
linear_vector<T>::remove(linear_vector<T>::size() - 1);
return value;
}
T& operator()() {
if(linear_vector<T>::size() == 0) throw;
return linear_vector<T>::operator[](linear_vector<T>::size() - 1);
}
};
template<typename T> struct has_size<stack<T>> { enum { value = true }; };
}
#endif

View File

@@ -2,7 +2,9 @@
#define NALL_STRING_HPP
#include <initializer_list>
#include <nall/array.hpp>
#include <nall/platform.hpp>
#include <nall/sha256.hpp>
#include <nall/utility.hpp>
#include <nall/string/base.hpp>

View File

@@ -6,12 +6,14 @@
#include <stdlib.h>
#include <string.h>
#include <nall/concept.hpp>
#include <nall/function.hpp>
#include <nall/stdint.hpp>
#include <nall/utf8.hpp>
#include <nall/vector.hpp>
#include <nall/windows/utf8.hpp>
namespace nall {
class string;
class lstring;
template<typename T> inline const char* to_string(T);
class string {
@@ -20,13 +22,13 @@ namespace nall {
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
inline string& assign_(const char*);
inline string& append_(const char*);
inline bool readfile(const string&);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
template<unsigned Limit = 0> inline string& replace(const char*, const char*);
template<unsigned Limit = 0> inline string& ireplace(const char*, const char*);
template<unsigned Limit = 0> inline string& qreplace(const char*, const char*);
template<unsigned Limit = 0> inline string& iqreplace(const char*, const char*);
inline unsigned length() const;
@@ -43,17 +45,18 @@ namespace nall {
inline string& lower();
inline string& upper();
inline string& qlower();
inline string& qupper();
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 = " ");
template<unsigned limit = 0> inline string& trim(const char *key = " ", const char *rkey = 0);
inline optional<unsigned> position(const char *key) const;
inline optional<unsigned> iposition(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);
inline optional<unsigned> iqposition(const char *key) const;
inline operator const char*() const;
inline char* operator()();
@@ -74,10 +77,16 @@ namespace nall {
inline string(string&&);
inline ~string();
//internal functions
inline string& assign_(const char*);
inline string& append_(const char*);
protected:
char *data;
unsigned size;
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(const char*, const char*);
#if defined(QSTRING_H)
public:
inline operator QString() const;
@@ -89,36 +98,43 @@ namespace nall {
template<typename T> inline lstring& operator<<(T value);
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*);
template<unsigned Limit = 0> inline lstring& split(const char*, const char*);
template<unsigned Limit = 0> inline lstring& isplit(const char*, const char*);
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
lstring();
lstring(std::initializer_list<string>);
protected:
template<unsigned Limit, bool Insensitive, bool Quoted> inline lstring& usplit(const char*, const char*);
};
//compare.hpp
inline char chrlower(char c);
inline char chrupper(char c);
inline int stricmp(const char *str1, const char *str2);
inline int istrcmp(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);
inline bool striend(const char *str, const char *key);
inline bool strbegin(const char *str, const char *key);
inline bool istrbegin(const char *str, const char *key);
inline bool strend(const char *str, const char *key);
inline bool istrend(const char *str, const char *key);
//convert.hpp
inline char* strlower(char *str);
inline char* strupper(char *str);
inline char* qstrlower(char *str);
inline char* qstrupper(char *str);
inline char* strtr(char *dest, const char *before, const char *after);
inline uintmax_t hex (const char *str);
inline intmax_t integer(const char *str);
inline uintmax_t hex(const char *str);
inline intmax_t integer(const char *str);
inline uintmax_t decimal(const char *str);
inline uintmax_t binary (const char *str);
inline double fp (const char *str);
inline uintmax_t binary(const char *str);
inline double fp(const char *str);
//math.hpp
inline bool strint (const char *str, int &result);
inline bool strint(const char *str, int &result);
inline bool strmath(const char *str, int &result);
//platform.hpp
@@ -132,26 +148,31 @@ namespace nall {
//strpos.hpp
inline optional<unsigned> strpos(const char *str, const char *key);
inline optional<unsigned> istrpos(const char *str, const char *key);
inline optional<unsigned> qstrpos(const char *str, const char *key);
inline optional<unsigned> iqstrpos(const char *str, const char *key);
template<bool Insensitive = false, bool Quoted = false> inline optional<unsigned> ustrpos(const char *str, const char *key);
//trim.hpp
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 = " ");
template<unsigned limit = 0> inline char* trim(char *str, const char *key = " ", const char *rkey = 0);
//utility.hpp
template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
template<bool Quoted, typename T> alwaysinline bool quoteskip(T *&p);
template<bool Quoted, typename T> alwaysinline bool quotecopy(char *&t, T *&p);
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 substr(const char *src, unsigned start = 0, unsigned length = ~0u);
inline string sha256(const uint8_t *data, unsigned size);
inline string integer(intmax_t value);
template<unsigned length = 0> inline string linteger(intmax_t value);
template<unsigned length = 0> inline string rinteger(intmax_t value);
inline string decimal(uintmax_t value);
template<unsigned length = 0> inline string ldecimal(uintmax_t value);
template<unsigned length = 0> inline string rdecimal(uintmax_t value);
template<unsigned length = 0> inline string hex(uintmax_t value);
template<unsigned length = 0> inline string binary(uintmax_t value);
template<unsigned length = 0, char padding = ' '> inline string integer(intmax_t value);
template<unsigned length = 0, char padding = ' '> inline string linteger(intmax_t value);
template<unsigned length = 0, char padding = ' '> inline string decimal(uintmax_t value);
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
inline unsigned fp(char *str, double value);
inline string fp(double value);

View File

@@ -6,16 +6,15 @@ namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline const char* to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; snprintf(temp, 255, "%+d", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; snprintf(temp, 255, "%u", v); return temp; }
template<> inline const char* to_string<intmax_t> (intmax_t v) { static char temp[256]; snprintf(temp, 255, "%+lld", (long long)v); return temp; }
template<> inline const char* to_string<uintmax_t> (uintmax_t v) { static char temp[256]; snprintf(temp, 255, "%llu", (unsigned long long)v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }
template<> inline const char* to_string<const string&>(const string &v) { return v; }
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
template<typename T> lstring& lstring::operator<<(T value) {
operator[](size()).assign(to_string<T>(value));
return *this;

View File

@@ -11,7 +11,7 @@ char chrupper(char c) {
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
int stricmp(const char *str1, const char *str2) {
int istrcmp(const char *str1, const char *str2) {
while(*str1) {
if(chrlower(*str1) != chrlower(*str2)) break;
str1++, str2++;
@@ -66,7 +66,7 @@ bool strbegin(const char *str, const char *key) {
return (!memcmp(str, key, ksl));
}
bool stribegin(const char *str, const char *key) {
bool istrbegin(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return false;
@@ -89,7 +89,7 @@ bool strend(const char *str, const char *key) {
return (!memcmp(str + ssl - ksl, key, ksl));
}
bool striend(const char *str, const char *key) {
bool istrend(const char *str, const char *key) {
int ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return false;

View File

@@ -23,6 +23,26 @@ char* strupper(char *str) {
return str;
}
char* qstrlower(char *s) {
if(!s) return 0;
bool quoted = false;
while(*s) {
if(*s == '\"' || *s == '\'') quoted ^= 1;
if(quoted == false && *s >= 'A' && *s <= 'Z') *s += 0x20;
s++;
}
}
char* qstrupper(char *s) {
if(!s) return 0;
bool quoted = false;
while(*s) {
if(*s == '\"' || *s == '\'') quoted ^= 1;
if(quoted == false && *s >= 'a' && *s <= 'z') *s -= 0x20;
s++;
}
}
char* strtr(char *dest, const char *before, const char *after) {
if(!dest || !before || !after) return dest;
int sl = strlen(dest), bsl = strlen(before), asl = strlen(after);

View File

@@ -3,6 +3,8 @@
namespace nall {
static function<int64_t (const char *&)> eval_fallback;
static int eval_integer(const char *&s) {
if(!*s) throw "unrecognized_integer";
int value = 0, x = *s, y = *(s + 1);
@@ -58,7 +60,7 @@ static int eval_integer(const char *&s) {
}
static int eval(const char *&s, int depth = 0) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) throw "unrecognized_token";
int value = 0, x = *s, y = *(s + 1);
@@ -74,10 +76,12 @@ static int eval(const char *&s, int depth = 0) {
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
else throw "unrecognized_token";
while(true) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) break;
x = *s, y = *(s + 1);

View File

@@ -3,100 +3,49 @@
namespace nall {
string& string::replace(const char *key, const char *token) {
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
unsigned int replace_count = 0, size = ssl;
char *buffer;
template<unsigned Limit, bool Insensitive, bool Quoted>
string& string::ureplace(const char *key, const char *token) {
if(!key || !*key) return *this;
enum : unsigned { limit = Limit ? Limit : ~0u };
if(ksl <= ssl) {
if(tsl > ksl) { //the new string may be longer than the old string...
for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need...
if(!memcmp(data + i, key, ksl)) {
replace_count++;
i += ksl;
} else i++;
}
size = ssl + ((tsl - ksl) * replace_count);
reserve(size);
const char *p = data;
unsigned counter = 0, keyLength = 0;
while(*p) {
if(quoteskip<Quoted>(p)) continue;
for(unsigned n = 0;; n++) {
if(key[n] == 0) { counter++; p += n; keyLength = n; break; }
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
}
buffer = new char[size + 1];
for(i = z = 0; i < ssl;) {
if(i <= ssl - ksl) {
if(!memcmp(data + i, key, ksl)) {
memcpy(buffer + z, token, tsl);
z += tsl;
i += ksl;
} else buffer[z++] = data[i++];
} else buffer[z++] = data[i++];
}
buffer[z] = 0;
assign(buffer);
delete[] buffer;
}
if(counter == 0) return *this;
if(Limit) counter = min(counter, Limit);
char *t = data, *base;
unsigned tokenLength = strlen(token);
if(tokenLength > keyLength) {
t = base = strdup(data);
reserve((unsigned)(p - data) + ((tokenLength - keyLength) * counter));
}
char *o = data;
while(*t && counter) {
if(quotecopy<Quoted>(o, t)) continue;
for(unsigned n = 0;; n++) {
if(key[n] == 0) { counter--; memcpy(o, token, tokenLength); t += keyLength; o += tokenLength; break; }
if(!chrequal<Insensitive>(key[n], t[n])) { *o++ = *t++; break; }
}
}
do *o++ = *t; while(*t++);
if(tokenLength > keyLength) free(base);
return *this;
}
string& string::qreplace(const char *key, const char *token) {
int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
unsigned int replace_count = 0, size = ssl;
uint8_t x;
char *buffer;
if(ksl <= ssl) {
if(tsl > ksl) {
for(i = 0; i <= ssl - ksl;) {
x = data[i];
if(x == '\"' || x == '\'') {
l = i;
i++;
while(data[i++] != x) {
if(i == ssl) {
i = l;
break;
}
}
}
if(!memcmp(data + i, key, ksl)) {
replace_count++;
i += ksl;
} else i++;
}
size = ssl + ((tsl - ksl) * replace_count);
reserve(size);
}
buffer = new char[size + 1];
for(i = z = 0; i < ssl;) {
x = data[i];
if(x == '\"' || x == '\'') {
l = i++;
while(data[i] != x && i < ssl)i++;
if(i >= ssl)i = l;
else {
memcpy(buffer + z, data + l, i - l);
z += i - l;
}
}
if(i <= ssl - ksl) {
if(!memcmp(data + i, key, ksl)) {
memcpy(buffer + z, token, tsl);
z += tsl;
i += ksl;
replace_count++;
} else buffer[z++] = data[i++];
} else buffer[z++] = data[i++];
}
buffer[z] = 0;
assign(buffer);
delete[] buffer;
}
return *this;
}
template<unsigned Limit> string &string::replace(const char *key, const char *token) { return ureplace<Limit, false, false>(key, token); }
template<unsigned Limit> string &string::ireplace(const char *key, const char *token) { return ureplace<Limit, true, false>(key, token); }
template<unsigned Limit> string &string::qreplace(const char *key, const char *token) { return ureplace<Limit, false, true>(key, token); }
template<unsigned Limit> string &string::iqreplace(const char *key, const char *token) { return ureplace<Limit, true, true>(key, token); }
};

View File

@@ -3,56 +3,36 @@
namespace nall {
template<unsigned Limit> void lstring::split(const char *key, const char *src) {
unsigned limit = Limit;
template<unsigned Limit, bool Insensitive, bool Quoted> lstring& lstring::usplit(const char *key, const char *base) {
reset();
if(!key || !*key) return *this;
int ssl = strlen(src), ksl = strlen(key);
int lp = 0, split_count = 0;
const char *p = base;
unsigned counter = 0;
for(int i = 0; i <= ssl - ksl;) {
if(!memcmp(src + i, key, ksl)) {
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
i += ksl;
lp = i;
if(!--limit) break;
} else i++;
}
operator[](split_count++) = src + lp;
}
template<unsigned Limit> void lstring::qsplit(const char *key, const char *src) {
unsigned limit = Limit;
reset();
int ssl = strlen(src), ksl = strlen(key);
int lp = 0, split_count = 0;
for(int i = 0; i <= ssl - ksl;) {
uint8_t x = src[i];
if(x == '\"' || x == '\'') {
int z = i++; //skip opening quote
while(i < ssl && src[i] != x) i++;
if(i >= ssl) i = z; //failed match, rewind i
else {
i++; //skip closing quote
continue; //restart in case next char is also a quote
while(*p) {
if(Limit) if(counter >= Limit) break;
if(quoteskip<Quoted>(p)) continue;
for(unsigned n = 0;; n++) {
if(key[n] == 0) {
strlcpy(operator[](counter++), base, (unsigned)(p - base + 1));
p += n;
base = p;
break;
}
if(!chrequal<Insensitive>(key[n], p[n])) { p++; break; }
}
if(!memcmp(src + i, key, ksl)) {
strlcpy(operator[](split_count++), src + lp, i - lp + 1);
i += ksl;
lp = i;
if(!--limit) break;
} else i++;
}
operator[](split_count++) = src + lp;
operator[](counter) = base;
return *this;
}
template<unsigned Limit> lstring& lstring::split(const char *key, const char *src) { return usplit<Limit, false, false>(key, src); }
template<unsigned Limit> lstring& lstring::isplit(const char *key, const char *src) { return usplit<Limit, true, false>(key, src); }
template<unsigned Limit> lstring& lstring::qsplit(const char *key, const char *src) { return usplit<Limit, false, true>(key, src); }
template<unsigned Limit> lstring& lstring::iqsplit(const char *key, const char *src) { return usplit<Limit, true, true>(key, src); }
};
#endif

View File

@@ -2,40 +2,33 @@
#define NALL_STRING_STRPOS_HPP
//usage example:
//if(auto pos = strpos(str, key)) print(pos(), "\n");
//prints position of key within str, only if it is found
//if(auto position = strpos(str, key)) print(position(), "\n");
//prints position of key within str; but only if it is found
namespace nall {
optional<unsigned> strpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 };
template<bool Insensitive, bool Quoted>
optional<unsigned> ustrpos(const char *str, const char *key) {
const char *base = str;
for(unsigned i = 0; i <= ssl - ksl; i++) {
if(!memcmp(str + i, key, ksl)) return { true, i };
}
return { false, 0 };
}
optional<unsigned> qstrpos(const char *str, const char *key) {
unsigned ssl = strlen(str), ksl = strlen(key);
if(ksl > ssl) return { false, 0 };
for(unsigned i = 0; i <= ssl - ksl;) {
uint8_t x = str[i];
if(x == '\"' || x == '\'') {
uint8_t z = i++;
while(str[i] != x && i < ssl) i++;
if(i >= ssl) i = z;
while(*str) {
if(quoteskip<Quoted>(str)) continue;
for(unsigned n = 0;; n++) {
if(key[n] == 0) return { true, (unsigned)(str - base) };
if(str[n] == 0) return { false, 0 };
if(!chrequal<Insensitive>(str[n], key[n])) break;
}
if(!memcmp(str + i, key, ksl)) return { true, i };
i++;
str++;
}
return { false, 0 };
}
optional<unsigned> strpos(const char *str, const char *key) { return ustrpos<false, false>(str, key); }
optional<unsigned> istrpos(const char *str, const char *key) { return ustrpos<true, false>(str, key); }
optional<unsigned> qstrpos(const char *str, const char *key) { return ustrpos<false, true>(str, key); }
optional<unsigned> iqstrpos(const char *str, const char *key) { return ustrpos<true, true>(str, key); }
}
#endif

View File

@@ -29,7 +29,8 @@ template<unsigned Limit> char* rtrim(char *str, const char *key) {
return str;
}
template<unsigned limit> char* trim(char *str, const char *key) {
template<unsigned limit> char* trim(char *str, const char *key, const char *rkey) {
if(rkey) return ltrim<limit>(rtrim<limit>(str, rkey), key);
return ltrim<limit>(rtrim<limit>(str, key), key);
}

View File

@@ -3,6 +3,38 @@
namespace nall {
template<bool Insensitive>
bool chrequal(char x, char y) {
if(Insensitive) return chrlower(x) == chrlower(y);
return x == y;
}
template<bool Quoted, typename T>
bool quoteskip(T *&p) {
if(Quoted == false) return false;
if(*p != '\'' && *p != '\"') return false;
while(*p == '\'' || *p == '\"') {
char x = *p++;
while(*p && *p++ != x);
}
return true;
}
template<bool Quoted, typename T>
bool quotecopy(char *&t, T *&p) {
if(Quoted == false) return false;
if(*p != '\'' && *p != '\"') return false;
while(*p == '\'' || *p == '\"') {
char x = *p++;
*t++ = x;
while(*p && *p != x) *t++ = *p++;
*t++ = *p++;
}
return true;
}
unsigned strlcpy(string &dest, const char *src, unsigned length) {
dest.reserve(length);
return strlcpy(dest(), src, length);
@@ -15,7 +47,7 @@ unsigned strlcat(string &dest, const char *src, unsigned length) {
string substr(const char *src, unsigned start, unsigned length) {
string dest;
if(length == 0) {
if(length == ~0u) {
//copy entire string
dest = src + start;
} else {
@@ -25,35 +57,21 @@ string substr(const char *src, unsigned start, unsigned length) {
return dest;
}
string sha256(const uint8_t *data, unsigned size) {
sha256_ctx sha;
uint8_t hash[32];
sha256_init(&sha);
sha256_chunk(&sha, data, size);
sha256_final(&sha);
sha256_hash(&sha, hash);
string result;
foreach(byte, hash) result.append(hex<2>(byte));
return result;
}
/* arithmetic <> string */
string integer(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string linteger(intmax_t value) {
template<unsigned length_, char padding> string integer(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
@@ -70,34 +88,7 @@ template<unsigned length_> string linteger(intmax_t value) {
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string rinteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
memset(result, padding, length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
@@ -107,29 +98,10 @@ template<unsigned length_> string rinteger(intmax_t value) {
return (const char*)result;
}
string decimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
char result[size + 1];
memset(result, '0', size);
result[size] = 0;
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_> string ldecimal(uintmax_t value) {
template<unsigned length_, char padding> string linteger(intmax_t value) {
bool negative = value < 0;
if(negative) value = abs(value);
char buffer[64];
unsigned size = 0;
@@ -138,11 +110,12 @@ template<unsigned length_> string ldecimal(uintmax_t value) {
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
memset(result, padding, length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
@@ -152,7 +125,7 @@ template<unsigned length_> string ldecimal(uintmax_t value) {
return (const char*)result;
}
template<unsigned length_> string rdecimal(uintmax_t value) {
template<unsigned length_, char padding> string decimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
@@ -165,7 +138,7 @@ template<unsigned length_> string rdecimal(uintmax_t value) {
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, ' ', length);
memset(result, padding, length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
@@ -175,7 +148,30 @@ template<unsigned length_> string rdecimal(uintmax_t value) {
return (const char*)result;
}
template<unsigned length_> string hex(uintmax_t value) {
template<unsigned length_, char padding> string ldecimal(uintmax_t value) {
char buffer[64];
unsigned size = 0;
do {
unsigned n = value % 10;
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, padding, length);
result[length] = 0;
for(signed x = 0, y = size - 1; x < length && y >= 0; x++, y--) {
result[x] = buffer[y];
}
return (const char*)result;
}
template<unsigned length_, char padding> string hex(uintmax_t value) {
char buffer[64];
unsigned size = 0;
@@ -187,7 +183,7 @@ template<unsigned length_> string hex(uintmax_t value) {
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, '0', length);
memset(result, padding, length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {
@@ -197,7 +193,7 @@ template<unsigned length_> string hex(uintmax_t value) {
return (const char*)result;
}
template<unsigned length_> string binary(uintmax_t value) {
template<unsigned length_, char padding> string binary(uintmax_t value) {
char buffer[256];
unsigned size = 0;
@@ -209,7 +205,7 @@ template<unsigned length_> string binary(uintmax_t value) {
unsigned length = (length_ == 0 ? size : length_);
char result[length + 1];
memset(result, '0', length);
memset(result, padding, length);
result[length] = 0;
for(signed x = length - 1, y = 0; x >= 0 && y < size; x--, y++) {

View File

@@ -6,27 +6,31 @@ 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::iequals(const char *str) const { return !istrcmp(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::ibeginswith(const char *str) const { return istrbegin(data, str); }
bool string::endswith(const char *str) const { return strend(data, str); }
bool string::iendswith(const char *str) const { return striend(data, str); }
bool string::iendswith(const char *str) const { return istrend(data, str); }
string& string::lower() { nall::strlower(data); return *this; }
string& string::upper() { nall::strupper(data); return *this; }
string& string::qlower() { nall::qstrlower(data); return *this; }
string& string::qupper() { nall::qstrupper(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; }
template<unsigned limit> string& string::trim(const char *key, const char *rkey) { nall::trim <limit>(data, key, rkey); return *this; }
optional<unsigned> string::position(const char *key) const { return strpos(data, key); }
optional<unsigned> string::iposition(const char *key) const { return istrpos(data, key); }
optional<unsigned> string::qposition(const char *key) const { return qstrpos(data, key); }
optional<unsigned> string::iqposition(const char *key) const { return iqstrpos(data, key); }
}

View File

@@ -77,7 +77,7 @@ inline string xml_element::parse() const {
if(auto pos = strpos(source, "]]>")) {
if(pos() - 9 > 0) {
string cdata = substr(source, 9, pos() - 9);
data << cdata;
data.append(cdata);
offset += strlen(cdata);
}
source += 9 + offset + 3;

View File

@@ -26,6 +26,7 @@ namespace nall {
public:
inline operator bool() const { return valid; }
inline const T& operator()() const { if(!valid) throw; return value; }
inline optional<T>& operator=(const optional<T> &source) { valid = source.valid; value = source.value; return *this; }
inline optional(bool valid, const T &value) : valid(valid), value(value) {}
};

View File

@@ -94,14 +94,15 @@ namespace nall {
else resize(objectsize - count);
}
inline T& operator[](unsigned index) {
if(index >= objectsize) resize(index + 1);
return pool[index];
linear_vector() : pool(0), poolsize(0), objectsize(0) {
}
inline const T& operator[](unsigned index) const {
if(index >= objectsize) throw "vector[] out of bounds";
return pool[index];
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
}
~linear_vector() {
reset();
}
//copy
@@ -132,17 +133,22 @@ namespace nall {
operator=(std::move(source));
}
//construction
linear_vector() : pool(0), poolsize(0), objectsize(0) {
//index
inline T& operator[](unsigned index) {
if(index >= objectsize) resize(index + 1);
return pool[index];
}
linear_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
inline const T& operator[](unsigned index) const {
if(index >= objectsize) throw "vector[] out of bounds";
return pool[index];
}
~linear_vector() {
reset();
}
//iteration
T* begin() { return &pool[0]; }
T* end() { return &pool[objectsize]; }
const T* begin() const { return &pool[0]; }
const T* end() const { return &pool[objectsize]; }
};
//pointer_vector
@@ -222,15 +228,15 @@ namespace nall {
else resize(objectsize - count);
}
inline T& operator[](unsigned index) {
if(index >= objectsize) resize(index + 1);
if(!pool[index]) pool[index] = new T;
return *pool[index];
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
}
inline const T& operator[](unsigned index) const {
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
return *pool[index];
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
}
~pointer_vector() {
reset();
}
//copy
@@ -261,17 +267,31 @@ namespace nall {
operator=(std::move(source));
}
//construction
pointer_vector() : pool(0), poolsize(0), objectsize(0) {
//index
inline T& operator[](unsigned index) {
if(index >= objectsize) resize(index + 1);
if(!pool[index]) pool[index] = new T;
return *pool[index];
}
pointer_vector(std::initializer_list<T> list) : pool(0), poolsize(0), objectsize(0) {
for(const T *p = list.begin(); p != list.end(); ++p) append(*p);
inline const T& operator[](unsigned index) const {
if(index >= objectsize || !pool[index]) throw "vector[] out of bounds";
return *pool[index];
}
~pointer_vector() {
reset();
}
//iteration
struct iterator {
bool operator!=(const iterator &source) const { return index != source.index; }
T& operator*() { return vector.operator[](index); }
iterator& operator++() { index++; return *this; }
iterator(pointer_vector &vector, unsigned index) : vector(vector), index(index) {}
private:
pointer_vector &vector;
unsigned index;
};
iterator begin() { return iterator(*this, 0); }
iterator end() { return iterator(*this, objectsize); }
};
template<typename T> struct has_size<linear_vector<T>> { enum { value = true }; };

192
bsnes/nall/windows/detour.hpp Executable file
View File

@@ -0,0 +1,192 @@
#ifndef NALL_WINDOWS_DETOUR_HPP
#define NALL_WINDOWS_DETOUR_HPP
#include <nall/foreach.hpp>
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utf8.hpp>
namespace nall {
#define Copy 0
#define RelNear 1
struct detour {
static bool insert(const string &moduleName, const string &functionName, void *&source, void *target);
static bool remove(const string &moduleName, const string &functionName, void *&source);
protected:
static unsigned length(const uint8_t *function);
static unsigned mirror(uint8_t *target, const uint8_t *source);
struct opcode {
uint16_t prefix;
unsigned length;
unsigned mode;
uint16_t modify;
};
static opcode opcodes[];
};
//TODO:
//* fs:, gs: should force another opcode copy
//* conditional branches within +5-byte range should fail
detour::opcode detour::opcodes[] = {
{ 0x50, 1 }, //push eax
{ 0x51, 1 }, //push ecx
{ 0x52, 1 }, //push edx
{ 0x53, 1 }, //push ebx
{ 0x54, 1 }, //push esp
{ 0x55, 1 }, //push ebp
{ 0x56, 1 }, //push esi
{ 0x57, 1 }, //push edi
{ 0x58, 1 }, //pop eax
{ 0x59, 1 }, //pop ecx
{ 0x5a, 1 }, //pop edx
{ 0x5b, 1 }, //pop ebx
{ 0x5c, 1 }, //pop esp
{ 0x5d, 1 }, //pop ebp
{ 0x5e, 1 }, //pop esi
{ 0x5f, 1 }, //pop edi
{ 0x64, 1 }, //fs:
{ 0x65, 1 }, //gs:
{ 0x68, 5 }, //push dword
{ 0x6a, 2 }, //push byte
{ 0x74, 2, RelNear, 0x0f84 }, //je near -> je far
{ 0x75, 2, RelNear, 0x0f85 }, //jne near -> jne far
{ 0x89, 2 }, //mov reg,reg
{ 0x8b, 2 }, //mov reg,reg
{ 0x90, 1 }, //nop
{ 0xa1, 5 }, //mov eax,[dword]
{ 0xeb, 2, RelNear, 0xe9 }, //jmp near -> jmp far
};
bool detour::insert(const string &moduleName, const string &functionName, void *&source, void *target) {
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
if(!module) return false;
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
if(!sourceData) return false;
unsigned sourceLength = detour::length(sourceData);
if(sourceLength < 5) {
//unable to clone enough bytes to insert hook
#if 1
string output = { "detour::insert(", moduleName, "::", functionName, ") failed: " };
for(unsigned n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " ");
output.rtrim<1>(" ");
MessageBoxA(0, output, "nall::detour", MB_OK);
#endif
return false;
}
uint8_t *mirrorData = new uint8_t[512]();
detour::mirror(mirrorData, sourceData);
DWORD privileges;
VirtualProtect((void*)mirrorData, 512, PAGE_EXECUTE_READWRITE, &privileges);
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
uintmax_t address = (uintmax_t)target - ((uintmax_t)sourceData + 5);
sourceData[0] = 0xe9; //jmp target
sourceData[1] = address >> 0;
sourceData[2] = address >> 8;
sourceData[3] = address >> 16;
sourceData[4] = address >> 24;
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
source = (void*)mirrorData;
return true;
}
bool detour::remove(const string &moduleName, const string &functionName, void *&source) {
HMODULE module = GetModuleHandleW(utf16_t(moduleName));
if(!module) return false;
uint8_t *sourceData = (uint8_t*)GetProcAddress(module, functionName);
if(!sourceData) return false;
uint8_t *mirrorData = (uint8_t*)source;
if(mirrorData == sourceData) return false; //hook was never installed
unsigned length = detour::length(256 + mirrorData);
if(length < 5) return false;
DWORD privileges;
VirtualProtect((void*)sourceData, 256, PAGE_EXECUTE_READWRITE, &privileges);
for(unsigned n = 0; n < length; n++) sourceData[n] = mirrorData[256 + n];
VirtualProtect((void*)sourceData, 256, privileges, &privileges);
source = (void*)sourceData;
delete[] mirrorData;
return true;
}
unsigned detour::length(const uint8_t *function) {
unsigned length = 0;
while(length < 5) {
detour::opcode *opcode = 0;
foreach(op, detour::opcodes) {
if(function[length] == op.prefix) {
opcode = &op;
break;
}
}
if(opcode == 0) break;
length += opcode->length;
}
return length;
}
unsigned detour::mirror(uint8_t *target, const uint8_t *source) {
const uint8_t *entryPoint = source;
for(unsigned n = 0; n < 256; n++) target[256 + n] = source[n];
unsigned size = detour::length(source);
while(size) {
detour::opcode *opcode = 0;
foreach(op, detour::opcodes) {
if(*source == op.prefix) {
opcode = &op;
break;
}
}
switch(opcode->mode) {
case Copy:
for(unsigned n = 0; n < opcode->length; n++) *target++ = *source++;
break;
case RelNear: {
source++;
uintmax_t sourceAddress = (uintmax_t)source + 1 + (int8_t)*source;
*target++ = opcode->modify;
if(opcode->modify >> 8) *target++ = opcode->modify >> 8;
uintmax_t targetAddress = (uintmax_t)target + 4;
uintmax_t address = sourceAddress - targetAddress;
*target++ = address >> 0;
*target++ = address >> 8;
*target++ = address >> 16;
*target++ = address >> 24;
source += 2;
} break;
}
size -= opcode->length;
}
uintmax_t address = (entryPoint + detour::length(entryPoint)) - (target + 5);
*target++ = 0xe9; //jmp entryPoint
*target++ = address >> 0;
*target++ = address >> 8;
*target++ = address >> 16;
*target++ = address >> 24;
return source - entryPoint;
}
#undef Implied
#undef RelNear
}
#endif

94
bsnes/nall/windows/launcher.hpp Executable file
View File

@@ -0,0 +1,94 @@
#ifndef NALL_WINDOWS_LAUNCHER_HPP
#define NALL_WINDOWS_LAUNCHER_HPP
namespace nall {
//launch a new process and inject specified DLL into it
bool launch(const char *applicationName, const char *libraryName, uint32_t entryPoint) {
//if a launcher does not send at least one message, a wait cursor will appear
PostThreadMessage(GetCurrentThreadId(), WM_USER, 0, 0);
MSG msg;
GetMessage(&msg, 0, 0, 0);
STARTUPINFOW si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFOW));
BOOL result = CreateProcessW(
utf16_t(applicationName), GetCommandLineW(), NULL, NULL, TRUE,
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, //do not break if application creates its own processes
NULL, NULL, &si, &pi
);
if(result == false) return false;
uint8_t entryData[1024], entryHook[1024] = {
0x68, 0x00, 0x00, 0x00, 0x00, //push libraryName
0xb8, 0x00, 0x00, 0x00, 0x00, //mov eax,LoadLibraryW
0xff, 0xd0, //call eax
0xcd, 0x03, //int 3
};
entryHook[1] = (uint8_t)((entryPoint + 14) >> 0);
entryHook[2] = (uint8_t)((entryPoint + 14) >> 8);
entryHook[3] = (uint8_t)((entryPoint + 14) >> 16);
entryHook[4] = (uint8_t)((entryPoint + 14) >> 24);
uint32_t pLoadLibraryW = (uint32_t)GetProcAddress(GetModuleHandleW(L"kernel32"), "LoadLibraryW");
entryHook[6] = pLoadLibraryW >> 0;
entryHook[7] = pLoadLibraryW >> 8;
entryHook[8] = pLoadLibraryW >> 16;
entryHook[9] = pLoadLibraryW >> 24;
utf16_t buffer = utf16_t(libraryName);
memcpy(entryHook + 14, buffer, 2 * wcslen(buffer) + 2);
while(true) {
DEBUG_EVENT event;
WaitForDebugEvent(&event, INFINITE);
if(event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
if(event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
if(event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) {
if(event.u.Exception.ExceptionRecord.ExceptionAddress == (void*)(entryPoint + 14 - 1)) {
HANDLE hProcess = OpenProcess(0, FALSE, event.dwProcessId);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, event.dwThreadId);
CONTEXT context;
context.ContextFlags = CONTEXT_FULL;
GetThreadContext(hThread, &context);
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
context.Eip = entryPoint;
SetThreadContext(hThread, &context);
CloseHandle(hThread);
CloseHandle(hProcess);
}
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
continue;
}
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
continue;
}
if(event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
ReadProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryData, sizeof entryData, NULL);
WriteProcessMemory(pi.hProcess, (void*)entryPoint, (void*)&entryHook, sizeof entryHook, NULL);
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
continue;
}
ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE);
}
return true;
}
}
#endif

124
bsnes/nall/zip.hpp Executable file
View File

@@ -0,0 +1,124 @@
#ifndef NALL_UNZIP_HPP
#define NALL_UNZIP_HPP
#include <nall/filemap.hpp>
#include <nall/inflate.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
struct zip {
struct File {
string name;
const uint8_t *data;
unsigned size;
unsigned csize;
unsigned cmode; //0 = uncompressed, 8 = deflate
unsigned crc32;
};
inline bool open(const string &filename) {
close();
if(fm.open(filename, filemap::mode::read) == false) return false;
if(open(fm.data(), fm.size()) == false) {
fm.close();
return false;
}
return true;
}
inline bool open(const uint8_t *data, unsigned size) {
if(size < 22) return false;
filedata = data;
filesize = size;
file.reset();
const uint8_t *footer = data + size - 22;
const uint8_t *directory = data + read(footer + 16, 4);
while(true) {
unsigned signature = read(directory + 0, 4);
if(signature != 0x02014b50) break;
File file;
file.cmode = read(directory + 10, 2);
file.crc32 = read(directory + 16, 4);
file.csize = read(directory + 20, 4);
file.size = read(directory + 24, 4);
unsigned namelength = read(directory + 28, 2);
unsigned extralength = read(directory + 30, 2);
unsigned commentlength = read(directory + 32, 2);
char *filename = new char[namelength + 1];
memcpy(filename, directory + 46, namelength);
filename[namelength] = 0;
file.name = filename;
delete[] filename;
unsigned offset = read(directory + 42, 4);
unsigned offsetNL = read(data + offset + 26, 2);
unsigned offsetEL = read(data + offset + 28, 2);
file.data = data + offset + 30 + offsetNL + offsetEL;
directory += 46 + namelength + extralength + commentlength;
this->file.append(file);
}
return true;
}
inline bool extract(File &file, uint8_t *&data, unsigned &size) {
data = 0, size = 0;
if(file.cmode == 0) {
size = file.size;
data = new uint8_t[size];
memcpy(data, file.data, size);
return true;
}
if(file.cmode == 8) {
size = file.size;
data = new uint8_t[size];
if(inflate(data, size, file.data, file.csize) == false) {
delete[] data;
size = 0;
return false;
}
return true;
}
return false;
}
inline void close() {
if(fm.open()) fm.close();
}
~zip() {
close();
}
protected:
filemap fm;
const uint8_t *filedata;
unsigned filesize;
unsigned read(const uint8_t *data, unsigned size) {
unsigned result = 0, shift = 0;
while(size--) { result |= *data++ << shift; shift += 8; }
return result;
}
public:
linear_vector<File> file;
};
}
#endif

View File

@@ -26,6 +26,7 @@ void OS::processEvents() { return pOS::processEvents(); }
void OS::quit() { return pOS::quit(); }
void OS::initialize() { static bool initialized = false; if(initialized == false) { initialized = true; return pOS::initialize(); } }
Geometry Font::geometry(const string &text) { return p.geometry(text); }
void Font::setBold(bool bold) { state.bold = bold; return p.setBold(bold); }
void Font::setFamily(const string &family) { state.family = family; return p.setFamily(family); }
void Font::setItalic(bool italic) { state.italic = italic; return p.setItalic(italic); }
@@ -33,6 +34,10 @@ void Font::setSize(unsigned size) { state.size = size; return p.setSize(size); }
void Font::setUnderline(bool underline) { state.underline = underline; return p.setUnderline(underline); }
Font::Font() : state(*new State), p(*new pFont(*this)) { p.constructor(); }
void Timer::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
void Timer::setInterval(unsigned milliseconds) { state.milliseconds = milliseconds; return p.setInterval(milliseconds); }
Timer::Timer() : state(*new State), p(*new pTimer(*this)) { p.constructor(); }
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::information(parent, text, buttons); }
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::question(parent, text, buttons); }
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::warning(parent, text, buttons); }
@@ -42,11 +47,12 @@ Window Window::None;
void Window::append(Layout &layout) { state.layout.append(layout); return p.append(layout); }
void Window::append(Menu &menu) { state.menu.append(menu); ((Action&)menu).state.parent = this; return p.append(menu); }
void Window::append(Widget &widget) { state.widget.append(widget); return p.append(widget); }
Color Window::backgroundColor() { return p.backgroundColor(); }
Geometry Window::frameGeometry() { Geometry geometry = p.geometry(), margin = p.frameMargin(); return { geometry.x - margin.x, geometry.y - margin.y, geometry.width + margin.width, geometry.height + margin.height }; }
Geometry Window::frameMargin() { return p.frameMargin(); }
bool Window::focused() { return p.focused(); }
Geometry Window::geometry() { return p.geometry(); }
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) { state.backgroundColor = true; state.backgroundColorRed = red; state.backgroundColorGreen = green; state.backgroundColorBlue = blue; return p.setBackgroundColor(red, green, blue); }
void Window::setBackgroundColor(const Color &color) { state.backgroundColorOverride = true; state.backgroundColor = color; return p.setBackgroundColor(color); }
void Window::setFrameGeometry(const Geometry &geometry) { Geometry margin = p.frameMargin(); return setGeometry({ geometry.x + margin.x, geometry.y + margin.y, geometry.width - margin.width, geometry.height - margin.height }); }
void Window::setFocused() { return p.setFocused(); }
void Window::setFullScreen(bool fullScreen) { state.fullScreen = fullScreen; return p.setFullScreen(fullScreen); }
@@ -87,6 +93,9 @@ void RadioItem::setText(const string &text) { state.text = text; return p.setTex
RadioItem::RadioItem() : state(*new State), base_from_member<pRadioItem&>(*new pRadioItem(*this)), Action(base_from_member<pRadioItem&>::value), p(base_from_member<pRadioItem&>::value) { p.constructor(); }
bool Widget::enabled() { return state.enabled; }
Font& Widget::font() { return p.font(); }
Geometry Widget::geometry() { return state.geometry; }
Geometry Widget::minimumGeometry() { return p.minimumGeometry(); }
void Widget::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); }
void Widget::setFocused() { return p.setFocused(); }
void Widget::setFont(Font &font) { state.font = &font; return p.setFont(font); }
@@ -99,6 +108,10 @@ Widget::Widget(pWidget &p) : state(*new State), p(p) { p.constructor(); }
void Button::setText(const string &text) { state.text = text; return p.setText(text); }
Button::Button() : state(*new State), base_from_member<pButton&>(*new pButton(*this)), Widget(base_from_member<pButton&>::value), p(base_from_member<pButton&>::value) { p.constructor(); }
uint32_t* Canvas::buffer() { return p.buffer(); }
void Canvas::update() { return p.update(); }
Canvas::Canvas() : base_from_member<pCanvas&>(*new pCanvas(*this)), Widget(base_from_member<pCanvas&>::value), p(base_from_member<pCanvas&>::value) { p.constructor(); }
bool CheckBox::checked() { return p.checked(); }
void CheckBox::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); }
void CheckBox::setText(const string &text) { state.text = text; return p.setText(text); }
@@ -117,6 +130,11 @@ void HexEdit::setRows(unsigned rows) { state.rows = rows; return p.setRows(rows)
void HexEdit::update() { return p.update(); }
HexEdit::HexEdit() : state(*new State), base_from_member<pHexEdit&>(*new pHexEdit(*this)), Widget(base_from_member<pHexEdit&>::value), p(base_from_member<pHexEdit&>::value) { p.constructor(); }
unsigned HorizontalScrollBar::position() { return p.position(); }
void HorizontalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
void HorizontalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
HorizontalScrollBar::HorizontalScrollBar() : state(*new State), base_from_member<pHorizontalScrollBar&>(*new pHorizontalScrollBar(*this)), Widget(base_from_member<pHorizontalScrollBar&>::value), p(base_from_member<pHorizontalScrollBar&>::value) { p.constructor(); }
unsigned HorizontalSlider::position() { return p.position(); }
void HorizontalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
void HorizontalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
@@ -161,6 +179,11 @@ void TextEdit::setWordWrap(bool wordWrap) { state.wordWrap = wordWrap; return p.
string TextEdit::text() { return p.text(); }
TextEdit::TextEdit() : state(*new State), base_from_member<pTextEdit&>(*new pTextEdit(*this)), Widget(base_from_member<pTextEdit&>::value), p(base_from_member<pTextEdit&>::value) { p.constructor(); }
unsigned VerticalScrollBar::position() { return p.position(); }
void VerticalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); }
void VerticalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }
VerticalScrollBar::VerticalScrollBar() : state(*new State), base_from_member<pVerticalScrollBar&>(*new pVerticalScrollBar(*this)), Widget(base_from_member<pVerticalScrollBar&>::value), p(base_from_member<pVerticalScrollBar&>::value) { p.constructor(); }
unsigned VerticalSlider::position() { return p.position(); }
void VerticalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); }
void VerticalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); }

View File

@@ -6,6 +6,7 @@ struct Widget;
struct pOS;
struct pFont;
struct pTimer;
struct pWindow;
struct pAction;
struct pMenu;
@@ -16,9 +17,11 @@ struct pRadioItem;
struct pLayout;
struct pWidget;
struct pButton;
struct pCanvas;
struct pCheckBox;
struct pComboBox;
struct pHexEdit;
struct pHorizontalScrollBar;
struct pHorizontalSlider;
struct pLabel;
struct pLineEdit;
@@ -26,9 +29,15 @@ struct pListView;
struct pProgressBar;
struct pRadioBox;
struct pTextEdit;
struct pVerticalScrollBar;
struct pVerticalSlider;
struct pViewport;
enum : unsigned {
MaximumSize = ~0u,
MinimumSize = 0u,
};
struct Geometry {
signed x, y;
unsigned width, height;
@@ -36,6 +45,12 @@ struct Geometry {
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
};
struct Color {
uint8_t red, green, blue, alpha;
inline Color() : red(0), green(0), blue(0), alpha(255) {}
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
};
struct Object {
Object();
Object& operator=(const Object&) = delete;
@@ -63,6 +78,7 @@ private:
};
struct Font : Object {
Geometry geometry(const nall::string &text);
void setBold(bool bold = true);
void setFamily(const nall::string &family);
void setItalic(bool italic = true);
@@ -75,6 +91,18 @@ struct Font : Object {
pFont &p;
};
struct Timer : Object {
nall::function<void ()> onTimeout;
void setEnabled(bool enabled = true);
void setInterval(unsigned milliseconds);
Timer();
struct State;
State &state;
pTimer &p;
};
struct MessageWindow : Object {
enum class Buttons : unsigned {
Ok,
@@ -104,11 +132,12 @@ struct Window : Object {
void append(Layout &layout);
void append(Menu &menu);
void append(Widget &widget);
Color backgroundColor();
Geometry frameGeometry();
Geometry frameMargin();
bool focused();
Geometry geometry();
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setBackgroundColor(const Color &color);
void setFrameGeometry(const Geometry &geometry);
void setFocused();
void setFullScreen(bool fullScreen = true);
@@ -195,13 +224,16 @@ struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
};
struct Layout : Object {
virtual void setGeometry(Geometry &geometry) = 0;
virtual void setGeometry(const Geometry &geometry) = 0;
virtual void setParent(Window &parent) = 0;
virtual void setVisible(bool visible = true) = 0;
};
struct Widget : Object {
bool enabled();
Font& font();
Geometry geometry();
Geometry minimumGeometry();
void setEnabled(bool enabled = true);
void setFocused();
void setFont(Font &font);
@@ -227,6 +259,14 @@ struct Button : private nall::base_from_member<pButton&>, Widget {
pButton &p;
};
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
uint32_t* buffer();
void update();
Canvas();
pCanvas &p;
};
struct CheckBox : private nall::base_from_member<pCheckBox&>, Widget {
nall::function<void ()> onTick;
@@ -270,6 +310,19 @@ struct HexEdit : private nall::base_from_member<pHexEdit&>, Widget {
pHexEdit &p;
};
struct HorizontalScrollBar : private nall::base_from_member<pHorizontalScrollBar&>, Widget {
nall::function<void ()> onChange;
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
HorizontalScrollBar();
struct State;
State &state;
pHorizontalScrollBar &p;
};
struct HorizontalSlider : private nall::base_from_member<pHorizontalSlider&>, Widget {
nall::function<void ()> onChange;
@@ -376,6 +429,19 @@ struct TextEdit : private nall::base_from_member<pTextEdit&>, Widget {
pTextEdit &p;
};
struct VerticalScrollBar : private nall::base_from_member<pVerticalScrollBar&>, Widget {
nall::function<void ()> onChange;
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
VerticalScrollBar();
struct State;
State &state;
pVerticalScrollBar &p;
};
struct VerticalSlider : private nall::base_from_member<pVerticalSlider&>, Widget {
nall::function<void ()> onChange;

View File

@@ -9,7 +9,7 @@ void FixedLayout::append(Widget &widget, const Geometry &geometry) {
children.append({ &widget, geometry });
}
void FixedLayout::setGeometry(Geometry &geometry) {
void FixedLayout::setGeometry(const Geometry &geometry) {
}
void FixedLayout::setVisible(bool visible) {

View File

@@ -1,6 +1,6 @@
struct FixedLayout : Layout {
void append(Widget &widget, const Geometry &geometry);
void setGeometry(Geometry &geometry);
void setGeometry(const Geometry &geometry);
void setParent(Window &parent);
void setVisible(bool visible);
FixedLayout();

View File

@@ -1,77 +1,130 @@
void HorizontalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void HorizontalLayout::append(VerticalLayout &layout, unsigned width, unsigned height, unsigned spacing) {
layout.width = width;
layout.height = height;
children.append({ &layout, 0, width, height, spacing });
void HorizontalLayout::append(VerticalLayout &layout, unsigned spacing) {
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
}
void HorizontalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
children.append({ 0, &widget, width, height, spacing });
}
void HorizontalLayout::setGeometry(Geometry &geometry) {
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
Geometry HorizontalLayout::minimumGeometry() {
unsigned width = 0, height = 0;
unsigned geometryWidth = width ? width : geometry.width;
unsigned geometryHeight = height ? height : geometry.height;
Geometry baseGeometry = geometry;
linear_vector<HorizontalLayout::Children> children = this->children;
unsigned minimumWidth = 0;
foreach(child, children) minimumWidth += child.width + child.spacing;
unsigned autosizeWidgets = 0;
foreach(child, children) {
if(child.width == 0) autosizeWidgets++;
}
foreach(child, children) {
if(child.width == 0) child.width = (geometryWidth - minimumWidth) / autosizeWidgets;
if(child.height == 0) child.height = geometryHeight;
width += child.spacing;
if(child.width == MinimumSize || child.width == MaximumSize) {
if(child.layout) width += child.layout->minimumGeometry().width;
if(child.widget) width += child.widget->minimumGeometry().width;
continue;
}
width += child.width;
}
unsigned maxHeight = 0;
foreach(child, children) {
maxHeight = max(maxHeight, child.height);
if(child.height == MinimumSize || child.height == MaximumSize) {
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
continue;
}
height = max(height, child.height);
}
return { 0, 0, margin * 2 + width, margin * 2 + height };
}
Geometry HorizontalLayout::minimumLayoutGeometry() {
unsigned width = 0, height = 0;
bool maximumWidth = false;
bool maximumHeight = false;
foreach(child, children) {
if(child.width == MaximumSize) {
maximumWidth = true;
break;
}
if(child.width == MinimumSize) {
if(child.layout) width += child.layout->minimumGeometry().width;
if(child.widget) width += child.widget->minimumGeometry().width;
continue;
}
width += child.width;
}
foreach(child, children) {
if(child.height == MaximumSize) {
maximumHeight = true;
break;
}
if(child.height == MinimumSize) {
if(child.layout) height = max(height, child.layout->minimumGeometry().height);
if(child.widget) height = max(height, child.widget->minimumGeometry().height);
continue;
}
height = max(height, child.height);
}
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
}
void HorizontalLayout::setGeometry(const Geometry &containerGeometry) {
auto children = this->children;
foreach(child, children) {
if(child.layout) {
child.layout->setGeometry(geometry);
geometry.x += child.spacing;
geometry.width -= child.spacing;
geometry.y = baseGeometry.y;
geometry.height = baseGeometry.height;
child.width = child.layout->minimumLayoutGeometry().width;
child.height = child.layout->minimumLayoutGeometry().height;
}
if(child.widget) {
child.widget->setGeometry({ geometry.x, geometry.y, child.width, child.height });
geometry.x += child.width + child.spacing;
geometry.width -= child.width + child.spacing;
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
}
}
geometry.y += maxHeight;
geometry.height -= maxHeight;
Geometry geometry = containerGeometry;
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
unsigned minimumWidth = 0, maximumWidthCounter = 0;
foreach(child, children) {
if(child.width == MaximumSize) maximumWidthCounter++;
if(child.width != MaximumSize) minimumWidth += child.width;
minimumWidth += child.spacing;
}
foreach(child, children) {
if(child.width == MaximumSize) child.width = (geometry.width - minimumWidth) / maximumWidthCounter;
if(child.height == MaximumSize) child.height = geometry.height;
}
unsigned maximumHeight = 0;
foreach(child, children) maximumHeight = max(maximumHeight, child.height);
foreach(child, children) {
unsigned pivot = (maximumHeight - child.height) / 2;
Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height };
if(child.layout) child.layout->setGeometry(childGeometry);
if(child.widget) child.widget->setGeometry(childGeometry);
geometry.x += child.width + child.spacing;
geometry.width -= child.width + child.spacing;
}
}
void HorizontalLayout::setMargin(unsigned margin_) {
margin = margin_;
void HorizontalLayout::setMargin(unsigned margin) {
this->margin = margin;
}
unsigned HorizontalLayout::minimumWidth() {
unsigned width = margin * 2;
foreach(child, children) width += child.width + child.spacing;
return width;
void HorizontalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void HorizontalLayout::setVisible(bool visible) {
@@ -83,6 +136,4 @@ void HorizontalLayout::setVisible(bool visible) {
HorizontalLayout::HorizontalLayout() {
margin = 0;
width = 0;
height = 0;
}

View File

@@ -1,10 +1,11 @@
struct VerticalLayout;
struct HorizontalLayout : public Layout {
void append(VerticalLayout &layout, unsigned width, unsigned height, unsigned spacing = 0);
void append(VerticalLayout &layout, unsigned spacing = 0);
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
unsigned minimumWidth();
void setGeometry(Geometry &geometry);
Geometry minimumLayoutGeometry();
Geometry minimumGeometry();
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setParent(Window &parent);
void setVisible(bool visible);
@@ -12,8 +13,6 @@ struct HorizontalLayout : public Layout {
//private:
unsigned margin;
unsigned width;
unsigned height;
struct Children {
VerticalLayout *layout;
Widget *widget;

View File

@@ -1,77 +1,130 @@
void VerticalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void VerticalLayout::append(HorizontalLayout &layout, unsigned width, unsigned height, unsigned spacing) {
layout.width = width;
layout.height = height;
children.append({ &layout, 0, width, height, spacing });
void VerticalLayout::append(HorizontalLayout &layout, unsigned spacing) {
children.append({ &layout, 0, MinimumSize, MinimumSize, spacing });
}
void VerticalLayout::append(Widget &widget, unsigned width, unsigned height, unsigned spacing) {
children.append({ 0, &widget, width, height, spacing });
}
void VerticalLayout::setGeometry(Geometry &geometry) {
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
Geometry VerticalLayout::minimumGeometry() {
unsigned width = 0, height = 0;
unsigned geometryWidth = width ? width : geometry.width;
unsigned geometryHeight = height ? height : geometry.height;
Geometry baseGeometry = geometry;
linear_vector<VerticalLayout::Children> children = this->children;
unsigned minimumHeight = 0;
foreach(child, children) minimumHeight += child.height + child.spacing;
unsigned autosizeWidgets = 0;
foreach(child, children) {
if(child.height == 0) autosizeWidgets++;
}
foreach(child, children) {
if(child.width == 0) child.width = geometryWidth;
if(child.height == 0) child.height = (geometryHeight - minimumHeight) / autosizeWidgets;
if(child.width == MinimumSize || child.width == MaximumSize) {
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
continue;
}
width = max(width, child.width);
}
unsigned maxWidth = 0;
foreach(child, children) {
maxWidth = max(maxWidth, child.width);
height += child.spacing;
if(child.height == MinimumSize || child.height == MaximumSize) {
if(child.layout) height += child.layout->minimumGeometry().height;
if(child.widget) height += child.widget->minimumGeometry().height;
continue;
}
height += child.height;
}
return { 0, 0, margin * 2 + width, margin * 2 + height };
}
Geometry VerticalLayout::minimumLayoutGeometry() {
unsigned width = 0, height = 0;
bool maximumWidth = false;
bool maximumHeight = false;
foreach(child, children) {
if(child.width == MaximumSize) {
maximumWidth = true;
break;
}
if(child.width == MinimumSize) {
if(child.layout) width = max(width, child.layout->minimumGeometry().width);
if(child.widget) width = max(width, child.widget->minimumGeometry().width);
continue;
}
width = max(width, child.width);
}
foreach(child, children) {
if(child.height == MaximumSize) {
maximumHeight = true;
break;
}
if(child.height == MinimumSize) {
if(child.layout) height += child.layout->minimumGeometry().height;
if(child.widget) height += child.widget->minimumGeometry().height;
continue;
}
height += child.height;
}
return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height };
}
void VerticalLayout::setGeometry(const Geometry &containerGeometry) {
auto children = this->children;
foreach(child, children) {
if(child.layout) {
child.layout->setGeometry(geometry);
geometry.x = baseGeometry.x;
geometry.width = baseGeometry.width;
geometry.y += child.spacing;
geometry.height -= child.spacing;
child.width = child.layout->minimumLayoutGeometry().width;
child.height = child.layout->minimumLayoutGeometry().height;
}
if(child.widget) {
child.widget->setGeometry({ geometry.x, geometry.y, child.width, child.height });
geometry.y += child.height + child.spacing;
geometry.height -= child.height + child.spacing;
if(child.width == MinimumSize) child.width = child.widget->minimumGeometry().width;
if(child.height == MinimumSize) child.height = child.widget->minimumGeometry().height;
}
}
geometry.x += maxWidth;
geometry.width -= maxWidth;
Geometry geometry = containerGeometry;
geometry.x += margin;
geometry.y += margin;
geometry.width -= margin * 2;
geometry.height -= margin * 2;
unsigned minimumHeight = 0, maximumHeightCounter = 0;
foreach(child, children) {
if(child.height == MaximumSize) maximumHeightCounter++;
if(child.height != MaximumSize) minimumHeight += child.height;
minimumHeight += child.spacing;
}
foreach(child, children) {
if(child.width == MaximumSize) child.width = geometry.width;
if(child.height == MaximumSize) child.height = (geometry.height - minimumHeight) / maximumHeightCounter;
}
unsigned maximumWidth = 0;
foreach(child, children) maximumWidth = max(maximumWidth, child.width);
foreach(child, children) {
unsigned pivot = 0; //(maximumWidth - child.width) / 2;
Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height };
if(child.layout) child.layout->setGeometry(childGeometry);
if(child.widget) child.widget->setGeometry(childGeometry);
geometry.y += child.height + child.spacing;
geometry.height -= child.height + child.spacing;
}
}
void VerticalLayout::setMargin(unsigned margin_) {
margin = margin_;
void VerticalLayout::setMargin(unsigned margin) {
this->margin = margin;
}
unsigned VerticalLayout::minimumHeight() {
unsigned height = margin * 2;
foreach(child, children) height += child.height + child.spacing;
return height;
void VerticalLayout::setParent(Window &parent) {
foreach(child, children) {
if(child.layout) child.layout->setParent(parent);
if(child.widget) parent.append(*child.widget);
}
}
void VerticalLayout::setVisible(bool visible) {
@@ -83,6 +136,4 @@ void VerticalLayout::setVisible(bool visible) {
VerticalLayout::VerticalLayout() {
margin = 0;
width = 0;
height = 0;
}

View File

@@ -1,10 +1,11 @@
struct HorizontalLayout;
struct VerticalLayout : public Layout {
void append(HorizontalLayout &layout, unsigned width, unsigned height, unsigned spacing = 0);
void append(HorizontalLayout &layout, unsigned spacing = 0);
void append(Widget &widget, unsigned width, unsigned height, unsigned spacing = 0);
unsigned minimumHeight();
void setGeometry(Geometry &geometry);
Geometry minimumGeometry();
Geometry minimumLayoutGeometry();
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setParent(Window &parent);
void setVisible(bool visible);
@@ -12,8 +13,6 @@ struct VerticalLayout : public Layout {
//private:
unsigned margin;
unsigned width;
unsigned height;
struct Children {
HorizontalLayout *layout;
Widget *widget;

View File

@@ -13,9 +13,19 @@ struct Font::State {
}
};
struct Timer::State {
bool enabled;
unsigned milliseconds;
State() {
enabled = false;
milliseconds = 0;
}
};
struct Window::State {
bool backgroundColor;
unsigned backgroundColorRed, backgroundColorGreen, backgroundColorBlue;
bool backgroundColorOverride;
Color backgroundColor;
bool fullScreen;
Geometry geometry;
reference_array<Layout&> layout;
@@ -32,10 +42,8 @@ struct Window::State {
Font *widgetFont;
State() {
backgroundColor = false;
backgroundColorRed = 0;
backgroundColorGreen = 0;
backgroundColorBlue = 0;
backgroundColorOverride = false;
backgroundColor = { 0, 0, 0, 255 };
fullScreen = false;
geometry = { 128, 128, 256, 256 };
menuFont = 0;
@@ -142,6 +150,16 @@ struct HexEdit::State {
}
};
struct HorizontalScrollBar::State {
unsigned length;
unsigned position;
State() {
length = 101;
position = 0;
}
};
struct HorizontalSlider::State {
unsigned length;
unsigned position;
@@ -213,6 +231,16 @@ struct TextEdit::State {
}
};
struct VerticalScrollBar::State {
unsigned length;
unsigned position;
State() {
length = 101;
position = 0;
}
};
struct VerticalSlider::State {
unsigned length;
unsigned position;

View File

@@ -1,3 +1,11 @@
Geometry pFont::geometry(const string &text) {
pango_layout_set_font_description(gtkLayout, gtkFont);
pango_layout_set_text(gtkLayout, text, -1);
int width = 0, height = 0;
pango_layout_get_pixel_size(gtkLayout, &width, &height);
return { 0, 0, width, height };
}
void pFont::setBold(bool bold) {
pango_font_description_set_weight(gtkFont, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
}
@@ -19,4 +27,8 @@ void pFont::setUnderline(bool underline) {
void pFont::constructor() {
gtkFont = pango_font_description_new();
PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default());
gtkLayout = pango_layout_new(context);
font.setFamily("Sans");
font.setSize(8);
}

View File

@@ -2,6 +2,7 @@
#include "settings.cpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -14,9 +15,11 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroll-bar.cpp"
#include "widget/horizontal-slider.cpp"
#include "widget/label.cpp"
#include "widget/line-edit.cpp"
@@ -24,14 +27,36 @@
#include "widget/progress-bar.cpp"
#include "widget/radio-box.cpp"
#include "widget/text-edit.cpp"
#include "widget/vertical-scroll-bar.cpp"
#include "widget/vertical-slider.cpp"
#include "widget/viewport.cpp"
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
//TODO: is there a GTK+ function for this?
//should return desktopGeometry() sans panels, toolbars, docks, etc.
Geometry geometry = desktopGeometry();
return { geometry.x + 64, geometry.y + 64, geometry.width - 128, geometry.height - 128 };
Display *display = XOpenDisplay(0);
int screen = DefaultScreen(display);
static Atom atom = X11None;
if(atom == X11None) atom = XInternAtom(display, "_NET_WORKAREA", True);
int format;
unsigned char *data = 0;
unsigned long items, after;
Atom returnAtom;
int result = XGetWindowProperty(
display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data
);
XCloseDisplay(display);
if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) {
unsigned long *workarea = (unsigned long*)data;
return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] };
}
return desktopGeometry();
}
Geometry pOS::desktopGeometry() {
@@ -146,7 +171,7 @@ void pOS::initialize() {
" GtkComboBox::appears-as-list = 1\n"
" GtkTreeView::vertical-separator = 0\n"
"}\n"
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
//"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
);
}

View File

@@ -26,6 +26,8 @@ struct pObject {
};
struct pOS : public pObject {
static Font defaultFont;
static Geometry availableGeometry();
static Geometry desktopGeometry();
static string fileLoad(Window &parent, const string &path, const lstring &filter);
@@ -42,7 +44,9 @@ struct pOS : public pObject {
struct pFont : public pObject {
Font &font;
PangoFontDescription *gtkFont;
PangoLayout *gtkLayout;
Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@@ -53,6 +57,16 @@ struct pFont : public pObject {
void constructor();
};
struct pTimer : public pObject {
Timer &timer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
@@ -68,14 +82,16 @@ struct pWindow : public pObject {
GtkWidget *statusContainer;
GtkWidget *menu;
GtkWidget *status;
GdkEventConfigure lastConfigure;
void append(Layout &layout);
void append(Menu &menu);
void append(Widget &widget);
Color backgroundColor();
bool focused();
Geometry frameMargin();
Geometry geometry();
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setBackgroundColor(const Color &color);
void setFocused();
void setFullScreen(bool fullScreen);
void setGeometry(const Geometry &geometry);
@@ -164,10 +180,12 @@ struct pWidget : public pObject {
pWindow *parentWindow;
bool enabled();
Font& font();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
virtual void setFocused();
virtual void setFont(Font &font);
void setGeometry(const Geometry &geometry);
virtual void setGeometry(const Geometry &geometry);
void setVisible(bool visible);
pWidget(Widget &widget) : widget(widget) {}
@@ -177,16 +195,30 @@ struct pWidget : public pObject {
struct pButton : public pWidget {
Button &button;
Geometry minimumGeometry();
void setText(const string &text);
pButton(Button &button) : pWidget(button), button(button) {}
void constructor();
};
struct pCanvas : public pWidget {
Canvas &canvas;
cairo_surface_t *surface;
uint32_t* buffer();
void setGeometry(const Geometry &geometry);
void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
};
struct pCheckBox : public pWidget {
CheckBox &checkBox;
bool checked();
Geometry minimumGeometry();
void setChecked(bool checked);
void setText(const string &text);
@@ -199,6 +231,7 @@ struct pComboBox : public pWidget {
unsigned itemCounter;
void append(const string &text);
Geometry minimumGeometry();
void reset();
unsigned selection();
void setSelection(unsigned row);
@@ -231,9 +264,22 @@ struct pHexEdit : public pWidget {
void updateScroll();
};
struct pHorizontalScrollBar : public pWidget {
HorizontalScrollBar &horizontalScrollBar;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
void constructor();
};
struct pHorizontalSlider : public pWidget {
HorizontalSlider &horizontalSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
@@ -245,6 +291,7 @@ struct pHorizontalSlider : public pWidget {
struct pLabel : public pWidget {
Label &label;
Geometry minimumGeometry();
void setText(const string &text);
pLabel(Label &label) : pWidget(label), label(label) {}
@@ -254,6 +301,7 @@ struct pLabel : public pWidget {
struct pLineEdit : public pWidget {
LineEdit &lineEdit;
Geometry minimumGeometry();
void setEditable(bool editable);
void setText(const string &text);
string text();
@@ -297,6 +345,7 @@ struct pListView : public pWidget {
struct pProgressBar : public pWidget {
ProgressBar &progressBar;
Geometry minimumGeometry();
void setPosition(unsigned position);
pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {}
@@ -307,6 +356,7 @@ struct pRadioBox : public pWidget {
RadioBox &radioBox;
bool checked();
Geometry minimumGeometry();
void setChecked();
void setGroup(const reference_array<RadioBox&> &group);
void setText(const string &text);
@@ -330,9 +380,22 @@ struct pTextEdit : public pWidget {
void constructor();
};
struct pVerticalScrollBar : public pWidget {
VerticalScrollBar &verticalScrollBar;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
void constructor();
};
struct pVerticalSlider : public pWidget {
VerticalSlider &verticalSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);

24
bsnes/phoenix/gtk/timer.cpp Executable file
View File

@@ -0,0 +1,24 @@
static guint Timer_trigger(pTimer *self) {
//timer may have been disabled prior to triggering, so check state
if(self->timer.state.enabled) {
if(self->timer.onTimeout) self->timer.onTimeout();
}
//callback may have disabled timer, so check state again
if(self->timer.state.enabled) {
g_timeout_add(self->timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)self);
}
//kill this timer instance (it is spawned above if needed again)
return false;
}
void pTimer::setEnabled(bool enabled) {
if(enabled) {
g_timeout_add(timer.state.milliseconds, (GSourceFunc)Timer_trigger, (gpointer)this);
}
}
void pTimer::setInterval(unsigned milliseconds) {
}
void pTimer::constructor() {
}

View File

@@ -2,6 +2,12 @@ static void Button_tick(Button *self) {
if(self->onTick) self->onTick();
}
Geometry pButton::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(button.state.text);
return { 0, 0, geometry.width + 24, geometry.height + 12 };
}
void pButton::setText(const string &text) {
gtk_button_set_label(GTK_BUTTON(gtkWidget), text);
}

View File

@@ -0,0 +1,38 @@
static gboolean Canvas_expose(GtkWidget *widget, GdkEvent *event, pCanvas *self) {
cairo_t *context = gdk_cairo_create(gtk_widget_get_window(widget));
cairo_set_source_surface(context, self->surface, 0, 0);
cairo_paint(context);
cairo_destroy(context);
return true;
}
uint32_t* pCanvas::buffer() {
return (uint32_t*)cairo_image_surface_get_data(surface);
}
void pCanvas::setGeometry(const Geometry &geometry) {
if(geometry.width == cairo_image_surface_get_width(surface)
&& geometry.height == cairo_image_surface_get_height(surface)) return;
cairo_surface_destroy(surface);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, geometry.width, geometry.height);
pWidget::setGeometry(geometry);
update();
}
void pCanvas::update() {
if(gtk_widget_get_realized(gtkWidget) == false) return;
gdk_window_invalidate_rect(gtk_widget_get_window(gtkWidget), 0, true);
}
void pCanvas::constructor() {
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 256, 256);
gtkWidget = gtk_drawing_area_new();
GdkColor color;
color.pixel = color.red = color.green = color.blue = 0;
gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color);
gtk_widget_set_double_buffered(gtkWidget, false);
gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK);
g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
}

View File

@@ -6,6 +6,12 @@ bool pCheckBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget));
}
Geometry pCheckBox::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(checkBox.state.text);
return { 0, 0, geometry.width + 28, geometry.height + 4 };
}
void pCheckBox::setChecked(bool checked) {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), checked);

View File

@@ -7,11 +7,18 @@ void pComboBox::append(const string &text) {
if(itemCounter++ == 0) setSelection(0);
}
Geometry pComboBox::minimumGeometry() {
Font &font = pWidget::font();
unsigned maximumWidth = 0;
foreach(item, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(item).width);
Geometry geometry = font.geometry(" ");
return { 0, 0, maximumWidth + 44, geometry.height + 12 };
}
void pComboBox::reset() {
locked = true;
for(signed n = itemCounter - 1; n >= 0; n--) {
gtk_combo_box_remove_text(GTK_COMBO_BOX(gtkWidget), n);
}
gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gtkWidget))));
itemCounter = 0;
locked = false;
}

View File

@@ -112,17 +112,17 @@ bool pHexEdit::keyPress(unsigned scancode) {
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
if(scancode == GDK_Home) {
if(scancode == GDK_KEY_Home) {
setCursorPosition(cursorY * lineWidth + 10);
return true;
}
if(scancode == GDK_End) {
if(scancode == GDK_KEY_End) {
setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1));
return true;
}
if(scancode == GDK_Up) {
if(scancode == GDK_KEY_Up) {
if(cursorY != 0) return false;
signed newOffset = hexEdit.state.offset - hexEdit.state.columns;
@@ -133,7 +133,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_Down) {
if(scancode == GDK_KEY_Down) {
if(cursorY != hexEdit.state.rows - 1) return false;
signed newOffset = hexEdit.state.offset + hexEdit.state.columns;
@@ -144,7 +144,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_Page_Up) {
if(scancode == GDK_KEY_Page_Up) {
signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows;
if(newOffset >= 0) {
hexEdit.setOffset(newOffset);
@@ -155,7 +155,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_Page_Down) {
if(scancode == GDK_KEY_Page_Down) {
signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows;
for(unsigned n = 0; n < hexEdit.state.rows; n++) {
if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) {

View File

@@ -0,0 +1,29 @@
static void HorizontalScrollBar_change(HorizontalScrollBar *self) {
if(self->state.position == self->position()) return;
self->state.position = self->position();
if(self->onChange) self->onChange();
}
Geometry pHorizontalScrollBar::minimumGeometry() {
return { 0, 0, 0, 20 };
}
unsigned pHorizontalScrollBar::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}
void pHorizontalScrollBar::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}
void pHorizontalScrollBar::setPosition(unsigned position) {
gtk_range_set_value(GTK_RANGE(gtkWidget), position);
}
void pHorizontalScrollBar::constructor() {
gtkWidget = gtk_hscrollbar_new(0);
setLength(101);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)&horizontalScrollBar);
}

View File

@@ -4,6 +4,10 @@ static void HorizontalSlider_change(HorizontalSlider *self) {
if(self->onChange) self->onChange();
}
Geometry pHorizontalSlider::minimumGeometry() {
return { 0, 0, 0, 20 };
}
unsigned pHorizontalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}
@@ -11,6 +15,7 @@ unsigned pHorizontalSlider::position() {
void pHorizontalSlider::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}
void pHorizontalSlider::setPosition(unsigned position) {
@@ -20,5 +25,6 @@ void pHorizontalSlider::setPosition(unsigned position) {
void pHorizontalSlider::constructor() {
gtkWidget = gtk_hscale_new_with_range(0, 100, 1);
gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false);
setLength(101);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider);
}

View File

@@ -1,3 +1,9 @@
Geometry pLabel::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(label.state.text);
return { 0, 0, geometry.width, geometry.height };
}
void pLabel::setText(const string &text) {
gtk_label_set_text(GTK_LABEL(gtkWidget), text);
}

View File

@@ -6,8 +6,14 @@ static void LineEdit_change(LineEdit *self) {
if(self->p.locked == false && self->onChange) self->onChange();
}
Geometry pLineEdit::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(lineEdit.state.text);
return { 0, 0, geometry.width + 10, geometry.height + 10 };
}
void pLineEdit::setEditable(bool editable) {
gtk_entry_set_editable(GTK_ENTRY(gtkWidget), editable);
gtk_editable_set_editable(GTK_EDITABLE(gtkWidget), editable);
}
void pLineEdit::setText(const string &text) {

View File

@@ -1,3 +1,7 @@
Geometry pProgressBar::minimumGeometry() {
return { 0, 0, 0, 25 };
}
void pProgressBar::setPosition(unsigned position) {
position = position <= 100 ? position : 0;
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkWidget), (double)position / 100.0);

View File

@@ -6,6 +6,12 @@ bool pRadioBox::checked() {
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkWidget));
}
Geometry pRadioBox::minimumGeometry() {
Font &font = pWidget::font();
Geometry geometry = font.geometry(radioBox.state.text);
return { 0, 0, geometry.width + 28, geometry.height + 4 };
}
void pRadioBox::setChecked() {
locked = true;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), true);

View File

@@ -0,0 +1,29 @@
static void VerticalScrollBar_change(VerticalScrollBar *self) {
if(self->state.position == self->position()) return;
self->state.position = self->position();
if(self->onChange) self->onChange();
}
Geometry pVerticalScrollBar::minimumGeometry() {
return { 0, 0, 20, 0 };
}
unsigned pVerticalScrollBar::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}
void pVerticalScrollBar::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}
void pVerticalScrollBar::setPosition(unsigned position) {
gtk_range_set_value(GTK_RANGE(gtkWidget), position);
}
void pVerticalScrollBar::constructor() {
gtkWidget = gtk_vscrollbar_new(0);
setLength(101);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)&verticalScrollBar);
}

View File

@@ -4,6 +4,10 @@ static void VerticalSlider_change(VerticalSlider *self) {
if(self->onChange) self->onChange();
}
Geometry pVerticalSlider::minimumGeometry() {
return { 0, 0, 20, 0 };
}
unsigned pVerticalSlider::position() {
return (unsigned)gtk_range_get_value(GTK_RANGE(gtkWidget));
}
@@ -11,6 +15,7 @@ unsigned pVerticalSlider::position() {
void pVerticalSlider::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}
void pVerticalSlider::setPosition(unsigned position) {
@@ -20,5 +25,6 @@ void pVerticalSlider::setPosition(unsigned position) {
void pVerticalSlider::constructor() {
gtkWidget = gtk_vscale_new_with_range(0, 100, 1);
gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false);
setLength(101);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider);
}

View File

@@ -1,5 +1,5 @@
uintptr_t pViewport::handle() {
return GDK_WINDOW_XID(gtkWidget->window);
return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget));
}
void pViewport::constructor() {

View File

@@ -6,6 +6,15 @@ static void Widget_setFont(GtkWidget *widget, gpointer font) {
}
}
Font& pWidget::font() {
if(widget.state.font) return *widget.state.font;
return pOS::defaultFont;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
}
bool pWidget::enabled() {
return gtk_widget_get_sensitive(gtkWidget);
}

View File

@@ -1,70 +1,79 @@
static void Action_setFont(GtkWidget *widget, gpointer font);
static void Widget_setFont(GtkWidget *widget, gpointer font);
static gint Window_close(Window *window) {
static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) {
if(window->onClose) window->onClose();
window->setVisible(false);
return true;
}
static gboolean Window_configure(Window *window) {
static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) {
cairo_t *context = gdk_cairo_create(widget->window);
Color color = window->backgroundColor();
double red = (double)color.red / 255.0;
double green = (double)color.green / 255.0;
double blue = (double)color.blue / 255.0;
double alpha = (double)color.alpha / 255.0;
if(gdk_screen_is_composited(gdk_screen_get_default())) {
cairo_set_source_rgba(context, red, green, blue, alpha);
} else {
cairo_set_source_rgb(context, red, green, blue);
}
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
cairo_paint(context);
cairo_destroy(context);
return false;
}
static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *window) {
if(gtk_widget_get_realized(window->p.widget) == false) return false;
GdkWindow *gdkWindow = gtk_widget_get_window(widget);
//update geometry settings
Display *display = XOpenDisplay(0);
XWindowAttributes attributes, parentAttributes;
XGetWindowAttributes(display, GDK_WINDOW_XID(window->p.widget->window), &attributes);
X11Window rootWindow, parentWindow, *childWindow = 0;
unsigned int childCount;
XQueryTree(display, GDK_WINDOW_XID(window->p.widget->window), &rootWindow, &parentWindow, &childWindow, &childCount);
XGetWindowAttributes(display, parentWindow, &parentAttributes);
if(childWindow) XFree(childWindow);
XCloseDisplay(display);
GdkRectangle border, client;
gdk_window_get_frame_extents(gdkWindow, &border);
gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0);
gdk_window_get_origin(gdkWindow, &client.x, &client.y);
settings.frameGeometryX = attributes.x;
settings.frameGeometryY = attributes.y;
settings.frameGeometryWidth = parentAttributes.width - attributes.width;
settings.frameGeometryHeight = parentAttributes.height - attributes.height;
GtkAllocation menuAllocation, statusAllocation;
gtk_widget_get_allocation(window->p.menu, &menuAllocation);
gtk_widget_get_allocation(window->p.status, &statusAllocation);
if(menuAllocation.height > 1) settings.menuGeometryHeight = menuAllocation.height;
if(statusAllocation.height > 1) settings.statusGeometryHeight = statusAllocation.height;
//calculate current window position
signed eventX = parentAttributes.x + attributes.x;
signed eventY = parentAttributes.y + attributes.y + window->p.menuHeight();
unsigned eventWidth = attributes.width;
unsigned eventHeight = attributes.height - window->p.menuHeight() - window->p.statusHeight();
settings.frameGeometryX = client.x - border.x;
settings.frameGeometryY = client.y - border.y;
settings.frameGeometryWidth = border.width - client.width;
settings.frameGeometryHeight = border.height - client.height;
//move
if(window->p.locked == false && window->state.fullScreen == false) {
if(window->state.geometry.x != eventX || window->state.geometry.y != eventY) {
window->state.geometry.x = eventX;
window->state.geometry.y = eventY;
if(event->configure.x != window->p.lastConfigure.x
|| event->configure.y != window->p.lastConfigure.y
) {
if(window->state.fullScreen == false) {
window->state.geometry.x = client.x;
window->state.geometry.y = client.y + window->p.menuHeight();
}
if(window->p.locked == false && window->onMove) window->onMove();
}
if(window->onMove) window->onMove();
//size
if(window->p.locked == false && window->state.fullScreen == false) {
if(window->state.geometry.width != eventWidth || window->state.geometry.height != eventHeight) {
window->state.geometry.width = eventWidth;
window->state.geometry.height = eventHeight;
if(event->configure.width != window->p.lastConfigure.width
|| event->configure.height != window->p.lastConfigure.height
) {
if(window->state.fullScreen == false) {
window->state.geometry.width = client.width;
window->state.geometry.height = client.height - window->p.menuHeight() - window->p.statusHeight();
}
foreach(layout, window->state.layout) {
Geometry geometry = window->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
if(window->p.locked == false && window->onSize) window->onSize();
}
foreach(layout, window->state.layout) {
Geometry geometry = window->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
if(window->onSize) window->onSize();
window->p.lastConfigure = event->configure;
return false;
}
@@ -77,7 +86,7 @@ void pWindow::append(Layout &layout) {
void pWindow::append(Menu &subMenu) {
if(window.state.menuFont) subMenu.p.setFont(*window.state.menuFont);
gtk_menu_bar_append(menu, subMenu.p.widget);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), subMenu.p.widget);
gtk_widget_show(subMenu.p.widget);
}
@@ -90,6 +99,12 @@ void pWindow::append(Widget &widget) {
widget.setVisible();
}
Color pWindow::backgroundColor() {
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
GdkColor color = widget->style->bg[GTK_STATE_NORMAL];
return { (uint8_t)(color.red >> 8), (uint8_t)(color.green >> 8), (uint8_t)(color.blue >> 8), 255 };
}
Geometry pWindow::frameMargin() {
if(window.state.fullScreen) return { 0, menuHeight(), 0, menuHeight() + statusHeight() };
return {
@@ -111,13 +126,13 @@ Geometry pWindow::geometry() {
return window.state.geometry;
}
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
GdkColor color;
color.pixel = (red << 16) | (green << 8) | (blue << 0);
color.red = (red << 8) | (red << 0);
color.green = (green << 8) | (green << 0);
color.blue = (blue << 8) | (blue << 0);
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color);
void pWindow::setBackgroundColor(const Color &color) {
GdkColor gdkColor;
gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0);
gdkColor.red = (color.red << 8) | (color.red << 0);
gdkColor.green = (color.green << 8) | (color.green << 0);
gdkColor.blue = (color.blue << 8) | (color.blue << 0);
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor);
}
void pWindow::setFocused() {
@@ -129,14 +144,12 @@ void pWindow::setFullScreen(bool fullScreen) {
gtk_window_unfullscreen(GTK_WINDOW(widget));
gtk_window_set_resizable(GTK_WINDOW(widget), window.state.resizable);
gtk_window_set_decorated(GTK_WINDOW(widget), true);
locked = true;
for(unsigned n = 0; n < 4; n++) {
setGeometry(window.state.geometry);
gtk_widget_set_size_request(widget, -1, -1);
OS::processEvents();
usleep(2000);
}
locked = false;
} else {
gtk_window_fullscreen(GTK_WINDOW(widget));
gtk_window_set_decorated(GTK_WINDOW(widget), false);
@@ -198,7 +211,15 @@ void pWindow::setWidgetFont(Font &font) {
}
void pWindow::constructor() {
memset(&lastConfigure, 0, sizeof(GdkEventConfigure));
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
if(gdk_screen_is_composited(gdk_screen_get_default())) {
gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(gdk_screen_get_default()));
} else {
gtk_widget_set_colormap(widget, gdk_screen_get_rgb_colormap(gdk_screen_get_default()));
}
gtk_window_set_resizable(GTK_WINDOW(widget), true);
gtk_widget_set_app_paintable(widget, true);
gtk_widget_add_events(widget, GDK_CONFIGURE);
@@ -224,8 +245,9 @@ void pWindow::constructor() {
setTitle("");
setGeometry(window.state.geometry);
g_signal_connect_swapped(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window);
g_signal_connect_swapped(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
}
unsigned pWindow::menuHeight() {

View File

@@ -1,3 +1,6 @@
#ifndef PHOENIX_CPP
#define PHOENIX_CPP
#if defined(PHOENIX_WINDOWS)
#define UNICODE
#define WINVER 0x0501
@@ -14,13 +17,16 @@
#include <QApplication>
#include <QtGui>
#elif defined(PHOENIX_GTK)
#define None X11None
#define None
#define Window X11Window
#define X11None 0L
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#include <X11/Xatom.h>
#undef None
#undef Window
@@ -35,3 +41,5 @@ using namespace nall;
namespace phoenix {
#include "core/core.cpp"
}
#endif

View File

@@ -1,3 +1,6 @@
#ifndef PHOENIX_HPP
#define PHOENIX_HPP
#include <nall/array.hpp>
#include <nall/config.hpp>
#include <nall/foreach.hpp>
@@ -11,3 +14,5 @@
namespace phoenix {
#include "core/core.hpp"
}
#endif

View File

@@ -1,3 +1,17 @@
Geometry pFont::geometry(const string &text) {
QFontMetrics metrics(*qtFont);
lstring lines;
lines.split("\n", text);
unsigned maxWidth = 0;
foreach(line, lines) {
maxWidth = max(maxWidth, metrics.width(line));
}
return { 0, 0, maxWidth, metrics.height() * lines.size() };
}
void pFont::setBold(bool bold) { update(); }
void pFont::setFamily(const string &family) { update(); }
void pFont::setItalic(bool italic) { update(); }
@@ -6,6 +20,8 @@ void pFont::setUnderline(bool underline) { update(); }
void pFont::constructor() {
qtFont = new QFont;
font.setFamily("Sans");
font.setSize(8);
}
void pFont::update() {

View File

@@ -3,6 +3,7 @@
#include "settings.cpp"
#include "font.cpp"
#include "timer.cpp"
#include "message-window.cpp"
#include "window.cpp"
@@ -15,9 +16,11 @@
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-box.cpp"
#include "widget/combo-box.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroll-bar.cpp"
#include "widget/horizontal-slider.cpp"
#include "widget/label.cpp"
#include "widget/line-edit.cpp"
@@ -25,10 +28,12 @@
#include "widget/progress-bar.cpp"
#include "widget/radio-box.cpp"
#include "widget/text-edit.cpp"
#include "widget/vertical-scroll-bar.cpp"
#include "widget/vertical-slider.cpp"
#include "widget/viewport.cpp"
QApplication *pOS::application = 0;
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
QRect rect = QApplication::desktop()->availableGeometry();

View File

@@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'qt.moc.hpp'
**
** Created: Tue Mar 15 13:54:13 2011
** Created: Mon Aug 8 04:51:19 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
**
** WARNING! All changes made in this file will be lost!
@@ -16,6 +16,67 @@
#endif
QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_pTimer[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
8, 7, 7, 7, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_pTimer[] = {
"pTimer\0\0onTimeout()\0"
};
const QMetaObject pTimer::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pTimer,
qt_meta_data_pTimer, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pTimer::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pTimer::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pTimer::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pTimer))
return static_cast<void*>(const_cast< pTimer*>(this));
if (!strcmp(_clname, "pObject"))
return static_cast< pObject*>(const_cast< pTimer*>(this));
return QObject::qt_metacast(_clname);
}
int pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onTimeout(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_pWindow[] = {
// content:
@@ -311,6 +372,57 @@ int pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
return _id;
}
static const uint qt_meta_data_pCanvas[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_pCanvas[] = {
"pCanvas\0"
};
const QMetaObject pCanvas::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pCanvas,
qt_meta_data_pCanvas, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pCanvas::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pCanvas::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pCanvas::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pCanvas))
return static_cast<void*>(const_cast< pCanvas*>(this));
if (!strcmp(_clname, "pWidget"))
return static_cast< pWidget*>(const_cast< pCanvas*>(this));
return QObject::qt_metacast(_clname);
}
int pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_pCheckBox[] = {
// content:
@@ -494,6 +606,67 @@ int pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
return _id;
}
static const uint qt_meta_data_pHorizontalScrollBar[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
22, 21, 21, 21, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_pHorizontalScrollBar[] = {
"pHorizontalScrollBar\0\0onChange()\0"
};
const QMetaObject pHorizontalScrollBar::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pHorizontalScrollBar,
qt_meta_data_pHorizontalScrollBar, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pHorizontalScrollBar::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pHorizontalScrollBar::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pHorizontalScrollBar::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pHorizontalScrollBar))
return static_cast<void*>(const_cast< pHorizontalScrollBar*>(this));
if (!strcmp(_clname, "pWidget"))
return static_cast< pWidget*>(const_cast< pHorizontalScrollBar*>(this));
return QObject::qt_metacast(_clname);
}
int pHorizontalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_pHorizontalSlider[] = {
// content:
@@ -633,15 +806,16 @@ static const uint qt_meta_data_pListView[] = {
// slots: signature, parameters, type, tag, flags
11, 10, 10, 10, 0x0a,
24, 10, 10, 10, 0x0a,
40, 35, 10, 10, 0x0a,
29, 24, 10, 10, 0x0a,
56, 24, 10, 10, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_pListView[] = {
"pListView\0\0onActivate()\0onChange()\0"
"item\0onTick(QTreeWidgetItem*)\0"
"pListView\0\0onActivate()\0item\0"
"onChange(QTreeWidgetItem*)\0"
"onTick(QTreeWidgetItem*)\0"
};
const QMetaObject pListView::staticMetaObject = {
@@ -676,7 +850,7 @@ int pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
case 1: onChange(); break;
case 1: onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
default: ;
}
@@ -806,6 +980,67 @@ int pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
return _id;
}
static const uint qt_meta_data_pVerticalScrollBar[] = {
// content:
5, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
// slots: signature, parameters, type, tag, flags
20, 19, 19, 19, 0x0a,
0 // eod
};
static const char qt_meta_stringdata_pVerticalScrollBar[] = {
"pVerticalScrollBar\0\0onChange()\0"
};
const QMetaObject pVerticalScrollBar::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_pVerticalScrollBar,
qt_meta_data_pVerticalScrollBar, 0 }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &pVerticalScrollBar::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *pVerticalScrollBar::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *pVerticalScrollBar::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_pVerticalScrollBar))
return static_cast<void*>(const_cast< pVerticalScrollBar*>(this));
if (!strcmp(_clname, "pWidget"))
return static_cast< pWidget*>(const_cast< pVerticalScrollBar*>(this));
return QObject::qt_metacast(_clname);
}
int pVerticalScrollBar::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_pVerticalSlider[] = {
// content:

View File

@@ -25,6 +25,7 @@ struct pObject {
struct pOS : public pObject {
static QApplication *application;
static Font defaultFont;
static Geometry availableGeometry();
static Geometry desktopGeometry();
@@ -43,6 +44,7 @@ struct pFont : public pObject {
Font &font;
QFont *qtFont;
Geometry geometry(const string &text);
void setBold(bool bold);
void setFamily(const string &family);
void setItalic(bool italic);
@@ -54,6 +56,23 @@ struct pFont : public pObject {
void update();
};
struct pTimer : public QObject, public pObject {
Q_OBJECT
public:
Timer &timer;
QTimer *qtTimer;
void setEnabled(bool enabled);
void setInterval(unsigned milliseconds);
pTimer(Timer &timer) : timer(timer) {}
void constructor();
public slots:
void onTimeout();
};
struct pMessageWindow : public pObject {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
@@ -82,10 +101,11 @@ public:
void append(Layout &layout);
void append(Menu &menu);
void append(Widget &widget);
Color backgroundColor();
Geometry frameMargin();
bool focused();
Geometry geometry();
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
void setBackgroundColor(const Color &color);
void setFocused();
void setFullScreen(bool fullScreen);
void setGeometry(const Geometry &geometry);
@@ -193,10 +213,12 @@ struct pWidget : public pObject {
Widget &widget;
QWidget *qtWidget;
Font& font();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();
void setFont(Font &font);
void setGeometry(const Geometry &geometry);
virtual void setGeometry(const Geometry &geometry);
void setVisible(bool visible);
pWidget(Widget &widget) : widget(widget) {}
@@ -210,6 +232,7 @@ public:
Button &button;
QPushButton *qtButton;
Geometry minimumGeometry();
void setText(const string &text);
pButton(Button &button) : pWidget(button), button(button) {}
@@ -219,6 +242,28 @@ public slots:
void onTick();
};
struct pCanvas : public QObject, public pWidget {
Q_OBJECT
public:
Canvas &canvas;
QImage *qtImage;
struct QtCanvas : public QWidget {
pCanvas &self;
void paintEvent(QPaintEvent*);
QtCanvas(pCanvas &self);
} *qtCanvas;
uint32_t* buffer();
void setGeometry(const Geometry &geometry);
void update();
pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
public slots:
};
struct pCheckBox : public QObject, public pWidget {
Q_OBJECT
@@ -227,6 +272,7 @@ public:
QCheckBox *qtCheckBox;
bool checked();
Geometry minimumGeometry();
void setChecked(bool checked);
void setText(const string &text);
@@ -245,6 +291,7 @@ public:
QComboBox *qtComboBox;
void append(const string &text);
Geometry minimumGeometry();
void reset();
unsigned selection();
void setSelection(unsigned row);
@@ -284,6 +331,25 @@ public slots:
void onScroll();
};
struct pHorizontalScrollBar : public QObject, public pWidget {
Q_OBJECT
public:
HorizontalScrollBar &horizontalScrollBar;
QScrollBar *qtScrollBar;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {}
void constructor();
public slots:
void onChange();
};
struct pHorizontalSlider : public QObject, public pWidget {
Q_OBJECT
@@ -291,6 +357,7 @@ public:
HorizontalSlider &horizontalSlider;
QSlider *qtSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
@@ -306,6 +373,7 @@ struct pLabel : public pWidget {
Label &label;
QLabel *qtLabel;
Geometry minimumGeometry();
void setText(const string &text);
pLabel(Label &label) : pWidget(label), label(label) {}
@@ -319,6 +387,7 @@ public:
LineEdit &lineEdit;
QLineEdit *qtLineEdit;
Geometry minimumGeometry();
void setEditable(bool editable);
void setText(const string &text);
string text();
@@ -357,7 +426,7 @@ public:
public slots:
void onActivate();
void onChange();
void onChange(QTreeWidgetItem *item);
void onTick(QTreeWidgetItem *item);
};
@@ -365,6 +434,7 @@ struct pProgressBar : public pWidget {
ProgressBar &progressBar;
QProgressBar *qtProgressBar;
Geometry minimumGeometry();
void setPosition(unsigned position);
pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {}
@@ -380,6 +450,7 @@ public:
QButtonGroup *qtGroup;
bool checked();
Geometry minimumGeometry();
void setChecked();
void setGroup(const reference_array<RadioBox&> &group);
void setText(const string &text);
@@ -411,6 +482,25 @@ public slots:
void onChange();
};
struct pVerticalScrollBar : public QObject, public pWidget {
Q_OBJECT
public:
VerticalScrollBar &verticalScrollBar;
QScrollBar *qtScrollBar;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);
pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {}
void constructor();
public slots:
void onChange();
};
struct pVerticalSlider : public QObject, public pWidget {
Q_OBJECT
@@ -418,6 +508,7 @@ public:
VerticalSlider &verticalSlider;
QSlider *qtSlider;
Geometry minimumGeometry();
unsigned position();
void setLength(unsigned length);
void setPosition(unsigned position);

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

@@ -0,0 +1,21 @@
void pTimer::setEnabled(bool enabled) {
if(enabled) {
qtTimer->start();
} else {
qtTimer->stop();
}
}
void pTimer::setInterval(unsigned milliseconds) {
qtTimer->setInterval(milliseconds);
}
void pTimer::constructor() {
qtTimer = new QTimer;
qtTimer->setInterval(0);
connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout()));
}
void pTimer::onTimeout() {
if(timer.onTimeout) timer.onTimeout();
}

View File

@@ -1,3 +1,9 @@
Geometry pButton::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(button.state.text);
return { 0, 0, geometry.width + 20, geometry.height + 12 };
}
void pButton::setText(const string &text) {
qtButton->setText(QString::fromUtf8(text));
}

View File

@@ -0,0 +1,27 @@
uint32_t* pCanvas::buffer() {
return (uint32_t*)qtImage->bits();
}
void pCanvas::setGeometry(const Geometry &geometry) {
qtImage = new QImage(geometry.width, geometry.height, QImage::Format_RGB32);
qtImage->fill(0);
update();
pWidget::setGeometry(geometry);
}
void pCanvas::update() {
qtCanvas->update();
}
void pCanvas::constructor() {
qtWidget = qtCanvas = new QtCanvas(*this);
qtImage = new QImage(256, 256, QImage::Format_RGB32);
}
void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) {
QPainter painter(self.qtCanvas);
painter.drawImage(0, 0, *self.qtImage);
}
pCanvas::QtCanvas::QtCanvas(pCanvas &self) : self(self) {
}

View File

@@ -2,6 +2,12 @@ bool pCheckBox::checked() {
return qtCheckBox->isChecked();
}
Geometry pCheckBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(checkBox.state.text);
return { 0, 0, geometry.width + 26, geometry.height + 6 };
}
void pCheckBox::setChecked(bool checked) {
locked = true;
qtCheckBox->setChecked(checked);

View File

@@ -2,6 +2,14 @@ void pComboBox::append(const string &text) {
qtComboBox->addItem(QString::fromUtf8(text));
}
Geometry pComboBox::minimumGeometry() {
Font &font = this->font();
unsigned maximumWidth = 0;
foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(text).width);
Geometry geometry = font.geometry(" ");
return { 0, 0, maximumWidth + 32, geometry.height + 12 };
}
void pComboBox::reset() {
while(qtComboBox->count()) qtComboBox->removeItem(0);
}

View File

@@ -0,0 +1,29 @@
Geometry pHorizontalScrollBar::minimumGeometry() {
return { 0, 0, 0, 15 };
}
unsigned pHorizontalScrollBar::position() {
return qtScrollBar->value();
}
void pHorizontalScrollBar::setLength(unsigned length) {
length += length == 0;
qtScrollBar->setRange(0, length - 1);
qtScrollBar->setPageStep(length >> 3);
}
void pHorizontalScrollBar::setPosition(unsigned position) {
qtScrollBar->setValue(position);
}
void pHorizontalScrollBar::constructor() {
qtWidget = qtScrollBar = new QScrollBar(Qt::Horizontal);
qtScrollBar->setRange(0, 100);
qtScrollBar->setPageStep(101 >> 3);
connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange()));
}
void pHorizontalScrollBar::onChange() {
horizontalScrollBar.state.position = position();
if(horizontalScrollBar.onChange) horizontalScrollBar.onChange();
}

View File

@@ -1,3 +1,7 @@
Geometry pHorizontalSlider::minimumGeometry() {
return { 0, 0, 0, 20 };
}
unsigned pHorizontalSlider::position() {
return qtSlider->value();
}

View File

@@ -1,3 +1,9 @@
Geometry pLabel::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(label.state.text);
return { 0, 0, geometry.width, geometry.height };
}
void pLabel::setText(const string &text) {
qtLabel->setText(QString::fromUtf8(text));
}

View File

@@ -1,3 +1,9 @@
Geometry pLineEdit::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(lineEdit.state.text);
return { 0, 0, geometry.width + 12, geometry.height + 12 };
}
void pLineEdit::setEditable(bool editable) {
qtLineEdit->setReadOnly(!editable);
}

View File

@@ -82,6 +82,7 @@ void pListView::setSelection(unsigned row) {
locked = true;
QTreeWidgetItem *item = qtListView->currentItem();
if(item) item->setSelected(false);
qtListView->setCurrentItem(0);
auto items = qtListView->findItems("", Qt::MatchContains);
for(unsigned n = 0; n < items.size(); n++) {
if(items[n]->data(0, Qt::UserRole).toUInt() == row) {
@@ -100,7 +101,7 @@ void pListView::constructor() {
qtListView->setRootIsDecorated(false);
connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
connect(qtListView, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*)));
connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*)));
}
@@ -108,7 +109,9 @@ void pListView::onActivate() {
if(locked == false && listView.onActivate) listView.onActivate();
}
void pListView::onChange() {
void pListView::onChange(QTreeWidgetItem *item) {
//Qt bug workaround: clicking items with mouse does not mark items as selected
if(item) item->setSelected(true);
listView.state.selected = selected();
if(listView.state.selected) listView.state.selection = selection();
if(locked == false && listView.onChange) listView.onChange();

View File

@@ -1,3 +1,7 @@
Geometry pProgressBar::minimumGeometry() {
return { 0, 0, 0, 25 };
}
void pProgressBar::setPosition(unsigned position) {
qtProgressBar->setValue(position);
}

View File

@@ -2,6 +2,12 @@ bool pRadioBox::checked() {
return qtRadioBox->isChecked();
}
Geometry pRadioBox::minimumGeometry() {
Font &font = this->font();
Geometry geometry = font.geometry(radioBox.state.text);
return { 0, 0, geometry.width + 26, geometry.height + 6 };
}
void pRadioBox::setChecked() {
locked = true;
foreach(item, radioBox.state.group) {

View File

@@ -0,0 +1,29 @@
Geometry pVerticalScrollBar::minimumGeometry() {
return { 0, 0, 15, 0 };
}
unsigned pVerticalScrollBar::position() {
return qtScrollBar->value();
}
void pVerticalScrollBar::setLength(unsigned length) {
length += length == 0;
qtScrollBar->setRange(0, length - 1);
qtScrollBar->setPageStep(length >> 3);
}
void pVerticalScrollBar::setPosition(unsigned position) {
qtScrollBar->setValue(position);
}
void pVerticalScrollBar::constructor() {
qtWidget = qtScrollBar = new QScrollBar(Qt::Vertical);
qtScrollBar->setRange(0, 100);
qtScrollBar->setPageStep(101 >> 3);
connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange()));
}
void pVerticalScrollBar::onChange() {
verticalScrollBar.state.position = position();
if(verticalScrollBar.onChange) verticalScrollBar.onChange();
}

View File

@@ -1,3 +1,7 @@
Geometry pVerticalSlider::minimumGeometry() {
return { 0, 0, 20, 0 };
}
unsigned pVerticalSlider::position() {
return qtSlider->value();
}

View File

@@ -1,3 +1,12 @@
Font& pWidget::font() {
if(widget.state.font) return *widget.state.font;
return pOS::defaultFont;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
}
void pWidget::setEnabled(bool enabled) {
qtWidget->setEnabled(enabled);
}

View File

@@ -18,6 +18,12 @@ void pWindow::append(Widget &widget) {
widget.setVisible(widget.state.visible);
}
Color pWindow::backgroundColor() {
if(window.state.backgroundColorOverride) return window.state.backgroundColor;
QColor color = qtWindow->palette().color(QPalette::ColorRole::Window);
return { (uint8_t)color.red(), (uint8_t)color.green(), (uint8_t)color.blue(), (uint8_t)color.alpha() };
}
Geometry pWindow::frameMargin() {
unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0;
unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0;
@@ -43,9 +49,9 @@ Geometry pWindow::geometry() {
return window.state.geometry;
}
void pWindow::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
void pWindow::setBackgroundColor(const Color &color) {
QPalette palette;
palette.setColor(QPalette::Window, QColor(red, green, blue));
palette.setColor(QPalette::Window, QColor(color.red, color.green, color.blue));
qtContainer->setPalette(palette);
qtContainer->setAutoFillBackground(true);
}

View File

@@ -1,3 +1,7 @@
Geometry pFont::geometry(const string &text) {
return { 0, 0, 0, 0 };
}
void pFont::setBold(bool bold) {
}

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