mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r48 release.
byuu says: The problems with the Windows and Qt4 ports have all been resolved, although there's a fairly gross hack on a few Qt widgets to not destruct once Application::quit() is called to avoid a double free crash (I'm unsure where Qt is destructing the widgets internally.) The Cocoa port compiles again at least, though it's bound to have endless problems. I improved the Label painting in the GTK ports, which fixes the background color on labels inside TabFrame widgets. I've optimized the Makefile system even further. I added a "redo state" command to bsnes, which is created whenever you load the undo state. There are also hotkeys for both now, although I don't think they're really something you want to map hotkeys to. I moved the nall::Locale object inside hiro::Application, so that it can be used to translate the BrowserDialog and MessageDialog window strings. I improved the Super Game Boy emulation of `MLT_REQ`, fixing Pokemon Yellow's custom border and probably more stuff. Lots of other small fixes and improvements. Things are finally stable once again after the harrowing layout redesign catastrophe. Errata: - ICD::joypID should be set to 3 on reset(). joypWrite() may as well take uint1 instead of bool. - hiro/Qt: remove pWindow::setMaximumSize() comment; found a workaround for it - nall/GNUmakefile: don't set object.path if it's already set (allow overrides before including the file)
This commit is contained in:
parent
6090c63958
commit
393c2395bb
|
@ -1,22 +1,21 @@
|
|||
name := genius
|
||||
build := stable
|
||||
flags += -I..
|
||||
|
||||
nall.path := ../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
object.path := obj
|
||||
flags += -I..
|
||||
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := data/$(name).rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
|
||||
objects := obj/hiro.o $(if $(call streq,$(platform),windows),obj/hiro-resource.o)
|
||||
objects += obj/genius.o
|
||||
objects := obj/genius.o
|
||||
|
||||
all: $(objects)
|
||||
obj/genius.o: genius.cpp
|
||||
|
||||
all: $(hiro.objects) $(objects)
|
||||
$(info Linking out/$(name) ...)
|
||||
+@$(strip $(compiler) -o out/$(name) $(objects) $(options) $(hiro.options))
|
||||
+@$(compiler) -o out/$(name) $(hiro.objects) $(objects) $(hiro.options) $(options)
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
mkdir -p out/$(name).app/Contents/MacOS/
|
||||
|
@ -26,16 +25,14 @@ ifeq ($(platform),macos)
|
|||
sips -s format icns data/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns
|
||||
endif
|
||||
|
||||
obj/genius.o: genius.cpp genius.hpp
|
||||
$(info Compiling $< ...)
|
||||
@$(compiler) $(flags.cpp) $(flags) -o obj/genius.o -c genius.cpp
|
||||
verbose: hiro.verbose nall.verbose all;
|
||||
|
||||
clean:
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
endif
|
||||
$(call rm,obj/*)
|
||||
$(call rm,out/*)
|
||||
$(call delete,obj/*)
|
||||
$(call delete,out/*)
|
||||
|
||||
install:
|
||||
ifeq ($(platform),macos)
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
target := bsnes
|
||||
binary := application
|
||||
build := performance
|
||||
openmp := true
|
||||
flags += -I. -I..
|
||||
|
||||
nall.path := ../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
binary := application
|
||||
target := bsnes
|
||||
objects := libco emulator audio video resource
|
||||
object.path := obj
|
||||
flags += -I. -I..
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
ifeq ($(binary),application)
|
||||
link += -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||
|
@ -37,18 +34,7 @@ else
|
|||
$(error "unsupported platform")
|
||||
endif
|
||||
|
||||
compile = \
|
||||
$(strip \
|
||||
$(if $(filter %.c,$<), \
|
||||
$(compiler) $(flags.c) $(flags) $1 -c $< -o $@ -MMD -MP -MF $(@:.o=.d), \
|
||||
$(if $(filter %.cpp,$<), \
|
||||
$(compiler) $(flags.cpp) $(flags) $1 -c $< -o $@ -MMD -MP -MF $(@:.o=.d) \
|
||||
)) \
|
||||
)
|
||||
|
||||
%.o: $<
|
||||
$(info Compiling $< ...)
|
||||
@$(call compile)
|
||||
objects := libco emulator audio video resource
|
||||
|
||||
obj/libco.o: ../libco/libco.c
|
||||
obj/emulator.o: emulator/emulator.cpp
|
||||
|
@ -61,5 +47,5 @@ include $(ui)/GNUmakefile
|
|||
-include obj/*.d
|
||||
|
||||
clean:
|
||||
$(call rm,out/*)
|
||||
$(call rm,obj/*)
|
||||
$(call delete,out/*)
|
||||
$(call delete,obj/*)
|
||||
|
|
|
@ -13,7 +13,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.47";
|
||||
static const string Version = "106.48";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -41,7 +41,6 @@ struct CPU : Processor::LR35902, Thread, MMIO {
|
|||
bool p15 = 0;
|
||||
bool p14 = 0;
|
||||
uint8 joyp;
|
||||
uint8 mltReq;
|
||||
|
||||
//$ff01 SB
|
||||
uint8 serialData;
|
||||
|
|
|
@ -29,7 +29,9 @@ auto CPU::joypPoll() -> void {
|
|||
}
|
||||
|
||||
status.joyp = 0x0f;
|
||||
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mltReq;
|
||||
if(status.p15 == 1 && status.p14 == 1 && Model::SuperGameBoy()) {
|
||||
status.joyp = superGameBoy->joypRead();
|
||||
}
|
||||
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
|
||||
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
|
||||
if(status.joyp != 0x0f) raise(Interrupt::Joypad);
|
||||
|
|
|
@ -10,7 +10,6 @@ auto CPU::serialize(serializer& s) -> void {
|
|||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
s.integer(status.joyp);
|
||||
s.integer(status.mltReq);
|
||||
|
||||
s.integer(status.serialData);
|
||||
s.integer(status.serialBits);
|
||||
|
|
|
@ -72,6 +72,7 @@ struct SuperGameBoyInterface {
|
|||
|
||||
virtual auto lcdScanline() -> void = 0;
|
||||
virtual auto lcdOutput(uint2 color) -> void = 0;
|
||||
virtual auto joypRead() -> uint4 = 0;
|
||||
virtual auto joypWrite(bool p15, bool p14) -> void = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ auto ICD::reset() -> void {
|
|||
writeAddress = 0;
|
||||
|
||||
packetSize = 0;
|
||||
joypID = 3;
|
||||
joypID = 0;
|
||||
joyp15Lock = 0;
|
||||
joyp14Lock = 0;
|
||||
pulseLock = true;
|
||||
|
|
|
@ -18,6 +18,7 @@ struct ICD : Emulator::Platform, GameBoy::SuperGameBoyInterface, Thread {
|
|||
//interface.cpp
|
||||
auto lcdScanline() -> void override;
|
||||
auto lcdOutput(uint2 color) -> void override;
|
||||
auto joypRead() -> uint4 override;
|
||||
auto joypWrite(bool p15, bool p14) -> void override;
|
||||
|
||||
//io.cpp
|
||||
|
|
|
@ -10,18 +10,26 @@ auto ICD::lcdOutput(uint2 color) -> void {
|
|||
uint y = writeAddress / 160;
|
||||
uint x = writeAddress % 160;
|
||||
uint addr = writeBank * 512 + y * 2 + x / 8 * 16;
|
||||
output[addr + 0] = (output[addr + 0] << 1) | (bool)(color & 1);
|
||||
output[addr + 1] = (output[addr + 1] << 1) | (bool)(color & 2);
|
||||
output[addr + 0] = (output[addr + 0] << 1) | color.bit(0);
|
||||
output[addr + 1] = (output[addr + 1] << 1) | color.bit(1);
|
||||
writeAddress = (writeAddress + 1) % 1280;
|
||||
}
|
||||
|
||||
auto ICD::joypRead() -> uint4 {
|
||||
return 0xf - joypID;
|
||||
}
|
||||
|
||||
auto ICD::joypWrite(bool p15, bool p14) -> void {
|
||||
//joypad handling
|
||||
if(p15 == 1 && p14 == 1) {
|
||||
if(joyp15Lock == 0 && joyp14Lock == 0) {
|
||||
joyp15Lock = 1;
|
||||
joyp14Lock = 1;
|
||||
joypID = (joypID + 1) & 3;
|
||||
joypID++;
|
||||
if(mltReq == 0) joypID &= 0; //1-player mode
|
||||
if(mltReq == 1) joypID &= 1; //2-player mode
|
||||
if(mltReq == 2) joypID &= 3; //4-player mode (unverified; but the most likely behavior)
|
||||
if(mltReq == 3) joypID &= 3; //4-player mode
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +73,7 @@ auto ICD::joypWrite(bool p15, bool p14) -> void {
|
|||
if(p15 == 1 && p14 == 0) {
|
||||
if((joypPacket[0] >> 3) == 0x11) {
|
||||
mltReq = joypPacket[1] & 3;
|
||||
if(mltReq == 2) mltReq = 3;
|
||||
joypID = 0;
|
||||
joypID = 3; //required: the next time P14==1 && P15==1; increment and start from ID=0 (Joypad 1)
|
||||
}
|
||||
|
||||
if(packetSize < 64) packet[packetSize++] = joypPacket;
|
||||
|
|
|
@ -3,10 +3,8 @@ auto ICD::audioSample(const double* samples, uint channels) -> void {
|
|||
}
|
||||
|
||||
auto ICD::inputPoll(uint port, uint device, uint id) -> int16 {
|
||||
GameBoy::cpu.status.mltReq = joypID & mltReq;
|
||||
|
||||
uint data = 0x00;
|
||||
switch(joypID & mltReq) {
|
||||
uint8 data = 0x00;
|
||||
switch(joypID) {
|
||||
case 0: data = ~r6004; break;
|
||||
case 1: data = ~r6005; break;
|
||||
case 2: data = ~r6006; break;
|
||||
|
@ -14,14 +12,14 @@ auto ICD::inputPoll(uint port, uint device, uint id) -> int16 {
|
|||
}
|
||||
|
||||
switch((GameBoy::Input)id) {
|
||||
case GameBoy::Input::Start: return (bool)(data & 0x80);
|
||||
case GameBoy::Input::Select: return (bool)(data & 0x40);
|
||||
case GameBoy::Input::B: return (bool)(data & 0x20);
|
||||
case GameBoy::Input::A: return (bool)(data & 0x10);
|
||||
case GameBoy::Input::Down: return (bool)(data & 0x08);
|
||||
case GameBoy::Input::Up: return (bool)(data & 0x04);
|
||||
case GameBoy::Input::Left: return (bool)(data & 0x02);
|
||||
case GameBoy::Input::Right: return (bool)(data & 0x01);
|
||||
case GameBoy::Input::Right: return data.bit(0);
|
||||
case GameBoy::Input::Left: return data.bit(1);
|
||||
case GameBoy::Input::Up: return data.bit(2);
|
||||
case GameBoy::Input::Down: return data.bit(3);
|
||||
case GameBoy::Input::A: return data.bit(4);
|
||||
case GameBoy::Input::B: return data.bit(5);
|
||||
case GameBoy::Input::Select: return data.bit(6);
|
||||
case GameBoy::Input::Start: return data.bit(7);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -5,35 +5,16 @@ include sfc/GNUmakefile
|
|||
include gb/GNUmakefile
|
||||
include processor/GNUmakefile
|
||||
|
||||
objects := ruby hiro $(if $(call streq,$(platform),windows),hiro-resource) $(objects)
|
||||
objects += ui-bsnes ui-program ui-input ui-presentation
|
||||
objects += ui-settings ui-tools ui-resource
|
||||
objects := $(objects:%=obj/%.o)
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
ruby += video.wgl video.direct3d video.directdraw video.gdi
|
||||
ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound
|
||||
ruby += input.windows
|
||||
else ifeq ($(platform),macos)
|
||||
ruby += video.cgl
|
||||
ruby += audio.openal
|
||||
ruby += input.quartz input.carbon
|
||||
else ifeq ($(platform),linux)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.xlib input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.openal
|
||||
ruby += input.sdl input.xlib
|
||||
endif
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := $(ui)/resource/bsnes.rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
|
||||
ruby.path := ../ruby
|
||||
include $(ruby.path)/GNUmakefile
|
||||
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := $(ui)/resource/bsnes.rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
objects += ui-bsnes ui-program ui-input ui-presentation
|
||||
objects += ui-settings ui-tools ui-resource
|
||||
objects := $(objects:%=obj/%.o)
|
||||
|
||||
obj/ui-bsnes.o: $(ui)/bsnes.cpp
|
||||
obj/ui-program.o: $(ui)/program/program.cpp
|
||||
|
@ -43,10 +24,9 @@ obj/ui-settings.o: $(ui)/settings/settings.cpp
|
|||
obj/ui-tools.o: $(ui)/tools/tools.cpp
|
||||
obj/ui-resource.o: $(ui)/resource/resource.cpp
|
||||
|
||||
# targets
|
||||
all: $(objects)
|
||||
all: $(hiro.objects) $(ruby.objects) $(objects)
|
||||
$(info Linking out/$(name) ...)
|
||||
+@$(strip $(compiler) -o out/$(name) $(objects) $(options) $(ruby.options) $(hiro.options))
|
||||
+@$(compiler) -o out/$(name) $(hiro.objects) $(ruby.objects) $(objects) $(hiro.options) $(ruby.options) $(options)
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
mkdir -p out/$(name).app/Contents/MacOS/
|
||||
|
@ -56,6 +36,8 @@ ifeq ($(platform),macos)
|
|||
sips -s format icns $(ui)/resource/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns
|
||||
endif
|
||||
|
||||
verbose: hiro.verbose ruby.verbose nall.verbose all;
|
||||
|
||||
install:
|
||||
ifeq ($(shell id -un),root)
|
||||
$(error "make install should not be run as root")
|
||||
|
|
|
@ -4,7 +4,6 @@ unique_pointer<Video> video;
|
|||
unique_pointer<Audio> audio;
|
||||
unique_pointer<Input> input;
|
||||
unique_pointer<Emulator::Interface> emulator;
|
||||
Locale ns;
|
||||
|
||||
auto locate(string name) -> string {
|
||||
string location = {Path::program(), name};
|
||||
|
@ -21,14 +20,15 @@ auto locate(string name) -> string {
|
|||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(string_vector arguments) -> void {
|
||||
ns.scan(locate("locales/"));
|
||||
ns.select("日本語");
|
||||
string locale; // = "日本語";
|
||||
for(auto argument : arguments) {
|
||||
if(argument.beginsWith("--locale=")) {
|
||||
ns.select(argument.trimLeft("--locale=", 1L));
|
||||
locale = argument.trimLeft("--locale=", 1L);
|
||||
}
|
||||
}
|
||||
Application::setName("bsnes");
|
||||
Application::locale().scan(locate("locales/"));
|
||||
Application::locale().select(locale);
|
||||
emulator = new SuperFamicom::Interface;
|
||||
new Program(arguments);
|
||||
Application::run();
|
||||
|
|
|
@ -11,7 +11,6 @@ extern unique_pointer<Input> input;
|
|||
#include <emulator/emulator.hpp>
|
||||
extern unique_pointer<Emulator::Interface> emulator;
|
||||
|
||||
extern Locale ns;
|
||||
#include "program/program.hpp"
|
||||
#include "input/input.hpp"
|
||||
#include "presentation/presentation.hpp"
|
||||
|
|
|
@ -24,6 +24,14 @@ auto InputManager::bindHotkeys() -> void {
|
|||
program->loadState({"quick/slot ", stateSlot});
|
||||
}));
|
||||
|
||||
hotkeys.append(InputHotkey("Load Undo State").onPress([&] {
|
||||
program->loadState("quick/undo");
|
||||
}));
|
||||
|
||||
hotkeys.append(InputHotkey("Load Redo State").onPress([&] {
|
||||
program->loadState("quick/redo");
|
||||
}));
|
||||
|
||||
hotkeys.append(InputHotkey("Increment State Slot").onPress([&] {
|
||||
if(--stateSlot < 1) stateSlot = 9;
|
||||
program->showMessage({"Selected state slot ", stateSlot});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
AboutWindow::AboutWindow() : Locale::Namespace(ns, "About") {
|
||||
AboutWindow::AboutWindow() {
|
||||
aboutWindow = this;
|
||||
|
||||
setTitle(tr("About {0} ...", "bsnes"));
|
||||
setTitle({tr("About {0}", "bsnes"), " ..."});
|
||||
setBackgroundColor({255, 255, 240});
|
||||
layout.setPadding(10);
|
||||
auto logo = image{Resource::Logo};
|
||||
|
@ -9,14 +9,17 @@ AboutWindow::AboutWindow() : Locale::Namespace(ns, "About") {
|
|||
canvas.setIcon(logo);
|
||||
tableLayout.setFont(Font().setBold());
|
||||
tableLayout.setSize({2, 4});
|
||||
tableLayout.column(0).setSpacing(3);
|
||||
versionLabel.setText(tr("Version:")).setAlignment(1.0);
|
||||
tableLayout.column(0).setSpacing(4);
|
||||
tableLayout.row(0).setSpacing(2);
|
||||
tableLayout.row(1).setSpacing(2);
|
||||
tableLayout.row(2).setSpacing(2);
|
||||
versionLabel.setText({tr("Version"), ":"}).setAlignment(1.0);
|
||||
versionValue.setText(Emulator::Version);
|
||||
authorLabel.setText(tr("Author:")).setAlignment(1.0);
|
||||
authorLabel.setText({tr("Author"), ":"}).setAlignment(1.0);
|
||||
authorValue.setText(Emulator::Author);
|
||||
licenseLabel.setText(tr("License:")).setAlignment(1.0);
|
||||
licenseLabel.setText({tr("License"), ":"}).setAlignment(1.0);
|
||||
licenseValue.setText(Emulator::License);
|
||||
websiteLabel.setText(tr("Website:")).setAlignment(1.0);
|
||||
websiteLabel.setText({tr("Website"), ":"}).setAlignment(1.0);
|
||||
websiteValue.setText(Emulator::Website);
|
||||
|
||||
setResizable(false);
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
unique_pointer<AboutWindow> aboutWindow;
|
||||
unique_pointer<Presentation> presentation;
|
||||
|
||||
Presentation::Presentation() : Locale::Namespace(ns, "Presentation") {
|
||||
Presentation::Presentation() {
|
||||
presentation = this;
|
||||
|
||||
systemMenu.setText(tr("System"));
|
||||
loadGame.setIcon(Icon::Action::Open).setText("Load Game ...").onActivate([&] {
|
||||
loadGame.setIcon(Icon::Action::Open).setText({tr("Load Game"), " ..."}).onActivate([&] {
|
||||
program->load();
|
||||
});
|
||||
loadRecentGame.setIcon(Icon::Action::Open).setText("Load Recent Game");
|
||||
loadRecentGame.setIcon(Icon::Action::Open).setText(tr("Load Recent Game"));
|
||||
updateRecentGames();
|
||||
resetSystem.setIcon(Icon::Action::Refresh).setText("Reset System").setEnabled(false).onActivate([&] {
|
||||
resetSystem.setIcon(Icon::Action::Refresh).setText(tr("Reset System")).setEnabled(false).onActivate([&] {
|
||||
program->reset();
|
||||
});
|
||||
unloadGame.setIcon(Icon::Action::Remove).setText("Unload Game").setEnabled(false).onActivate([&] {
|
||||
unloadGame.setIcon(Icon::Action::Remove).setText(tr("Unload Game")).setEnabled(false).onActivate([&] {
|
||||
program->unload();
|
||||
});
|
||||
controllerPort1.setIcon(Icon::Device::Joypad).setText("Controller Port 1");
|
||||
controllerPort2.setIcon(Icon::Device::Joypad).setText("Controller Port 2");
|
||||
expansionPort.setIcon(Icon::Device::Storage).setText("Expansion Port");
|
||||
controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1"));
|
||||
controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2"));
|
||||
expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port"));
|
||||
for(auto& port : emulator->ports) {
|
||||
Menu* menu = nullptr;
|
||||
if(port.name == "Controller Port 1") menu = &controllerPort1;
|
||||
|
@ -33,7 +33,7 @@ Presentation::Presentation() : Locale::Namespace(ns, "Presentation") {
|
|||
if(port.name != "Expansion Port" && device.name == "None") continue;
|
||||
if(port.name == "Expansion Port" && device.name == "21fx") continue;
|
||||
MenuRadioItem item{menu};
|
||||
item.setText(device.name).onActivate([=] {
|
||||
item.setText(tr(device.name)).onActivate([=] {
|
||||
auto path = string{"Emulator/", port.name}.replace(" ", "");
|
||||
settings(path).setValue(device.name);
|
||||
emulator->connect(port.id, device.id);
|
||||
|
@ -53,7 +53,7 @@ Presentation::Presentation() : Locale::Namespace(ns, "Presentation") {
|
|||
devices.objects<MenuRadioItem>()(0).doActivate();
|
||||
}
|
||||
}
|
||||
quit.setIcon(Icon::Action::Quit).setText("Quit").onActivate([&] { program->quit(); });
|
||||
quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); });
|
||||
|
||||
settingsMenu.setText(tr("Settings"));
|
||||
sizeMenu.setIcon(Icon::Emblem::Image).setText("Size");
|
||||
|
@ -132,6 +132,9 @@ Presentation::Presentation() : Locale::Namespace(ns, "Presentation") {
|
|||
loadState.append(MenuItem().setIcon(Icon::Edit::Undo).setText("Undo Last Save").onActivate([&] {
|
||||
program->loadState("quick/undo");
|
||||
}));
|
||||
loadState.append(MenuItem().setIcon(Icon::Edit::Redo).setText("Redo Last Undo").onActivate([&] {
|
||||
program->loadState("quick/redo");
|
||||
}));
|
||||
speedMenu.setIcon(Icon::Device::Clock).setText("Speed");
|
||||
speedSlowest.setText("50% (Slowest)").setProperty("multiplier", "2.0").onActivate([&] { program->updateAudioFrequency(); });
|
||||
speedSlow.setText("75% (Slow)").setProperty("multiplier", "1.333").onActivate([&] { program->updateAudioFrequency(); });
|
||||
|
@ -153,10 +156,10 @@ Presentation::Presentation() : Locale::Namespace(ns, "Presentation") {
|
|||
manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsWindow->show(2); });
|
||||
|
||||
helpMenu.setText(tr("Help"));
|
||||
documentation.setIcon(Icon::Application::Browser).setText("Documentation ...").onActivate([&] {
|
||||
documentation.setIcon(Icon::Application::Browser).setText({tr("Documentation"), " ..."}).onActivate([&] {
|
||||
invoke("https://doc.byuu.org/bsnes/");
|
||||
});
|
||||
about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] {
|
||||
about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] {
|
||||
aboutWindow->setCentered(*this).setVisible().setFocused();
|
||||
});
|
||||
|
||||
|
@ -245,7 +248,7 @@ auto Presentation::updateStatusIcon() -> void {
|
|||
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
|
||||
return;
|
||||
|
||||
int ox = width - 144;
|
||||
int ox = width - 144;
|
||||
int oy = height - 128;
|
||||
if(ox >= 0 && oy >= 0) {
|
||||
image icon{Resource::Icon};
|
||||
|
@ -259,11 +262,8 @@ auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint heig
|
|||
}
|
||||
|
||||
auto Presentation::clearViewport() -> void {
|
||||
if(!visible() && !video) return;
|
||||
|
||||
if(!emulator->loaded()) {
|
||||
viewportLayout.setPadding();
|
||||
}
|
||||
if(!emulator->loaded()) viewportLayout.setPadding();
|
||||
if(!visible() || !video) return;
|
||||
|
||||
uint32_t* output;
|
||||
uint length;
|
||||
|
@ -288,7 +288,7 @@ auto Presentation::resizeViewport() -> void {
|
|||
uint height = (settings["View/OverscanCropping"].boolean() ? 224.0 : 240.0);
|
||||
uint viewportWidth, viewportHeight;
|
||||
|
||||
if(!fullScreen()) {
|
||||
if(visible() && !fullScreen()) {
|
||||
uint widthMultiplier = windowWidth / width;
|
||||
uint heightMultiplier = windowHeight / height;
|
||||
uint multiplier = max(1, min(widthMultiplier, heightMultiplier));
|
||||
|
@ -300,8 +300,8 @@ auto Presentation::resizeViewport() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
if(!visible() || !video) return;
|
||||
if(!emulator->loaded()) return clearViewport();
|
||||
if(!video) return;
|
||||
|
||||
if(settings["View/Output"].text() == "Center") {
|
||||
uint widthMultiplier = windowWidth / width;
|
||||
|
@ -450,14 +450,14 @@ auto Presentation::updateRecentGames() -> void {
|
|||
program->load();
|
||||
});
|
||||
} else {
|
||||
item.setText("<empty>");
|
||||
item.setText(tr("Empty"));
|
||||
item.setEnabled(false);
|
||||
}
|
||||
loadRecentGame.append(item);
|
||||
}
|
||||
|
||||
loadRecentGame.append(MenuSeparator());
|
||||
loadRecentGame.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Clear List").onActivate([&] {
|
||||
loadRecentGame.append(MenuItem().setIcon(Icon::Edit::Clear).setText(tr("Clear List")).onActivate([&] {
|
||||
for(auto index : range(RecentGames)) {
|
||||
settings({"Game/Recent/", 1 + index}).setValue("");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
struct AboutWindow : Locale::Namespace, Window {
|
||||
struct AboutWindow : Window {
|
||||
Application::Namespace tr{"AboutWindow"};
|
||||
|
||||
AboutWindow();
|
||||
|
||||
VerticalLayout layout{this};
|
||||
|
@ -17,7 +19,9 @@ struct AboutWindow : Locale::Namespace, Window {
|
|||
Label websiteValue{&tableLayout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct Presentation : Locale::Namespace, Window {
|
||||
struct Presentation : Window {
|
||||
Application::Namespace tr{"Presentation"};
|
||||
|
||||
enum : uint { RecentGames = 9, QuickStates = 9 };
|
||||
enum : uint { StatusHeight = 24 };
|
||||
|
||||
|
@ -103,7 +107,7 @@ struct Presentation : Locale::Namespace, Window {
|
|||
Canvas statusIcon{&statusLayout, Size{16, ~0}, 0};
|
||||
Label spacerLeft{&statusLayout, Size{4, ~0}, 0};
|
||||
Label statusLeft{&statusLayout, Size{~0, ~0}, 0};
|
||||
Label statusRight{&statusLayout, Size{80, ~0}, 0};
|
||||
Label statusRight{&statusLayout, Size{100, ~0}, 0};
|
||||
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ auto Program::load() -> void {
|
|||
program->loadState("quick/undo");
|
||||
}
|
||||
showMessage({
|
||||
verified() ? "Verified" : "Unverified", " game loaded",
|
||||
verified() ? "Verified game loaded" : "Game loaded",
|
||||
appliedPatch() ? " and patch applied" : ""
|
||||
});
|
||||
presentation->setTitle(emulator->title());
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "hacks.cpp"
|
||||
unique_pointer<Program> program;
|
||||
|
||||
Program::Program(string_vector arguments) : Locale::Namespace(ns, "Program") {
|
||||
Program::Program(string_vector arguments) {
|
||||
program = this;
|
||||
Emulator::platform = this;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
struct Program : Locale::Namespace, Emulator::Platform {
|
||||
struct Program : Emulator::Platform {
|
||||
Application::Namespace tr{"Program"};
|
||||
|
||||
//program.cpp
|
||||
Program(string_vector arguments);
|
||||
auto main() -> void;
|
||||
|
@ -51,6 +53,7 @@ struct Program : Locale::Namespace, Emulator::Platform {
|
|||
auto loadState(string filename) -> bool;
|
||||
auto saveState(string filename) -> bool;
|
||||
auto saveUndoState() -> bool;
|
||||
auto saveRedoState() -> bool;
|
||||
auto removeState(string filename) -> bool;
|
||||
auto renameState(string from, string to) -> bool;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ auto Program::loadState(string filename) -> bool {
|
|||
string location = {statePath(), filename, ".bst"};
|
||||
if(!file::exists(location)) return showMessage({"[", prefix, "] not found"}), false;
|
||||
if(filename != "quick/undo") saveUndoState();
|
||||
if(filename == "quick/undo") saveRedoState();
|
||||
memory = file::read(location);
|
||||
} else {
|
||||
string location = {filename, ".bst"};
|
||||
|
@ -96,6 +97,15 @@ auto Program::saveUndoState() -> bool {
|
|||
return result;
|
||||
}
|
||||
|
||||
auto Program::saveRedoState() -> bool {
|
||||
auto statusTime = this->statusTime;
|
||||
auto statusMessage = this->statusMessage;
|
||||
auto result = saveState("quick/redo");
|
||||
this->statusTime = statusTime;
|
||||
this->statusMessage = statusMessage;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Program::removeState(string filename) -> bool {
|
||||
if(!emulator->loaded()) return false;
|
||||
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
locale
|
||||
language: 日本語
|
||||
|
||||
namespace: MessageDialog
|
||||
map
|
||||
input: Yes
|
||||
value: はい
|
||||
map
|
||||
input: No
|
||||
value: いいえ
|
||||
map
|
||||
input: Cancel
|
||||
value: キャンセル
|
||||
|
||||
namespace: BrowserDialog
|
||||
map
|
||||
input: Open
|
||||
value: 開く
|
||||
map
|
||||
input: Save
|
||||
value: 保存
|
||||
map
|
||||
input: Select
|
||||
value: 選択
|
||||
map
|
||||
input: Cancel
|
||||
value: キャンセル
|
||||
|
||||
namespace: Program
|
||||
map
|
||||
input: Unloaded
|
||||
value: アンロードされる
|
||||
map
|
||||
input: Paused
|
||||
value: ポーズ
|
||||
|
@ -10,6 +38,60 @@ namespace: Presentation
|
|||
map
|
||||
input: System
|
||||
value: システム
|
||||
map
|
||||
input: Load Game
|
||||
value: ゲームを読み込み
|
||||
map
|
||||
input: Load Recent Game
|
||||
value: 最新ゲームを読み込み
|
||||
map
|
||||
input: Empty
|
||||
value: なし
|
||||
map
|
||||
input: Clear List
|
||||
value: 全部を消す
|
||||
map
|
||||
input: Reset System
|
||||
value: システムをリセット
|
||||
map
|
||||
input: Unload Game
|
||||
value: ゲームをアンロード
|
||||
map
|
||||
input: Controller Port 1
|
||||
value: コントローラポート1
|
||||
map
|
||||
input: Controller Port 2
|
||||
value: コントローラポート2
|
||||
map
|
||||
input: Expansion Port
|
||||
value: 拡張ポート
|
||||
map
|
||||
input: Gamepad
|
||||
value: ゲームパッド
|
||||
map
|
||||
input: Mouse
|
||||
value: マウス
|
||||
map
|
||||
input: Super Multitap
|
||||
value: スーパーマルチタップ
|
||||
map
|
||||
input: Super Scope
|
||||
value: スーパースコップ
|
||||
map
|
||||
input: Justifier
|
||||
value: 1挺のジャスティファイアー
|
||||
map
|
||||
input: Justifiers
|
||||
value: 2挺のジャスティファイアー
|
||||
map
|
||||
input: None
|
||||
value: なし
|
||||
map
|
||||
input: Satellaview
|
||||
value: サテラビュー
|
||||
map
|
||||
input: Quit
|
||||
value: 終了
|
||||
map
|
||||
input: Settings
|
||||
value: 設定
|
||||
|
@ -19,22 +101,27 @@ namespace: Presentation
|
|||
map
|
||||
input: Help
|
||||
value: ヘルプ
|
||||
map
|
||||
input: Documentation
|
||||
value: オンラインマニュアル
|
||||
map
|
||||
input: About
|
||||
value: 情報
|
||||
|
||||
namespace: About
|
||||
namespace: AboutWindow
|
||||
map
|
||||
input: About {0} ...
|
||||
value: {0}について ...
|
||||
|
||||
map
|
||||
input: Version:
|
||||
value: バージョン:
|
||||
map
|
||||
input: Author:
|
||||
value: 作者:
|
||||
map
|
||||
input: License:
|
||||
value: ライセンス:
|
||||
map
|
||||
input: Website:
|
||||
value: 公式サイト:
|
||||
input: About {0}
|
||||
value: {0}について
|
||||
map
|
||||
input: Version
|
||||
value: バージョン
|
||||
map
|
||||
input: Author
|
||||
value: 作者
|
||||
map
|
||||
input: License
|
||||
value: ライセンス
|
||||
map
|
||||
input: Website
|
||||
value: 公式サイト
|
||||
|
||||
|
|
|
@ -11,35 +11,16 @@ include gba/GNUmakefile
|
|||
include ws/GNUmakefile
|
||||
include processor/GNUmakefile
|
||||
|
||||
objects := ruby hiro $(if $(call streq,$(platform),windows),hiro-resource) $(objects)
|
||||
objects += ui-higan ui-program ui-input
|
||||
objects += ui-settings ui-tools ui-presentation ui-resource
|
||||
objects := $(objects:%=obj/%.o)
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
ruby += video.wgl video.direct3d video.directdraw video.gdi
|
||||
ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound
|
||||
ruby += input.windows
|
||||
else ifeq ($(platform),macos)
|
||||
ruby += video.cgl
|
||||
ruby += audio.openal
|
||||
ruby += input.quartz input.carbon
|
||||
else ifeq ($(platform),linux)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.xlib input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.openal
|
||||
ruby += input.sdl input.xlib
|
||||
endif
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := $(ui)/resource/higan.rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
|
||||
ruby.path := ../ruby
|
||||
include $(ruby.path)/GNUmakefile
|
||||
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := $(ui)/resource/higan.rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
objects += ui-higan ui-program ui-input
|
||||
objects += ui-settings ui-tools ui-presentation ui-resource
|
||||
objects := $(objects:%=obj/%.o)
|
||||
|
||||
obj/ui-higan.o: $(ui)/higan.cpp
|
||||
obj/ui-program.o: $(ui)/program/program.cpp
|
||||
|
@ -49,10 +30,9 @@ obj/ui-tools.o: $(ui)/tools/tools.cpp
|
|||
obj/ui-presentation.o: $(ui)/presentation/presentation.cpp
|
||||
obj/ui-resource.o: $(ui)/resource/resource.cpp
|
||||
|
||||
# targets
|
||||
all: $(objects)
|
||||
all: $(hiro.objects) $(ruby.objects) $(objects)
|
||||
$(info Linking out/$(name) ...)
|
||||
+@$(strip $(compiler) -o out/$(name) $(objects) $(options) $(ruby.options) $(hiro.options))
|
||||
+@$(compiler) -o out/$(name) $(hiro.objects) $(ruby.objects) $(objects) $(hiro.options) $(ruby.options) $(options)
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
mkdir -p out/$(name).app/Contents/MacOS/
|
||||
|
@ -62,6 +42,8 @@ ifeq ($(platform),macos)
|
|||
sips -s format icns $(ui)/resource/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns
|
||||
endif
|
||||
|
||||
verbose: hiro.verbose ruby.verbose nall.verbose all;
|
||||
|
||||
install:
|
||||
ifeq ($(shell id -un),root)
|
||||
$(error "make install should not be run as root")
|
||||
|
|
|
@ -63,16 +63,24 @@ ifneq ($(filter $(platform),linux bsd),)
|
|||
endif
|
||||
endif
|
||||
|
||||
$(object.path)/hiro.o: $(hiro.path)/hiro.cpp $(call rwildcard,$(hiro.path)) $(call rwildcard,$(nall.path))
|
||||
$(if $(filter qt%,$(hiro)),$(info Compiling $(hiro.path)/qt/qt.moc ...))
|
||||
$(if $(filter qt%,$(hiro)),@$(moc) -i -o $(hiro.path)/qt/qt.moc $(hiro.path)/qt/qt.hpp)
|
||||
$(info Compiling $< ...)
|
||||
@$(compiler) $(flags) $(hiro.flags) -c $< -o $@
|
||||
|
||||
ifeq ($(hiro.resource),)
|
||||
hiro.resource := $(hiro.path)/windows/hiro.rc
|
||||
endif
|
||||
|
||||
hiro.objects := \
|
||||
$(object.path)/hiro-$(hiro).o \
|
||||
$(if $(filter windows,$(hiro)),$(object.path)/hiro-resource.o)
|
||||
|
||||
$(object.path)/hiro-$(hiro).o: $(hiro.path)/hiro.cpp
|
||||
$(if $(filter qt%,$(hiro)),$(info Compiling $(hiro.path)/qt/qt.moc ...))
|
||||
$(if $(filter qt%,$(hiro)),@$(moc) -i -o $(hiro.path)/qt/qt.moc $(hiro.path)/qt/qt.hpp)
|
||||
$(info Compiling $< ...)
|
||||
@$(compiler) $(hiro.flags) $(flags) $(flags.deps) -c $< -o $@
|
||||
|
||||
$(object.path)/hiro-resource.o: $(hiro.resource)
|
||||
$(if $(filter windows,$(hiro)),$(info Compiling $< ...))
|
||||
$(if $(filter windows,$(hiro)),@$(windres) $< $@)
|
||||
$(info Compiling $< ...)
|
||||
@$(windres) $< $@
|
||||
|
||||
hiro.verbose:
|
||||
$(info hiro Target:)
|
||||
$(info $([space]) $(hiro))
|
||||
|
|
|
@ -5,7 +5,10 @@ namespace hiro {
|
|||
auto pDesktop::size() -> Size {
|
||||
@autoreleasepool {
|
||||
NSRect primary = [[[NSScreen screens] objectAtIndex:0] frame];
|
||||
return {(int)primary.size.width, (int)primary.size.height};
|
||||
return {
|
||||
(int)primary.size.width,
|
||||
(int)primary.size.height
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +16,12 @@ auto pDesktop::workspace() -> Geometry {
|
|||
@autoreleasepool {
|
||||
auto screen = Desktop::size();
|
||||
NSRect area = [[[NSScreen screens] objectAtIndex:0] visibleFrame];
|
||||
return {(int)area.origin.x, (int)(screen.height() - area.size.height - area.origin.y), (int)area.size.width, (int)area.size.height};
|
||||
return {
|
||||
(int)area.origin.x,
|
||||
(int)area.origin.y,
|
||||
(int)area.size.width,
|
||||
(int)area.size.height
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,15 +20,33 @@ auto pMonitor::dpi(uint monitor) -> Position {
|
|||
auto pMonitor::geometry(uint monitor) -> Geometry {
|
||||
@autoreleasepool {
|
||||
NSRect rectangle = [[[NSScreen screens] objectAtIndex:monitor] frame];
|
||||
return {(int)rectangle.origin.x, (int)rectangle.origin.y, (int)rectangle.size.width, (int)rectangle.size.height};
|
||||
return {
|
||||
(int)rectangle.origin.x,
|
||||
(int)rectangle.origin.y,
|
||||
(int)rectangle.size.width,
|
||||
(int)rectangle.size.height
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
auto pMonitor::primary() -> uint {
|
||||
//on OS X, the primary monitor is always the first monitor
|
||||
//on macOS, the primary monitor is always the first monitor
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pMonitor::workspace(uint monitor) -> Geometry {
|
||||
@autoreleasepool {
|
||||
NSRect size = [[[NSScreen screens] objectAtIndex:monitor] frame];
|
||||
NSRect area = [[[NSScreen screens] objectAtIndex:monitor] visibleFrame];
|
||||
return {
|
||||
(int)area.origin.x,
|
||||
(int)area.origin.y,
|
||||
(int)area.size.width,
|
||||
(int)area.size.height
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@ struct pMonitor {
|
|||
static auto dpi(uint monitor) -> Position;
|
||||
static auto geometry(uint monitor) -> Geometry;
|
||||
static auto primary() -> uint;
|
||||
static auto workspace(uint monitor) -> Geometry;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
namespace hiro {
|
||||
struct pFont;
|
||||
struct pWindow;
|
||||
struct pMenu;
|
||||
struct pLayout;
|
||||
struct pWidget;
|
||||
}
|
||||
|
||||
#define Declare(Name, Base) \
|
||||
p##Name(m##Name& reference) : p##Base(reference) {} \
|
||||
auto self() const -> m##Name& { return (m##Name&)reference; } \
|
||||
|
|
|
@ -39,14 +39,14 @@ auto pFrame::remove(sSizable sizable) -> void {
|
|||
|
||||
auto pFrame::setEnabled(bool enabled) -> void {
|
||||
pWidget::setEnabled(enabled);
|
||||
if(auto& sizable = _sizable()) sizable->setEnabled(sizable->self().enabled(true));
|
||||
if(auto sizable = _sizable()) sizable->setEnabled(sizable->self().enabled(true));
|
||||
}
|
||||
|
||||
auto pFrame::setFont(const Font& font) -> void {
|
||||
@autoreleasepool {
|
||||
[cocoaView setTitleFont:pFont::create(font)];
|
||||
}
|
||||
if(auto& sizable = _sizable()) sizable->setFont(sizable->self().font(true));
|
||||
if(auto sizable = _sizable()) sizable->setFont(sizable->self().font(true));
|
||||
}
|
||||
|
||||
auto pFrame::setGeometry(Geometry geometry) -> void {
|
||||
|
@ -56,7 +56,7 @@ auto pFrame::setGeometry(Geometry geometry) -> void {
|
|||
geometry.x() - 3, geometry.y() - (empty ? size.height() - 2 : 1),
|
||||
geometry.width() + 6, geometry.height() + (empty ? size.height() + 2 : 5)
|
||||
});
|
||||
if(auto& sizable = state().sizable) {
|
||||
if(auto sizable = _sizable()) {
|
||||
sizable->setGeometry({
|
||||
geometry.x() + 1, geometry.y() + (empty ? 1 : size.height() - 2),
|
||||
geometry.width() - 2, geometry.height() - (empty ? 1 : size.height() - 1)
|
||||
|
@ -72,14 +72,14 @@ auto pFrame::setText(const string& text) -> void {
|
|||
|
||||
auto pFrame::setVisible(bool visible) -> void {
|
||||
pWidget::setVisible(visible);
|
||||
if(auto& sizable = _sizable()) sizable->setVisible(sizable->self().visible(true));
|
||||
if(auto sizable = _sizable()) sizable->setVisible(sizable->self().visible(true));
|
||||
}
|
||||
|
||||
auto pFrame::_sizable() -> maybe<pSizable&> {
|
||||
if(auto sizable = state().sizable) {
|
||||
if(auto self = sizable->self()) return *self;
|
||||
}
|
||||
return nothing;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
}
|
||||
|
||||
-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
|
||||
tabFrame->self()->_synchronizeLayout();
|
||||
tabFrame->self()->_synchronizeSizable();
|
||||
tabFrame->doChange();
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,8 @@ auto pTabFrame::remove(sTabFrameItem item) -> void {
|
|||
auto pTabFrame::setEnabled(bool enabled) -> void {
|
||||
pWidget::setEnabled(enabled);
|
||||
for(auto& item : state().items) {
|
||||
if(auto& layout = item->state.layout) {
|
||||
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) self->setEnabled(sizable->enabled(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,8 +113,8 @@ auto pTabFrame::setEnabled(bool enabled) -> void {
|
|||
auto pTabFrame::setFont(const Font& font) -> void {
|
||||
pWidget::setFont(font);
|
||||
for(auto& item : state().items) {
|
||||
if(auto& layout = item->state.layout) {
|
||||
if(auto self = layout->self()) self->setFont(layout->font(true));
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) self->setFont(sizable->font(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,11 +129,11 @@ auto pTabFrame::setGeometry(Geometry geometry) -> void {
|
|||
geometry.width() - 2, geometry.height() - 32
|
||||
});
|
||||
for(auto& item : state().items) {
|
||||
if(auto& layout = item->state.layout) {
|
||||
layout->setGeometry(geometry);
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
sizable->setGeometry(geometry);
|
||||
}
|
||||
}
|
||||
_synchronizeLayout();
|
||||
_synchronizeSizable();
|
||||
}
|
||||
|
||||
auto pTabFrame::setNavigation(Navigation navigation) -> void {
|
||||
|
@ -142,20 +142,20 @@ auto pTabFrame::setNavigation(Navigation navigation) -> void {
|
|||
auto pTabFrame::setVisible(bool visible) -> void {
|
||||
pWidget::setVisible(visible);
|
||||
for(auto& item : state().items) {
|
||||
if(auto& layout = item->state.layout) {
|
||||
if(auto self = layout->self()) self->setVisible(layout->visible(true));
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) self->setVisible(sizable->visible(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pTabFrame::_synchronizeLayout() -> void {
|
||||
auto pTabFrame::_synchronizeSizable() -> void {
|
||||
@autoreleasepool {
|
||||
NSTabViewItem* tabViewItem = [cocoaView selectedTabViewItem];
|
||||
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
|
||||
for(auto& item : state().items) {
|
||||
item->state.selected = item->offset() == selected;
|
||||
if(auto& layout = item->state.layout) {
|
||||
if(auto self = layout->self()) self->setVisible(layout->visible(true) && item->selected());
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) self->setVisible(sizable->visible(true) && item->selected());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ struct pTabFrame : pWidget {
|
|||
auto setNavigation(Navigation navigation) -> void;
|
||||
auto setVisible(bool visible) -> void override;
|
||||
|
||||
auto _synchronizeLayout() -> void;
|
||||
auto _synchronizeSizable() -> void;
|
||||
|
||||
CocoaTabFrame* cocoaTabFrame = nullptr;
|
||||
vector<CocoaTabFrameItem*> tabs;
|
||||
|
|
|
@ -406,7 +406,7 @@ auto pTableView::_width(uint column) -> uint {
|
|||
uint width = 1;
|
||||
if(!header->column(column).visible()) return width;
|
||||
if(header->visible()) width = max(width, _columnWidth(column));
|
||||
for(auto row : range(state().items)) {
|
||||
for(auto row : range(state().items.size())) {
|
||||
width = max(width, _cellWidth(row, column));
|
||||
}
|
||||
return width;
|
||||
|
|
|
@ -217,7 +217,7 @@ auto pWindow::append(sMenuBar menuBar) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::append(sSizable sizable) -> void {
|
||||
layout->setGeometry(self().geometry().setPosition(0, 0));
|
||||
sizable->setGeometry(self().geometry().setPosition());
|
||||
statusBarReposition();
|
||||
}
|
||||
|
||||
|
@ -320,8 +320,8 @@ auto pWindow::setGeometry(Geometry geometry) -> void {
|
|||
display:YES
|
||||
];
|
||||
|
||||
if(auto& layout = state().layout) {
|
||||
layout->setGeometry(self().geometry().setPosition(0, 0));
|
||||
if(auto& sizable = state().sizable) {
|
||||
sizable->setGeometry(self().geometry().setPosition());
|
||||
}
|
||||
|
||||
statusBarReposition();
|
||||
|
@ -402,8 +402,8 @@ auto pWindow::sizeEvent() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
if(auto& layout = state().layout) {
|
||||
layout->setGeometry(self().geometry().setPosition(0, 0));
|
||||
if(auto& sizable = state().sizable) {
|
||||
sizable->setGeometry(self().geometry().setPosition());
|
||||
}
|
||||
|
||||
statusBarReposition();
|
||||
|
|
|
@ -10,6 +10,10 @@ auto Application::font() -> Font {
|
|||
return state.font;
|
||||
}
|
||||
|
||||
auto Application::locale() -> Locale& {
|
||||
return state.locale;
|
||||
}
|
||||
|
||||
auto Application::modal() -> bool {
|
||||
return state.modal > 0;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <nall/directory.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/image.hpp>
|
||||
#include <nall/locale.hpp>
|
||||
#include <nall/maybe.hpp>
|
||||
#include <nall/path.hpp>
|
||||
#include <nall/range.hpp>
|
||||
|
@ -16,6 +17,7 @@
|
|||
|
||||
using nall::function;
|
||||
using nall::image;
|
||||
using nall::Locale;
|
||||
using nall::maybe;
|
||||
using nall::nothing;
|
||||
using nall::set;
|
||||
|
@ -373,6 +375,7 @@ struct Application {
|
|||
|
||||
static auto doMain() -> void;
|
||||
static auto font() -> Font;
|
||||
static auto locale() -> Locale&;
|
||||
static auto modal() -> bool;
|
||||
static auto name() -> string;
|
||||
static auto onMain(const function<void ()>& callback = {}) -> void;
|
||||
|
@ -405,9 +408,14 @@ struct Application {
|
|||
static auto onQuit(const function<void ()>& callback = {}) -> void;
|
||||
};
|
||||
|
||||
struct Namespace : Locale::Namespace {
|
||||
Namespace(const string& value) : Locale::Namespace(Application::locale(), value) {}
|
||||
};
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
Font font;
|
||||
Locale locale;
|
||||
int modal = 0;
|
||||
string name;
|
||||
function<void ()> onMain;
|
||||
|
|
|
@ -3,16 +3,50 @@
|
|||
//shared functionality used for pObject on all platforms
|
||||
|
||||
struct mLock {
|
||||
auto locked() const -> bool { return locks || Application::state.quit; }
|
||||
auto lock() -> void { ++locks; }
|
||||
auto unlock() -> void { --locks; }
|
||||
|
||||
struct Handle {
|
||||
Handle(const mLock& self) : self(self) { ++self.locks; }
|
||||
~Handle() { --self.locks; }
|
||||
const mLock& self;
|
||||
Handle(const mLock* self) : self(self) {
|
||||
if(self) {
|
||||
++self->locks;
|
||||
}
|
||||
}
|
||||
|
||||
~Handle() {
|
||||
release();
|
||||
}
|
||||
|
||||
auto release() -> bool {
|
||||
if(self) {
|
||||
--self->locks;
|
||||
self = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const mLock* self = nullptr;
|
||||
};
|
||||
auto acquire() const -> Handle { return {*this}; }
|
||||
|
||||
auto acquired() const -> bool {
|
||||
return locks || Application::state.quit;
|
||||
}
|
||||
|
||||
auto acquire() const -> Handle {
|
||||
return {this};
|
||||
}
|
||||
|
||||
//deprecated C-style manual functions
|
||||
//prefer RAII acquire() functionality instead in newly written code
|
||||
auto locked() const -> bool {
|
||||
return acquired();
|
||||
}
|
||||
|
||||
auto lock() -> void {
|
||||
++locks;
|
||||
}
|
||||
|
||||
auto unlock() -> void {
|
||||
--locks;
|
||||
}
|
||||
|
||||
mutable int locks = 0;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#if defined(Hiro_BrowserDialog)
|
||||
|
||||
struct BrowserDialogWindow {
|
||||
Application::Namespace tr{"BrowserDialog"};
|
||||
|
||||
BrowserDialogWindow(BrowserDialog::State& state) : state(state) {}
|
||||
auto accept() -> void;
|
||||
auto activate() -> void;
|
||||
|
@ -171,10 +173,10 @@ auto BrowserDialogWindow::run() -> BrowserDialog::Response {
|
|||
fileName.setBackgroundColor(acceptButton.enabled() ? Color{} : Color{255, 224, 224});
|
||||
});
|
||||
acceptButton.onActivate([&] { accept(); });
|
||||
if(state.action.beginsWith("open")) acceptButton.setText("Open");
|
||||
if(state.action.beginsWith("save")) acceptButton.setText("Save");
|
||||
if(state.action.beginsWith("select")) acceptButton.setText("Select");
|
||||
cancelButton.setText("Cancel").onActivate([&] { window.setModal(false); });
|
||||
if(state.action.beginsWith("open")) acceptButton.setText(tr("Open"));
|
||||
if(state.action.beginsWith("save")) acceptButton.setText(tr("Save"));
|
||||
if(state.action.beginsWith("select")) acceptButton.setText(tr("Select"));
|
||||
cancelButton.setText(tr("Cancel")).onActivate([&] { window.setModal(false); });
|
||||
|
||||
if(!state.filters) state.filters.append("All|*");
|
||||
for(auto& filter : state.filters) {
|
||||
|
|
|
@ -129,7 +129,7 @@ auto mFixedLayoutCell::setVisible(bool visible) -> type& {
|
|||
}
|
||||
|
||||
auto mFixedLayoutCell::sizable() const -> Sizable {
|
||||
return state.sizable;
|
||||
return state.sizable ? state.sizable : Sizable();
|
||||
}
|
||||
|
||||
auto mFixedLayoutCell::synchronize() -> type& {
|
||||
|
|
|
@ -99,8 +99,6 @@ auto mHorizontalLayout::setFont(const Font& font) -> type& {
|
|||
|
||||
auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
|
||||
mSizable::setGeometry(geometry);
|
||||
auto window = parentWindow(true);
|
||||
if(!window || !window->visible()) return *this;
|
||||
|
||||
geometry.setX(geometry.x() + padding().x());
|
||||
geometry.setY(geometry.y() + padding().y());
|
||||
|
@ -259,7 +257,7 @@ auto mHorizontalLayoutCell::setVisible(bool visible) -> type& {
|
|||
}
|
||||
|
||||
auto mHorizontalLayoutCell::sizable() const -> Sizable {
|
||||
return state.sizable;
|
||||
return state.sizable ? state.sizable : Sizable();
|
||||
}
|
||||
|
||||
auto mHorizontalLayoutCell::size() const -> Size {
|
||||
|
|
|
@ -44,6 +44,8 @@ auto MessageDialog::warning(const string_vector& buttons) -> string {
|
|||
}
|
||||
|
||||
auto MessageDialog::_run() -> string {
|
||||
Application::Namespace tr{"MessageDialog"};
|
||||
|
||||
Window window;
|
||||
VerticalLayout layout{&window};
|
||||
HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5};
|
||||
|
@ -57,14 +59,17 @@ auto MessageDialog::_run() -> string {
|
|||
messageText.setText(state.text);
|
||||
for(auto n : range(state.buttons.size())) {
|
||||
Button button{&controlLayout, Size{80, 0}, 5};
|
||||
button.onActivate([&, n] { state.response = state.buttons[n]; window.setModal(false); });
|
||||
button.setText(state.buttons[n]);
|
||||
button.onActivate([&, n] {
|
||||
state.response = state.buttons[n];
|
||||
window.setModal(false);
|
||||
});
|
||||
button.setText(tr(state.buttons[n]));
|
||||
button.setFocused(); //the last button will have effective focus
|
||||
}
|
||||
|
||||
signed widthMessage = 5 + 16 + 5 + Font().size(state.text).width() + 5;
|
||||
signed widthButtons = 5 + state.buttons.size() * 85;
|
||||
signed width = max(320, widthMessage, widthButtons);
|
||||
int widthMessage = 5 + 16 + 5 + Font().size(state.text).width() + 5;
|
||||
int widthButtons = 5 + state.buttons.size() * 85;
|
||||
int width = max(320, widthMessage, widthButtons);
|
||||
|
||||
window.onClose([&] { window.setModal(false); });
|
||||
window.setTitle(state.title);
|
||||
|
|
|
@ -134,8 +134,6 @@ auto mTableLayout::setFont(const Font& font) -> type& {
|
|||
|
||||
auto mTableLayout::setGeometry(Geometry geometry) -> type& {
|
||||
mSizable::setGeometry(geometry);
|
||||
auto window = parentWindow(true);
|
||||
if(!window || !window->visible()) return *this;
|
||||
|
||||
geometry.setX(geometry.x() + padding().x());
|
||||
geometry.setY(geometry.y() + padding().y());
|
||||
|
@ -394,7 +392,7 @@ auto mTableLayoutCell::setVisible(bool visible) -> type& {
|
|||
}
|
||||
|
||||
auto mTableLayoutCell::sizable() const -> Sizable {
|
||||
return state.sizable;
|
||||
return state.sizable ? state.sizable : Sizable();
|
||||
}
|
||||
|
||||
auto mTableLayoutCell::size() const -> Size {
|
||||
|
|
|
@ -109,8 +109,6 @@ auto mVerticalLayout::setFont(const Font& font) -> type& {
|
|||
|
||||
auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
|
||||
mSizable::setGeometry(geometry);
|
||||
auto window = parentWindow(true);
|
||||
if(!window || !window->visible()) return *this;
|
||||
|
||||
geometry.setX(geometry.x() + padding().x());
|
||||
geometry.setY(geometry.y() + padding().y());
|
||||
|
@ -269,7 +267,7 @@ auto mVerticalLayoutCell::setVisible(bool visible) -> type& {
|
|||
}
|
||||
|
||||
auto mVerticalLayoutCell::sizable() const -> Sizable {
|
||||
return state.sizable;
|
||||
return state.sizable ? state.sizable : Sizable();
|
||||
}
|
||||
|
||||
auto mVerticalLayoutCell::size() const -> Size {
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
namespace hiro {
|
||||
struct pWindow;
|
||||
struct pMenu;
|
||||
struct pLayout;
|
||||
struct pWidget;
|
||||
}
|
||||
|
||||
#define Declare(Name, Base) \
|
||||
p##Name(m##Name& reference) : p##Base(reference) {} \
|
||||
auto self() const -> m##Name& { return (m##Name&)reference; } \
|
||||
|
|
|
@ -39,6 +39,7 @@ auto pFrame::setFont(const Font& font) -> void {
|
|||
}
|
||||
|
||||
auto pFrame::setGeometry(Geometry geometry) -> void {
|
||||
pWidget::setGeometry(geometry);
|
||||
if(auto& sizable = state().sizable) {
|
||||
Size size = pFont::size(self().font(true), state().text);
|
||||
if(!state().text) size.setHeight(10);
|
||||
|
|
|
@ -2,6 +2,50 @@
|
|||
|
||||
namespace hiro {
|
||||
|
||||
static auto Label_draw(GtkWidget* widget, cairo_t* context, pLabel* p) -> int {
|
||||
auto color = p->state().backgroundColor;
|
||||
if(auto window = p->self().parentWindow(true)) {
|
||||
if(!color) color = window->backgroundColor();
|
||||
}
|
||||
|
||||
if(color) {
|
||||
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())
|
||||
&& gdk_screen_get_rgba_visual(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);
|
||||
} else {
|
||||
#if HIRO_GTK==3
|
||||
auto style = gtk_widget_get_style_context(widget);
|
||||
if(auto tabFrame = p->self().parentTabFrame(true)) {
|
||||
if(auto self = tabFrame->self()) style = gtk_widget_get_style_context(self->gtkWidget);
|
||||
}
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(widget, &allocation);
|
||||
gtk_render_background(style, context, 0, 0, allocation.width, allocation.height);
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto Label_expose(GtkWidget* widget, GdkEvent* event, pLabel* p) -> int {
|
||||
cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget));
|
||||
Label_draw(widget, context, p);
|
||||
cairo_destroy(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pLabel::construct() -> void {
|
||||
gtkWidget = gtk_event_box_new();
|
||||
subWidget = gtk_label_new("");
|
||||
|
@ -13,6 +57,12 @@ auto pLabel::construct() -> void {
|
|||
setForegroundColor(state().foregroundColor);
|
||||
setText(state().text);
|
||||
|
||||
#if HIRO_GTK==2
|
||||
g_signal_connect(G_OBJECT(subWidget), "expose-event", G_CALLBACK(Label_expose), (gpointer)this);
|
||||
#elif HIRO_GTK==3
|
||||
g_signal_connect(G_OBJECT(subWidget), "draw", G_CALLBACK(Label_draw), (gpointer)this);
|
||||
#endif
|
||||
|
||||
pWidget::construct();
|
||||
}
|
||||
|
||||
|
@ -36,9 +86,9 @@ auto pLabel::setAlignment(Alignment alignment) -> void {
|
|||
}
|
||||
|
||||
auto pLabel::setBackgroundColor(Color color) -> void {
|
||||
if(!color) color = self().parentWindow(true)->backgroundColor();
|
||||
auto gdkColor = CreateColor(color);
|
||||
gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
|
||||
//GTK3 will paint the wrong background color when a label is inside of a TabFrame
|
||||
//this is caused by the GtkEventBox wrapper that is required to paint custom backgrounds
|
||||
//handle background painting via "draw" or "expose-event" signals instead
|
||||
}
|
||||
|
||||
auto pLabel::setForegroundColor(Color color) -> void {
|
||||
|
|
|
@ -157,8 +157,7 @@ auto pTabFrame::setFont(const Font& font) -> void {
|
|||
|
||||
auto pTabFrame::setGeometry(Geometry geometry) -> void {
|
||||
pWidget::setGeometry(geometry);
|
||||
|
||||
geometry.setPosition(0, 0);
|
||||
geometry.setPosition();
|
||||
if(state().navigation == Navigation::Top || state().navigation == Navigation::Bottom) {
|
||||
geometry.setWidth(geometry.width() - 6);
|
||||
geometry.setHeight(geometry.height() - (15 + _tabHeight()));
|
||||
|
|
|
@ -66,7 +66,7 @@ GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void {
|
|||
static auto Window_getPreferredWidth(GtkWidget* widget, int* minimalWidth, int* naturalWidth) -> void {
|
||||
if(auto p = (pWindow*)g_object_get_data(G_OBJECT(widget), "hiro::window")) {
|
||||
*minimalWidth = 1;
|
||||
*naturalWidth = 1; //p->state().geometry.width();
|
||||
*naturalWidth = p->state().geometry.width();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ static auto Window_sizeRequest(GtkWidget* widget, GtkRequisition* requisition, p
|
|||
static auto Window_stateEvent(GtkWidget* widget, GdkEvent* event, pWindow* p) -> void {
|
||||
p->_synchronizeState();
|
||||
|
||||
/*if(event->type == GDK_WINDOW_STATE) {
|
||||
if(event->type == GDK_WINDOW_STATE) {
|
||||
auto windowStateEvent = (GdkEventWindowState*)event;
|
||||
if(windowStateEvent->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
|
||||
p->state().maximized = windowStateEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED;
|
||||
|
@ -122,7 +122,7 @@ static auto Window_stateEvent(GtkWidget* widget, GdkEvent* event, pWindow* p) ->
|
|||
if(windowStateEvent->changed_mask & GDK_WINDOW_STATE_ICONIFIED) {
|
||||
p->state().minimized = windowStateEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
auto pWindow::construct() -> void {
|
||||
|
@ -191,7 +191,7 @@ auto pWindow::construct() -> void {
|
|||
g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)this);
|
||||
#elif HIRO_GTK==3
|
||||
auto widgetClass = GTK_WIDGET_GET_CLASS(formContainer);
|
||||
widgetClass->get_preferred_width = Window_getPreferredWidth;
|
||||
widgetClass->get_preferred_width = Window_getPreferredWidth;
|
||||
widgetClass->get_preferred_height = Window_getPreferredHeight;
|
||||
#endif
|
||||
g_signal_connect(G_OBJECT(widget), "window-state-event", G_CALLBACK(Window_stateEvent), (gpointer)this);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef HIRO_CPP
|
||||
#define HIRO_CPP
|
||||
|
||||
#define foreach(T, ...) ([&] { for(auto& $ : T) { __VA_ARGS__; }}())
|
||||
|
||||
#include "components.hpp"
|
||||
#include "core/core.cpp"
|
||||
#include "extension/extension.cpp"
|
||||
|
|
|
@ -23,6 +23,7 @@ auto pMenuRadioItem::construct() -> void {
|
|||
}
|
||||
|
||||
auto pMenuRadioItem::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtMenuRadioItem;
|
||||
delete qtActionGroup;
|
||||
qtMenuRadioItem = nullptr;
|
||||
|
@ -47,6 +48,7 @@ auto pMenuRadioItem::setGroup(sGroup group) -> void {
|
|||
}
|
||||
}
|
||||
}
|
||||
_setState();
|
||||
}
|
||||
|
||||
auto pMenuRadioItem::setText(const string& text) -> void {
|
||||
|
|
|
@ -23,6 +23,7 @@ auto pMenu::construct() -> void {
|
|||
}
|
||||
|
||||
auto pMenu::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtMenu;
|
||||
qtMenu = nullptr;
|
||||
}
|
||||
|
|
|
@ -38,12 +38,10 @@
|
|||
#include "widget/check-label.cpp"
|
||||
#include "widget/combo-button.cpp"
|
||||
#include "widget/combo-button-item.cpp"
|
||||
#include "widget/console.cpp"
|
||||
#include "widget/frame.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroll-bar.cpp"
|
||||
#include "widget/horizontal-slider.cpp"
|
||||
#include "widget/icon-view.cpp"
|
||||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.cpp"
|
||||
#include "widget/progress-bar.cpp"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "settings.hpp"
|
||||
|
||||
#define Declare(Name, Base) \
|
||||
p##Name(m##Name& reference) : p##Base(reference) {} \
|
||||
auto self() const -> m##Name& { return (m##Name&)reference; } \
|
||||
|
@ -8,6 +6,7 @@
|
|||
auto destruct() -> void override; \
|
||||
|
||||
#include "application.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "font.hpp"
|
||||
#include "desktop.hpp"
|
||||
#include "monitor.hpp"
|
||||
|
|
|
@ -15,6 +15,10 @@ static auto CreateBrush(Color color) -> QBrush {
|
|||
return color ? QColor(color.red(), color.green(), color.blue()) : QBrush();
|
||||
}
|
||||
|
||||
static auto CreateColor(Color color, QColor fallback = {}) -> QColor {
|
||||
return color ? QColor(color.red(), color.green(), color.blue()) : fallback;
|
||||
}
|
||||
|
||||
static auto CreateIcon(const image& icon, bool scale = false) -> QIcon {
|
||||
if(!icon) return QIcon();
|
||||
auto qtBuffer = icon;
|
||||
|
|
|
@ -18,7 +18,7 @@ auto pCanvas::destruct() -> void {
|
|||
}
|
||||
|
||||
auto pCanvas::minimumSize() const -> Size {
|
||||
if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()};
|
||||
if(auto& icon = state().icon) return {icon.width(), icon.height()};
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ auto pComboButton::construct() -> void {
|
|||
}
|
||||
|
||||
auto pComboButton::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtComboButton;
|
||||
qtWidget = qtComboButton = nullptr;
|
||||
}
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
#if defined(Hiro_Console)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
void pConsole::print(string text) {
|
||||
}
|
||||
|
||||
void pConsole::reset() {
|
||||
}
|
||||
|
||||
void pConsole::setBackgroundColor(Color color) {
|
||||
QPalette palette = qtConsole->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue));
|
||||
qtConsole->setPalette(palette);
|
||||
qtConsole->setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
void pConsole::setForegroundColor(Color color) {
|
||||
QPalette palette = qtConsole->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue));
|
||||
qtConsole->setPalette(palette);
|
||||
}
|
||||
|
||||
void pConsole::setPrompt(string prompt) {
|
||||
}
|
||||
|
||||
void pConsole::constructor() {
|
||||
qtWidget = qtConsole = new QtConsole(*this);
|
||||
|
||||
pWidget::synchronizeState();
|
||||
}
|
||||
|
||||
void pConsole::destructor() {
|
||||
delete qtConsole;
|
||||
qtWidget = qtConsole = nullptr;
|
||||
}
|
||||
|
||||
void pConsole::orphan() {
|
||||
destructor();
|
||||
constructor();
|
||||
}
|
||||
|
||||
void pConsole::keyPressEvent(QKeyEvent* event) {
|
||||
}
|
||||
|
||||
void pConsole::QtConsole::keyPressEvent(QKeyEvent* event) {
|
||||
self.keyPressEvent(event);
|
||||
}
|
||||
|
||||
void pConsole::QtConsole::keyPressEventAcknowledge(QKeyEvent* event) {
|
||||
QTextEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -22,6 +22,8 @@ auto pHexEdit::construct() -> void {
|
|||
qtScrollBar->connect(qtScrollBar, SIGNAL(actionTriggered(int)), SLOT(onScroll()));
|
||||
|
||||
pWidget::construct();
|
||||
setBackgroundColor(state().backgroundColor);
|
||||
setForegroundColor(state().foregroundColor);
|
||||
_setState();
|
||||
}
|
||||
|
||||
|
@ -39,7 +41,12 @@ auto pHexEdit::setAddress(unsigned address) -> void {
|
|||
}
|
||||
|
||||
auto pHexEdit::setBackgroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtHexEdit->palette().color(QPalette::Base);
|
||||
|
||||
auto palette = qtHexEdit->palette();
|
||||
palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
|
||||
qtHexEdit->setPalette(palette);
|
||||
qtHexEdit->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
auto pHexEdit::setColumns(unsigned columns) -> void {
|
||||
|
@ -47,7 +54,11 @@ auto pHexEdit::setColumns(unsigned columns) -> void {
|
|||
}
|
||||
|
||||
auto pHexEdit::setForegroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtHexEdit->palette().color(QPalette::Text);
|
||||
|
||||
auto palette = qtHexEdit->palette();
|
||||
palette.setColor(QPalette::Text, color ? CreateColor(color) : defaultColor);
|
||||
qtHexEdit->setPalette(palette);
|
||||
}
|
||||
|
||||
auto pHexEdit::setLength(unsigned length) -> void {
|
||||
|
@ -242,29 +253,13 @@ auto pHexEdit::_scrollTo(signed position) -> void {
|
|||
}
|
||||
|
||||
auto pHexEdit::_setState() -> void {
|
||||
lock();
|
||||
if(auto color = state().backgroundColor) {
|
||||
QPalette palette = qtHexEdit->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue()));
|
||||
qtHexEdit->setPalette(palette);
|
||||
qtHexEdit->setAutoFillBackground(true);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
if(auto color = state().foregroundColor) {
|
||||
QPalette palette = qtHexEdit->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue()));
|
||||
qtHexEdit->setPalette(palette);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
auto lock = acquire();
|
||||
//add one if last row is not equal to column length (eg only part of the row is present)
|
||||
bool indivisible = state().columns == 0 || (state().length % state().columns) != 0;
|
||||
qtScrollBar->setRange(0, state().length / state().columns + indivisible - state().rows);
|
||||
qtScrollBar->setSliderPosition(state().address / state().columns);
|
||||
qtScrollBar->setPageStep(state().rows);
|
||||
update();
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto QtHexEdit::keyPressEvent(QKeyEvent* event) -> void {
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
#if defined(Hiro_IconView)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
void pIconView::append() {
|
||||
lock();
|
||||
auto item = new QListWidgetItem(qtIconView);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::remove(unsigned selection) {
|
||||
lock();
|
||||
if(auto item = qtIconView->item(selection)) {
|
||||
delete item;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::reset() {
|
||||
lock();
|
||||
qtIconView->clear();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::setBackgroundColor(Color color) {
|
||||
QPalette palette = qtIconView->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red, color.green, color.blue));
|
||||
qtIconView->setPalette(palette);
|
||||
qtIconView->setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
void pIconView::setFlow(Orientation flow) {
|
||||
qtIconView->setFlow(flow == Orientation::Horizontal ? QListView::LeftToRight : QListView::TopToBottom);
|
||||
qtIconView->resize(qtIconView->size()); //adjust visibility of scroll bars
|
||||
}
|
||||
|
||||
void pIconView::setForegroundColor(Color color) {
|
||||
QPalette palette = qtIconView->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red, color.green, color.blue));
|
||||
qtIconView->setPalette(palette);
|
||||
}
|
||||
|
||||
void pIconView::setImage(unsigned selection, const image& image) {
|
||||
if(auto item = qtIconView->item(selection)) {
|
||||
item->setIcon(CreateIcon(image));
|
||||
}
|
||||
}
|
||||
|
||||
void pIconView::setOrientation(Orientation orientation) {
|
||||
qtIconView->setViewMode(orientation == Orientation::Horizontal ? QListView::ListMode : QListView::IconMode);
|
||||
qtIconView->setWrapping(true);
|
||||
}
|
||||
|
||||
void pIconView::setSelected(unsigned selection, bool selected) {
|
||||
lock();
|
||||
if(auto item = qtIconView->item(selection)) {
|
||||
item->setSelected(selected);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::setSelected(const vector<unsigned>& selections) {
|
||||
lock();
|
||||
qtIconView->clearSelection();
|
||||
for(auto& selection : selections) {
|
||||
if(auto item = qtIconView->item(selection)) {
|
||||
item->setSelected(true);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::setSelectedAll() {
|
||||
lock();
|
||||
qtIconView->selectAll();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::setSelectedNone() {
|
||||
lock();
|
||||
qtIconView->clearSelection();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void pIconView::setSingleSelection(bool singleSelection) {
|
||||
qtIconView->setSelectionMode(singleSelection ? QAbstractItemView::SingleSelection : QAbstractItemView::ExtendedSelection);
|
||||
}
|
||||
|
||||
void pIconView::setText(unsigned selection, const string& text) {
|
||||
if(auto item = qtIconView->item(selection)) {
|
||||
item->setText(QString::fromUtf8(text));
|
||||
}
|
||||
}
|
||||
|
||||
void pIconView::constructor() {
|
||||
qtWidget = qtIconView = new QtListWidget;
|
||||
qtIconView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
qtIconView->setMovement(QListView::Static);
|
||||
qtIconView->setResizeMode(QListView::Adjust);
|
||||
qtIconView->setSelectionRectVisible(true);
|
||||
qtIconView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
qtIconView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
connect(qtIconView, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(onActivate()));
|
||||
connect(qtIconView, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
|
||||
connect(qtIconView, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(onContext()));
|
||||
|
||||
setFlow(iconView.state.flow);
|
||||
setOrientation(iconView.state.orientation);
|
||||
setSingleSelection(iconView.state.singleSelection);
|
||||
}
|
||||
|
||||
void pIconView::destructor() {
|
||||
delete qtIconView;
|
||||
qtWidget = qtIconView = nullptr;
|
||||
}
|
||||
|
||||
void pIconView::orphan() {
|
||||
destructor();
|
||||
constructor();
|
||||
}
|
||||
|
||||
void pIconView::onActivate() {
|
||||
if(!locked() && iconView.onActivate) iconView.onActivate();
|
||||
}
|
||||
|
||||
void pIconView::onChange() {
|
||||
for(auto& selected : iconView.state.selected) selected = false;
|
||||
for(unsigned n = 0; n < qtIconView->count(); n++) {
|
||||
if(auto item = qtIconView->item(n)) {
|
||||
if(item->isSelected()) iconView.state.selected[n] = true;
|
||||
}
|
||||
}
|
||||
if(!locked() && iconView.onChange) iconView.onChange();
|
||||
}
|
||||
|
||||
void pIconView::onContext() {
|
||||
if(!locked() && iconView.onContext) iconView.onContext();
|
||||
}
|
||||
|
||||
void pIconView::QtListWidget::resizeEvent(QResizeEvent* event) {
|
||||
//Qt::ScrollBarAsNeeded results in the scroll bar area being reserved from the icon viewport even when scroll bar is hidden
|
||||
//this creates the appearance of an invisible gap that wastes precious screen space
|
||||
//below code simulates a Qt::ScrollBarAsNeeded which uses the extra space when the scroll bar is hidden
|
||||
setHorizontalScrollBarPolicy(horizontalScrollBar()->maximum() > horizontalScrollBar()->minimum() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(verticalScrollBar()->maximum() > verticalScrollBar()->minimum() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff);
|
||||
return QListWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -28,27 +28,20 @@ auto pLabel::setAlignment(Alignment alignment) -> void {
|
|||
}
|
||||
|
||||
auto pLabel::setBackgroundColor(Color color) -> void {
|
||||
if(!color) color = self().parentWindow(true)->backgroundColor();
|
||||
if(color) {
|
||||
QPalette palette = qtLabel->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue()));
|
||||
qtLabel->setBackgroundRole(QPalette::Base);
|
||||
qtLabel->setPalette(palette);
|
||||
qtLabel->setAutoFillBackground(true);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
static auto defaultColor = qtLabel->palette().color(QPalette::Base);
|
||||
|
||||
auto palette = qtLabel->palette();
|
||||
palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
|
||||
qtLabel->setPalette(palette);
|
||||
qtLabel->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
auto pLabel::setForegroundColor(Color color) -> void {
|
||||
if(color) {
|
||||
QPalette palette = qtLabel->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue()));
|
||||
qtLabel->setForegroundRole(QPalette::Text);
|
||||
qtLabel->setPalette(palette);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
static auto defaultColor = qtLabel->palette().color(QPalette::Text);
|
||||
|
||||
auto palette = qtLabel->palette();
|
||||
palette.setColor(QPalette::Text, CreateColor(color, defaultColor));
|
||||
qtLabel->setPalette(palette);
|
||||
}
|
||||
|
||||
auto pLabel::setText(const string& text) -> void {
|
||||
|
|
|
@ -8,7 +8,10 @@ auto pLineEdit::construct() -> void {
|
|||
qtLineEdit->connect(qtLineEdit, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
|
||||
|
||||
pWidget::construct();
|
||||
_setState();
|
||||
setBackgroundColor(state().backgroundColor);
|
||||
setEditable(state().editable);
|
||||
setForegroundColor(state().foregroundColor);
|
||||
setText(state().text);
|
||||
}
|
||||
|
||||
auto pLineEdit::destruct() -> void {
|
||||
|
@ -22,38 +25,27 @@ auto pLineEdit::minimumSize() const -> Size {
|
|||
}
|
||||
|
||||
auto pLineEdit::setBackgroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtLineEdit->palette().color(QPalette::Base);
|
||||
|
||||
auto palette = qtLineEdit->palette();
|
||||
palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
|
||||
qtLineEdit->setPalette(palette);
|
||||
qtLineEdit->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
auto pLineEdit::setEditable(bool editable) -> void {
|
||||
_setState();
|
||||
qtLineEdit->setReadOnly(!state().editable);
|
||||
}
|
||||
|
||||
auto pLineEdit::setForegroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtLineEdit->palette().color(QPalette::Text);
|
||||
|
||||
auto palette = qtLineEdit->palette();
|
||||
palette.setColor(QPalette::Text, CreateColor(color, defaultColor));
|
||||
qtLineEdit->setPalette(palette);
|
||||
}
|
||||
|
||||
auto pLineEdit::setText(const string& text) -> void {
|
||||
_setState();
|
||||
}
|
||||
|
||||
auto pLineEdit::_setState() -> void {
|
||||
if(auto color = state().backgroundColor) {
|
||||
QPalette palette = qtLineEdit->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue()));
|
||||
qtLineEdit->setPalette(palette);
|
||||
qtLineEdit->setAutoFillBackground(true);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
qtLineEdit->setReadOnly(!state().editable);
|
||||
if(auto color = state().foregroundColor) {
|
||||
QPalette palette = qtLineEdit->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue()));
|
||||
qtLineEdit->setPalette(palette);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
qtLineEdit->setText(QString::fromUtf8(state().text));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ struct pLineEdit : pWidget {
|
|||
auto setForegroundColor(Color color) -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
|
||||
auto _setState() -> void;
|
||||
|
||||
QtLineEdit* qtLineEdit = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ auto pTabFrameItem::setClosable(bool closable) -> void {
|
|||
auto pTabFrameItem::setGeometry(Geometry geometry) -> void {
|
||||
if(auto& sizable = state().sizable) {
|
||||
auto offset = qtTabFrameItem->geometry();
|
||||
geometry.setPosition({0, 0});
|
||||
geometry.setPosition();
|
||||
geometry.setWidth(geometry.width() - (geometry.width() - offset.width()));
|
||||
geometry.setHeight(geometry.height() - (geometry.height() - offset.height()));
|
||||
sizable->setGeometry(geometry);
|
||||
|
@ -72,7 +72,7 @@ auto pTabFrameItem::_setState() -> void {
|
|||
geometry.setWidth(geometry.width() - (geometry.width() - offset.width()));
|
||||
geometry.setHeight(geometry.height() - (geometry.height() - offset.height()));
|
||||
sizable->setGeometry(geometry);
|
||||
sizable->setVisible(sizable->visible(true));
|
||||
sizable->setVisible(sizable->visible());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ auto pTabFrame::construct() -> void {
|
|||
}
|
||||
|
||||
auto pTabFrame::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtTabFrame;
|
||||
qtWidget = qtTabFrame = nullptr;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ auto pTableViewItem::_parent() -> maybe<pTableView&> {
|
|||
|
||||
auto pTableViewItem::_setState() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
parent->lock();
|
||||
auto lock = parent->acquire();
|
||||
qtItem->setSelected(state().selected);
|
||||
if(state().selected) {
|
||||
parent->qtTableView->setCurrentItem(qtItem);
|
||||
|
|
|
@ -32,6 +32,7 @@ auto pTableView::construct() -> void {
|
|||
}
|
||||
|
||||
auto pTableView::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtTableViewDelegate;
|
||||
delete qtTableView;
|
||||
qtWidget = qtTableView = nullptr;
|
||||
|
@ -99,15 +100,13 @@ auto pTableView::setAlignment(Alignment alignment) -> void {
|
|||
}
|
||||
|
||||
auto pTableView::setBackgroundColor(Color color) -> void {
|
||||
if(color) {
|
||||
QPalette palette = qtTableView->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue()));
|
||||
palette.setColor(QPalette::AlternateBase, QColor(max(0, (signed)color.red() - 17), max(0, (signed)color.green() - 17), max(0, (signed)color.blue() - 17)));
|
||||
qtTableView->setPalette(palette);
|
||||
qtTableView->setAutoFillBackground(true);
|
||||
} else {
|
||||
//todo: set default color
|
||||
}
|
||||
//note: QPalette::AlternateBase can be used for alternating row colors
|
||||
static auto defaultColor = qtTableView->palette().color(QPalette::Base);
|
||||
|
||||
auto palette = qtTableView->palette();
|
||||
palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
|
||||
qtTableView->setPalette(palette);
|
||||
qtTableView->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
auto pTableView::setBatchable(bool batchable) -> void {
|
||||
|
@ -121,13 +120,12 @@ auto pTableView::setBordered(bool bordered) -> void {
|
|||
}
|
||||
|
||||
auto pTableView::setForegroundColor(Color color) -> void {
|
||||
if(color) {
|
||||
QPalette palette = qtTableView->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue()));
|
||||
qtTableView->setPalette(palette);
|
||||
} else {
|
||||
//todo: set default color
|
||||
}
|
||||
static auto defaultColor = qtTableView->palette().color(QPalette::Text);
|
||||
|
||||
auto palette = qtTableView->palette();
|
||||
palette.setColor(QPalette::Text, CreateColor(color, defaultColor));
|
||||
qtTableView->setPalette(palette);
|
||||
qtTableView->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
//called on resize/show events
|
||||
|
|
|
@ -7,16 +7,24 @@ auto pTextEdit::construct() -> void {
|
|||
qtTextEdit->connect(qtTextEdit, SIGNAL(textChanged()), SLOT(onChange()));
|
||||
|
||||
pWidget::construct();
|
||||
setBackgroundColor(state().backgroundColor);
|
||||
setForegroundColor(state().foregroundColor);
|
||||
_setState();
|
||||
}
|
||||
|
||||
auto pTextEdit::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtTextEdit;
|
||||
qtWidget = qtTextEdit = nullptr;
|
||||
}
|
||||
|
||||
auto pTextEdit::setBackgroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtTextEdit->palette().color(QPalette::Base);
|
||||
|
||||
auto palette = qtTextEdit->palette();
|
||||
palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
|
||||
qtTextEdit->setPalette(palette);
|
||||
qtTextEdit->setAutoFillBackground((bool)color);
|
||||
}
|
||||
|
||||
auto pTextEdit::setCursor(Cursor cursor) -> void {
|
||||
|
@ -28,7 +36,11 @@ auto pTextEdit::setEditable(bool editable) -> void {
|
|||
}
|
||||
|
||||
auto pTextEdit::setForegroundColor(Color color) -> void {
|
||||
_setState();
|
||||
static auto defaultColor = qtTextEdit->palette().color(QPalette::Text);
|
||||
|
||||
auto palette = qtTextEdit->palette();
|
||||
palette.setColor(QPalette::Text, CreateColor(color, defaultColor));
|
||||
qtTextEdit->setPalette(palette);
|
||||
}
|
||||
|
||||
auto pTextEdit::setText(const string& text) -> void {
|
||||
|
@ -44,14 +56,6 @@ auto pTextEdit::text() const -> string {
|
|||
}
|
||||
|
||||
auto pTextEdit::_setState() -> void {
|
||||
if(auto color = state().backgroundColor) {
|
||||
QPalette palette = qtTextEdit->palette();
|
||||
palette.setColor(QPalette::Base, QColor(color.red(), color.green(), color.blue()));
|
||||
qtTextEdit->setPalette(palette);
|
||||
qtTextEdit->setAutoFillBackground(true);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
QTextCursor cursor = qtTextEdit->textCursor();
|
||||
signed lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData());
|
||||
cursor.setPosition(max(0, min(lastCharacter, state().cursor.offset())));
|
||||
|
@ -61,13 +65,6 @@ auto pTextEdit::_setState() -> void {
|
|||
? Qt::TextEditorInteraction
|
||||
: Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse
|
||||
);
|
||||
if(auto color = state().foregroundColor) {
|
||||
QPalette palette = qtTextEdit->palette();
|
||||
palette.setColor(QPalette::Text, QColor(color.red(), color.green(), color.blue()));
|
||||
qtTextEdit->setPalette(palette);
|
||||
} else {
|
||||
//todo
|
||||
}
|
||||
qtTextEdit->setWordWrapMode(state().wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap);
|
||||
qtTextEdit->setHorizontalScrollBarPolicy(state().wordWrap ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAlwaysOn);
|
||||
qtTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
|
|
|
@ -44,6 +44,7 @@ auto pWindow::construct() -> void {
|
|||
}
|
||||
|
||||
auto pWindow::destruct() -> void {
|
||||
if(Application::state.quit) return; //TODO: hack
|
||||
delete qtStatusBar;
|
||||
delete qtContainer;
|
||||
delete qtMenuBar;
|
||||
|
@ -90,14 +91,14 @@ auto pWindow::remove(sStatusBar statusBar) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setBackgroundColor(Color color) -> void {
|
||||
if(color) {
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Background, QColor(color.red(), color.green(), color.blue() /*, color.alpha() */));
|
||||
qtContainer->setPalette(palette);
|
||||
qtContainer->setAutoFillBackground(true);
|
||||
//translucency results are very unpleasant without a compositor; so disable for now
|
||||
//qtWindow->setAttribute(Qt::WA_TranslucentBackground, color.alpha() != 255);
|
||||
}
|
||||
static auto defaultColor = qtContainer->palette().color(QPalette::Background);
|
||||
|
||||
auto palette = qtContainer->palette();
|
||||
palette.setColor(QPalette::Background, CreateColor(color, defaultColor));
|
||||
qtContainer->setPalette(palette);
|
||||
qtContainer->setAutoFillBackground((bool)color);
|
||||
//translucency results are very unpleasant without a compositor; so disable for now
|
||||
//qtWindow->setAttribute(Qt::WA_TranslucentBackground, color && color.alpha() != 255);
|
||||
}
|
||||
|
||||
auto pWindow::setDismissable(bool dismissable) -> void {
|
||||
|
@ -133,7 +134,7 @@ auto pWindow::setFullScreen(bool fullScreen) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setGeometry(Geometry geometry) -> void {
|
||||
lock();
|
||||
auto lock = acquire();
|
||||
Application::processEvents();
|
||||
#if HIRO_QT==4
|
||||
QApplication::syncX();
|
||||
|
@ -145,13 +146,14 @@ auto pWindow::setGeometry(Geometry geometry) -> void {
|
|||
qtWindow->move(geometry.x() - frameMargin().x(), geometry.y() - frameMargin().y());
|
||||
//qtWindow->adjustSize() fails if larger than 2/3rds screen size
|
||||
qtWindow->resize(qtWindow->sizeHint());
|
||||
qtContainer->setMinimumSize(1, 1);
|
||||
if(state().resizable) {
|
||||
//required to allow shrinking window from default size
|
||||
qtWindow->setMinimumSize(1, 1);
|
||||
qtContainer->setMinimumSize(1, 1);
|
||||
setMaximumSize(state().maximumSize);
|
||||
setMinimumSize(state().minimumSize);
|
||||
} else {
|
||||
setMaximumSize(geometry.size());
|
||||
setMinimumSize(geometry.size());
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pWindow::setMaximized(bool maximized) -> void {
|
||||
|
@ -159,7 +161,14 @@ auto pWindow::setMaximized(bool maximized) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setMaximumSize(Size size) -> void {
|
||||
//todo
|
||||
static auto maximumSize = qtWindow->maximumSize();
|
||||
|
||||
if(size) {
|
||||
//once this is called, no matter what the size is, Qt will no longer allow the window to be maximized
|
||||
qtWindow->setMaximumSize(size.width(), size.height() + _menuHeight() + _statusHeight());
|
||||
} else {
|
||||
qtWindow->setMaximumSize(maximumSize);
|
||||
}
|
||||
}
|
||||
|
||||
auto pWindow::setMinimized(bool minimized) -> void {
|
||||
|
@ -167,7 +176,7 @@ auto pWindow::setMinimized(bool minimized) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setMinimumSize(Size size) -> void {
|
||||
//todo
|
||||
qtWindow->setMinimumSize(size.width(), size.height() + _menuHeight() + _statusHeight());
|
||||
}
|
||||
|
||||
auto pWindow::setModal(bool modal) -> void {
|
||||
|
@ -200,7 +209,7 @@ auto pWindow::setResizable(bool resizable) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setTitle(const string& text) -> void {
|
||||
qtWindow->setWindowTitle(QString::fromUtf8(text));
|
||||
qtWindow->setWindowTitle(text ? QString::fromUtf8(text) : " ");
|
||||
}
|
||||
|
||||
auto pWindow::setVisible(bool visible) -> void {
|
||||
|
@ -220,8 +229,10 @@ auto pWindow::_append(mWidget& widget) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::_menuHeight() const -> uint {
|
||||
if(!qtMenuBar->isVisible()) return 0;
|
||||
return settings.geometry.menuHeight + _menuTextHeight();
|
||||
if(auto& menuBar = state().menuBar) {
|
||||
if(menuBar->visible()) return settings.geometry.menuHeight + _menuTextHeight();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pWindow::_menuTextHeight() const -> uint {
|
||||
|
@ -235,8 +246,10 @@ auto pWindow::_menuTextHeight() const -> uint {
|
|||
}
|
||||
|
||||
auto pWindow::_statusHeight() const -> uint {
|
||||
if(!qtStatusBar->isVisible()) return 0;
|
||||
return settings.geometry.statusHeight + _statusTextHeight();
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(statusBar->visible()) return settings.geometry.statusHeight + _statusTextHeight();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pWindow::_statusTextHeight() const -> uint {
|
||||
|
@ -314,7 +327,7 @@ auto QtWindow::keyReleaseEvent(QKeyEvent* event) -> void {
|
|||
//if(sym != Keyboard::Keycode::None && self.window.onKeyRelease) self.window.onKeyRelease(sym);
|
||||
}
|
||||
|
||||
auto QtWindow::resizeEvent(QResizeEvent*) -> void {
|
||||
auto QtWindow::resizeEvent(QResizeEvent* event) -> void {
|
||||
if(!p.locked() && !p.state().fullScreen && p.qtWindow->isVisible()) {
|
||||
p.state().geometry.setSize({
|
||||
p.qtContainer->geometry().width(),
|
||||
|
@ -334,8 +347,8 @@ auto QtWindow::resizeEvent(QResizeEvent*) -> void {
|
|||
auto QtWindow::sizeHint() const -> QSize {
|
||||
uint width = p.state().geometry.width();
|
||||
uint height = p.state().geometry.height();
|
||||
if(p.qtMenuBar->isVisible()) height += settings.geometry.menuHeight;
|
||||
if(p.qtStatusBar->isVisible()) height += settings.geometry.statusHeight;
|
||||
height += p._menuHeight();
|
||||
height += p._statusHeight();
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ auto pApplication::initialize() -> void {
|
|||
#endif
|
||||
|
||||
pKeyboard::initialize();
|
||||
pWindow::initialize();
|
||||
}
|
||||
|
||||
static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> bool {
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
namespace hiro {
|
||||
|
||||
struct pFont;
|
||||
struct pObject;
|
||||
struct pWindow;
|
||||
struct pMenu;
|
||||
struct pLayout;
|
||||
struct pWidget;
|
||||
|
||||
struct AppMessage {
|
||||
enum : uint {
|
||||
None = WM_APP,
|
||||
|
|
|
@ -6,37 +6,49 @@ auto pStatusBar::construct() -> void {
|
|||
if(auto parent = _parent()) {
|
||||
hwnd = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, parent->hwnd, nullptr, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
|
||||
setEnabled(self().enabled(true));
|
||||
setFont(self().font(true));
|
||||
setEnabled(self().enabled());
|
||||
setFont(self().font());
|
||||
setText(self().text());
|
||||
setVisible(self().visible(true));
|
||||
setVisible(self().visible());
|
||||
}
|
||||
}
|
||||
|
||||
auto pStatusBar::destruct() -> void {
|
||||
if(hfont) { DeleteObject(hfont); hfont = nullptr; }
|
||||
if(hwnd) { DestroyWindow(hwnd); hwnd = nullptr; }
|
||||
|
||||
if(auto parent = _parent()) {
|
||||
parent->setGeometry(parent->state().geometry);
|
||||
}
|
||||
}
|
||||
|
||||
auto pStatusBar::setEnabled(bool enabled) -> void {
|
||||
auto pStatusBar::setEnabled(bool) -> void {
|
||||
//unsupported
|
||||
}
|
||||
|
||||
auto pStatusBar::setFont(const Font& font) -> void {
|
||||
auto pStatusBar::setFont(const Font&) -> void {
|
||||
auto font = self().font(true);
|
||||
if(hfont) DeleteObject(hfont);
|
||||
hfont = pFont::create(font);
|
||||
if(hwnd) SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0);
|
||||
|
||||
auto& text = state().text;
|
||||
auto height = font.size(text ? text : " ").height();
|
||||
SendMessage(hwnd, SB_SETMINHEIGHT, (WPARAM)height, 0);
|
||||
|
||||
if(auto parent = _parent()) {
|
||||
parent->setGeometry(parent->state().geometry);
|
||||
}
|
||||
}
|
||||
|
||||
auto pStatusBar::setText(const string& text) -> void {
|
||||
if(hwnd) SendMessage(hwnd, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
auto pStatusBar::setText(const string&) -> void {
|
||||
auto& text = state().text;
|
||||
SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
}
|
||||
|
||||
auto pStatusBar::setVisible(bool visible) -> void {
|
||||
if(hwnd) ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE);
|
||||
auto pStatusBar::setVisible(bool) -> void {
|
||||
ShowWindow(hwnd, self().visible() ? SW_SHOWNORMAL : SW_HIDE);
|
||||
|
||||
if(auto parent = _parent()) {
|
||||
parent->setGeometry(parent->state().geometry);
|
||||
}
|
||||
|
@ -46,7 +58,7 @@ auto pStatusBar::_parent() -> maybe<pWindow&> {
|
|||
if(auto parent = self().parentWindow(true)) {
|
||||
if(auto self = parent->self()) return *self;
|
||||
}
|
||||
return nothing;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -219,6 +219,20 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms
|
|||
break;
|
||||
}
|
||||
|
||||
case WM_GETMINMAXINFO: {
|
||||
auto info = (LPMINMAXINFO)lparam;
|
||||
auto frameMargin = pWindow->frameMargin();
|
||||
if(auto minimumSize = window->state.minimumSize) {
|
||||
info->ptMinTrackSize.x = minimumSize.width() + frameMargin.width();
|
||||
info->ptMinTrackSize.y = minimumSize.height() + frameMargin.height();
|
||||
}
|
||||
if(auto maximumSize = window->state.maximumSize) {
|
||||
info->ptMaxTrackSize.x = maximumSize.width() + frameMargin.width();
|
||||
info->ptMaxTrackSize.y = maximumSize.height() + frameMargin.height();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MENUCOMMAND: {
|
||||
return Menu_windowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,19 @@ namespace hiro {
|
|||
static const uint FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN;
|
||||
static const uint ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN;
|
||||
|
||||
uint pWindow::minimumStatusHeight = 0;
|
||||
|
||||
auto pWindow::initialize() -> void {
|
||||
HWND hwnd = CreateWindow(L"hiroWindow", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0);
|
||||
HWND hstatus = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, hwnd, nullptr, GetModuleHandle(0), 0);
|
||||
SetWindowPos(hstatus, nullptr, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
RECT rc;
|
||||
GetWindowRect(hstatus, &rc);
|
||||
minimumStatusHeight = rc.bottom - rc.top;
|
||||
DestroyWindow(hstatus);
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
auto pWindow::construct() -> void {
|
||||
hwnd = CreateWindow(L"hiroWindow", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
|
||||
|
@ -35,21 +48,11 @@ auto pWindow::focused() const -> bool {
|
|||
}
|
||||
|
||||
auto pWindow::frameMargin() const -> Geometry {
|
||||
unsigned style = state().resizable ? ResizableStyle : FixedStyle;
|
||||
if(state().fullScreen) style = 0;
|
||||
RECT rc{0, 0, 640, 480};
|
||||
AdjustWindowRect(&rc, style, (bool)GetMenu(hwnd));
|
||||
signed statusHeight = 0;
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(auto self = statusBar->self()) {
|
||||
if(statusBar->visible()) {
|
||||
RECT src;
|
||||
GetClientRect(self->hwnd, &src);
|
||||
statusHeight = src.bottom - src.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + statusHeight - 480};
|
||||
uint style = state().fullScreen ? 0 : state().resizable ? ResizableStyle : FixedStyle;
|
||||
bool menuVisible = state().menuBar && state().menuBar->visible();
|
||||
AdjustWindowRect(&rc, style, menuVisible);
|
||||
return {abs(rc.left), abs(rc.top), (rc.right - rc.left) - 640, (rc.bottom - rc.top) + _statusHeight() - 480};
|
||||
}
|
||||
|
||||
auto pWindow::remove(sMenuBar menuBar) -> void {
|
||||
|
@ -183,14 +186,9 @@ auto pWindow::setTitle(string text) -> void {
|
|||
}
|
||||
|
||||
auto pWindow::setVisible(bool visible) -> void {
|
||||
lock();
|
||||
auto lock = acquire();
|
||||
ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE);
|
||||
if(!visible) setModal(false);
|
||||
|
||||
if(auto& sizable = state().sizable) {
|
||||
if(auto self = sizable->self()) self->setVisible(sizable->visible(true));
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -301,6 +299,18 @@ auto pWindow::_modalityUpdate() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto pWindow::_statusHeight() const -> int {
|
||||
int height = 0;
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(statusBar->visible()) {
|
||||
auto& text = statusBar->state.text;
|
||||
height = statusBar->font(true).size(text ? text : " ").height();
|
||||
height = max(height, minimumStatusHeight);
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,10 @@ namespace hiro {
|
|||
struct pWindow : pObject {
|
||||
Declare(Window, Object)
|
||||
|
||||
static auto initialize() -> void;
|
||||
|
||||
static uint minimumStatusHeight;
|
||||
|
||||
auto append(sMenuBar menuBar) -> void;
|
||||
auto append(sSizable sizable) -> void;
|
||||
auto append(sStatusBar statusBar) -> void;
|
||||
|
@ -42,6 +46,7 @@ struct pWindow : pObject {
|
|||
auto _modalityCount() -> unsigned;
|
||||
auto _modalityDisabled() -> bool;
|
||||
auto _modalityUpdate() -> void;
|
||||
auto _statusHeight() const -> int;
|
||||
|
||||
HWND hwnd = nullptr;
|
||||
HFONT hstatusfont = nullptr;
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
name := icarus
|
||||
build := performance
|
||||
flags += -I..
|
||||
|
||||
nall.path := ../nall
|
||||
include $(nall.path)/GNUmakefile
|
||||
|
||||
object.path := obj
|
||||
flags += -I..
|
||||
|
||||
hiro.path := ../hiro
|
||||
hiro.resource := data/$(name).rc
|
||||
include $(hiro.path)/GNUmakefile
|
||||
|
||||
objects += obj/hiro.o $(if $(call streq,$(platform),windows),obj/hiro-resource.o)
|
||||
objects += obj/icarus.o
|
||||
objects := obj/icarus.o
|
||||
|
||||
all: $(objects)
|
||||
obj/icarus.o: icarus.cpp
|
||||
|
||||
all: $(hiro.objects) $(objects)
|
||||
$(info Linking out/$(name) ...)
|
||||
+@$(strip $(compiler) -o out/$(name) $(objects) $(options) $(hiro.options))
|
||||
+@$(compiler) -o out/$(name) $(hiro.objects) $(objects) $(hiro.options) $(options)
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
mkdir -p out/$(name).app/Contents/MacOS/
|
||||
|
@ -26,16 +25,14 @@ ifeq ($(platform),macos)
|
|||
sips -s format icns data/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns
|
||||
endif
|
||||
|
||||
obj/icarus.o: icarus.cpp $(call rwildcard,core/) $(call rwildcard,heuristics/) $(call rwildcard,ui/)
|
||||
$(info Compiling $< ...)
|
||||
@$(compiler) $(flags.cpp) $(flags) -o obj/icarus.o -c icarus.cpp
|
||||
verbose: hiro.verbose nall.verbose all;
|
||||
|
||||
clean:
|
||||
ifeq ($(platform),macos)
|
||||
rm -rf out/$(name).app
|
||||
endif
|
||||
$(call rm,obj/*)
|
||||
$(call rm,out/*)
|
||||
$(call delete,obj/*)
|
||||
$(call delete,out/*)
|
||||
|
||||
install:
|
||||
ifeq ($(platform),macos)
|
||||
|
|
|
@ -31,21 +31,19 @@ ifeq ($(platform),)
|
|||
|
||||
# common commands
|
||||
ifeq ($(uname),)
|
||||
rm = $(info Deleting $1 ...) @del /q $(subst /,\,$1)
|
||||
rmdir = $(info Deleting $1 ...) @del /s /q $(subst /,\,$1) && if exist $(subst /,\,$1) (rmdir /s /q $(subst /,\,$1))
|
||||
delete = $(info Deleting $1 ...) @del /q $(subst /,\,$1)
|
||||
rdelete = $(info Deleting $1 ...) @del /s /q $(subst /,\,$1) && if exist $(subst /,\,$1) (rmdir /s /q $(subst /,\,$1))
|
||||
else
|
||||
rm = $(info Deleting $1 ...) @rm -f $1
|
||||
rmdir = $(info Deleting $1 ...) @rm -rf $1
|
||||
delete = $(info Deleting $1 ...) @rm -f $1
|
||||
rdelete = $(info Deleting $1 ...) @rm -rf $1
|
||||
endif
|
||||
endif
|
||||
|
||||
flags.c := -x c -std=c11
|
||||
flags.cpp := -x c++ -std=c++14
|
||||
flags.objc := -x objective-c -std=c11
|
||||
flags.objcpp := -x objective-c++ -std=c++14
|
||||
|
||||
flags :=
|
||||
options :=
|
||||
flags.c = -x c -std=c11
|
||||
flags.cpp = -x c++ -std=c++14
|
||||
flags.objc = -x objective-c -std=c11
|
||||
flags.objcpp = -x objective-c++ -std=c++14
|
||||
flags.deps = -MMD -MP -MF $(@:.o=.d)
|
||||
|
||||
# compiler detection
|
||||
ifeq ($(compiler),)
|
||||
|
@ -135,16 +133,31 @@ endif
|
|||
|
||||
# paths
|
||||
prefix := $(HOME)/.local
|
||||
object.path := obj
|
||||
|
||||
# targets
|
||||
# rules
|
||||
default: all;
|
||||
verbose: information all;
|
||||
information:
|
||||
|
||||
nall.verbose:
|
||||
$(info Compiler Flags:)
|
||||
$(foreach n,$(sort $(call unique,$(flags))),$(if $(filter-out -I%,$n),$(info $([space]) $n)))
|
||||
$(info Linker Options:)
|
||||
$(foreach n,$(sort $(call unique,$(options))),$(if $(filter-out -l%,$n),$(info $([space]) $n)))
|
||||
|
||||
%.o: $<
|
||||
$(info Compiling $< ...)
|
||||
@$(call compile)
|
||||
|
||||
# function compile([arguments])
|
||||
compile = \
|
||||
$(strip \
|
||||
$(if $(filter %.c,$<), \
|
||||
$(compiler) $(flags.c) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
,$(if $(filter %.cpp,$<), \
|
||||
$(compiler) $(flags.cpp) $(flags.deps) $(flags) $1 -c $< -o $@ \
|
||||
)) \
|
||||
)
|
||||
|
||||
# function rwildcard(directory, pattern)
|
||||
rwildcard = \
|
||||
$(strip \
|
||||
|
|
|
@ -63,6 +63,11 @@ struct Locale {
|
|||
struct Namespace {
|
||||
Namespace(Locale& _locale, string _namespace) : _locale(_locale), _namespace(_namespace) {}
|
||||
|
||||
template<typename... P>
|
||||
auto operator()(string input, P&&... p) const -> string {
|
||||
return _locale(_namespace, input, forward<P>(p)...);
|
||||
}
|
||||
|
||||
template<typename... P>
|
||||
auto tr(string input, P&&... p) const -> string {
|
||||
return _locale(_namespace, input, forward<P>(p)...);
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
ifeq ($(ruby),)
|
||||
ifeq ($(platform),windows)
|
||||
ruby += video.wgl video.direct3d video.directdraw video.gdi
|
||||
ruby += audio.asio audio.wasapi audio.xaudio2 audio.directsound
|
||||
ruby += input.windows
|
||||
else ifeq ($(platform),macos)
|
||||
ruby += video.cgl
|
||||
ruby += audio.openal
|
||||
ruby += input.quartz input.carbon
|
||||
else ifeq ($(platform),linux)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.alsa audio.openal audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.xlib input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
ruby += video.glx video.xvideo video.xshm
|
||||
ruby += audio.oss audio.openal
|
||||
ruby += input.sdl input.xlib
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(platform),macos)
|
||||
ruby.flags := $(flags.objcpp)
|
||||
else
|
||||
|
@ -46,6 +66,12 @@ ifeq ($(platform),bsd)
|
|||
ruby.options += $(if $(findstring audio.openal,$(ruby)),-lopenal)
|
||||
endif
|
||||
|
||||
$(object.path)/ruby.o: $(ruby.path)/ruby.cpp $(call rwildcard,$(ruby.path)) $(call rwildcard,$(nall.path))
|
||||
ruby.objects := $(object.path)/ruby.o
|
||||
|
||||
$(object.path)/ruby.o: $(ruby.path)/ruby.cpp
|
||||
$(info Compiling $< ...)
|
||||
@$(compiler) $(ruby.flags) $(flags) -c $< -o $@
|
||||
@$(compiler) $(ruby.flags) $(flags) $(flags.deps) -c $< -o $@
|
||||
|
||||
ruby.verbose:
|
||||
$(info ruby Drivers:)
|
||||
$(foreach n,$(ruby),$(info $([space]) $n))
|
||||
|
|
Loading…
Reference in New Issue