diff --git a/license.txt b/license.txt index e1edb2fb..18995f5d 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -bsnes (TM) Open Source Reference License +bsnes (TM) Reference License Copyright (C) 2004 - 2007 byuu All rights reserved diff --git a/readme.txt b/readme.txt index 1bf51298..e2398abd 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ bsnes -Version 0.026 +Version 0.027 Author: byuu -------- diff --git a/src/Makefile b/src/Makefile index b8a47930..0ada8639 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,321 +1,333 @@ -###################### -### bsnes makefile ### -###################### - -ifeq ($(PLATFORM),) -_null_: help -endif - -################################## -### platform-specific settings ### -################################## - -ifeq ($(PLATFORM),x-gcc-lui) -OS = unix -CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI `pkg-config --cflags gtk+-2.0` -AS = nasm -ASFLAGS = -f elf -LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao -LIBCO = libco_x86 -LIBUI = libui_gtk -endif - -ifeq ($(PLATFORM),x-gcc-lui-x64) -OS = unix -CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_LUI `pkg-config --cflags gtk+-2.0` -AS = yasm -ASFLAGS = -f elf64 -LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao -LIBCO = libco_x86_64 -LIBUI = libui_gtk -endif - -ifeq ($(PLATFORM),win-visualc-lui) -OS = win -CC = cl -CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib -LIBCO = libco_x86 -LIBUI = libui_win -endif - -ifeq ($(PLATFORM),win-visualc-lui-pgi) -OS = win -CC = cl -CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib -LINK = /link /PGD:bsnes.pgd /LTCG:PGINSTRUMENT -LIBCO = libco_x86 -LIBUI = libui_win -endif - -ifeq ($(PLATFORM),win-visualc-lui-pgo) -OS = win -CC = cl -CFLAGS = /nologo /wd4996 /O2 /GL /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_LUI -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib -LINK = /link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE -LIBCO = libco_x86 -LIBUI = libui_win -endif - -ifeq ($(PLATFORM),win-mingw-lui) -OS = win -CC = mingw32-gcc -CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_LUI -AS = nasm -ASFLAGS = -f win32 -DWIN32 -LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32 -LIBCO = libco_x86 -LIBUI = libui_win -endif - -##################################### -### compiler / assembler switches ### -##################################### - -ifeq ($(CC),gcc) -OUT = -obsnes -CPP = g++ -OBJ = o -CARGS = -c $< -o $@ -DEFINE = -D -endif - -ifeq ($(CC),mingw32-gcc) -OUT = -obsnes -CPP = mingw32-g++ -OBJ = o -CARGS = -c $< -o $@ -DEFINE = -D -endif - -ifeq ($(CC),cl) -OUT = /Febsnes -CPP = cl -OBJ = obj -CARGS = /c $< /Fo$@ -DEFINE = /D -endif - -ifeq ($(AS),nasm) -ASARGS = $< -o $@ -endif - -ifeq ($(AS),yasm) -ASARGS = $< -o $@ -endif - -################### -### OS switches ### -################### - -ifeq ($(OS),unix) -RM = rm -f -endif - -ifeq ($(OS),win) -OUT := $(OUT).exe -RM = del -endif - -#################################### -### main target and dependencies ### -#################################### - -OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(LIBUI).$(OBJ) \ - libstring.$(OBJ) \ - reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) smemory.$(OBJ) \ - cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \ - bppu.$(OBJ) snes.$(OBJ) bsx.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) \ - sdd1.$(OBJ) cx4.$(OBJ) dsp1.$(OBJ) dsp2.$(OBJ) dsp3.$(OBJ) dsp4.$(OBJ) \ - obc1.$(OBJ) st010.$(OBJ) - -ifeq ($(GZIP_SUPPORT),true) - OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \ - gzio.$(OBJ) inffast.$(OBJ) inflate.$(OBJ) inftrees.$(OBJ) ioapi.$(OBJ) \ - trees.$(OBJ) unzip.$(OBJ) zip.$(OBJ) zutil.$(OBJ) - CFLAGS += $(DEFINE)GZIP_SUPPORT -endif - -ifeq ($(JMA_SUPPORT),true) - OBJECTS += jma.$(OBJ) jcrc32.$(OBJ) lzmadec.$(OBJ) 7zlzma.$(OBJ) \ - iiostrm.$(OBJ) inbyte.$(OBJ) lzma.$(OBJ) winout.$(OBJ) - CFLAGS += $(DEFINE)JMA_SUPPORT -endif - -ifeq ($(OS),win) - ifeq ($(CC),cl) - OBJECTS += bsnes.res - endif - ifeq ($(CC),mingw32-gcc) - OBJECTS += bsnesrc.o - endif -endif - -all: $(OBJECTS) - $(CPP) $(OUT) $(CFLAGS) $(OBJECTS) $(LIBS) $(LINK) - -install: - cp bsnes /usr/local/bin/bsnes - cp data/bsnes.png /usr/local/share/icons/bsnes.png - chmod 775 /usr/local/bin/bsnes /usr/local/share/icons/bsnes.png - -###################### -### implicit rules ### -###################### - -%.$(OBJ): $< - $(if $(filter %.asm,$<),$(AS) $(ASFLAGS) $(ASARGS)) - $(if $(filter %.c,$<),$(CC) $(CFLAGS) $(CARGS)) - $(if $(filter %.cpp,$<),$(CPP) $(CFLAGS) $(CARGS)) - -######################### -### platform-specific ### -######################### -main.$(OBJ): ui/main.cpp config/* ui/* ui/video/* ui/audio/* ui/input/* \ -ui/lui/* ui/lui/loader/* ui/lui/settings/* \ -ui/win/* ui/win/settings/* ui/win/debugger/* - -bsnes.res: ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc -bsnesrc.o: ui/bsnes.rc ; windres -I data ui/bsnes.rc bsnesrc.o - -############# -### libco ### -############# -libco_x86.$(OBJ) : lib/libco_x86.asm lib/* -libco_x86_64.$(OBJ): lib/libco_x86_64.asm lib/* - -############# -### libui ### -############# -libui_gtk.$(OBJ): lib/libui_gtk.cpp lib/* -libui_win.$(OBJ): lib/libui_win.cpp lib/* - -################# -### libraries ### -################# -libstring.$(OBJ): lib/libstring.cpp lib/* - -################# -### utilities ### -################# -reader.$(OBJ): reader/reader.cpp reader/* -cart.$(OBJ) : cart/cart.cpp cart/* -cheat.$(OBJ) : cheat/cheat.cpp cheat/* - -############## -### memory ### -############## -memory.$(OBJ) : memory/memory.cpp memory/* -bmemory.$(OBJ): memory/bmemory/bmemory.cpp memory/bmemory/* memory/bmemory/mapper/* -smemory.$(OBJ): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/mapper/* - -########### -### cpu ### -########### -cpu.$(OBJ) : cpu/cpu.cpp cpu/* -scpu.$(OBJ): cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/core/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/* - -########### -### smp ### -########### -smp.$(OBJ) : smp/smp.cpp smp/* -ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ssmp/timing/* - -########### -### dsp ### -########### -adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/* -bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/* - -########### -### ppu ### -########### -ppu.$(OBJ) : ppu/ppu.cpp ppu/* -bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/* - -############ -### snes ### -############ -snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/* - -##################### -### special chips ### -##################### -bsx.$(OBJ) : chip/bsx/bsx.cpp chip/bsx/* -superfx.$(OBJ): chip/superfx/superfx.cpp chip/superfx/* chip/superfx/core/* chip/superfx/memory/* -srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/* -sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/* -cx4.$(OBJ) : chip/cx4/cx4.cpp chip/cx4/* -dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/* -dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/* -dsp3.$(OBJ) : chip/dsp3/dsp3.cpp chip/dsp3/* -dsp4.$(OBJ) : chip/dsp4/dsp4.cpp chip/dsp4/* -obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/* -st010.$(OBJ) : chip/st010/st010.cpp chip/st010/* - -############ -### zlib ### -############ -adler32.$(OBJ) : reader/zlib/adler32.c reader/zlib/* -compress.$(OBJ): reader/zlib/compress.c reader/zlib/* -crc32.$(OBJ) : reader/zlib/crc32.c reader/zlib/* -deflate.$(OBJ) : reader/zlib/deflate.c reader/zlib/* -gzio.$(OBJ) : reader/zlib/gzio.c reader/zlib/* -inffast.$(OBJ) : reader/zlib/inffast.c reader/zlib/* -inflate.$(OBJ) : reader/zlib/inflate.c reader/zlib/* -inftrees.$(OBJ): reader/zlib/inftrees.c reader/zlib/* -ioapi.$(OBJ) : reader/zlib/ioapi.c reader/zlib/* -trees.$(OBJ) : reader/zlib/trees.c reader/zlib/* -unzip.$(OBJ) : reader/zlib/unzip.c reader/zlib/* -zip.$(OBJ) : reader/zlib/zip.c reader/zlib/* -zutil.$(OBJ) : reader/zlib/zutil.c reader/zlib/* - -########### -### jma ### -########### -jma.$(OBJ) : reader/jma/jma.cpp reader/jma/* -jcrc32.$(OBJ) : reader/jma/jcrc32.cpp reader/jma/* -lzmadec.$(OBJ): reader/jma/lzmadec.cpp reader/jma/* -7zlzma.$(OBJ) : reader/jma/7zlzma.cpp reader/jma/* -iiostrm.$(OBJ): reader/jma/iiostrm.cpp reader/jma/* -inbyte.$(OBJ) : reader/jma/inbyte.cpp reader/jma/* -lzma.$(OBJ) : reader/jma/lzma.cpp reader/jma/* -winout.$(OBJ) : reader/jma/winout.cpp reader/jma/* - -#################### -### misc targets ### -#################### -clean: - -@$(RM) *.$(OBJ) - -@$(RM) *.res - -@$(RM) *.pgd - -@$(RM) *.pgc - -@$(RM) *.ilk - -@$(RM) *.pdb - -@$(RM) *.manifest - -help: - @echo "Usage: $(MAKE) PLATFORM=platform [options]" - @echo "" - @echo "Available platform targets:" - @echo " x-gcc-lui - Linux / BSD (i386) (requires nasm)" - @echo " x-gcc-lui-x64 - Linux / BSD (amd64) (requires yasm)" - @echo " win-mingw-lui - Windows (i386) (requires nasm)" - @echo " win-visualc-lui - Windows (i386) (requires nasm)" - @echo "" - @echo "Available options:" - @echo " GZIP_SUPPORT=[true|false] - Enable ZIP / GZ support (default=false)" - @echo " JMA_SUPPORT=[true|false] - Enable JMA support (default=false)" - @echo "" - @echo "Example: $(MAKE) PLATFORM=x-gcc-lui GZIP_SUPPORT=true" - @echo "" +###################### +### bsnes makefile ### +###################### + +ifeq ($(PLATFORM),) +null_: help +endif + +################################## +### platform-specific settings ### +################################## + +PREFIX = /usr/local + +ifeq ($(PLATFORM),x-gcc-x86) +OS = unix +CC = gcc +CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_MIU `pkg-config --cflags gtk+-2.0` +AS = yasm +ASFLAGS = -f elf +LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao +LIBCO = libco.x86 +MIU = miu.gtk +VAI = video.xv.$(OBJ) video.gtk.$(OBJ) audio.ao.$(OBJ) input.x.$(OBJ) +endif + +ifeq ($(PLATFORM),x-gcc-x86-64) +OS = unix +CC = gcc +CFLAGS = -O3 -fomit-frame-pointer -DPLATFORM_X -DCOMPILER_GCC -DPROCESSOR_X86_64 -DUI_MIU `pkg-config --cflags gtk+-2.0` +AS = yasm +ASFLAGS = -f elf64 +LIBS = `pkg-config --libs gtk+-2.0` -lXv -lao +LIBCO = libco.x86-64 +MIU = miu.gtk +VAI = video.xv.$(OBJ) video.gtk.$(OBJ) audio.ao.$(OBJ) input.x.$(OBJ) +endif + +ifeq ($(PLATFORM),win-mingw-x86) +OS = win +CC = mingw32-gcc +CFLAGS = -mwindows -O3 -fomit-frame-pointer -DPLATFORM_WIN -DCOMPILER_GCC -DPROCESSOR_X86 -DUI_MIU +AS = nasm +ASFLAGS = -f win32 -DWIN +LIBS = -ld3d9 -lddraw -ldsound -ldinput8 -ldxguid -luuid -lkernel32 -luser32 -lgdi32 -lshell32 -lwinmm -lcomdlg32 -lcomctl32 +LIBCO = libco.x86 +MIU = miu.win +VAI = video.direct3d.$(OBJ) video.directdraw.$(OBJ) video.gdi.$(OBJ) audio.directsound.$(OBJ) input.directinput.$(OBJ) +endif + +ifeq ($(PLATFORM),win-visualc-x86) +OS = win +CC = cl +CFLAGS = /nologo /wd4996 /O2 /EHsc /DPLATFORM_WIN /DCOMPILER_VISUALC /DPROCESSOR_X86 /DUI_MIU +AS = nasm +ASFLAGS = -f win32 -DWIN +LIBS = d3d9.lib ddraw.lib dsound.lib dinput8.lib dxguid.lib kernel32.lib user32.lib gdi32.lib shell32.lib winmm.lib comdlg32.lib comctl32.lib +LIBCO = libco.x86 +MIU = miu.win +VAI = video.direct3d.$(OBJ) video.directdraw.$(OBJ) video.gdi.$(OBJ) audio.directsound.$(OBJ) input.directinput.$(OBJ) +endif + +##################################### +### compiler / assembler switches ### +##################################### + +ifeq ($(CC),gcc) +OUT = -obsnes +CPP = g++ +OBJ = o +CARGS = -c $< -o $@ +DEFINE = -D +endif + +ifeq ($(CC),mingw32-gcc) +OUT = -obsnes +CPP = mingw32-g++ +OBJ = o +CARGS = -c $< -o $@ +DEFINE = -D +endif + +ifeq ($(CC),cl) +OUT = /Febsnes +CPP = cl +OBJ = obj +CARGS = /c $< /Fo$@ +DEFINE = /D +endif + +ifeq ($(AS),nasm) +ASARGS = $< -o $@ +endif + +ifeq ($(AS),yasm) +ASARGS = $< -o $@ +endif + +################### +### OS switches ### +################### + +ifeq ($(OS),unix) +RM = rm -f +endif + +ifeq ($(OS),win) +OUT := $(OUT).exe +RM = del +endif + +#################################### +### main target and dependencies ### +#################################### + +OBJECTS = main.$(OBJ) $(LIBCO).$(OBJ) $(MIU).$(OBJ) $(VAI) bstring.$(OBJ) \ + reader.$(OBJ) cart.$(OBJ) cheat.$(OBJ) memory.$(OBJ) smemory.$(OBJ) \ + cpu.$(OBJ) scpu.$(OBJ) smp.$(OBJ) ssmp.$(OBJ) bdsp.$(OBJ) ppu.$(OBJ) \ + bppu.$(OBJ) snes.$(OBJ) bsx.$(OBJ) superfx.$(OBJ) srtc.$(OBJ) \ + sdd1.$(OBJ) cx4.$(OBJ) dsp1.$(OBJ) dsp2.$(OBJ) dsp3.$(OBJ) dsp4.$(OBJ) \ + obc1.$(OBJ) st010.$(OBJ) + +ifeq ($(GZIP_SUPPORT),true) + OBJECTS += adler32.$(OBJ) compress.$(OBJ) crc32.$(OBJ) deflate.$(OBJ) \ + gzio.$(OBJ) inffast.$(OBJ) inflate.$(OBJ) inftrees.$(OBJ) ioapi.$(OBJ) \ + trees.$(OBJ) unzip.$(OBJ) zip.$(OBJ) zutil.$(OBJ) + CFLAGS += $(DEFINE)GZIP_SUPPORT +endif + +ifeq ($(JMA_SUPPORT),true) + OBJECTS += jma.$(OBJ) jcrc32.$(OBJ) lzmadec.$(OBJ) 7zlzma.$(OBJ) \ + iiostrm.$(OBJ) inbyte.$(OBJ) lzma.$(OBJ) winout.$(OBJ) + CFLAGS += $(DEFINE)JMA_SUPPORT +endif + +ifeq ($(OS),win) + ifeq ($(CC),cl) + OBJECTS += bsnes.res + endif + ifeq ($(CC),mingw32-gcc) + OBJECTS += bsnesrc.o + endif +endif + +all: $(OBJECTS) + $(CPP) $(OUT) $(CFLAGS) $(OBJECTS) $(LIBS) $(LINK) + +###################### +### implicit rules ### +###################### + +%.$(OBJ): $< + $(if $(filter %.asm,$<),$(AS) $(ASFLAGS) $(ASARGS)) + $(if $(filter %.s,$<),$(AS) $(ASFLAGS) $(ASARGS)) + $(if $(filter %.c,$<),$(CC) $(CFLAGS) $(CARGS)) + $(if $(filter %.cpp,$<),$(CPP) $(CFLAGS) $(CARGS)) + +############ +### main ### +############ + +main.$(OBJ): ui/main.cpp config/* \ +ui/* ui/vai/* \ +ui/miu/* ui/miu/loader/* ui/miu/settings/* + +bsnes.res: ui/bsnes.rc ; rc /r /fobsnes.res ui/bsnes.rc +bsnesrc.o: ui/bsnes.rc ; windres -I data ui/bsnes.rc bsnesrc.o + +########## +### ui ### +########## + +video.direct3d.$(OBJ) : ui/vai/video/video.direct3d.cpp ui/vai/video/* +video.directdraw.$(OBJ) : ui/vai/video/video.directdraw.cpp ui/vai/video/* +video.gdi.$(OBJ) : ui/vai/video/video.gdi.cpp ui/vai/video/* +video.gtk.$(OBJ) : ui/vai/video/video.gtk.cpp ui/vai/video/* +video.xv.$(OBJ) : ui/vai/video/video.xv.cpp ui/vai/video/* +audio.ao.$(OBJ) : ui/vai/audio/audio.ao.cpp ui/vai/audio/* +audio.directsound.$(OBJ): ui/vai/audio/audio.directsound.cpp ui/vai/audio/* +input.directinput.$(OBJ): ui/vai/input/input.directinput.cpp ui/vai/input/* +input.x.$(OBJ) : ui/vai/input/input.x.cpp ui/vai/input/* + +############# +### libco ### +############# + +libco.x86.$(OBJ) : lib/libco/libco.x86.asm lib/libco/* +libco.x86-64.$(OBJ): lib/libco/libco.x86-64.asm lib/libco/* +libco.pcc.$(OBJ) : lib/libco/libco.ppc.s lib/libco/* +libco.ppc64.$(OBJ) : lib/libco/libco.ppc64.s lib/libco/* + +########### +### miu ### +########### + +miu.gtk.$(OBJ): lib/miu.gtk/miu.gtk.cpp lib/miu.gtk/* +miu.win.$(OBJ): lib/miu.win/miu.win.cpp lib/miu.win/* + +################# +### libraries ### +################# + +bstring.$(OBJ): lib/bstring.cpp lib/* + +################# +### utilities ### +################# + +reader.$(OBJ): reader/reader.cpp reader/* +cart.$(OBJ) : cart/cart.cpp cart/* +cheat.$(OBJ) : cheat/cheat.cpp cheat/* + +############## +### memory ### +############## + +memory.$(OBJ) : memory/memory.cpp memory/* +bmemory.$(OBJ): memory/bmemory/bmemory.cpp memory/bmemory/* memory/bmemory/mapper/* +smemory.$(OBJ): memory/smemory/smemory.cpp memory/smemory/* memory/smemory/mapper/* + +########### +### cpu ### +########### + +cpu.$(OBJ) : cpu/cpu.cpp cpu/* +scpu.$(OBJ): cpu/scpu/scpu.cpp cpu/scpu/* cpu/scpu/core/* cpu/scpu/dma/* cpu/scpu/memory/* cpu/scpu/mmio/* cpu/scpu/timing/* + +########### +### smp ### +########### + +smp.$(OBJ) : smp/smp.cpp smp/* +ssmp.$(OBJ): smp/ssmp/ssmp.cpp smp/ssmp/* smp/ssmp/core/* smp/ssmp/memory/* smp/ssmp/timing/* + +########### +### dsp ### +########### + +adsp.$(OBJ): dsp/adsp/adsp.cpp dsp/adsp/* +bdsp.$(OBJ): dsp/bdsp/bdsp.cpp dsp/bdsp/* + +########### +### ppu ### +########### + +ppu.$(OBJ) : ppu/ppu.cpp ppu/* +bppu.$(OBJ): ppu/bppu/bppu.cpp ppu/bppu/* + +############ +### snes ### +############ + +snes.$(OBJ): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/* snes/input/* + +##################### +### special chips ### +##################### + +bsx.$(OBJ) : chip/bsx/bsx.cpp chip/bsx/* +superfx.$(OBJ): chip/superfx/superfx.cpp chip/superfx/* chip/superfx/core/* chip/superfx/memory/* +srtc.$(OBJ) : chip/srtc/srtc.cpp chip/srtc/* +sdd1.$(OBJ) : chip/sdd1/sdd1.cpp chip/sdd1/* +cx4.$(OBJ) : chip/cx4/cx4.cpp chip/cx4/* +dsp1.$(OBJ) : chip/dsp1/dsp1.cpp chip/dsp1/* +dsp2.$(OBJ) : chip/dsp2/dsp2.cpp chip/dsp2/* +dsp3.$(OBJ) : chip/dsp3/dsp3.cpp chip/dsp3/* +dsp4.$(OBJ) : chip/dsp4/dsp4.cpp chip/dsp4/* +obc1.$(OBJ) : chip/obc1/obc1.cpp chip/obc1/* +st010.$(OBJ) : chip/st010/st010.cpp chip/st010/* + +############ +### zlib ### +############ + +adler32.$(OBJ) : reader/zlib/adler32.c reader/zlib/* +compress.$(OBJ): reader/zlib/compress.c reader/zlib/* +crc32.$(OBJ) : reader/zlib/crc32.c reader/zlib/* +deflate.$(OBJ) : reader/zlib/deflate.c reader/zlib/* +gzio.$(OBJ) : reader/zlib/gzio.c reader/zlib/* +inffast.$(OBJ) : reader/zlib/inffast.c reader/zlib/* +inflate.$(OBJ) : reader/zlib/inflate.c reader/zlib/* +inftrees.$(OBJ): reader/zlib/inftrees.c reader/zlib/* +ioapi.$(OBJ) : reader/zlib/ioapi.c reader/zlib/* +trees.$(OBJ) : reader/zlib/trees.c reader/zlib/* +unzip.$(OBJ) : reader/zlib/unzip.c reader/zlib/* +zip.$(OBJ) : reader/zlib/zip.c reader/zlib/* +zutil.$(OBJ) : reader/zlib/zutil.c reader/zlib/* + +########### +### jma ### +########### + +jma.$(OBJ) : reader/jma/jma.cpp reader/jma/* +jcrc32.$(OBJ) : reader/jma/jcrc32.cpp reader/jma/* +lzmadec.$(OBJ): reader/jma/lzmadec.cpp reader/jma/* +7zlzma.$(OBJ) : reader/jma/7zlzma.cpp reader/jma/* +iiostrm.$(OBJ): reader/jma/iiostrm.cpp reader/jma/* +inbyte.$(OBJ) : reader/jma/inbyte.cpp reader/jma/* +lzma.$(OBJ) : reader/jma/lzma.cpp reader/jma/* +winout.$(OBJ) : reader/jma/winout.cpp reader/jma/* + +#################### +### misc targets ### +#################### + +install: + install -m 775 bsnes $(PREFIX)/bin/bsnes + install -m 775 data/bsnes.png $(PREFIX)/share/icons/bsnes.png + +clean: + -@$(RM) *.$(OBJ) + -@$(RM) *.res + -@$(RM) *.pgd + -@$(RM) *.pgc + -@$(RM) *.ilk + -@$(RM) *.pdb + -@$(RM) *.manifest + +help: + @echo "Usage: $(MAKE) PLATFORM=platform [options]" + @echo "" + @echo "Available platform targets:" + @echo " x-gcc-x86 - Linux / BSD (x86) (requires yasm)" + @echo " x-gcc-x86-64 - Linux / BSD (x86-64) (requires yasm)" + @echo " win-mingw-x86 - Windows (x86) (requires nasm)" + @echo " win-visualc-x86 - Windows (x86) (requires nasm)" + @echo "" + @echo "Available options:" + @echo " GZIP_SUPPORT=[true|false] - Enable ZIP / GZ support (default=false)" + @echo " JMA_SUPPORT=[true|false] - Enable JMA support (default=false)" + @echo "" + @echo "Example: $(MAKE) PLATFORM=x-gcc-lui GZIP_SUPPORT=true" + @echo "" diff --git a/src/base.h b/src/base.h index 75ba8073..0d5bf36f 100644 --- a/src/base.h +++ b/src/base.h @@ -1,53 +1,54 @@ -#define BSNES_VERSION "0.026" -#define BSNES_TITLE "bsnes v" BSNES_VERSION - -#define BUSCORE sBus -#define CPUCORE sCPU -#define SMPCORE sSMP -#define DSPCORE bDSP -#define PPUCORE bPPU - -//#define FAVOR_ACCURACY -#define FAVOR_SPEED - -//game genie + pro action replay code support (~1-3% speed hit) -#define CHEAT_SYSTEM - -#if defined(PROCESSOR_X86) - #define ARCH_LSB - #include "lib/libco_x86.h" -#elif defined(PROCESSOR_X86_64) - #define ARCH_LSB - #include "lib/libco_x86_64.h" -#elif defined(PROCESSOR_G5) - #define ARCH_MSB -#else - #error "unsupported processor" -#endif - -#include "lib/libbase.h" -#include "lib/libfunction.h" -#include "lib/libarray.h" -#include "lib/libvector.h" -#include "lib/libstring.h" -#include "lib/libconfig.h" - -//platform-specific global functions -void alert(const char*, ...); -void dprintf(const char*, ...); -void dprintf(uint, const char*, ...); - -namespace source { - enum { - none = 0, - debug, - cpu, - ppu, - smp, - dsp, - bus, - }; -}; - -//various class interfaces -#include "interface.h" +#define BSNES_VERSION "0.027" +#define BSNES_TITLE "bsnes v" BSNES_VERSION + +#define BUSCORE sBus +#define CPUCORE sCPU +#define SMPCORE sSMP +#define DSPCORE bDSP +#define PPUCORE bPPU + +//FAVOR_ACCURACY calculates RTO during frameskip, whereas FAVOR_SPEED does not +//frameskip offers near-zero speedup if RTO is calculated +//accuracy is not affected by this define when frameskipping is off + +//#define FAVOR_ACCURACY +#define FAVOR_SPEED + +//game genie + pro action replay code support (~1-3% speed hit) +#define CHEAT_SYSTEM + +#if defined(PROCESSOR_X86) || defined(PROCESSOR_X86_64) + #define ARCH_LSB +#elif defined(PROCESSOR_PPC) || defined(PROCESSOR_PPC64) + #define ARCH_MSB +#else //guess + #define ARCH_LSB +#endif + +#include "lib/libco.h" +#include "lib/bbase.h" +#include "lib/bfunction.h" +#include "lib/barray.h" +#include "lib/bvector.h" +#include "lib/bkeymap.h" +#include "lib/bstring.h" +#include "lib/bconfig.h" + +//platform-specific global functions +void alert(const char*, ...); +void dprintf(const char*, ...); +void dprintf(uint, const char*, ...); + +namespace source { + enum { + none = 0, + debug, + cpu, + ppu, + smp, + dsp, + bus, + }; +}; + +#include "interface.h" diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index 0898bb79..8ad84b62 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -82,6 +82,14 @@ void Cartridge::load_end() { memory::stBrom.write_protect(true); memory::stBram.write_protect(false); +char fn[PATH_MAX]; + strcpy(fn, cart.fn); + modify_extension(fn, "cht"); + if(fexists(fn)) { + cheat.clear(); + cheat.load(fn); + } + cart.loaded = true; bus.load_cart(); } @@ -106,6 +114,14 @@ bool Cartridge::unload() { safe_free(stB.rom); safe_free(stB.ram); +char fn[PATH_MAX]; + strcpy(fn, cart.fn); + modify_extension(fn, "cht"); + if(cheat.count() > 0 || fexists(fn)) { + cheat.save(fn); + cheat.clear(); + } + cart.loaded = false; return true; } diff --git a/src/cart/cart_file.cpp b/src/cart/cart_file.cpp index e637e9a1..ac1158ce 100644 --- a/src/cart/cart_file.cpp +++ b/src/cart/cart_file.cpp @@ -29,7 +29,7 @@ char* Cartridge::get_save_filename(const char *source, const char *extension) { //override path with user-specified folder, if one was defined if(config::path.save != "") { - stringarray part; + lstring part; split(part, "/", savefn); string fn = config::path.save(); if(strend(fn, "/") == false) strcat(fn, "/"); @@ -38,7 +38,7 @@ char* Cartridge::get_save_filename(const char *source, const char *extension) { //resolve relative path, if found if(strbegin(fn, "./") == true) { - strltrim(fn, "./"); + ltrim(fn, "./"); strcpy(savefn, config::path.base); strcat(savefn, fn); } @@ -50,53 +50,50 @@ char* Cartridge::get_save_filename(const char *source, const char *extension) { bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) { dprintf("* Loading \"%s\"...", fn); - if(fexists(fn) == false) { - return false; - } + if(fexists(fn) == false) return false; switch(Reader::detect(fn)) { + default: + case Reader::RF_NORMAL: { + FileReader ff(fn); + if(!ff.ready()) { + alert("Error loading image file (%s)!", fn); + return false; + } + size = ff.size(); + data = ff.read(); + } break; - case Reader::RF_NORMAL: { - FileReader ff(fn); - if(!ff.ready()) { - alert("Error loading image file (%s)!", fn); - return false; - } - size = ff.size(); - data = ff.read(); - } break; + #ifdef GZIP_SUPPORT + case Reader::RF_GZ: { + GZReader gf(fn); + if(!gf.ready()) { + alert("Error loading image file (%s)!", fn); + return false; + } + size = gf.size(); + data = gf.read(); + } break; -#ifdef GZIP_SUPPORT - case Reader::RF_GZ: { - GZReader gf(fn); - if(!gf.ready()) { - alert("Error loading image file (%s)!", fn); - return false; - } - size = gf.size(); - data = gf.read(); - } break; - - case Reader::RF_ZIP: { - ZipReader zf(fn); - size = zf.size(); - data = zf.read(); - } break; -#endif - -#ifdef JMA_SUPPORT - case Reader::RF_JMA: { - try { - JMAReader jf(fn); - size = jf.size(); - data = jf.read(); - } catch(JMA::jma_errors jma_error) { - alert("Error loading image file (%s)!", fn); - return false; - } - } break; -#endif + case Reader::RF_ZIP: { + ZipReader zf(fn); + size = zf.size(); + data = zf.read(); + } break; + #endif + #ifdef JMA_SUPPORT + case Reader::RF_JMA: { + try { + JMAReader jf(fn); + size = jf.size(); + data = jf.read(); + } catch(JMA::jma_errors jma_error) { + alert("Error loading image file (%s)!", fn); + return false; + } + } break; + #endif } return true; diff --git a/src/cc.bat b/src/cc.bat index a1dc3907..19a5664a 100644 --- a/src/cc.bat +++ b/src/cc.bat @@ -1,6 +1,6 @@ -@make -r PLATFORM=win-mingw-lui -::@make -r PLATFORM=win-mingw-lui GZIP_SUPPORT=true JMA_SUPPORT=true -::@make -r PLATFORM=win-visualc-lui -::@make -r PLATFORM=win-visualc-lui GZIP_SUPPORT=true JMA_SUPPORT=true +@make -r PLATFORM=win-mingw-x86 +::@make -r PLATFORM=win-mingw-x86 GZIP_SUPPORT=true JMA_SUPPORT=true +::@make -r PLATFORM=win-visualc-x86 +::@make -r PLATFORM=win-visualc-x86 GZIP_SUPPORT=true JMA_SUPPORT=true @move bsnes.exe ../bsnes.exe>nul @pause \ No newline at end of file diff --git a/src/cc.sh b/src/cc.sh index b38b88fc..02258c8d 100644 --- a/src/cc.sh +++ b/src/cc.sh @@ -1,3 +1 @@ -#!/bin/sh -make PLATFORM=x-gcc-lui -#make PLATFORM=x-gcc-lui GZIP_SUPPORT=true JMA_SUPPORT=true +make PLATFORM=x-gcc-x86 diff --git a/src/cheat/cheat.cpp b/src/cheat/cheat.cpp index 8726c684..a177b38e 100644 --- a/src/cheat/cheat.cpp +++ b/src/cheat/cheat.cpp @@ -10,17 +10,17 @@ Cheat cheat; *****/ bool Cheat::decode(char *str, uint32 &addr, uint8 &data, uint8 &type) { -stringarray t, part; +string t, part; strcpy(t, str); - strlower(t); - if(strlen(t) == 8 || (strlen(t) == 9 && strptr(t)[6] == ':')) { + strlower(t()); + if(strlen(t) == 8 || (strlen(t) == 9 && t()[6] == ':')) { type = CT_PRO_ACTION_REPLAY; replace(t, ":", ""); uint32 r = strhex(t); addr = r >> 8; data = r & 0xff; return true; - } else if(strlen(t) == 9 && strptr(t)[4] == '-') { + } else if(strlen(t) == 9 && t()[4] == '-') { type = CT_GAME_GENIE; replace(t, "-", ""); strtr(t, "df4709156bc8a23e", "0123456789abcdef"); @@ -269,51 +269,40 @@ void Cheat::disable(uint32 n) { * cheat file manipulation routines *****/ +/* file format: */ +/* nnnn-nnnn = status, "description" \r\n */ +/* ... */ + bool Cheat::load(const char *fn) { -FileReader rf(fn); - if(!rf.ready())return false; - -uint8 *raw_data = rf.read(); -stringarray data, line; - raw_data[rf.size()] = 0; - strcpy(data, (char*)raw_data); - safe_free(raw_data); +string data; + if(!fread(data, fn)) return false; replace(data, "\r\n", "\n"); + qreplace(data, "=", ","); + qreplace(data, " ", ""); +lstring line; split(line, "\n", data); for(int i = 0; i < ::count(line); i++) { - stringarray part; - uint8 en = *(strptr(line[i])); - if(en == '+') { - strltrim(line[i], "+"); - } else if(en == '-') { - strltrim(line[i], "-"); - } else { - continue; - } - qreplace(line[i], " ", ""); - qsplit(part, ",", line[i]); - if(::count(part) != 2)continue; - strunquote(part[1]); - add(en == '+', strptr(part[0]), strptr(part[1])); + lstring part; + split(part, ",", line[i]); + if(::count(part) != 3) continue; + trim(part[2], "\""); + add(part[1] == "enabled", part[0](), part[2]()); } return true; } bool Cheat::save(const char *fn) { -FileWriter wf(fn); - if(!wf.ready())return false; - -string data; -char t[4096]; - strcpy(data, ""); +FILE *fp = fopen(fn, "wb"); + if(!fp) return false; for(int i = 0; i < cheat_count; i++) { - sprintf(t, "%c%s, \"%s\"\r\n", index[i].enabled ? '+' : '-', index[i].code, index[i].desc); - strcat(data, t); + fprintf(fp, "%9s = %8s, \"%s\"\r\n", + index[i].code, + index[i].enabled ? "enabled" : "disabled", + index[i].desc); } - - wf.write((uint8*)strptr(data), strlen(data)); + fclose(fp); return true; } @@ -323,12 +312,12 @@ char t[4096]; void Cheat::clear() { cheat_enabled = false; - cheat_count = 0; + cheat_count = 0; memset(mask, 0, 0x200000); - for(int i = 0; i < CHEAT_LIMIT + 1; i++) { + for(int i = 0; i <= CHEAT_LIMIT; i++) { index[i].enabled = false; - index[i].addr = 0x000000; - index[i].data = 0x00; + index[i].addr = 0x000000; + index[i].data = 0x00; strcpy(index[i].code, ""); strcpy(index[i].desc, ""); } diff --git a/src/clean.bat b/src/clean.bat index 83ce6cfa..80cc34cc 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -1,2 +1,2 @@ -@make PLATFORM=win-mingw-lui clean -::@make PLATFORM=win-visualc-lui clean +@make PLATFORM=win-mingw-x86 clean +::@make PLATFORM=win-visualc-x86 clean diff --git a/src/clean.sh b/src/clean.sh index 0b82ddb6..0709a319 100644 --- a/src/clean.sh +++ b/src/clean.sh @@ -1,2 +1 @@ -#!/bin/sh -make PLATFORM=x-gcc-lui clean \ No newline at end of file +make PLATFORM=x-gcc-x86 clean diff --git a/src/config/config.cpp b/src/config/config.cpp index d322d2e7..dea6cd8b 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -15,14 +15,14 @@ string path(req_path); if(!strend(path, "/")) { strcat(path, "/"); } if(strbegin(path, "./")) { - strltrim(path, "./"); + ltrim(path(), "./"); string temp; strcpy(temp, config::path.base); strcat(temp, path); strcpy(path, temp); } -stringarray part; +lstring part; split(part, "/", file); strcat(path, part[count(part) - 1]); return path; diff --git a/src/configure b/src/configure deleted file mode 100644 index d3b8d0c4..00000000 --- a/src/configure +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -echo "Warning: bsnes does not use a configure script" -echo "To compile bsnes, use make ..." -echo "" -make #prints make usage instructions diff --git a/src/interface.h b/src/interface.h index a1ffaf81..8041270a 100644 --- a/src/interface.h +++ b/src/interface.h @@ -1,36 +1,37 @@ -#include "memory/memory.h" -#include "memory/smemory/smemory.h" - -#include "cpu/cpu.h" -#include "cpu/scpu/scpu.h" - -#include "smp/smp.h" -#include "smp/ssmp/ssmp.h" - -#include "dsp/dsp.h" -//#include "dsp/adsp/adsp.h" -#include "dsp/bdsp/bdsp.h" - -#include "ppu/ppu.h" -#include "ppu/bppu/bppu.h" - -#include "snes/snes.h" -#include "chip/chip.h" - -#include "reader/reader.h" -#include "cart/cart.h" -#include "cheat/cheat.h" -#include "config/config.h" - -#ifdef INTERFACE_MAIN - #include "config/config.cpp" - #define extern -#endif - -extern BUSCORE bus; -extern CPUCORE cpu; -extern SMPCORE smp; -extern DSPCORE dsp; -extern PPUCORE ppu; - -#undef extern +#include "reader/reader.h" +#include "cheat/cheat.h" +#include "config/config.h" + +#include "memory/memory.h" +#include "memory/smemory/smemory.h" + +#include "cart/cart.h" + +#include "cpu/cpu.h" +#include "cpu/scpu/scpu.h" + +#include "smp/smp.h" +#include "smp/ssmp/ssmp.h" + +#include "dsp/dsp.h" +//#include "dsp/adsp/adsp.h" +#include "dsp/bdsp/bdsp.h" + +#include "ppu/ppu.h" +#include "ppu/bppu/bppu.h" + +#include "snes/snes.h" +#include "chip/chip.h" + +#ifdef INTERFACE_MAIN + #include "config/config.cpp" + #define extern +#endif + +extern BUSCORE bus; +extern CPUCORE cpu; +extern SMPCORE smp; +extern DSPCORE dsp; +extern PPUCORE ppu; + +#undef extern diff --git a/src/lib/barray.h b/src/lib/barray.h new file mode 100644 index 00000000..62cf32ad --- /dev/null +++ b/src/lib/barray.h @@ -0,0 +1,87 @@ +/* + barray : version 0.10 ~byuu (2007-11-29) + license: public domain +*/ + +#ifndef BARRAY_H +#define BARRAY_H + +template class array { +protected: + T *pool; + uint poolsize, buffersize; + + uint findsize(uint size) { + if(size <= 0x100) return 0x100; + if(size <= 0x400) return 0x400; + if(size <= 0x1000) return 0x1000; + if(size <= 0x4000) return 0x4000; + if(size <= 0x10000) return 0x10000; + if(size <= 0x40000) return 0x40000; + if(size <= 0x100000) return 0x100000; + + return (size + 0x100000) & ~0xfffff; + } + +public: + uint size() { return buffersize; } + uint capacity() { return poolsize; } + + void reset() { + safe_free(pool); + poolsize = 0; + buffersize = 0; + } + + void reserve(uint size) { + if(size == poolsize) return; + if(size < poolsize) buffersize = size; + + pool = (T*)realloc(pool, sizeof(T) * size); + poolsize = size; + } + + T* get(uint size = 0) { + if(size > buffersize) resize(size); + if(size > buffersize) throw "array[] out of bounds"; + return pool; + } + + void add(T data) { + operator[](buffersize) = data; + } + + void clear() { + memset(pool, 0, sizeof(T) * buffersize); + } + + void resize(uint size) { + reserve(findsize(size)); + buffersize = size; + } + + array() { + pool = 0; + poolsize = 0; + buffersize = 0; + } + + ~array() { reset(); } + + array& operator=(array &source) { + safe_free(pool); + buffersize = source.buffersize; + poolsize = source.poolsize; + pool = (T*)realloc(pool, sizeof(T) * poolsize); //allocate entire pool size ... + memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects + return *this; + } + + inline T& operator[](int index) { + if(index >= buffersize) resize(index + 1); + if(index >= buffersize) throw "array[] out of bounds"; + return pool[index]; + } +}; + +#endif //ifndef BARRAY_H diff --git a/src/lib/libbase.h b/src/lib/bbase.h similarity index 92% rename from src/lib/libbase.h rename to src/lib/bbase.h index 163e68dd..5908a98b 100644 --- a/src/lib/libbase.h +++ b/src/lib/bbase.h @@ -1,10 +1,10 @@ /* - libbase : version 0.11a ~byuu (2007-10-14) + bbase : version 0.12 ~byuu (2007-12-12) license: public domain */ -#ifndef LIBBASE_H -#define LIBBASE_H +#ifndef BBASE_H +#define BBASE_H #include #include @@ -109,7 +109,27 @@ struct passwd *userinfo = getpwuid(getuid()); #endif /***** - * templates + * template classes + *****/ + +class noncopyable { +protected: + noncopyable() {} + ~noncopyable() {} + +private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); +}; + +template +struct base_from_member { + T value; + base_from_member(T value_) : value(value_) {} +}; + +/***** + * template functions *****/ template inline void safe_free(T &handle) { @@ -324,4 +344,4 @@ uint32 crc32 = ~0; return ~crc32; } -#endif +#endif //ifndef BBASE_H diff --git a/src/lib/libconfig.h b/src/lib/bconfig.h similarity index 64% rename from src/lib/libconfig.h rename to src/lib/bconfig.h index 52ba1b64..926c25b6 100644 --- a/src/lib/libconfig.h +++ b/src/lib/bconfig.h @@ -1,54 +1,52 @@ /* - libconfig : version 0.15 ~byuu (2007-11-01) + bconfig : version 0.16 ~byuu (2007-11-28) license: public domain */ -#ifndef LIBCONFIG_H -#define LIBCONFIG_H +#ifndef BCONFIG_H +#define BCONFIG_H -#include "libbase.h" -#include "libarray.h" -#include "libstring.h" +#include "bbase.h" +#include "barray.h" +#include "bstring.h" class Setting; -class Config { public: -array list; -uint list_count; +class Config { +public: + array list; + uint list_count; -string data; -stringarray line, part, subpart; + string data; + lstring line, part, subpart; bool load(const char *fn); bool save(const char *fn); - bool load(const string &fn) { return load(strptr(fn)); } - bool save(const string &fn) { return save(strptr(fn)); } void add(Setting *setting) { list[list_count++] = setting; } Config() : list_count(0) {} }; -class Setting { public: -uint type; -char *name, *desc, *def; - -enum Type { - Integer, - String, -}; +class Setting { +public: + enum Type { + Integer, + String, + } type; + char *name, *desc, *def; virtual void set(const char *input) = 0; virtual void get(string &output) = 0; }; -class IntegerSetting : public Setting { public: -uint ifmt, data, idef; - -enum Format { - Boolean, - Decimal, - Hex, -}; +class IntegerSetting : public Setting { +public: + enum Format { + Boolean, + Decimal, + Hex, + } ifmt; + uint data, idef; void set(const char *input) { if(ifmt == Boolean) { data = !strcmp(input, "true"); } @@ -57,9 +55,10 @@ enum Format { } void get(string &output) { - if(ifmt == Boolean) { sprintf(output, "%s", data ? "true" : "false"); } - if(ifmt == Decimal) { sprintf(output, "%d", data); } - if(ifmt == Hex) { sprintf(output, "0x%x", data); } + output.reserve(64); + if(ifmt == Boolean) { sprintf(output(), "%s", data ? "true" : "false"); } + if(ifmt == Decimal) { sprintf(output(), "%d", data); } + if(ifmt == Hex) { sprintf(output(), "0x%x", data); } } uint operator()() { return data; } @@ -72,7 +71,7 @@ enum Format { template bool operator<=(T x) { return (T(data) <= x); } template bool operator< (T x) { return (T(data) < x); } - IntegerSetting(Config *parent, const char *r_name, const char *r_desc, uint r_format, uint r_data) { + IntegerSetting(Config *parent, const char *r_name, const char *r_desc, Format r_format, uint r_data) { type = Setting::Integer; name = strdup(r_name); desc = strdup(r_desc); @@ -80,25 +79,26 @@ enum Format { data = idef = r_data; string t; get(t); - def = strdup(strptr(t)); + def = strdup(t); if(parent) { parent->add(this); } } ~IntegerSetting() { - free(name); - free(desc); - free(def); + safe_free(name); + safe_free(desc); + safe_free(def); } }; -class StringSetting : public Setting { public: -string data; - void set(const char *input) { data = input; strunquote(data); } - void get(string &output) { output = data; strquote(output); } +class StringSetting : public Setting { +public: + string data; + void set(const char *input) { data = input; trim(data(), "\""); } + void get(string &output) { output = string() << "\"" << data << "\""; } - const char* operator()() { return strptr(data); } - operator const char*() { return strptr(data); } + char* operator()() { return data(); } + operator const char*() { return data; } StringSetting &operator=(const char *x) { data = x; return *this; } bool operator==(const char *x) { return !strcmp(data, x); } bool operator!=(const char *x) { return strcmp(data, x); } @@ -110,15 +110,15 @@ string data; data = r_data; string t; get(t); - def = strdup(strptr(t)); + def = strdup(t); if(parent) { parent->add(this); } } ~StringSetting() { - free(name); - free(desc); - free(def); + safe_free(name); + safe_free(desc); + safe_free(def); } }; @@ -145,12 +145,12 @@ char *buffer = (char*)malloc(fsize + 1); for(int i = 0; i < count(line); i++) { if(strlen(line[i]) == 0)continue; - if(*strptr(line[i]) == '#')continue; + if(*line[i] == '#')continue; qsplit(part, "=", line[i]); for(int l = 0; l < list_count; l++) { if(!strcmp(list[l]->name, part[0])) { - list[l]->set(strptr(part[1])); + list[l]->set(part[1]); break; } } @@ -170,16 +170,16 @@ string t; replace(data, "\r\n", "\n"); split(line, "\n", data); for(int l = 0; l < count(line); l++) { - if(line[l] != "") { fprintf(fp, "# %s\r\n", strptr(line[l])); } + if(line[l] != "") { fprintf(fp, "# %s\r\n", line[l]()); } } fprintf(fp, "# (default = %s)\r\n", list[i]->def); list[i]->get(t); - fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, strptr(t)); + fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, t()); } fclose(fp); return true; } -#endif +#endif //ifndef BCONFIG_H diff --git a/src/lib/libfunction.h b/src/lib/bfunction.h similarity index 86% rename from src/lib/libfunction.h rename to src/lib/bfunction.h index 068ce597..ce602a8d 100644 --- a/src/lib/libfunction.h +++ b/src/lib/bfunction.h @@ -1,10 +1,10 @@ /* - libfunction : version 0.06 ~byuu (2007-10-14) + bfunction : version 0.06 ~byuu (2007-10-14) license: public domain */ -#ifndef LIBFUNCTION_H -#define LIBFUNCTION_H +#ifndef BFUNCTION_H +#define BFUNCTION_H //prologue @@ -19,7 +19,7 @@ template class function; #define PL #define CL -#include "libfunction.h" +#include "bfunction.h" //parameters = 1 @@ -28,7 +28,7 @@ template class function; #define PL P1 p1 #define CL p1 -#include "libfunction.h" +#include "bfunction.h" //parameters = 2 @@ -37,7 +37,7 @@ template class function; #define PL P1 p1, P2 p2 #define CL p1, p2 -#include "libfunction.h" +#include "bfunction.h" //parameters = 3 @@ -46,7 +46,7 @@ template class function; #define PL P1 p1, P2 p2, P3 p3 #define CL p1, p2, p3 -#include "libfunction.h" +#include "bfunction.h" //parameters = 4 @@ -55,7 +55,7 @@ template class function; #define PL P1 p1, P2 p2, P3 p3, P4 p4 #define CL p1, p2, p3, p4 -#include "libfunction.h" +#include "bfunction.h" //parameters = 5 @@ -64,7 +64,7 @@ template class function; #define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 #define CL p1, p2, p3, p4, p5 -#include "libfunction.h" +#include "bfunction.h" //parameters = 6 @@ -73,7 +73,7 @@ template class function; #define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 #define CL p1, p2, p3, p4, p5, p6 -#include "libfunction.h" +#include "bfunction.h" //parameters = 7 @@ -82,7 +82,7 @@ template class function; #define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 #define CL p1, p2, p3, p4, p5, p6, p7 -#include "libfunction.h" +#include "bfunction.h" //parameters = 8 @@ -91,13 +91,14 @@ template class function; #define PL P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8 #define CL p1, p2, p3, p4, p5, p6, p7, p8 -#include "libfunction.h" +#include "bfunction.h" //epilogue #undef TN +#define BFUNCTION_TH -#else //defined(LIBFUNCTION_H) +#elif !defined(BFUNCTION_TH) //function implementation template class diff --git a/src/lib/libkeymap.h b/src/lib/bkeymap.h similarity index 94% rename from src/lib/libkeymap.h rename to src/lib/bkeymap.h index a0e0109c..b11af5a5 100644 --- a/src/lib/libkeymap.h +++ b/src/lib/bkeymap.h @@ -1,9 +1,10 @@ /* - libkeymap : version 0.02 ~byuu (2007-05-28) + bkeymap : version 0.02 ~byuu (2007-05-28) + license: public domain */ -#ifndef LIBKEYMAP_H -#define LIBKEYMAP_H +#ifndef BKEYMAP_H +#define BKEYMAP_H namespace keymap { @@ -306,4 +307,4 @@ static const char *find(uint16 key) { }; -#endif +#endif //ifndef BKEYMAP_H diff --git a/src/lib/bstring.cpp b/src/lib/bstring.cpp new file mode 100644 index 00000000..65fc66f8 --- /dev/null +++ b/src/lib/bstring.cpp @@ -0,0 +1,95 @@ +#include "bstring.h" + +#include "bstring/bstring.list.cpp" +#include "bstring/bstring.strl.cpp" +#include "bstring/bstring.math.cpp" +#include "bstring/bstring.misc.cpp" +#include "bstring/bstring.replace.cpp" +#include "bstring/bstring.split.cpp" +#include "bstring/bstring.trim.cpp" + +void string::reserve(uint size_) { + if(size_ > size) { + size = size_; + data = (char*)realloc(data, size + 1); + data[size] = 0; + } +} + +//implicit-conversion, read-only +string::operator const char*() const { + return data; +} + +//explicit-coversion, read-write +char* string::operator()() { + return data; +} + +//index, read-write +char& string::operator[](const uint index) { + reserve(index); + return data[index]; +} + +string& string::operator=(const int num) { + itoa(*this, num); + return *this; +} + +string& string::operator=(const char *str) { + strcpy(*this, str); + return *this; +} + +string& string::operator=(const string &str) { + strcpy(*this, str); + return *this; +} + +string& string::operator<<(const int num) { +string temp(num); + strcat(*this, temp); + return *this; +} + +string& string::operator<<(const char *str) { + strcat(*this, str); + return *this; +} + +bool string::operator==(const char *str) { return strcmp(data, str) == 0; } +bool string::operator!=(const char *str) { return strcmp(data, str) != 0; } +bool string::operator< (const char *str) { return strcmp(data, str) < 0; } +bool string::operator<=(const char *str) { return strcmp(data, str) <= 0; } +bool string::operator> (const char *str) { return strcmp(data, str) > 0; } +bool string::operator>=(const char *str) { return strcmp(data, str) >= 0; } + +string::string() { + size = 64; + data = (char*)malloc(size + 1); + *data = 0; +} + +string::string(const int source) { + size = 64; + data = (char*)malloc(size + 1); + *data = 0; + itoa(*this, source); +} + +string::string(const char *source) { + size = strlen(source); + data = (char*)malloc(size + 1); + strcpy(data, source); +} + +string::string(const string &source) { + size = strlen(source); + data = (char*)malloc(size + 1); + strcpy(data, source); +} + +string::~string() { + safe_free(data); +} diff --git a/src/lib/bstring.h b/src/lib/bstring.h new file mode 100644 index 00000000..64602e4d --- /dev/null +++ b/src/lib/bstring.h @@ -0,0 +1,99 @@ +/* + bstring : version 0.01a ~byuu (2007-12-12) + license: public domain +*/ + +#ifndef BSTRING_H +#define BSTRING_H + +#include "bbase.h" +#include "bvector.h" + +class string; +typedef linear_vector lstring; + +uint count(lstring&); +int find(lstring &str, const char *key); + +uint strlcpy(char *dest, const char *src, uint length); +uint strlcat(char *dest, const char *src, uint length); +uint strlcpy(string &dest, const char *src, uint length); +uint strlcat(string &dest, const char *src, uint length); + +int strmath(const char *str); + +char chrlower(char c); +char chrupper(char c); +int stricmp(const char *dest, const char *src); +void strcpy(string &dest, const char *src); +void strcat(string &dest, const char *src); +string substr(string &dest, const char *src, uint start = 0, uint length = 0); +char* strlower(char *str); +char* strupper(char *str); +string& strlower(string &str); +string& strupper(string &str); +int strpos(const char *str, const char *key); +int qstrpos(const char *str, const char *key); +char* strtr(char *dest, const char *before, const char *after); +string& strtr(string &dest, const char *before, const char *after); +bool strbegin(const char *str, const char *key); +bool stribegin(const char *str, const char *key); +bool strend(const char *str, const char *key); +bool striend(const char *str, const char *key); + +uint strhex(const char *str); +uint strdec(const char *str); +uint strbin(const char *str); + +string& utoa(string &str, uint num); +string& itoa(string &str, uint num); +string& htoa(string &str, uint num); +string& btoa(string &str, uint num); + +bool fread(string &str, const char *filename); + +string& replace(string &str, const char *key, const char *token); +string& qreplace(string &str, const char *key, const char *token); + +void split(lstring &dest, const char *key, const char *src); +void qsplit(lstring &dest, const char *key, const char *src); + +char* ltrim(char *str, const char *key = " "); +char* rtrim(char *str, const char *key = " "); +char* trim(char *str, const char *key = " "); +string& ltrim(string &str, const char *key = " "); +string& rtrim(string &str, const char *key = " "); +string& trim(string &str, const char *key = " "); + +class string { +public: + char *data; + uint size; + + void reserve(uint size_); + + operator const char*() const; + char* operator()(); + char& operator[](const uint); + + string& operator=(const int num); + string& operator=(const char *str); + string& operator=(const string &str); + string& operator<<(const int num); + string& operator<<(const char *str); + + bool operator==(const char *str); + bool operator!=(const char *str); + bool operator< (const char *str); + bool operator<=(const char *str); + bool operator> (const char *str); + bool operator>=(const char *str); + + string(); + string(const int num); + string(const char *source); + string(const string &source); + ~string(); +}; + +#endif //ifndef BSTRING_H diff --git a/src/lib/bstring/bstring.list.cpp b/src/lib/bstring/bstring.list.cpp new file mode 100644 index 00000000..c924ead0 --- /dev/null +++ b/src/lib/bstring/bstring.list.cpp @@ -0,0 +1,14 @@ +#ifdef BSTRING_H + +uint count(lstring &str) { + return str.size(); +} + +int find(lstring &str, const char *key) { + for(uint i = 0; i < count(str); i++) { + if(str[i] == key) return i; + } + return -1; +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/libstring_math.cpp b/src/lib/bstring/bstring.math.cpp similarity index 64% rename from src/lib/libstring_math.cpp rename to src/lib/bstring/bstring.math.cpp index a641d7f0..8f08c5f1 100644 --- a/src/lib/libstring_math.cpp +++ b/src/lib/bstring/bstring.math.cpp @@ -1,121 +1,194 @@ -/* - c-style Math Evaluator v1.0 (07/03/2006) - Algorithm: Recursive Descent Processor - Written by: gladius - Optimized by: gladius and byuu - Public Domain -*/ - -#define maxlevel 12 -int strmath_rdp(const char *&s, int level = 0) { - if(level == maxlevel) { - if(*s == '(') { - int result = strmath_rdp(++s, 0); - s++; - return result; - } else if(*s == '+') { - return +strmath_rdp(++s, maxlevel); - } else if(*s == '-') { - return -strmath_rdp(++s, maxlevel); - } else if(*s == '!') { - return !strmath_rdp(++s, maxlevel); - } else if(*s == '~') { - return ~strmath_rdp(++s, maxlevel); - } else if(*s >= '0' && *s <= '9') { - int num, len; - sscanf(s, "%d%n", &num, &len); - s += len; - return num; - } - } - -int lhs = strmath_rdp(s, level + 1); - while(*s) { - int a = *s; - int b = *s ? *(s + 1) : 0; - switch(level) { - case 0: - if(a == '?')break; - return lhs; - case 1: - if(a == '|' && b == '|') { s++; break; } - return lhs; - case 2: - if(a == '^' && b == '^') { s++; break; } - return lhs; - case 3: - if(a == '&' && b == '&') { s++; break; } - return lhs; - case 4: - if(a == '|' && b != '|')break; - return lhs; - case 5: - if(a == '^' && b != '^')break; - return lhs; - case 6: - if(a == '&' && b != '&')break; - return lhs; - case 7: - if(a == '=' && b == '=') { s++; break; } - if(a == '!' && b == '=') { s++; break; } - return lhs; - case 8: - if(a == '<' && b == '=') { s++; break; } - if(a == '>' && b == '=') { s++; break; } - if(a == '<')break; - if(a == '>')break; - return lhs; - case 9: - if(a == '<' && b == '<') { s++; break; } - if(a == '>' && b == '>') { s++; break; } - return lhs; - case 10: - if(a == '+')break; - if(a == '-')break; - return lhs; - case 11: - if(a == '*')break; - if(a == '/')break; - if(a == '%')break; - return lhs; - } - if(a == '?') { - int tr = strmath_rdp(++s, level); - int fr = strmath_rdp(++s, level); - lhs = (lhs) ? tr : fr; - } else { - int rhs = strmath_rdp(++s, level + 1); - if (a == '|' && b == '|') lhs = (lhs || rhs); - else if(a == '^' && b == '^') lhs = (!lhs != !rhs); - else if(a == '&' && b == '&') lhs = (lhs && rhs); - else if(a == '|' && b != '|') lhs |= rhs; - else if(a == '^' && b != '^') lhs ^= rhs; - else if(a == '&' && b != '&') lhs &= rhs; - else if(a == '=' && b == '=') lhs = (lhs == rhs); - else if(a == '!' && b == '=') lhs = (lhs != rhs); - else if(a == '<' && b == '=') lhs = (lhs <= rhs); - else if(a == '>' && b == '=') lhs = (lhs >= rhs); - else if(a == '<' && b != '<') lhs = (lhs < rhs); - else if(a == '>' && b != '>') lhs = (lhs > rhs); - else if(a == '<' && b == '<') lhs <<= rhs; - else if(a == '>' && b == '>') lhs >>= rhs; - else if(a == '+') lhs += rhs; - else if(a == '-') lhs -= rhs; - else if(a == '*') lhs *= rhs; - else if(a == '/') lhs /= rhs; - else if(a == '%') lhs %= rhs; - } - } - return lhs; -} -#undef maxlevel - -int strmath(const char *str) { - return strmath_rdp(str); -} - -#ifdef __LIBSTRING -int strmath(const string &str) { - return strmath(strptr(str)); -} -#endif +#ifdef BSTRING_H + +/* + recursive descent math processor v0.02 (2007-11-28) + authors: gladius, byuu + license: public domain +*/ + +void strmath_space(const char *&s) { + while(*s == ' ' || *s == '\t')s++; +} + +int strmath_number(const char *&s) { +int result = 0; +enum type { dec, hex, bin, oct }; +type t = dec; + if(*s == '0') { + s++; + if(*s == 'x' || *s == 'X') { s++; t = hex; } + else if(*s == 'b' || *s == 'B') { s++; t = bin; } + else { t = oct; } + } else if(*s == '$') { + s++; + t = hex; + } else if(*s == '%') { + s++; + t = bin; + } + + switch(t) { + + case dec: { + while(true) { + char x = *s; + if(x >= '0' && x <= '9')x = x - '0'; + else break; + result = result * 10 + x; + s++; + } + } break; + + case hex: { + while(true) { + char x = *s; + if(x >= '0' && x <= '9')x = x - '0'; + else if(x >= 'a' && x <= 'f')x = x - 'a' + 0x0a; + else if(x >= 'A' && x <= 'F')x = x - 'A' + 0x0a; + else break; + result = result * 16 + x; + s++; + } + } break; + + case bin: { + while(true) { + char x = *s; + if(x >= '0' && x <= '1')x = x - '0'; + else break; + result = result * 2 + x; + s++; + } + } break; + + case oct: { + while(true) { + char x = *s; + if(x >= '0' && x <= '7')x = x - '0'; + else break; + result = result * 8 + x; + s++; + } + } break; + + } + + return result; + +int num, len; + sscanf(s, "%d%n", &num, &len); + s += len; + return num; +} + +#define maxlevel 12 +int strmath_rdp(const char *&s, int level = 0) { + strmath_space(s); + + if(level == maxlevel) { + if(*s == '(') { + int result = strmath_rdp(++s, 0); + s++; + return result; + } else if(*s == '+') { + return +strmath_rdp(++s, maxlevel); + } else if(*s == '-') { + return -strmath_rdp(++s, maxlevel); + } else if(*s == '!') { + return !strmath_rdp(++s, maxlevel); + } else if(*s == '~') { + return ~strmath_rdp(++s, maxlevel); + } else if((*s >= '0' && *s <= '9') || *s == '$' || *s == '%') { + return strmath_number(s); + } else { + return 0; //error + } + } + +int lhs = strmath_rdp(s, level + 1); + strmath_space(s); + while(*s) { + int a = *s; + int b = *s ? *(s + 1) : 0; + switch(level) { + case 0: + if(a == '?')break; + return lhs; + case 1: + if(a == '|' && b == '|') { s++; break; } + return lhs; + case 2: + if(a == '^' && b == '^') { s++; break; } + return lhs; + case 3: + if(a == '&' && b == '&') { s++; break; } + return lhs; + case 4: + if(a == '|' && b != '|')break; + return lhs; + case 5: + if(a == '^' && b != '^')break; + return lhs; + case 6: + if(a == '&' && b != '&')break; + return lhs; + case 7: + if(a == '=' && b == '=') { s++; break; } + if(a == '!' && b == '=') { s++; break; } + return lhs; + case 8: + if(a == '<' && b == '=') { s++; break; } + if(a == '>' && b == '=') { s++; break; } + if(a == '<')break; + if(a == '>')break; + return lhs; + case 9: + if(a == '<' && b == '<') { s++; break; } + if(a == '>' && b == '>') { s++; break; } + return lhs; + case 10: + if(a == '+')break; + if(a == '-')break; + return lhs; + case 11: + if(a == '*')break; + if(a == '/')break; + if(a == '%')break; + return lhs; + } + if(a == '?') { + int tr = strmath_rdp(++s, level); + int fr = strmath_rdp(++s, level); + lhs = (lhs) ? tr : fr; + } else { + int rhs = strmath_rdp(++s, level + 1); + if (a == '|' && b == '|') lhs = (lhs || rhs); + else if(a == '^' && b == '^') lhs = (!lhs != !rhs); + else if(a == '&' && b == '&') lhs = (lhs && rhs); + else if(a == '|' && b != '|') lhs |= rhs; + else if(a == '^' && b != '^') lhs ^= rhs; + else if(a == '&' && b != '&') lhs &= rhs; + else if(a == '=' && b == '=') lhs = (lhs == rhs); + else if(a == '!' && b == '=') lhs = (lhs != rhs); + else if(a == '<' && b == '=') lhs = (lhs <= rhs); + else if(a == '>' && b == '=') lhs = (lhs >= rhs); + else if(a == '<' && b != '<') lhs = (lhs < rhs); + else if(a == '>' && b != '>') lhs = (lhs > rhs); + else if(a == '<' && b == '<') lhs <<= rhs; + else if(a == '>' && b == '>') lhs >>= rhs; + else if(a == '+') lhs += rhs; + else if(a == '-') lhs -= rhs; + else if(a == '*') lhs *= rhs; + else if(a == '/') lhs /= rhs; + else if(a == '%') lhs %= rhs; + } + } + return lhs; +} +#undef maxlevel + +int strmath(const char *str) { + return strmath_rdp(str); +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/bstring/bstring.misc.cpp b/src/lib/bstring/bstring.misc.cpp new file mode 100644 index 00000000..8bf85fad --- /dev/null +++ b/src/lib/bstring/bstring.misc.cpp @@ -0,0 +1,277 @@ +#ifdef BSTRING_H + +char chrlower(char c) { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; +} + +char chrupper(char c) { + return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c; +} + +int stricmp(const char *dest, const char *src) { + while(*dest) { + if(chrlower(*dest) != chrlower(*src)) break; + dest++; + src++; + } + + return (int)chrlower(*dest) - (int)chrlower(*src); +} + +void strcpy(string &dest, const char *src) { +int srclen = strlen(src); + dest.reserve(srclen); + strcpy(dest(), src); +} + +void strcat(string &dest, const char *src) { +int srclen = strlen(src); +int destlen = strlen(dest); + dest.reserve(srclen + destlen); + strcat(dest(), src); +} + +string substr(const char *src, uint start, uint length) { +string dest; + if(length == 0) { + //copy entire string + strcpy(dest, src + start); + } else { + //copy partial string + strlcpy(dest, src + start, length + 1); + } + return dest; +} + +char* strlower(char *str) { +uint i = 0; + while(str[i]) { + str[i] = chrlower(str[i]); + i++; + } + return str; +} + +char* strupper(char *str) { +uint i = 0; + while(str[i]) { + str[i] = chrupper(str[i]); + i++; + } + return str; +} + +string& strlower(string &str) { + strlower(str()); + return str; +} + +string& strupper(string &str) { + strupper(str()); + return str; +} + +int strpos(const char *str, const char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl) return -1; + for(int i = 0; i <= ssl - ksl; i++) { + if(!memcmp(str + i, key, ksl)) { + return i; + } + } + return -1; +} + +int qstrpos(const char *str, const char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl) return -1; + for(int i = 0; i <= ssl - ksl;) { + uint8 x = str[i]; + if(x == '\"' || x == '\'') { + uint8 z = i++; + while(str[i] != x && i < ssl) i++; + if(i >= ssl) i = z; + } + if(!memcmp(str + i, key, ksl)) { + return i; + } else { + i++; + } + } + return -1; +} + +char* strtr(char *dest, const char *before, const char *after) { +int sl = strlen(dest), bsl = strlen(before), asl = strlen(after); + if(bsl != asl || bsl == 0) return dest; //patterns must be the same length for 1:1 replace + for(int i = 0; i < sl; i++) { + for(int l = 0; l < bsl; l++) { + if(dest[i] == before[l]) { + dest[i] = after[l]; + break; + } + } + } + return dest; +} + +string& strtr(string &dest, const char *before, const char *after) { + strtr(dest(), before, after); + return dest; +} + +bool strbegin(const char *str, const char *key) { +int i, ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return false; + return (!memcmp(str, key, ksl)); +} + +bool stribegin(const char *str, const char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return false; + for(int i = 0; i < ksl; i++) { + if(str[i] >= 'A' && str[i] <= 'Z') { + if(str[i] != key[i] && str[i]+0x20 != key[i])return false; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[i] && str[i]-0x20 != key[i])return false; + } else { + if(str[i] != key[i])return false; + } + } + return true; +} + +bool strend(const char *str, const char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return false; + return (!memcmp(str + ssl - ksl, key, ksl)); +} + +bool striend(const char *str, const char *key) { +int ssl = strlen(str), ksl = strlen(key); + if(ksl > ssl)return false; + for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) { + if(str[i] >= 'A' && str[i] <= 'Z') { + if(str[i] != key[z] && str[i]+0x20 != key[z])return false; + } else if(str[i] >= 'a' && str[i] <= 'z') { + if(str[i] != key[z] && str[i]-0x20 != key[z])return false; + } else { + if(str[i] != key[z])return false; + } + } + return true; +} + +uint strhex(const char *str) { +uint r = 0, m = 0; +int i = 0, ssl = strlen(str); +uint8 x; +bool negate = (str[0] == '-'); + if(negate)i++; + for(; i < ssl; i++) { + if(str[i] >= '0' && str[i] <= '9'); + else if(str[i] >= 'A' && str[i] <= 'F'); + else if(str[i] >= 'a' && str[i] <= 'f'); + else break; + } + for(--i; i >= 0; i--, m += 4) { + x = str[i]; + if(x >= '0' && x <= '9')x -= '0'; + else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a; + else if(x >= 'a' && x <= 'f')x -= 'a' - 0x0a; + else break; + r |= x << m; + } + return !negate ? r : (uint)-r; +} + +uint strdec(const char *str) { +uint m = 1; +int i = 0, r = 0, ssl = strlen(str); +uint8 x; +bool negate = (str[0] == '-'); + if(negate)i++; + for(; i < ssl; i++) { + if(str[i] >= '0' && str[i] <= '9'); + else break; + } + for(--i; i >= 0; i--, m *= 10) { + x = str[i]; + if(x >= '0' && x <= '9')x -= '0'; + else break; + r += x * m; + } + return !negate ? r : (uint)-r; +} + +uint strbin(const char *str) { +uint r = 0, m = 0; +int i = 0, ssl = strlen(str); +uint8 x; +bool negate = (str[0] == '-'); + if(negate)i++; + for(; i < ssl; i++) { + if(str[i] == '0' || str[i] == '1'); + else break; + } + for(--i; i >= 0; i--, m++) { + x = str[i]; + if(str[i] == '0' || str[i] == '1')x -= '0'; + else break; + r |= x << m; + } + return !negate ? r : (uint)-r; +} + +string &utoa(string &str, uint num) { + str.reserve(16); + sprintf(str(), "%u", num); + return str; +} + +string &itoa(string &str, uint num) { + str.reserve(16); + sprintf(str(), "%d", num); + return str; +} + +string &htoa(string &str, uint num) { + str.reserve(16); + sprintf(str(), "%x", num); + return str; +} + +string &btoa(string &str, uint num) { + str.reserve(64); + +char *pstr = str(); +uint mask = 0x80000000; + while(mask && (num & mask) == 0)mask >>= 1; + while(mask > 1) { + *pstr++ = (num & mask) ? '1' : '0'; + mask >>= 1; + } + *pstr++ = (num & mask) ? '1' : '0'; + *pstr = 0; + + return str; +} + +bool fread(string &str, const char *filename) { + strcpy(str, ""); + +FILE *fp = fopen(filename, "rb"); + if(!fp)return false; + +uint size = fsize(fp); +char *fdata = (char*)malloc(size + 1); + fread(fdata, 1, size, fp); + fclose(fp); + fdata[size] = 0; + strcpy(str, fdata); + free(fdata); + + return true; +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/libstring_replace.cpp b/src/lib/bstring/bstring.replace.cpp similarity index 68% rename from src/lib/libstring_replace.cpp rename to src/lib/bstring/bstring.replace.cpp index f5a3c032..3c35c78c 100644 --- a/src/lib/libstring_replace.cpp +++ b/src/lib/bstring/bstring.replace.cpp @@ -1,86 +1,88 @@ -string &replace(string &str, const char *key, const char *token) { -int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); -uint replace_count = 0, size = ssl; -char *data; - if(ksl > ssl)return str; - if(tsl > ksl) { //the new string may be longer than the old string... - for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need... - if(!memcmp(str.s + i, key, ksl)) { - replace_count++; - i += ksl; - } else i++; - } - size = ssl + ((tsl - ksl) * replace_count); - str.reserve(size); - } - data = (char*)malloc(size + 1); - for(i = z = 0; i < ssl;) { - if(i <= ssl - ksl) { - if(!memcmp(str.s + i, key, ksl)) { - memcpy(data + z, token, tsl); - z += tsl; - i += ksl; - } else data[z++] = str.s[i++]; - } else data[z++] = str.s[i++]; - } - data[z] = 0; - strcpy(str, data); - free(data); - return str; -} -string &replace(string &str, const char *key, const string &token) { return replace(str, key, strptr(token)); } - -string &qreplace(string &str, const char *key, const char *token) { -int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); -uint replace_count = 0, size = ssl; -uint8 x; -char *data; - if(ksl > ssl)return str; - if(tsl > ksl) { - for(i = 0; i <= ssl - ksl;) { - x = str.s[i]; - if(x == '\"' || x == '\'') { - l = i; - i++; - while(str.s[i++] != x) { - if(i == ssl) { - i = l; - break; - } - } - } - if(!memcmp(str.s + i, key, ksl)) { - replace_count++; - i += ksl; - } else i++; - } - size = ssl + ((tsl - ksl) * replace_count); - str.reserve(size); - } - data = (char*)malloc(size + 1); - for(i = z = 0; i < ssl;) { - x = str.s[i]; - if(x == '\"' || x == '\'') { - l = i++; - while(str.s[i] != x && i < ssl)i++; - if(i >= ssl)i = l; - else { - memcpy(data + z, str.s + l, i - l); - z += i - l; - } - } - if(i <= ssl - ksl) { - if(!memcmp(str.s + i, key, ksl)) { - memcpy(data + z, token, tsl); - z += tsl; - i += ksl; - replace_count++; - } else data[z++] = str.s[i++]; - } else data[z++] = str.s[i++]; - } - data[z] = 0; - strcpy(str, data); - free(data); - return str; -} -string &qreplace(string &str, const char *key, const string &token) { return qreplace(str, key, strptr(token)); } +#ifdef BSTRING_H + +string &replace(string &str, const char *key, const char *token) { +int i, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); +uint replace_count = 0, size = ssl; +char *data; + if(ksl > ssl)return str; + if(tsl > ksl) { //the new string may be longer than the old string... + for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need... + if(!memcmp(str() + i, key, ksl)) { + replace_count++; + i += ksl; + } else i++; + } + size = ssl + ((tsl - ksl) * replace_count); + str.reserve(size); + } + data = (char*)malloc(size + 1); + for(i = z = 0; i < ssl;) { + if(i <= ssl - ksl) { + if(!memcmp(str() + i, key, ksl)) { + memcpy(data + z, token, tsl); + z += tsl; + i += ksl; + } else data[z++] = str()[i++]; + } else data[z++] = str()[i++]; + } + data[z] = 0; + strcpy(str, data); + free(data); + return str; +} + +string &qreplace(string &str, const char *key, const char *token) { +int i, l, z, ksl = strlen(key), tsl = strlen(token), ssl = strlen(str); +uint replace_count = 0, size = ssl; +uint8 x; +char *data; + if(ksl > ssl)return str; + if(tsl > ksl) { + for(i = 0; i <= ssl - ksl;) { + x = str()[i]; + if(x == '\"' || x == '\'') { + l = i; + i++; + while(str()[i++] != x) { + if(i == ssl) { + i = l; + break; + } + } + } + if(!memcmp(str() + i, key, ksl)) { + replace_count++; + i += ksl; + } else i++; + } + size = ssl + ((tsl - ksl) * replace_count); + str.reserve(size); + } + data = (char*)malloc(size + 1); + for(i = z = 0; i < ssl;) { + x = str()[i]; + if(x == '\"' || x == '\'') { + l = i++; + while(str()[i] != x && i < ssl)i++; + if(i >= ssl)i = l; + else { + memcpy(data + z, str() + l, i - l); + z += i - l; + } + } + if(i <= ssl - ksl) { + if(!memcmp(str() + i, key, ksl)) { + memcpy(data + z, token, tsl); + z += tsl; + i += ksl; + replace_count++; + } else data[z++] = str()[i++]; + } else data[z++] = str()[i++]; + } + data[z] = 0; + strcpy(str, data); + free(data); + return str; +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/libstring_split.cpp b/src/lib/bstring/bstring.split.cpp similarity index 67% rename from src/lib/libstring_split.cpp rename to src/lib/bstring/bstring.split.cpp index 8fb29dc7..24436f77 100644 --- a/src/lib/libstring_split.cpp +++ b/src/lib/bstring/bstring.split.cpp @@ -1,37 +1,39 @@ -void split(stringarray &dest, const char *key, const char *src) { - dest.reset(); - -int ssl = strlen(src), ksl = strlen(key); -int lp = 0, split_count = 0; - for(int i = 0; i <= ssl - ksl;) { - if(!memcmp(src + i, key, ksl)) { - strlcpy(dest[split_count++], src + lp, i - lp + 1); - i += ksl; - lp = i; - } else i++; - } - strcpy(dest[split_count++], src + lp); -} -void split(stringarray &dest, const char *key, const string &src) { split(dest, key, strptr(src)); } - -void qsplit(stringarray &dest, const char *key, const char *src) { - dest.reset(); - -int z, ssl = strlen(src), ksl = strlen(key); -int lp = 0, split_count = 0; - for(int i = 0; i <= ssl - ksl;) { - uint8 x = src[i]; - if(x == '\"' || x == '\'') { - z = i++; - while(src[i] != x && i < ssl)i++; - if(i >= ssl)i = z; - } - if(!memcmp(src + i, key, ksl)) { - strlcpy(dest[split_count++], src + lp, i - lp + 1); - i += ksl; - lp = i; - } else i++; - } - strcpy(dest[split_count++], src + lp); -} -void qsplit(stringarray &dest, const char *key, const string &src) { qsplit(dest, key, strptr(src)); } +#ifdef BSTRING_H + +void split(lstring &dest, const char *key, const char *src) { + dest.reset(); + +int ssl = strlen(src), ksl = strlen(key); +int lp = 0, split_count = 0; + for(int i = 0; i <= ssl - ksl;) { + if(!memcmp(src + i, key, ksl)) { + strlcpy(dest[split_count++], src + lp, i - lp + 1); + i += ksl; + lp = i; + } else i++; + } + strcpy(dest[split_count++], src + lp); +} + +void qsplit(lstring &dest, const char *key, const char *src) { + dest.reset(); + +int z, ssl = strlen(src), ksl = strlen(key); +int lp = 0, split_count = 0; + for(int i = 0; i <= ssl - ksl;) { + uint8 x = src[i]; + if(x == '\"' || x == '\'') { + z = i++; + while(src[i] != x && i < ssl)i++; + if(i >= ssl)i = z; + } + if(!memcmp(src + i, key, ksl)) { + strlcpy(dest[split_count++], src + lp, i - lp + 1); + i += ksl; + lp = i; + } else i++; + } + strcpy(dest[split_count++], src + lp); +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/bstring/bstring.strl.cpp b/src/lib/bstring/bstring.strl.cpp new file mode 100644 index 00000000..33c4e1f8 --- /dev/null +++ b/src/lib/bstring/bstring.strl.cpp @@ -0,0 +1,31 @@ +#ifdef BSTRING_H + +uint strlcpy(char *dest, const char *src, uint length) { +uint srclen = strlen(src); + length--; + if(length > srclen) length = srclen; + memcpy(dest, src, length); + dest[length] = 0; + return srclen; +} + +uint strlcat(char *dest, const char *src, uint length) { +uint destlen = strlen(dest), srclen = strlen(src); + length--; + if(length > destlen + srclen) length = destlen + srclen; + memcpy(dest + destlen, src, length - destlen); + dest[length] = 0; + return destlen + srclen; +} + +uint strlcpy(string &dest, const char *src, uint length) { + dest.reserve(length); + return strlcpy(dest(), src, length); +} + +uint strlcat(string &dest, const char *src, uint length) { + dest.reserve(length); + return strlcat(dest(), src, length); +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/bstring/bstring.trim.cpp b/src/lib/bstring/bstring.trim.cpp new file mode 100644 index 00000000..59ba3c1a --- /dev/null +++ b/src/lib/bstring/bstring.trim.cpp @@ -0,0 +1,39 @@ +#ifdef BSTRING_H + +char* ltrim(char *str, const char *key) { + if(!key || !*key) return str; + while(strbegin(str, key)) { + string temp = str; + strcpy(str, temp() + strlen(key)); + } + return str; +} + +char* rtrim(char *str, const char *key) { + if(!key || !*key) return str; + while(strend(str, key)) { + str[strlen(str) - strlen(key)] = 0; + } + return str; +} + +char* trim(char *str, const char *key) { + return ltrim(rtrim(str, key), key); +} + +string& ltrim(string &str, const char *key) { + ltrim(str(), key); + return str; +} + +string& rtrim(string &str, const char *key) { + rtrim(str(), key); + return str; +} + +string& trim(string &str, const char *key) { + trim(str(), key); + return str; +} + +#endif //ifdef BSTRING_H diff --git a/src/lib/libvector.h b/src/lib/bvector.h similarity index 94% rename from src/lib/libvector.h rename to src/lib/bvector.h index d4ac97c6..c4a67ba2 100644 --- a/src/lib/libvector.h +++ b/src/lib/bvector.h @@ -1,5 +1,6 @@ /* - libvector : version 0.05 ~byuu (2006-12-16) + bvector : version 0.05 ~byuu (2006-12-16) + license: public domain */ /***** @@ -64,8 +65,8 @@ * and speed is less critical. *****/ -#ifndef LIBVECTOR_H -#define LIBVECTOR_H +#ifndef BVECTOR_H +#define BVECTOR_H template class linear_vector { protected: @@ -204,4 +205,4 @@ public: } }; -#endif +#endif //ifndef BVECTOR_H diff --git a/src/lib/libarray.h b/src/lib/libarray.h deleted file mode 100644 index 790a0e80..00000000 --- a/src/lib/libarray.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - libarray : version 0.09 ~byuu (2007-03-06) -*/ - -#ifndef LIBARRAY_H -#define LIBARRAY_H - -template class array { -protected: -T *pool; -uint poolsize, buffersize; - -protected: - uint findsize(uint size) { - if(size <= 0x100) { return 0x100; } - if(size <= 0x400) { return 0x400; } - if(size <= 0x1000) { return 0x1000; } - if(size <= 0x4000) { return 0x4000; } - if(size <= 0x10000) { return 0x10000; } - if(size <= 0x40000) { return 0x40000; } - if(size <= 0x100000) { return 0x100000; } - - return (size + 0x100000) & ~0xfffff; - } - -public: - uint size() { return buffersize; } - uint capacity() { return poolsize; } - - void reset() { - safe_free(pool); - poolsize = 0; - buffersize = 0; - } - - void reserve(uint size) { - if(size == poolsize)return; - - if(size < poolsize) { - buffersize = size; - } - - pool = (T*)realloc(pool, sizeof(T) * size); - poolsize = size; - } - - T *get(uint size = 0) { - if(size > buffersize)resize(size); - if(size > buffersize)throw "array[] out of bounds"; - return pool; - } - - void clear() { memset(pool, 0, sizeof(T) * buffersize); } - - void resize(uint size) { - reserve(findsize(size)); - buffersize = size; - } - - array() { - pool = 0; - poolsize = 0; - buffersize = 0; - } - - ~array() { reset(); } - - array &operator=(array &source) { - safe_free(pool); - buffersize = source.buffersize; - poolsize = source.poolsize; - //allocate entire pool size ... - pool = (T*)realloc(pool, sizeof(T) * poolsize); - //... but only copy used pool objects - memcpy(pool, source.pool, sizeof(T) * buffersize); - return *this; - } - - inline T &operator[](int index) { - if(index >= buffersize)resize(index + 1); - if(index >= buffersize)throw "array[] out of bounds"; - return pool[index]; - } -}; - -#endif diff --git a/src/lib/libco.h b/src/lib/libco.h new file mode 100644 index 00000000..74cf8bc6 --- /dev/null +++ b/src/lib/libco.h @@ -0,0 +1,37 @@ +/* + libco + version: 0.11 (2007-12-11) + license: public domain +*/ + +#ifndef LIBCO_H +#define LIBCO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__i386__) + #if defined(__GNUC__) + #define calltype __attribute__((fastcall)) + #elif defined(_MSC_VER) + #define calltype __fastcall + #endif +#else + #define calltype +#endif + +typedef void* cothread_t; + +cothread_t calltype co_active(); +cothread_t calltype co_create(unsigned int heapsize, void (*coentry)()); +void calltype co_delete(cothread_t cothread); +void calltype co_switch(cothread_t cothread); + +#undef calltype + +#ifdef __cplusplus +} //extern "C" +#endif + +#endif //ifndef LIBCO_H diff --git a/src/lib/libco/libco.ppc.s b/src/lib/libco/libco.ppc.s new file mode 100644 index 00000000..d7f6b758 --- /dev/null +++ b/src/lib/libco/libco.ppc.s @@ -0,0 +1,478 @@ +;***** +;libco.ppc (2007-11-29) +;author: Vas Crabb +;license: public domain +; +;cross-platform PowerPC implementation of libco +;special thanks to byuu for writing the original version +; +;[ABI compatibility] +;- gcc; mac os x; ppc +; +;[nonvolatile registers] +;- GPR1, GPR13 - GPR31 +;- FPR14 - FPR31 +;- V20 - V31 +;- VRSAVE, CR2 - CR4 +; +;[volatile registers] +;- GPR0, GPR2 - GPR12 +;- FPR0 - FPR13 +;- V0 - V19 +;- LR, CTR, XER, CR0, CR1, CR5 - CR7 +;***** + + +;Declare some target-specific stuff + + .section __TEXT,__text,regular,pure_instructions + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .machine ppc + + +;Constants + + .cstring + .align 2 + +_sysctl_altivec: + .ascii "hw.optional.altivec\0" + + +;Declare space for variables + +.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX +.lcomm _co_primary_buffer,1024,2 ;buffer (will be zeroed by loader) + + .data + .align 2 + +_co_active_context: + .long _co_primary_buffer + + + .text + .align 2 + + +;Declare exported names + +.globl _co_active +.globl _co_create +.globl _co_delete +.globl _co_switch + + +;***** +;extern "C" cothread_t co_active(); +;return = GPR3 +;***** + +_co_active: + mflr r0 ;GPR0 = return address + bcl 20,31,L_co_active$spb +L_co_active$spb: + mflr r2 ;GPR2 set for position-independance + addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3 + lwz r3,lo16(_co_active_context-L_co_active$spb)(r3) + mtlr r0 ;LR = return address + blr ;return + + +;***** +;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)()); +;GPR3 = heapsize +;GPR4 = coentry +;return = GPR3 +;***** + +_co_create: + mflr r0 ;GPR0 = return address + stmw r30,-8(r1) ;save GPR30 and GPR31 + stw r0,8(r1) ;save return address + stwu r1,-(2*4+16+24)(r1) ;allocate 16 bytes for locals/parameters + +;create heap space (stack + register storage) + addi r31,r3,1024-24 ;subtract space for linkage + mr r30,r4 ;GPR30 = coentry + addi r3,r3,1024 ;allocate extra memory for contextual info + bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024) + add r4,r3,r31 ;GPR4 points to top-of-stack + rlwinm r5,r4,0,0,27 ;force 16-byte alignment + +;store thread entry point + registers, so that first call to co_switch will execute coentry + stw r30,8(r5) ;store entry point + addi r6,0,2+19+18*2+12*4+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE + addi r0,0,0 + addi r7,0,4 ;start at 4(GPR5) + mtctr r6 +L_co_create$clear_loop: + stwx r0,r5,r7 ;clear a word + addi r7,r7,-4 ;increment pointer + bdnz L_co_create$clear_loop ;loop + stwu r5,-448(r5) ;store top of stack + +;initialize context memory heap and return + stw r5,0(r3) ;*cothread_t = stack heap pointer (GPR1) + lwz r1,0(r1) ;deallocate stack frame + lwz r8,8(r1) ;fetch return address + lmw r30,-8(r1) ;restore GPR30 and GPR31 + mtlr r8 ;return address in LR + blr ;return + + +;***** +;extern "C" void co_delete(cothread_t cothread); +;GPR3 = cothread +;***** + +_co_delete: + b L_free$stub ;free(GPR3) + + +;***** +;extern "C" void co_switch(cothread_t cothread); +;GPR3 = cothread +;***** +; +;Frame looks like: +; +;Old New Value +; 8(r1) 456(r1) Saved LR +; 4(r1) 452(r1) Saved CR +; 0(r1) 448(r1) Old GPR1 +; -4(r1) 444(r1) Saved GPR31 +; -8(r1) 440(r1) Saved GPR30 +;... ... ... +; -72(r1) 376(r1) Saved GPR14 +; -76(r1) 372(r1) Saved GPR13 +; -80(r1) 368(r1) Saved VRSAVE +; -84(r1) 364(r1) +++ +; -88(r1) 360(r1) Saved FPR31 +; -92(r1) 356(r1) +++ +; -96(r1) 352(r1) Saved FPR30 +;... ... ... +;-212(r1) 236(r1) +++ +;-216(r1) 232(r1) Saved FPR15 +;-220(r1) 228(r1) +++ +;-224(r1) 224(r1) Saved FPR14 +;-228(r1) 220(r1) +++ value +;-232(r1) 216(r1) +++ len +;-236(r1) 212(r1) +++ +;-240(r1) 208(r1) Saved VR31 +;-244(r1) 204(r1) +++ +;-248(r1) 200(r1) +++ +;-252(r1) 196(r1) +++ +;-256(r1) 192(r1) Saved VR30 +;... ... ... +;-388(r1) 60(r1) +++ +;-392(r1) 56(r1) +++ +;-396(r1) 52(r1) +++ +;-400(r1) 48(r1) Saved VR21 +;-404(r1) 44(r1) +++ +;-408(r1) 40(r1) +++ Param 5 (GPR7) +;-412(r1) 36(r1) +++ Param 4 (GPR6) +;-416(r1) 32(r1) Saved VR20 Param 3 (GPR5) +;-420(r1) 28(r1) - Param 2 (GPR4) +;-424(r1) 24(r1) - Param 1 (GPR3) +;-428(r1) 20(r1) - Reserved +;-432(r1) 16(r1) - Reserved +;-436(r1) 12(r1) - Reserved +;-440(r1) 8(r1) - New LR +;-444(r1) 4(r1) - New CR +;-448(r1) 0(r1) Saved GPR1 + + +_co_switch: + stmw r13,-76(r1) ;save preserved GPRs + stfd f14,-224(r1) ;save preserved FPRs + stfd f15,-216(r1) + stfd f16,-208(r1) + stfd f17,-200(r1) + stfd f18,-192(r1) + stfd f19,-184(r1) + stfd f20,-176(r1) + stfd f21,-168(r1) + stfd f22,-160(r1) + stfd f23,-152(r1) + stfd f24,-144(r1) + stfd f25,-136(r1) + stfd f26,-128(r1) + stfd f27,-120(r1) + stfd f28,-112(r1) + stfd f29,-104(r1) + stfd f30,-96(r1) + stfd f31,-88(r1) + mflr r0 ;save return address + stw r0,8(r1) + mfcr r2 ;save condition codes + stw r2,4(r1) + stwu r1,-448(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE) + + mr r30,r3 ;save new context pointer + bcl 20,31,L_co_switch$spb ;get address of co_active_context +L_co_switch$spb: + mflr r31 + + addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags + lwz r8,lo16(_co_environ-L_co_switch$spb)(r29) + andis. r9,r8,0x8000 ;is it initialised? + bne+ L_co_switch$initialised + + addi r0,0,4 ;len = sizeof(int) + stw r0,216(r1) + addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec" + addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb) + addi r4,r1,220 ;GPR4 = &value + addi r5,r1,216 ;GPR5 = &len + addi r6,0,0 ;newp = 0 + addi r7,0,0 ;newlen = 0 + bl L_sysctlbyname$stub ;call sysctlbyname + lwz r2,220(r1) ;fetch result + addis r8,0,0x8000 ;set initialised bit + cmpwi cr5,r3,0 ;assume error means not present + cmpwi cr6,r2,0 ;test result + blt- cr5,L_co_switch$store_environ + beq cr6,L_co_switch$store_environ + oris r8,r8,0x4000 ;set the flag to say we have it! +L_co_switch$store_environ: + stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags +L_co_switch$initialised: + + andis. r10,r8,0x4000 ;do we have Altivec/VMX? + beq L_co_switch$save_no_vmx + mfspr r11,256 ;save VRSAVE + andi. r0,r11,0x0FFF ;short-circuit if it's zero + stw r11,368(r1) + beq L_co_switch$save_no_vmx + andi. r0,r11,0x0800 ;check bit 20 + addi r2,0,32 ;starting index + beq L_co_switch$save_skip_vr20 + stvx v20,r1,r2 ;save VR20 +L_co_switch$save_skip_vr20: + addi r2,r2,16 ;stride + andi. r0,r11,0x0400 ;check bit 21 + beq L_co_switch$save_skip_vr21 + stvx v21,r1,r2 ;save VR21 +L_co_switch$save_skip_vr21: + addi r2,r2,16 ;stride + andi. r0,r11,0x0200 ;check bit 22 + beq L_co_switch$save_skip_vr22 + stvx v22,r1,r2 ;save VR22 +L_co_switch$save_skip_vr22: + addi r2,r2,16 ;stride + andi. r0,r11,0x0100 ;check bit 23 + beq L_co_switch$save_skip_vr23 + stvx v23,r1,r2 ;save VR23 +L_co_switch$save_skip_vr23: + addi r2,r2,16 ;stride + andi. r0,r11,0x0080 ;check bit 24 + beq L_co_switch$save_skip_vr24 + stvx v24,r1,r2 ;save VR24 +L_co_switch$save_skip_vr24: + addi r2,r2,16 ;stride + andi. r0,r11,0x0040 ;check bit 25 + beq L_co_switch$save_skip_vr25 + stvx v25,r1,r2 ;save VR25 +L_co_switch$save_skip_vr25: + addi r2,r2,16 ;stride + andi. r0,r11,0x0020 ;check bit 26 + beq L_co_switch$save_skip_vr26 + stvx v26,r1,r2 ;save VR26 +L_co_switch$save_skip_vr26: + addi r2,r2,16 ;stride + andi. r0,r11,0x0010 ;check bit 27 + beq L_co_switch$save_skip_vr27 + stvx v27,r1,r2 ;save VR27 +L_co_switch$save_skip_vr27: + addi r2,r2,16 ;stride + andi. r0,r11,0x0008 ;check bit 28 + beq L_co_switch$save_skip_vr28 + stvx v28,r1,r2 ;save VR28 +L_co_switch$save_skip_vr28: + addi r2,r2,16 ;stride + andi. r0,r11,0x0004 ;check bit 29 + beq L_co_switch$save_skip_vr29 + stvx v29,r1,r2 ;save VR29 +L_co_switch$save_skip_vr29: + addi r2,r2,16 ;stride + andi. r0,r11,0x0002 ;check bit 30 + beq L_co_switch$save_skip_vr30 + stvx v30,r1,r2 ;save VR30 +L_co_switch$save_skip_vr30: + addi r2,r2,16 ;stride + andi. r0,r11,0x0001 ;check bit 31 + beq L_co_switch$save_skip_vr31 + stvx v31,r1,r2 ;save VR31 +L_co_switch$save_skip_vr31: +L_co_switch$save_no_vmx: + + addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context + lwz r5,lo16(_co_active_context-L_co_switch$spb)(r4) + stw r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context + stw r1,0(r5) ;save current stack pointer + lwz r1,0(r30) ;get new stack pointer + + andis. r10,r8,0x4000 ;do we have Altivec/VMX? + beq L_co_switch$restore_no_vmx + lwz r11,368(r1) ;restore VRSAVE + andi. r0,r11,0x0FFF ;short-circuit if it's zero + mtspr 256,r11 + beq L_co_switch$restore_no_vmx + andi. r0,r11,0x0800 ;check bit 20 + addi r2,0,32 ;starting index + beq L_co_switch$restore_skip_vr20 + lvx v20,r1,r2 ;restore VR20 +L_co_switch$restore_skip_vr20: + addi r2,r2,16 ;stride + andi. r0,r11,0x0400 ;check bit 21 + beq L_co_switch$restore_skip_vr21 + lvx v21,r1,r2 ;restore VR21 +L_co_switch$restore_skip_vr21: + addi r2,r2,16 ;stride + andi. r0,r11,0x0200 ;check bit 22 + beq L_co_switch$restore_skip_vr22 + lvx v22,r1,r2 ;restore VR22 +L_co_switch$restore_skip_vr22: + addi r2,r2,16 ;stride + andi. r0,r11,0x0100 ;check bit 23 + beq L_co_switch$restore_skip_vr23 + lvx v23,r1,r2 ;restore VR23 +L_co_switch$restore_skip_vr23: + addi r2,r2,16 ;stride + andi. r0,r11,0x0080 ;check bit 24 + beq L_co_switch$restore_skip_vr24 + lvx v24,r1,r2 ;restore VR24 +L_co_switch$restore_skip_vr24: + addi r2,r2,16 ;stride + andi. r0,r11,0x0040 ;check bit 25 + beq L_co_switch$restore_skip_vr25 + lvx v25,r1,r2 ;restore VR25 +L_co_switch$restore_skip_vr25: + addi r2,r2,16 ;stride + andi. r0,r11,0x0020 ;check bit 26 + beq L_co_switch$restore_skip_vr26 + lvx v26,r1,r2 ;restore VR26 +L_co_switch$restore_skip_vr26: + addi r2,r2,16 ;stride + andi. r0,r11,0x0010 ;check bit 27 + beq L_co_switch$restore_skip_vr27 + lvx v27,r1,r2 ;restore VR27 +L_co_switch$restore_skip_vr27: + addi r2,r2,16 ;stride + andi. r0,r11,0x0008 ;check bit 28 + beq L_co_switch$restore_skip_vr28 + lvx v28,r1,r2 ;restore VR28 +L_co_switch$restore_skip_vr28: + addi r2,r2,16 ;stride + andi. r0,r11,0x0004 ;check bit 29 + beq L_co_switch$restore_skip_vr29 + lvx v29,r1,r2 ;restore VR29 +L_co_switch$restore_skip_vr29: + addi r2,r2,16 ;stride + andi. r0,r11,0x0002 ;check bit 30 + beq L_co_switch$restore_skip_vr30 + lvx v30,r1,r2 ;restore VR30 +L_co_switch$restore_skip_vr30: + addi r2,r2,16 ;stride + andi. r0,r11,0x0001 ;check bit 31 + beq L_co_switch$restore_skip_vr31 + lvx v31,r1,r2 ;restore VR31 +L_co_switch$restore_skip_vr31: +L_co_switch$restore_no_vmx: + + lwz r1,0(r1) ;deallocate stack frame + lwz r6,8(r1) ;return address in GPR6 + lwz r7,4(r1) ;condition codes in GPR7 + addi r0,0,0 ;make thread main crash if it returns + lmw r13,-76(r1) ;restore preserved GPRs + lfd f14,-224(r1) ;restore preserved FPRs + lfd f15,-216(r1) + lfd f16,-208(r1) + lfd f17,-200(r1) + lfd f18,-192(r1) + lfd f19,-184(r1) + lfd f20,-176(r1) + lfd f21,-168(r1) + lfd f22,-160(r1) + lfd f23,-152(r1) + lfd f24,-144(r1) + lfd f25,-136(r1) + lfd f26,-128(r1) + lfd f27,-120(r1) + lfd f28,-112(r1) + lfd f29,-104(r1) + lfd f30,-96(r1) + lfd f31,-88(r1) + mtlr r0 + mtctr r6 ;restore return address + mtcrf 32,r7 ;restore preserved condition codes + mtcrf 16,r7 + mtcrf 8,r7 + bctr ;return + + + +;Import external functions + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_malloc$stub: + .indirect_symbol _malloc + mflr r0 + bcl 20,31,L_malloc$spb +L_malloc$spb: + mflr r11 + addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb) + mtlr r0 + lwzu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_malloc$lazy_ptr: + .indirect_symbol _malloc + .long dyld_stub_binding_helper + + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_free$stub: + .indirect_symbol _free + mflr r0 + bcl 20,31,L_free$spb +L_free$spb: + mflr r11 + addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb) + mtlr r0 + lwzu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_free$lazy_ptr: + .indirect_symbol _free + .long dyld_stub_binding_helper + + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_sysctlbyname$stub: + .indirect_symbol _sysctlbyname + mflr r0 + bcl 20,31,L_sysctlbyname$spb +L_sysctlbyname$spb: + mflr r11 + addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb) + mtlr r0 + lwzu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_sysctlbyname$lazy_ptr: + .indirect_symbol _sysctlbyname + .long dyld_stub_binding_helper + + +;This needs to be here! + + .subsections_via_symbols + diff --git a/src/lib/libco/libco.ppc64.s b/src/lib/libco/libco.ppc64.s new file mode 100644 index 00000000..2fb048d7 --- /dev/null +++ b/src/lib/libco/libco.ppc64.s @@ -0,0 +1,513 @@ +;***** +;libco.ppc64 (2007-12-05) +;author: Vas Crabb +;license: public domain +; +;cross-platform 64-bit PowerPC implementation of libco +;special thanks to byuu for writing the original version +; +;[ABI compatibility] +;- gcc; mac os x; ppc64 +; +;[nonvolatile registers] +;- GPR1, GPR13 - GPR31 +;- FPR14 - FPR31 +;- V20 - V31 +;- VRSAVE, CR2 - CR4 +; +;[volatile registers] +;- GPR0, GPR2 - GPR12 +;- FPR0 - FPR13 +;- V0 - V19 +;- LR, CTR, XER, CR0, CR1, CR5 - CR7 +;***** + + +;Declare some target-specific stuff + + .section __TEXT,__text,regular,pure_instructions + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .machine ppc64 + + +;Constants + + .cstring + .align 3 + +_sysctl_altivec: + .ascii "hw.optional.altivec\0" + + +;Declare space for variables + +.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX +.lcomm _co_primary_buffer,1024,3 ;buffer (will be zeroed by loader) + + .data + .align 3 + +_co_active_context: + .quad _co_primary_buffer + + + .text + .align 2 + + +;Declare exported names + +.globl _co_active +.globl _co_create +.globl _co_delete +.globl _co_switch + + +;***** +;extern "C" cothread_t co_active(); +;return = GPR3 +;***** + +_co_active: + mflr r0 ;GPR0 = return address + bcl 20,31,L_co_active$spb +L_co_active$spb: + mflr r2 ;GPR2 set for position-independance + addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3 + ld r3,lo16(_co_active_context-L_co_active$spb)(r3) + mtlr r0 ;LR = return address + blr ;return + + +;***** +;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)()); +;GPR3 = heapsize +;GPR4 = coentry +;return = GPR3 +;***** + +_co_create: + mflr r0 ;GPR0 = return address + std r30,-16(r1) ;save GPR30 and GPR31 + std r31,-8(r1) + std r0,16(r1) ;save return address + stdu r1,-(2*8+16+48)(r1) ;allocate 16 bytes for locals/parameters + +;create heap space (stack + register storage) + addi r31,r3,1024-48 ;subtract space for linkage + mr r30,r4 ;GPR30 = coentry + addi r3,r3,1024 ;allocate extra memory for contextual info + bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024) + add r4,r3,r31 ;GPR4 points to top-of-stack + rldicr r5,r4,0,59 ;force 16-byte alignment + +;store thread entry point + registers, so that first call to co_switch will execute coentry + std r30,16(r5) ;store entry point + addi r6,0,2+19+18+12*2+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE + addi r0,0,0 + addi r7,0,8 ;start at 8(GPR5) + mtctr r6 +L_co_create$clear_loop: + stdx r0,r5,r7 ;clear a double + addi r7,r7,-8 ;increment pointer + bdnz L_co_create$clear_loop ;loop + stdu r5,-544(r5) ;store top of stack + +;initialize context memory heap and return + addis r9,0,0x8000 ;GPR13 not set (system TLS) + std r5,0(r3) ;*cothread_t = stack heap pointer (GPR1) + stw r9,8(r3) ;this is a flag word + ld r1,0(r1) ;deallocate stack frame + ld r8,16(r1) ;fetch return address + ld r30,-16(r1) ;restore GPR30 and GPR31 + ld r31,-8(r1) + mtlr r8 ;return address in LR + blr ;return + + +;***** +;extern "C" void co_delete(cothread_t cothread); +;GPR3 = cothread +;***** + +_co_delete: + b L_free$stub ;free(GPR3) + + +;***** +;extern "C" void co_switch(cothread_t cothread); +;GPR3 = cothread +;***** +; +;Frame looks like: +; +;Old New Value +; 16(r1) 560(r1) Saved LR +; 8(r1) 552(r1) Saved CR +; 0(r1) 544(r1) Old GPR1 +; -8(r1) 536(r1) Saved GPR31 +; -16(r1) 528(r1) Saved GPR30 +;... ... ... +;-144(r1) 400(r1) Saved GPR14 +;-152(r1) 392(r1) Saved GPR13 +;-160(r1) 384(r1) Saved FPR31 +;-168(r1) 376(r1) Saved FPR30 +;... ... ... +;-288(r1) 256(r1) Saved FPR15 +;-296(r1) 248(r1) Saved FPR14 +;-304(r1) 240(r1) Saved VRSAVE +;-312(r1) 232(r1) +++ value +;-320(r1) 224(r1) Saved VR31 len +;-328(r1) 216(r1) +++ +;-336(r1) 208(r1) Saved VR30 +;... ... ... +;-456(r1) 88(r1) +++ +;-464(r1) 80(r1) Saved VR22 Param 5 (GPR7) +;-472(r1) 72(r1) +++ Param 4 (GPR6) +;-480(r1) 64(r1) Saved VR21 Param 3 (GPR5) +;-488(r1) 56(r1) +++ Param 2 (GPR4) +;-496(r1) 48(r1) Saved VR20 Param 1 (GPR3) +;-504(r1) 40(r1) - Reserved +;-512(r1) 32(r1) - Reserved +;-520(r1) 24(r1) - Reserved +;-528(r1) 16(r1) - New LR +;-536(r1) 8(r1) - New CR +;-544(r1) 0(r1) Saved GPR1 + + +_co_switch: + std r13,-152(r1) ;save preserved GPRs + std r14,-144(r1) + std r15,-136(r1) + std r16,-128(r1) + std r17,-120(r1) + std r18,-112(r1) + std r19,-104(r1) + std r20,-96(r1) + std r21,-88(r1) + std r22,-80(r1) + std r23,-72(r1) + std r24,-64(r1) + std r25,-56(r1) + std r26,-48(r1) + std r27,-40(r1) + std r28,-32(r1) + std r29,-24(r1) + std r30,-16(r1) + std r31,-8(r1) + mflr r0 ;save return address + std r0,16(r1) + mfcr r2 ;save condition codes + stw r2,8(r1) + stdu r1,-544(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE) + stfd f14,248(r1) ;save preserved FPRs + stfd f15,256(r1) + stfd f16,264(r1) + stfd f17,272(r1) + stfd f18,280(r1) + stfd f19,288(r1) + stfd f20,296(r1) + stfd f21,304(r1) + stfd f22,312(r1) + stfd f23,320(r1) + stfd f24,328(r1) + stfd f25,336(r1) + stfd f26,344(r1) + stfd f27,352(r1) + stfd f28,360(r1) + stfd f29,368(r1) + stfd f30,376(r1) + stfd f31,384(r1) + + mr r30,r3 ;save new context pointer + bcl 20,31,L_co_switch$spb ;get address of co_active_context +L_co_switch$spb: + mflr r31 + + addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags + lwz r8,lo16(_co_environ-L_co_switch$spb)(r29) + andis. r9,r8,0x8000 ;is it initialised? + bne+ L_co_switch$initialised + + addi r0,0,4 ;len = sizeof(int) + std r0,224(r1) + addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec" + addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb) + addi r4,r1,232 ;GPR4 = &value + addi r5,r1,224 ;GPR5 = &len + addi r6,0,0 ;newp = 0 + addi r7,0,0 ;newlen = 0 + bl L_sysctlbyname$stub ;call sysctlbyname + lwz r2,232(r1) ;fetch result + addis r8,0,0x8000 ;set initialised bit + cmpdi cr5,r3,0 ;assume error means not present + cmpwi cr6,r2,0 ;test result + blt- cr5,L_co_switch$store_environ + beq cr6,L_co_switch$store_environ + oris r8,r8,0x4000 ;set the flag to say we have it! +L_co_switch$store_environ: + stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags +L_co_switch$initialised: + + andis. r10,r8,0x4000 ;do we have Altivec/VMX? + beq L_co_switch$save_no_vmx + mfspr r11,256 ;save VRSAVE + andi. r0,r11,0x0FFF ;short-circuit if it's zero + stw r11,240(r1) + beq L_co_switch$save_no_vmx + andi. r0,r11,0x0800 ;check bit 20 + addi r2,0,48 ;starting index + beq L_co_switch$save_skip_vr20 + stvx v20,r1,r2 ;save VR20 +L_co_switch$save_skip_vr20: + addi r2,r2,16 ;stride + andi. r0,r11,0x0400 ;check bit 21 + beq L_co_switch$save_skip_vr21 + stvx v21,r1,r2 ;save VR21 +L_co_switch$save_skip_vr21: + addi r2,r2,16 ;stride + andi. r0,r11,0x0200 ;check bit 22 + beq L_co_switch$save_skip_vr22 + stvx v22,r1,r2 ;save VR22 +L_co_switch$save_skip_vr22: + addi r2,r2,16 ;stride + andi. r0,r11,0x0100 ;check bit 23 + beq L_co_switch$save_skip_vr23 + stvx v23,r1,r2 ;save VR23 +L_co_switch$save_skip_vr23: + addi r2,r2,16 ;stride + andi. r0,r11,0x0080 ;check bit 24 + beq L_co_switch$save_skip_vr24 + stvx v24,r1,r2 ;save VR24 +L_co_switch$save_skip_vr24: + addi r2,r2,16 ;stride + andi. r0,r11,0x0040 ;check bit 25 + beq L_co_switch$save_skip_vr25 + stvx v25,r1,r2 ;save VR25 +L_co_switch$save_skip_vr25: + addi r2,r2,16 ;stride + andi. r0,r11,0x0020 ;check bit 26 + beq L_co_switch$save_skip_vr26 + stvx v26,r1,r2 ;save VR26 +L_co_switch$save_skip_vr26: + addi r2,r2,16 ;stride + andi. r0,r11,0x0010 ;check bit 27 + beq L_co_switch$save_skip_vr27 + stvx v27,r1,r2 ;save VR27 +L_co_switch$save_skip_vr27: + addi r2,r2,16 ;stride + andi. r0,r11,0x0008 ;check bit 28 + beq L_co_switch$save_skip_vr28 + stvx v28,r1,r2 ;save VR28 +L_co_switch$save_skip_vr28: + addi r2,r2,16 ;stride + andi. r0,r11,0x0004 ;check bit 29 + beq L_co_switch$save_skip_vr29 + stvx v29,r1,r2 ;save VR29 +L_co_switch$save_skip_vr29: + addi r2,r2,16 ;stride + andi. r0,r11,0x0002 ;check bit 30 + beq L_co_switch$save_skip_vr30 + stvx v30,r1,r2 ;save VR30 +L_co_switch$save_skip_vr30: + addi r2,r2,16 ;stride + andi. r0,r11,0x0001 ;check bit 31 + beq L_co_switch$save_skip_vr31 + stvx v31,r1,r2 ;save VR31 +L_co_switch$save_skip_vr31: +L_co_switch$save_no_vmx: + + addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context + ld r5,lo16(_co_active_context-L_co_switch$spb)(r4) + std r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context + std r1,0(r5) ;save current stack pointer + ld r1,0(r30) ;get new stack pointer + lwz r12,8(r30) ;have we already set GPR13 (system TLS)? + andis. r0,r12,0x8000 + beq+ L_co_switch$gpr13_set + std r13,392(r1) + xoris r12,r12,0x8000 + stw r12,8(r30) +L_co_switch$gpr13_set: + + andis. r10,r8,0x4000 ;do we have Altivec/VMX? + beq L_co_switch$restore_no_vmx + lwz r11,240(r1) ;restore VRSAVE + andi. r0,r11,0x0FFF ;short-circuit if it's zero + mtspr 256,r11 + beq L_co_switch$restore_no_vmx + andi. r0,r11,0x0800 ;check bit 20 + addi r2,0,48 ;starting index + beq L_co_switch$restore_skip_vr20 + lvx v20,r1,r2 ;restore VR20 +L_co_switch$restore_skip_vr20: + addi r2,r2,16 ;stride + andi. r0,r11,0x0400 ;check bit 21 + beq L_co_switch$restore_skip_vr21 + lvx v21,r1,r2 ;restore VR21 +L_co_switch$restore_skip_vr21: + addi r2,r2,16 ;stride + andi. r0,r11,0x0200 ;check bit 22 + beq L_co_switch$restore_skip_vr22 + lvx v22,r1,r2 ;restore VR22 +L_co_switch$restore_skip_vr22: + addi r2,r2,16 ;stride + andi. r0,r11,0x0100 ;check bit 23 + beq L_co_switch$restore_skip_vr23 + lvx v23,r1,r2 ;restore VR23 +L_co_switch$restore_skip_vr23: + addi r2,r2,16 ;stride + andi. r0,r11,0x0080 ;check bit 24 + beq L_co_switch$restore_skip_vr24 + lvx v24,r1,r2 ;restore VR24 +L_co_switch$restore_skip_vr24: + addi r2,r2,16 ;stride + andi. r0,r11,0x0040 ;check bit 25 + beq L_co_switch$restore_skip_vr25 + lvx v25,r1,r2 ;restore VR25 +L_co_switch$restore_skip_vr25: + addi r2,r2,16 ;stride + andi. r0,r11,0x0020 ;check bit 26 + beq L_co_switch$restore_skip_vr26 + lvx v26,r1,r2 ;restore VR26 +L_co_switch$restore_skip_vr26: + addi r2,r2,16 ;stride + andi. r0,r11,0x0010 ;check bit 27 + beq L_co_switch$restore_skip_vr27 + lvx v27,r1,r2 ;restore VR27 +L_co_switch$restore_skip_vr27: + addi r2,r2,16 ;stride + andi. r0,r11,0x0008 ;check bit 28 + beq L_co_switch$restore_skip_vr28 + lvx v28,r1,r2 ;restore VR28 +L_co_switch$restore_skip_vr28: + addi r2,r2,16 ;stride + andi. r0,r11,0x0004 ;check bit 29 + beq L_co_switch$restore_skip_vr29 + lvx v29,r1,r2 ;restore VR29 +L_co_switch$restore_skip_vr29: + addi r2,r2,16 ;stride + andi. r0,r11,0x0002 ;check bit 30 + beq L_co_switch$restore_skip_vr30 + lvx v30,r1,r2 ;restore VR30 +L_co_switch$restore_skip_vr30: + addi r2,r2,16 ;stride + andi. r0,r11,0x0001 ;check bit 31 + beq L_co_switch$restore_skip_vr31 + lvx v31,r1,r2 ;restore VR31 +L_co_switch$restore_skip_vr31: +L_co_switch$restore_no_vmx: + + lfd f14,248(r1) ;restore preserved FPRs + lfd f15,256(r1) + lfd f16,264(r1) + lfd f17,272(r1) + lfd f18,280(r1) + lfd f19,288(r1) + lfd f20,296(r1) + lfd f21,304(r1) + lfd f22,312(r1) + lfd f23,320(r1) + lfd f24,328(r1) + lfd f25,336(r1) + lfd f26,344(r1) + lfd f27,352(r1) + lfd f28,360(r1) + lfd f29,368(r1) + lfd f30,376(r1) + lfd f31,384(r1) + addi r0,0,0 ;make thread main crash if it returns + ld r1,0(r1) ;deallocate stack frame + ld r6,16(r1) ;return address in GPR6 + lwz r7,8(r1) ;condition codes in GPR7 + ld r13,-152(r1) ;restore preserved GPRs + ld r14,-144(r1) + ld r15,-136(r1) + ld r16,-128(r1) + ld r17,-120(r1) + ld r18,-112(r1) + ld r19,-104(r1) + ld r20,-96(r1) + ld r21,-88(r1) + ld r22,-80(r1) + ld r23,-72(r1) + ld r24,-64(r1) + ld r25,-56(r1) + ld r26,-48(r1) + ld r27,-40(r1) + ld r28,-32(r1) + ld r29,-24(r1) + ld r30,-16(r1) + ld r31,-8(r1) + mtlr r0 + mtctr r6 ;restore return address + mtcrf 32,r7 ;restore preserved condition codes + mtcrf 16,r7 + mtcrf 8,r7 + bctr ;return + + + +;Import external functions + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_malloc$stub: + .indirect_symbol _malloc + mflr r0 + bcl 20,31,L_malloc$spb +L_malloc$spb: + mflr r11 + addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb) + mtlr r0 + ldu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_malloc$lazy_ptr: + .indirect_symbol _malloc + .quad dyld_stub_binding_helper + + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_free$stub: + .indirect_symbol _free + mflr r0 + bcl 20,31,L_free$spb +L_free$spb: + mflr r11 + addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb) + mtlr r0 + ldu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_free$lazy_ptr: + .indirect_symbol _free + .quad dyld_stub_binding_helper + + + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align 5 +L_sysctlbyname$stub: + .indirect_symbol _sysctlbyname + mflr r0 + bcl 20,31,L_sysctlbyname$spb +L_sysctlbyname$spb: + mflr r11 + addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb) + mtlr r0 + ldu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11) + mtctr r12 + bctr + .lazy_symbol_pointer +L_sysctlbyname$lazy_ptr: + .indirect_symbol _sysctlbyname + .quad dyld_stub_binding_helper + + +;This needs to be here! + + .subsections_via_symbols + diff --git a/src/lib/libco/libco.ucontext.cpp b/src/lib/libco/libco.ucontext.cpp new file mode 100644 index 00000000..da236326 --- /dev/null +++ b/src/lib/libco/libco.ucontext.cpp @@ -0,0 +1,80 @@ +/* + libco.ucontext (2007-09-08) + author: byuu + license: public domain +*/ + +#include +#include +#include "../libco.h" + +//WARNING: the overhead of POSIX ucontext is very high, +//averaging ~450x that of standard subroutine calls. +//(tested on FreeBSD 6.2-RELEASE) +//By contrast, on the same system, libco_x86's overhead +//is ~7.25x standard subroutine calls; or fifty times faster. +// +//This library only exists for two reasons: +//1 - as an initial test for the viability of a ucontext implementation +//2 - to demonstrate the power and speed of libco over existing implementations, +// such as pth (which defaults to wrapping ucontext on unix targets) +// +//Use this library only as a *last resort* + +struct cothread_struct { + ucontext_t cohandle; + void (*coentry)(); +}; + +cothread_t __co_active = 0, __co_primary = 0; +void co_entrypoint(cothread_t cothread); +void co_init(); + +/***** + * library functions + *****/ + +cothread_t co_active() { + if(__co_primary == 0)co_init(); + return __co_active; +} + +cothread_t co_create(unsigned int heapsize, void (*coentry)()) { + if(__co_primary == 0)co_init(); +cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct)); + thread->coentry = coentry; + getcontext(&thread->cohandle); + heapsize += 512; + thread->cohandle.uc_stack.ss_sp = (char*)malloc(heapsize); + thread->cohandle.uc_stack.ss_size = heapsize; + makecontext(&thread->cohandle, (void (*)())co_entrypoint, 1, thread); + return (cothread_t)thread; +} + +void co_delete(cothread_t cothread) { +cothread_struct *thread = (cothread_struct*)cothread; + free(thread->cohandle.uc_stack.ss_sp); + free(thread); +} + +void co_switch(cothread_t cothread) { +cothread_struct *active = (cothread_struct*)__co_active; +cothread_struct *swap = (cothread_struct*)cothread; + __co_active = cothread; + swapcontext(&active->cohandle, &swap->cohandle); +} + +/***** + * internal functions + *****/ + +void co_entrypoint(cothread_t cothread) { + ((cothread_struct*)cothread)->coentry(); +} + +void co_init() { +cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct)); + thread->coentry = 0; + getcontext(&thread->cohandle); + __co_active = __co_primary = (cothread_t)thread; +} diff --git a/src/lib/libco/libco.win.cpp b/src/lib/libco/libco.win.cpp new file mode 100644 index 00000000..f0d16626 --- /dev/null +++ b/src/lib/libco/libco.win.cpp @@ -0,0 +1,66 @@ +/* + libco.win (2007-09-08) + author: byuu + license: public domain +*/ + +#define WINVER 0x0400 +#define _WIN32_WINNT 0x0400 +#include +#include "../libco.h" + +struct cothread_struct { + void *cohandle; + void (*coentry)(); +}; + +cothread_t __co_active = 0, __co_primary = 0; + +void __stdcall co_entryproc(void*); +cothread_t co_init(); + +/***** + * library functions + *****/ + +cothread_t co_active() { + if(__co_primary == 0)co_init(); + return __co_active; +} + +cothread_t co_create(unsigned int heapsize, void (*coentry)()) { + if(__co_primary == 0)co_init(); +cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct)); + s->coentry = coentry; + s->cohandle = CreateFiber(heapsize + 512, co_entryproc, (void*)s); + return (cothread_t)s; +} + +void co_delete(cothread_t cothread) { +cothread_struct *s = (cothread_struct*)cothread; + DeleteFiber(s->cohandle); + free(cothread); +} + +void co_switch(cothread_t cothread) { + __co_active = cothread; +cothread_struct *s = (cothread_struct*)cothread; + SwitchToFiber(s->cohandle); +} + +/***** + * internal functions + *****/ + +void __stdcall co_entryproc(void *cothread) { + ((cothread_struct*)cothread)->coentry(); +} + +cothread_t co_init() { + ConvertThreadToFiber(0); +cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct)); + s->coentry = 0; + s->cohandle = GetCurrentFiber(); + __co_active = __co_primary = (cothread_t)s; + return __co_active; +} diff --git a/src/lib/libco_x86_64.asm b/src/lib/libco/libco.x86-64.asm similarity index 61% rename from src/lib/libco_x86_64.asm rename to src/lib/libco/libco.x86-64.asm index 224a7c0a..051987f0 100644 --- a/src/lib/libco_x86_64.asm +++ b/src/lib/libco/libco.x86-64.asm @@ -1,123 +1,146 @@ -;***** -;libco_x86_64 : version 0.10 ~byuu (2007-09-08) -;cross-platform x86-64 implementation of libco -;special thanks to Aaron Giles and Joel Yliluoma for various optimizations -; -;[ABI compatibility] -;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf ) -;- gcc; linux; x86-64 -;- gcc; freebsd; x86-64 -; -;[nonvolatile registers] -;- rsp, rbp, rbx, r12, r13, r14, r15 -; -;[volatile registers] -;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi -;- st0 - st7 -;- xmm0 - xmm15 -;***** - -bits 64 - -section .bss - -align 8 -co_primary_buffer resb 512 - -section .data - -align 8 -co_active_context dq co_primary_buffer - -section .text - -extern malloc -extern free - -global co_active -global co_create -global co_delete -global co_switch - -;***** -;extern "C" cothread_t co_active(); -;return = rax -;***** - -align 16 -co_active: - mov rax,[co_active_context wrt rip] - ret - -;***** -;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)()); -;rdi = heapsize -;rsi = coentry -;return = rax -;***** - -align 16 -co_create: -;create heap space (stack + register storage) - add rdi,512 ;allocate extra memory for contextual info - push rdi - push rsi - - call malloc ;rax = malloc(rdi) - - pop rsi - pop rdi - - add rdi,rax ;set rsi to point to top of stack heap - and rdi,-16 ;force 16-byte alignment of stack heap - -;store thread entry point + registers, so that first call to co_switch will execute coentry - mov qword[rdi-8],rsi ;entry point - mov qword[rdi-16],0 ;r15 - mov qword[rdi-24],0 ;r14 - mov qword[rdi-32],0 ;r13 - mov qword[rdi-40],0 ;r12 - mov qword[rdi-48],0 ;rbx - mov qword[rdi-56],0 ;rbp - sub rdi,56 - -;initialize context memory heap and return - mov [rax],rdi ;*cothread_t = stack heap pointer (rsp) - ret ;return allocated memory block as thread handle - -;***** -;extern "C" void co_delete(cothread_t cothread); -;rdi = cothread -;***** - -align 16 -co_delete: - jmp free ;free(rdi) - -;***** -;extern "C" void co_switch(cothread_t cothread); -;rdi = cothread -;***** - -align 16 -co_switch: - mov rax,[co_active_context wrt rip] ;backup current context - mov [co_active_context wrt rip],rdi ;set new active context - - push rbp - push rbx - push r12 - push r13 - push r14 - push r15 - mov [rax],rsp - - mov rsp,[rdi] - pop r15 - pop r14 - pop r13 - pop r12 - pop rbx - pop rbp - - ret +;***** +;libco.x86-64 (2007-12-11) +;author: byuu +;license: public domain +; +;cross-platform x86-64 implementation of libco +;thanks to Aaron Giles and Joel Yliluoma for various optimizations +;thanks to Lucas Newman and Vas Crabb for assistance with OS X support +; +;[ABI compatibility] +;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf ) +;- gcc; mac os x; x86-64 +;- gcc; linux; x86-64 +;- gcc; freebsd; x86-64 +; +;[nonvolatile registers] +;- rsp, rbp, rbx, r12, r13, r14, r15 +; +;[volatile registers] +;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi +;- st0 - st7 +;- xmm0 - xmm15 +;***** + +;***** +;linker-specific name decorations +;***** + +%ifdef OSX +%define malloc _malloc +%define free _free + +%define co_active _co_active +%define co_create _co_create +%define co_delete _co_delete +%define co_switch _co_switch +%endif + +bits 64 + +section .bss + +align 8 +co_primary_buffer resb 512 + +section .data + +align 8 +co_active_context dq co_primary_buffer + +section .text + +extern malloc +extern free + +global co_active +global co_create +global co_delete +global co_switch + +;***** +;extern "C" cothread_t co_active(); +;return = rax +;***** + +align 16 +co_active: + mov rax,[co_active_context wrt rip] + ret + +;***** +;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)()); +;rdi = heapsize +;rsi = coentry +;return = rax +;***** + +align 16 +co_create: +;create heap space (stack + context) + add rdi,512 ;allocate extra memory for contextual info + + push rdi ;backup volatile registers before malloc call + push rsi + + sub rsp,8 ;SSE 16-byte stack alignment + call malloc ;rax = malloc(rdi) + add rsp,8 + + pop rsi ;restore volatile registers + pop rdi + + add rdi,rax ;set rdi to point to top of stack heap + and rdi,-16 ;force 16-byte alignment of stack heap + +;store thread entry point + registers, so that first call to co_switch will execute coentry + mov qword[rdi-8],0 ;crash if entry point returns + mov qword[rdi-16],rsi ;entry point + mov qword[rdi-24],0 ;r15 + mov qword[rdi-32],0 ;r14 + mov qword[rdi-40],0 ;r13 + mov qword[rdi-48],0 ;r12 + mov qword[rdi-56],0 ;rbx + mov qword[rdi-64],0 ;rbp + sub rdi,64 + +;initialize context memory heap and return + mov [rax],rdi ;*cothread_t = stack heap pointer (rsp) + ret ;return allocated memory block as thread handle + +;***** +;extern "C" void co_delete(cothread_t cothread); +;rdi = cothread +;***** + +align 16 +co_delete: + jmp free ;free(rdi) + +;***** +;extern "C" void co_switch(cothread_t cothread); +;rdi = cothread +;***** + +align 16 +co_switch: + mov rax,[co_active_context wrt rip] ;backup current context + mov [co_active_context wrt rip],rdi ;set new active context + + push rbp + push rbx + push r12 + push r13 + push r14 + push r15 + mov [rax],rsp + + mov rsp,[rdi] + pop r15 + pop r14 + pop r13 + pop r12 + pop rbx + pop rbp + + ret diff --git a/src/lib/libco_x86.asm b/src/lib/libco/libco.x86.asm similarity index 72% rename from src/lib/libco_x86.asm rename to src/lib/libco/libco.x86.asm index c243a537..f151c4a8 100644 --- a/src/lib/libco_x86.asm +++ b/src/lib/libco/libco.x86.asm @@ -1,148 +1,155 @@ -;***** -;libco_x86 : version 0.10 ~byuu (2007-09-08) -;cross-platform x86 implementation of libco -;special thanks to Aaron Giles and Joel Yliluoma for various optimizations -; -;[ABI compatibility] -;- visual c++; windows; x86 -;- mingw; windows; x86 -;- gcc; mac os x; x86 -;- gcc; linux; x86 -;- gcc; freebsd; x86 -; -;[nonvolatile registers] -;- esp, ebp, edi, esi, ebx -; -;[volatile registers] -;- eax, ecx, edx -;- st0 - st7 -;- xmm0 - xmm15 -;***** - -;***** -;linker-specific name decorations -;***** - -%ifdef WIN32 -%define malloc _malloc -%define free _free - -%define co_active @co_active@0 -%define co_create @co_create@8 -%define co_delete @co_delete@4 -%define co_switch @co_switch@4 -%endif - -%ifdef OSX86 -%define malloc _malloc -%define free _free - -%define co_active _co_active -%define co_create _co_create -%define co_delete _co_delete -%define co_switch _co_switch -%endif - -bits 32 - -section .bss - -align 4 -co_primary_buffer resb 512 - -section .data - -align 4 -co_active_context dd co_primary_buffer - -section .text - -extern malloc -extern free - -global co_active -global co_create -global co_delete -global co_switch - -;***** -;extern "C" cothread_t fastcall co_active(); -;return = eax -;***** - -align 16 -co_active: - mov eax,[co_active_context] - ret - -;***** -;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)()); -;ecx = heapsize -;edx = coentry -;return = eax -;***** - -align 16 -co_create: -;create heap space (stack + register storage) - add ecx,512 ;allocate extra memory for contextual info - push ecx - push edx - - push ecx - call malloc ;eax = malloc(edx) - add esp,4 - - pop edx - pop ecx - - add ecx,eax ;set edx to point to top of stack heap - and ecx,-16 ;force 16-byte alignment of stack heap - -;store thread entry point + registers, so that first call to co_switch will execute coentry - mov dword[ecx-4],edx ;entry point - mov dword[ecx-8],0 ;ebp - mov dword[ecx-12],0 ;esi - mov dword[ecx-16],0 ;edi - mov dword[ecx-20],0 ;ebx - sub ecx,20 - -;initialize context memory heap and return - mov [eax],ecx ;*cothread_t = stack heap pointer (esp) - ret ;return allocated memory block as thread handle - -;***** -;extern "C" void fastcall co_delete(cothread_t cothread); -;ecx = cothread -;***** - -align 16 -co_delete: - push ecx - call free ;free(ecx) - add esp,4 - ret - -;***** -;extern "C" void fastcall co_switch(cothread_t cothread); -;ecx = cothread -;***** - -align 16 -co_switch: - mov eax,[co_active_context] ;backup current context - mov [co_active_context],ecx ;set new active context - - push ebp - push esi - push edi - push ebx - mov [eax],esp - - mov esp,[ecx] - pop ebx - pop edi - pop esi - pop ebp - - ret +;***** +;libco.x86 (2007-12-11) +;author: byuu +;license: public domain +; +;cross-platform x86 implementation of libco +;thanks to Aaron Giles and Joel Yliluoma for various optimizations +;thanks to Lucas Newman and Vas Crabb for assistance with OS X support +; +;[ABI compatibility] +;- visual c++; windows; x86 +;- mingw; windows; x86 +;- gcc; mac os x; x86 +;- gcc; linux; x86 +;- gcc; freebsd; x86 +; +;[nonvolatile registers] +;- esp, ebp, edi, esi, ebx +; +;[volatile registers] +;- eax, ecx, edx +;- st0 - st7 +;- xmm0 - xmm15 +;***** + +;***** +;linker-specific name decorations +;***** + +%ifdef WIN +%define malloc _malloc +%define free _free + +%define co_active @co_active@0 +%define co_create @co_create@8 +%define co_delete @co_delete@4 +%define co_switch @co_switch@4 +%endif + +%ifdef OSX +%define malloc _malloc +%define free _free + +%define co_active _co_active +%define co_create _co_create +%define co_delete _co_delete +%define co_switch _co_switch +%endif + +bits 32 + +section .bss + +align 4 +co_primary_buffer resb 512 + +section .data + +align 4 +co_active_context dd co_primary_buffer + +section .text + +extern malloc +extern free + +global co_active +global co_create +global co_delete +global co_switch + +;***** +;extern "C" cothread_t fastcall co_active(); +;return = eax +;***** + +align 16 +co_active: + mov eax,[co_active_context] + ret + +;***** +;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)()); +;ecx = heapsize +;edx = coentry +;return = eax +;***** + +align 16 +co_create: +;create heap space (stack + context) + add ecx,512 ;allocate extra memory for contextual info + + push ecx ;backup volatile registers before malloc call + push edx + + push ecx + call malloc ;eax = malloc(ecx) + add esp,4 + + pop edx ;restore volatile registers + pop ecx + + add ecx,eax ;set edx to point to top of stack heap + and ecx,-16 ;force 16-byte alignment of stack heap + +;store thread entry point + registers, so that first call to co_switch will execute coentry + mov dword[ecx-4],0 ;crash if entry point returns + mov dword[ecx-8],edx ;entry point + mov dword[ecx-12],0 ;ebp + mov dword[ecx-16],0 ;esi + mov dword[ecx-20],0 ;edi + mov dword[ecx-24],0 ;ebx + sub ecx,24 + +;initialize context memory heap and return + mov [eax],ecx ;*cothread_t = stack heap pointer (esp) + ret ;return allocated memory block as thread handle + +;***** +;extern "C" void fastcall co_delete(cothread_t cothread); +;ecx = cothread +;***** + +align 16 +co_delete: + sub esp,8 ;SSE 16-byte stack alignment + push ecx + call free ;free(ecx) + add esp,4+8 + ret + +;***** +;extern "C" void fastcall co_switch(cothread_t cothread); +;ecx = cothread +;***** + +align 16 +co_switch: + mov eax,[co_active_context] ;backup current context + mov [co_active_context],ecx ;set new active context + + push ebp + push esi + push edi + push ebx + mov [eax],esp + + mov esp,[ecx] + pop ebx + pop edi + pop esi + pop ebp + + ret diff --git a/src/lib/libco_x86.h b/src/lib/libco_x86.h deleted file mode 100644 index 96744c68..00000000 --- a/src/lib/libco_x86.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - libco_x86 : version 0.10 ~byuu (2007-09-08) - license: public domain -*/ - -#ifndef LIBCO_H -#define LIBCO_H - -#if !defined(fastcall) - #if defined(_MSC_VER) - #define fastcall __fastcall - #elif defined(__GNUC__) - #define fastcall __attribute__((fastcall)) - #else - #error "fastcall undefined" - #endif -#endif - -typedef void *cothread_t; - -extern "C" cothread_t fastcall co_active(); -extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)()); -extern "C" void fastcall co_delete(cothread_t cothread); -extern "C" void fastcall co_switch(cothread_t cothread); - -#endif diff --git a/src/lib/libco_x86_64.h b/src/lib/libco_x86_64.h deleted file mode 100644 index e7d2c98a..00000000 --- a/src/lib/libco_x86_64.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - libco_x86_64 : version 0.10 ~byuu (2007-09-08) - license: public domain -*/ - -#ifndef LIBCO_H -#define LIBCO_H - -typedef void *cothread_t; - -extern "C" cothread_t co_active(); -extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)()); -extern "C" void co_delete(cothread_t cothread); -extern "C" void co_switch(cothread_t cothread); - -#endif diff --git a/src/lib/libstring.cpp b/src/lib/libstring.cpp deleted file mode 100644 index c841598f..00000000 --- a/src/lib/libstring.cpp +++ /dev/null @@ -1,456 +0,0 @@ -#include "libbase.h" -#include "libstring.h" -#include "libstring_oo.cpp" - -#include "libstring_array.cpp" - -char chrlower(char c) { - if(c >= 'A' && c <= 'Z')return c + ('a' - 'A'); - return c; -} - -char chrupper(char c) { - if(c >= 'a' && c <= 'z')return c - ('a' - 'A'); - return c; -} - -char *strptr(const string &str) { return str.s; } -uint strlen(const string &str) { return strlen(strptr(str)); } - -int strcmp(const string &dest, const char *src) { return strcmp(strptr(dest), src); } -int strcmp(const char *dest, const string &src) { return strcmp(dest, strptr(src)); } -int strcmp(const string &dest, const string &src) { return strcmp(strptr(dest), strptr(src)); } - -int __stricmp(const char *dest, const char *src) { - while(*dest) { - if(chrlower(*dest) != chrlower(*src))break; - dest++; - src++; - } - return (int)chrlower(*dest) - (int)chrlower(*src); -} -int stricmp(const string &dest, const char *src) { return __stricmp(strptr(dest), src); } -int stricmp(const char *dest, const string &src) { return __stricmp(dest, strptr(src)); } -int stricmp(const string &dest, const string &src) { return __stricmp(strptr(dest), strptr(src)); } - -void strcpy(string &dest, const char *src) { -int srclen = strlen(src); - dest.reserve(srclen); - strcpy(dest.s, src); -} -void strcpy(string &dest, const string &src) { strcpy(dest, strptr(src)); } - -uint strlcpy(char *dest, const char *src, uint length) { -uint srclen = strlen(src); - length--; - if(length > srclen)length = srclen; - memcpy(dest, src, length); - dest[length] = 0; - return srclen; -} - -uint strlcpy(string &dest, const char *src, uint length) { - dest.reserve(length); - return strlcpy(strptr(dest), src, length); -} - -uint strlcpy(string &dest, const string &src, uint length) { - dest.reserve(length); - return strlcpy(strptr(dest), strptr(src), length); -} - -void strcat(string &dest, const char *src) { -int srclen = strlen(src); -int destlen = strlen(dest); - dest.reserve(srclen + destlen); - strcat(dest.s, src); -} -void strcat(string &dest, const string &src) { strcat(dest, strptr(src)); } - -uint strlcat(char *dest, const char *src, uint length) { -uint destlen = strlen(dest), srclen = strlen(src); - length--; - if(length > destlen + srclen)length = destlen + srclen; - memcpy(dest + destlen, src, length - destlen); - dest[length] = 0; - return destlen + srclen; -} - -uint strlcat(string &dest, const char *src, uint length) { - dest.reserve(length); - return strlcat(strptr(dest), src, length); -} - -uint strlcat(string &dest, const string &src, uint length) { - dest.reserve(length); - return strlcat(strptr(dest), strptr(src), length); -} - -string substr(string &dest, const char *src, uint start, uint length) { -string temp; - if(length == 0) { - //copy entire string - strcpy(temp, src + start); - } else { - //copy partial string - strlcpy(temp, src + start, length + 1); - } - return temp; -} -string substr(string &dest, const string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); } - -void strinsert(string &dest, const char *src, uint pos) { -string temp; - strcpy(temp, strptr(dest) + pos); - dest[pos] = 0; - strcat(dest, src); - strcat(dest, temp); -} -void strinsert(string &dest, const string &src, uint pos) { strinsert(dest, strptr(src), pos); } - -void strremove(string &dest, uint start, uint length) { -int i, destlen = strlen(dest); - dest.reserve(start); - if(!length) { - dest[start] = 0; - return; - } - for(i = start; i < destlen; i++) { dest.s[i] = dest.s[i + length]; } - dest.s[i] = 0; -} - -char *strlower(char *str) { -uint i = 0; - while(str[i]) { - str[i] = chrlower(str[i]); - i++; - } - return str; -} -string &strlower(string &str) { strlower(strptr(str)); return str; } - -char *strupper(char *str) { -uint i = 0; - while(str[i]) { - str[i] = chrupper(str[i]); - i++; - } - return str; -} -string &strupper(string &str) { strupper(strptr(str)); return str; } - -int strpos(const char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return -1; - for(int i = 0; i <= ssl - ksl; i++) { - if(!memcmp(str + i, key, ksl)) { - return i; - } - } - return -1; -} -int strpos(const string &str, const char *key) { return strpos(strptr(str), key); } -int strpos(const char *str, const string &key) { return strpos(str, strptr(key)); } -int strpos(const string &str, const string &key) { return strpos(strptr(str), strptr(key)); } - -int qstrpos(const char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return -1; - for(int i = 0; i <= ssl - ksl;) { - uint8 x = str[i]; - if(x == '\"' || x == '\'') { - uint8 z = i++; - while(str[i] != x && i < ssl)i++; - if(i >= ssl)i = z; - } - if(!memcmp(str + i, key, ksl)) { - return i; - } else { - i++; - } - } - return -1; -} -int qstrpos(const string &str, const char *key) { return qstrpos(strptr(str), key); } -int qstrpos(const char *str, const string &key) { return qstrpos(str, strptr(key)); } -int qstrpos(const string &str, const string &key) { return qstrpos(strptr(str), strptr(key)); } - -void strtr(char *dest, const char *before, const char *after) { -int sl = strlen(dest), bsl = strlen(before), asl = strlen(after); - if(bsl != asl || bsl == 0)return; - for(int i = 0; i < sl; i++) { - for(int l = 0; l < bsl; l++) { - if(dest[i] == before[l]) { - dest[i] = after[l]; - break; - } - } - } -} -void strtr(string &dest, const char *before, const char *after) { strtr(strptr(dest), before, after); } - -bool strbegin(const char *str, const char *key) { -int i, ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return false; - return (!memcmp(str, key, ksl)); -} -bool strbegin(const string &str, const char *key) { return strbegin(strptr(str), key); } - -bool stribegin(const char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return false; - for(int i = 0; i < ksl; i++) { - if(str[i] >= 'A' && str[i] <= 'Z') { - if(str[i] != key[i] && str[i]+0x20 != key[i])return false; - } else if(str[i] >= 'a' && str[i] <= 'z') { - if(str[i] != key[i] && str[i]-0x20 != key[i])return false; - } else { - if(str[i] != key[i])return false; - } - } - return true; -} -bool stribegin(const string &str, const char *key) { return stribegin(strptr(str), key); } - -bool strend(const char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return false; - return (!memcmp(str + ssl - ksl, key, ksl)); -} -bool strend(const string &str, const char *key) { return strend(strptr(str), key); } - -bool striend(const char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return false; - for(int i = ssl - ksl, z = 0; i < ssl; i++, z++) { - if(str[i] >= 'A' && str[i] <= 'Z') { - if(str[i] != key[z] && str[i]+0x20 != key[z])return false; - } else if(str[i] >= 'a' && str[i] <= 'z') { - if(str[i] != key[z] && str[i]-0x20 != key[z])return false; - } else { - if(str[i] != key[z])return false; - } - } - return true; -} -bool striend(const string &str, const char *key) { return striend(strptr(str), key); } - -void strltrim(char *str, const char *key) { -int i, ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return; - if(strbegin(str, key)) { - for(i = 0; i < (ssl - ksl); i++)str[i] = str[i + ksl]; - str[i] = 0; - } -} -void strltrim(string &str, const char *key) { strltrim(strptr(str), key); } - -void striltrim(char *str, const char *key) { -int i, ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return; - if(stribegin(str, key)) { - for(i = 0; i < (ssl-ksl); i++)str[i] = str[i + ksl]; - str[i] = 0; - } -} -void striltrim(string &str, const char *key) { striltrim(strptr(str), key); } - -void strrtrim(char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return; - if(strend(str, key)) { - str[ssl - ksl] = 0; - } -} -void strrtrim(string &str, const char *key) { strrtrim(strptr(str), key); } - -void strirtrim(char *str, const char *key) { -int ssl = strlen(str), ksl = strlen(key); - if(ksl > ssl)return; - if(striend(str, key)) { - str[ssl - ksl] = 0; - } -} -void strirtrim(string &str, const char *key) { strirtrim(strptr(str), key); } - -void strtrim(char *str, const char *key) { - strltrim(str, key); - strrtrim(str, key); -} -void strtrim(string &str, const char *key) { strtrim(strptr(str), key); } - -void stritrim(char *str, const char *key) { - striltrim(str, key); - strirtrim(str, key); -} -void stritrim(string &str, const char *key) { stritrim(strptr(str), key); } - -//does not support char* type because function increases string length -void strquote(string &str) { -string t; - strcpy(t, "\""); - strcat(t, str); - strcat(t, "\""); - strcpy(str, t); -} - -bool strunquote(char *str) { -int i, ssl = strlen(str); -//make sure string is long enough to have quotes - if(ssl < 2)return false; - -//make sure string actually has quotes - if(str[0] == '\"' && str[ssl - 1] == '\"'); - else if(str[0] == '\'' && str[ssl - 1] == '\''); - else return false; - -//now remove them - for(i = 0; i < ssl; i++) { - str[i] = str[i + 1]; - } - str[i - 2] = 0; - - return true; -} -bool strunquote(string &str) { return strunquote(strptr(str)); } - -uint strhex(const char *str) { -uint r = 0, m = 0; -int i = 0, ssl = strlen(str); -uint8 x; -bool negate = (str[0] == '-'); - if(negate)i++; - for(; i < ssl; i++) { - if(str[i] >= '0' && str[i] <= '9'); - else if(str[i] >= 'A' && str[i] <= 'F'); - else if(str[i] >= 'a' && str[i] <= 'f'); - else break; - } - for(--i; i >= 0; i--, m += 4) { - x = str[i]; - if(x >= '0' && x <= '9')x -= '0'; - else if(x >= 'A' && x <= 'F')x -= 'A' - 0x0a; - else if(x >= 'a' && x <= 'f')x -= 'a' - 0x0a; - else break; - r |= x << m; - } - return !negate ? r : (uint)-r; -} -uint strhex(const string &str) { return strhex(strptr(str)); } - -uint strdec(const char *str) { -uint m = 1; -int i = 0, r = 0, ssl = strlen(str); -uint8 x; -bool negate = (str[0] == '-'); - if(negate)i++; - for(; i < ssl; i++) { - if(str[i] >= '0' && str[i] <= '9'); - else break; - } - for(--i; i >= 0; i--, m *= 10) { - x = str[i]; - if(x >= '0' && x <= '9')x -= '0'; - else break; - r += x * m; - } - return !negate ? r : (uint)-r; -} -uint strdec(const string &str) { return strdec(strptr(str)); } - -uint strbin(const char *str) { -uint r = 0, m = 0; -int i = 0, ssl = strlen(str); -uint8 x; -bool negate = (str[0] == '-'); - if(negate)i++; - for(; i < ssl; i++) { - if(str[i] == '0' || str[i] == '1'); - else break; - } - for(--i; i >= 0; i--, m++) { - x = str[i]; - if(str[i] == '0' || str[i] == '1')x -= '0'; - else break; - r |= x << m; - } - return !negate ? r : (uint)-r; -} -uint strbin(const string &str) { return strbin(strptr(str)); } - -char *utoa(char *str, uint num) { - sprintf(str, "%u", num); - return str; -} - -string &utoa(string &str, uint num) { - str.reserve(16); - utoa(strptr(str), num); - return str; -} - -char *itoa(char *str, uint num) { - sprintf(str, "%d", num); - return str; -} - -string &itoa(string &str, uint num) { - str.reserve(16); - itoa(strptr(str), num); - return str; -} - -char *htoa(char *str, uint num) { - sprintf(str, "%x", num); - return str; -} - -string &htoa(string &str, uint num) { - str.reserve(16); - htoa(strptr(str), num); - return str; -} - -char *btoa(char *str, uint num) { -char *pstr = str; -uint mask = 0x80000000; - while(mask && (num & mask) == 0)mask >>= 1; - while(mask > 1) { - str[0] = (num & mask) ? '1' : '0'; - str++; - mask >>= 1; - } - str[0] = (num & mask) ? '1' : '0'; - str++; - str[0] = 0; - return pstr; -} - -string &btoa(string &str, uint num) { - str.reserve(64); - btoa(strptr(str), num); - return str; -} - -bool strfread(string &str, const char *filename) { - strcpy(str, ""); - -FILE *fp = fopen(filename, "rb"); - if(!fp)return false; - -uint size = fsize(fp); -char *fdata = (char*)malloc(size + 1); - fread(fdata, 1, size, fp); - fclose(fp); - fdata[size] = 0; - strcpy(str, fdata); - free(fdata); - - return true; -} - -#include "libstring_int.cpp" -#include "libstring_math.cpp" -#include "libstring_split.cpp" -#include "libstring_replace.cpp" -#include "libstring_sprintf.cpp" diff --git a/src/lib/libstring.h b/src/lib/libstring.h deleted file mode 100644 index 8c7ad831..00000000 --- a/src/lib/libstring.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - libstring : version 0.18 ~byuu (2007-06-06) -*/ - -#ifndef LIBSTRING_H -#define LIBSTRING_H - -#include "libbase.h" -#include "libvector.h" - -class string; -typedef linear_vector stringarray; - -char chrlower(char c); -char chrupper(char c); - -uint count(stringarray &str); - -int find(stringarray &str, const char *key); -int find(stringarray &str, const string &key); - -char *strptr(const string &str); -uint strlen(const string &str); - -int strcmp(const string &dest, const char *src); -int strcmp(const char *dest, const string &src); -int strcmp(const string &dest, const string &src); - -//vc6/win32 and gcc/dos only support stricmp, whereas -//gcc/unix only supports strcasecmp. this is an attempt -//to avoid platform-specific defines... -#define stricmp __stricmp -int __stricmp(const char *dest, const char *src); -int stricmp(const string &dest, const char *src); -int stricmp(const char *dest, const string &src); -int stricmp(const string &dest, const string &src); - -void strcpy(string &dest, const char *src); -void strcpy(string &dest, const string &src); -uint strlcpy(char *dest, const char *src, uint length); -uint strlcpy(string &dest, const char *src, uint length); -uint strlcpy(string &dest, const string &src, uint length); - -void strcat(string &dest, const char *src); -void strcat(string &dest, const string &src); -uint strlcat(char *dest, const char *src, uint length); -uint strlcat(string &dest, const char *src, uint length); -uint strlcat(string &dest, const string &src, uint length); - -string substr(string &dest, const char *src, uint start = 0, uint length = 0); -string substr(string &dest, const string &src, uint start = 0, uint length = 0); - -void strinsert(string &dest, const char *src, uint pos); -void strinsert(string &dest, const string &src, uint pos); - -void strremove(string &dest, uint start, uint length = 0); - -char *strlower(char *str); -string &strlower(string &str); - -char *strupper(char *str); -string &strupper(string &str); - -int strpos(const char *str, const char *key); -int strpos(const string &str, const char *key); -int strpos(const char *str, const string &key); -int strpos(const string &str, const string &key); - -int qstrpos(const char *str, const char *key); -int qstrpos(const string &str, const char *key); -int qstrpos(const char *str, const string &key); -int qstrpos(const string &str, const string &key); - -void strtr(char *dest, const char *before, const char *after); -void strtr(string &dest, const char *before, const char *after); - -bool strbegin(const char *str, const char *key); -bool strbegin(const string &str, const char *key); - -bool stribegin(const char *str, const char *key); -bool stribegin(const string &str, const char *key); - -bool strend(const char *str, const char *key); -bool strend(const string &str, const char *key); - -bool striend(const char *str, const char *key); -bool striend(const string &str, const char *key); - -void strltrim(char *str, const char *key); -void strltrim(string &str, const char *key); - -void striltrim(char *str, const char *key); -void striltrim(string &str, const char *key); - -void strrtrim(char *str, const char *key); -void strrtrim(string &str, const char *key); - -void strirtrim(char *str, const char *key); -void strirtrim(string &str, const char *key); - -void strtrim(char *str, const char *key); -void strtrim(string &str, const char *key); - -void stritrim(char *str, const char *key); -void stritrim(string &str, const char *key); - -void strquote(string &str); - -bool strunquote(char *str); -bool strunquote(string &str); - -uint strhex(const char *str); -uint strhex(const string &str); - -uint strdec(const char *str); -uint strdec(const string &str); - -uint strbin(const char *str); -uint strbin(const string &str); - -char *utoa(char *str, uint num); -string &utoa(string &str, uint num); - -char *itoa(char *str, uint num); -string &itoa(string &str, uint num); - -char *htoa(char *str, uint num); -string &htoa(string &str, uint num); - -char *btoa(char *str, uint num); -string &btoa(string &str, uint num); - -bool strfread(string &str, const char *filename); - -string strfmt(const char *fmt, int num); - -int strmath(const char *str); -int strmath(const string &str); - -string &replace(string &str, const char *key, const char *token); -string &replace(string &str, const char *key, const string &token); - -string &qreplace(string &str, const char *key, const char *token); -string &qreplace(string &str, const char *key, const string &token); - -void split(stringarray &dest, const char *key, const char *src); -void split(stringarray &dest, const char *key, const string &src); - -void qsplit(stringarray &dest, const char *key, const char *src); -void qsplit(stringarray &dest, const char *key, const string &src); - -uint vsprintf(string &str, const char *s, va_list args); -uint sprintf(string &str, const char *s, ...); - -class string { -public: -char *s; -uint size; - void reserve(uint reqsize) { - if(reqsize > size) { - size = reqsize; - s = (char*)realloc(s, size + 1); - s[size] = 0; - } - } - - void swap(string &str) { - ::swap(s, str.s); - ::swap(size, str.size); - } - - string() { - size = 16; - s = (char*)malloc(size + 1); - s[0] = 0; - } - - string(const char *str) { - size = strlen(str); - s = (char*)malloc(size + 1); - strcpy(s, str); - } - - string(const string &str) { - size = strlen(str); - s = (char*)malloc(size + 1); - strcpy(s, strptr(str)); - } - - ~string() { safe_free(s); } - - operator const char*() const { return s; } - const char* operator()() const { return s; } - char& operator[](const uint); - - string& operator=(const int); - string& operator=(const char*); - string& operator=(const string&); - - string& operator<<(const int); - string& operator<<(const char*); - string& operator<<(const string&); - - bool operator==(const char*); - bool operator==(const string&); - bool operator!=(const char*); - bool operator!=(const string&); - bool operator< (const char*); - bool operator< (const string&); - bool operator<=(const char*); - bool operator<=(const string&); - bool operator> (const char*); - bool operator> (const string&); - bool operator>=(const char*); - bool operator>=(const string&); -}; - -inline void swap(string &x, string &y) { x.swap(y); } - -#endif //LIBSTRING_H diff --git a/src/lib/libstring_array.cpp b/src/lib/libstring_array.cpp deleted file mode 100644 index 7c731fbd..00000000 --- a/src/lib/libstring_array.cpp +++ /dev/null @@ -1,11 +0,0 @@ -uint count(stringarray &str) { - return str.size(); -} - -int find(stringarray &str, const char *key) { - for(uint i = 0; i < count(str); i++) { - if(str[i] == key) { return i; } - } - return -1; -} -int find(stringarray &str, const string &key) { return find(str, strptr(key)); } diff --git a/src/lib/libstring_int.cpp b/src/lib/libstring_int.cpp deleted file mode 100644 index 9c4c7ae4..00000000 --- a/src/lib/libstring_int.cpp +++ /dev/null @@ -1,5 +0,0 @@ -string strfmt(const char *fmt, int num) { -string temp; - sprintf(temp, fmt, num); - return temp; -} diff --git a/src/lib/libstring_oo.cpp b/src/lib/libstring_oo.cpp deleted file mode 100644 index 01dc8f48..00000000 --- a/src/lib/libstring_oo.cpp +++ /dev/null @@ -1,47 +0,0 @@ -char &string::operator[](const uint index) { - reserve(index); - return s[index]; -} - -string &string::operator=(const int num) { - strcpy(*this, strfmt("%d", num)); - return *this; -} - -string &string::operator=(const char *str) { - strcpy(*this, str); - return *this; -} - -string &string::operator=(const string &str) { - strcpy(*this, str); - return *this; -} - -string& string::operator<<(const int num) { - strcat(*this, strfmt("%d", num)); - return *this; -} - -string& string::operator<<(const char* str) { - strcat(*this, str); - return *this; -} - -string& string::operator<<(const string& str) { - strcat(*this, str); - return *this; -} - -bool string::operator==(const char *str) { return strcmp(strptr(*this), str) == 0; } -bool string::operator==(const string &str) { return strcmp(strptr(*this), strptr(str)) == 0; } -bool string::operator!=(const char *str) { return strcmp(strptr(*this), str) != 0; } -bool string::operator!=(const string &str) { return strcmp(strptr(*this), strptr(str)) != 0; } -bool string::operator< (const char *str) { return strcmp(strptr(*this), str) < 0; } -bool string::operator< (const string &str) { return strcmp(strptr(*this), strptr(str)) < 0; } -bool string::operator<=(const char *str) { return strcmp(strptr(*this), str) <= 0; } -bool string::operator<=(const string &str) { return strcmp(strptr(*this), strptr(str)) <= 0; } -bool string::operator> (const char *str) { return strcmp(strptr(*this), str) > 0; } -bool string::operator> (const string &str) { return strcmp(strptr(*this), strptr(str)) > 0; } -bool string::operator>=(const char *str) { return strcmp(strptr(*this), str) >= 0; } -bool string::operator>=(const string &str) { return strcmp(strptr(*this), strptr(str)) >= 0; } diff --git a/src/lib/libstring_sprintf.cpp b/src/lib/libstring_sprintf.cpp deleted file mode 100644 index 3a852354..00000000 --- a/src/lib/libstring_sprintf.cpp +++ /dev/null @@ -1,220 +0,0 @@ -uint vsprintf(string &str, const char *s, va_list args) { -va_list temp; - va_copy(temp, args); -int length = vsnprintf(0, 0, s, temp); - if(length < 0) length = 16 * 1024; //temp fix for non-C99-complaint vsnprintf - va_end(temp); - - str.reserve(length); - - va_copy(temp, args); - length = vsprintf(strptr(str), s, temp); - va_end(temp); - - return length; -} - -uint sprintf(string &str, const char *s, ...) { -va_list args; - va_start(args, s); -uint length = vsprintf(str, s, args); - va_end(args); - return length; -} - -/* -uint vsprintf(string &str, const char *s, va_list args) { -bool leftalign; -bool showbase; -char positivesign; -char pad; -uint width; -bool useprecision; -uint precision; -char modifier; -char type; - -uint32 vararg32; -uint64 vararg64; -char *varptr; -char varstr[256]; -uint varstrlen; - - strcpy(str, ""); -uint i = 0; - while(s[i]) { - if(s[i] != '%') { - strcat(str, s[i++]); - } else if(s[i + 1] == '%' || !s[i + 1]) { - strcat(str, '%'); - } else { //s[i] == '%' - //format: %[flags][width][.precision][modifiers]type - i++; - - //flags - leftalign = false; - positivesign = 0; - showbase = false; - - while(s[i]) { - if(s[i] == '-') { - leftalign = true; - i++; - } else if(s[i] == '+') { - positivesign = '+'; - i++; - } else if(s[i] == ' ') { - positivesign = ' '; - i++; - } else if(s[i] == '#') { - showbase = true; - i++; - } else { - break; - } - } - - //zero padding - if(s[i] == '0') { - pad = '0'; - i++; - } else { - pad = ' '; - } - - //width - width = 0; - if(s[i] == '*') { - width = va_arg(args, uint32); - i++; - } else { - while(s[i]) { - if(s[i] < '0' || s[i] > '9')break; - width *= 10; - width += s[i++] - '0'; - } - } - if(width == 0)width = 1; - - //precision - useprecision = false; - precision = 0; - if(s[i] == '.') { - useprecision = true; - i++; - - if(s[i] == '*') { - precision = va_arg(args, uint32); - i++; - } else { - while(s[i]) { - if(s[i] < '0' || s[i] > '9')break; - precision *= 10; - precision += s[i++] - '0'; - } - } - } - if(precision == 0)precision = 1; - - //modifier - if(s[i] == 'h') { - modifier = 'h'; - i++; - } else if(s[i] == 'l') { - modifier = 'l'; - i++; - } else if(s[i] == 'L') { - modifier = 'L'; - i++; - } - - //type - type = s[i++]; - switch(type) { - - case 'c': { - //character - vararg32 = va_arg(args, uint32); - - if(leftalign == false) { while(width-- > 1)strcat(str, pad); } - strcat(str, char(vararg32)); - if(leftalign == true) { while(width-- > 1)strcat(str, pad); } - } break; - - case 's': { - //string - varptr = va_arg(args, char*); - - varstrlen = strlen(varptr); - if(useprecision && precision < varstrlen)varstrlen = precision; - if(leftalign == false) { while(width-- > varstrlen)strcat(str, pad); } - uint index = 0; - //todo: optimize to a fixed-width strcat - while(index < varstrlen)strcat(str, varptr[index++]); - if(leftalign == true) { while(width-- > varstrlen)strcat(str, pad); } - } break; - - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': { - //signed integer - vararg32 = va_arg(args, uint32); - - if(type == 'd' || type == 'i') { - itoa(varstr, vararg32); - } else if(type == 'u') { - utoa(varstr, vararg32); - } else if(type == 'x') { - htoa(varstr, vararg32); - } else if(type == 'X') { - uhtoa(varstr, vararg32); - } - - uint basestrlen = strlen(varstr); - varstrlen = (useprecision && precision > basestrlen) ? precision : basestrlen; - - if(type == 'd' || type == 'i') { - if(int32(vararg32) >= 0 && positivesign) { varstrlen++; } - } - - if(type == 'x' || type == 'X') { - if(showbase) { varstrlen += 2; } - } - - if(leftalign == false) { while(width-- > varstrlen)strcat(str, pad); } - if(type == 'd' || type == 'i') { - if(int32(vararg32) >= 0 && positivesign) { strcat(str, positivesign); } - } - if(type == 'x' || type == 'X') { - if(showbase)strcat(str, (type == 'x') ? "0x" : "0X"); - } - if(useprecision) { - while(basestrlen < precision) { strcat(str, "0"); basestrlen++; } - } - strcat(str, varstr); - if(leftalign == true) { while(width-- > varstrlen)strcat(str, pad); } - } break; - - case 'p': { - //todo: add 64-bit pointer support - vararg32 = va_arg(args, uint32); - - strcpy(varstr, "00000000"); - uint index = 8; - htoa(varstr + index, vararg32); - varstrlen = strlen(varstr + index); - index -= 8 - varstrlen; - - if(leftalign == false) { while(width-- > 8)strcat(str, pad); } - strcat(str, varstr + index); - if(leftalign == true) { while(width-- > 8)strcat(str, pad); } - } break; - - } - } - } - return strlen(str); -} -*/ diff --git a/src/lib/libui_gtk.cpp b/src/lib/libui_gtk.cpp deleted file mode 100644 index 276573a5..00000000 --- a/src/lib/libui_gtk.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include -#include -#include "libui_gtk.h" -#include "libui_gtk_window.cpp" -#include "libui_gtk_control.cpp" - -namespace libui { - -void init() { -int argc = 1; -char **argv; - argv = (char**)malloc(1 * sizeof(char*)); - argv[0] = (char*)malloc(64 * sizeof(char)); - strcpy(argv[0], "./libui"); -//GTK+ insists you provide main()'s argc, argv parameters for -//some special command-line processing options that are likely -//never used by anything. -//However, I insist on libui_init() not requiring arguments so -//that it can be called from anywhere, including a global -//constructor that is invoked before main() is reached. - gtk_init(&argc, &argv); - safe_free(argv[0]); - safe_free(argv); -} - -void term() { -} - -bool run() { - gtk_main_iteration_do(false); - return events_pending(); -} - -bool events_pending() { - return gtk_events_pending(); -} - -uint get_screen_width() { return gdk_screen_width(); } -uint get_screen_height() { return gdk_screen_height(); } - -// - -bool file_load(Window *owner, char *filename, const char *filter, const char *path) { - strcpy(filename, ""); - -GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File", - owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0, - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, (const gchar*)0); - - if(path && strcmp(path, "")) { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); - } - - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - strcpy(filename, fn); - g_free(fn); - } - - gtk_widget_destroy(dialog); - return strcmp(filename, ""); //return true if filename != "" -} - -bool file_save(Window *owner, char *filename, const char *filter, const char *path) { - strcpy(filename, ""); - -GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File", - owner ? GTK_WINDOW(owner->info.window) : (GtkWindow*)0, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, (const gchar*)0); - - if(path && strcmp(path, "")) { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); - } - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - strcpy(filename, fn); - g_free(fn); - } - - gtk_widget_destroy(dialog); - return strcmp(filename, ""); //return true if filename != "" -} - -// - -uint16 translate_key(uint key) { - switch(key) { - - case GDK_Escape: return keymap::esc; - - case GDK_F1: return keymap::f1; - case GDK_F2: return keymap::f2; - case GDK_F3: return keymap::f3; - case GDK_F4: return keymap::f4; - case GDK_F5: return keymap::f5; - case GDK_F6: return keymap::f6; - case GDK_F7: return keymap::f7; - case GDK_F8: return keymap::f8; - case GDK_F9: return keymap::f9; - case GDK_F10: return keymap::f10; - case GDK_F11: return keymap::f11; - case GDK_F12: return keymap::f12; - - case GDK_Print: return keymap::print_screen; - case GDK_Sys_Req: return keymap::sys_req; - case GDK_Scroll_Lock: return keymap::scroll_lock; - case GDK_Pause: return keymap::pause; - case GDK_Break: return keymap::brk; - - case GDK_grave: return keymap::grave; - case GDK_asciitilde: return keymap::tilde; - - case GDK_1: return keymap::num_1; - case GDK_2: return keymap::num_2; - case GDK_3: return keymap::num_3; - case GDK_4: return keymap::num_4; - case GDK_5: return keymap::num_5; - case GDK_6: return keymap::num_6; - case GDK_7: return keymap::num_7; - case GDK_8: return keymap::num_8; - case GDK_9: return keymap::num_9; - case GDK_0: return keymap::num_0; - - case GDK_exclam: return keymap::exclamation; - case GDK_at: return keymap::at; - case GDK_numbersign: return keymap::pound; - case GDK_dollar: return keymap::dollar; - case GDK_percent: return keymap::percent; - case GDK_asciicircum: return keymap::power; - case GDK_ampersand: return keymap::ampersand; - case GDK_asterisk: return keymap::asterisk; - case GDK_parenleft: return keymap::lparenthesis; - case GDK_parenright: return keymap::rparenthesis; - - case GDK_minus: return keymap::minus; - case GDK_underscore: return keymap::underscore; - case GDK_equal: return keymap::equal; - case GDK_plus: return keymap::plus; - case GDK_BackSpace: return keymap::backspace; - - case GDK_Insert: return keymap::ins; - case GDK_Delete: return keymap::del; - case GDK_Home: return keymap::home; - case GDK_End: return keymap::end; - case GDK_Page_Up: return keymap::page_up; - case GDK_Page_Down: return keymap::page_down; - - case GDK_a: return keymap::a; - case GDK_b: return keymap::b; - case GDK_c: return keymap::c; - case GDK_d: return keymap::d; - case GDK_e: return keymap::e; - case GDK_f: return keymap::f; - case GDK_g: return keymap::g; - case GDK_h: return keymap::h; - case GDK_i: return keymap::i; - case GDK_j: return keymap::j; - case GDK_k: return keymap::k; - case GDK_l: return keymap::l; - case GDK_m: return keymap::m; - case GDK_n: return keymap::n; - case GDK_o: return keymap::o; - case GDK_p: return keymap::p; - case GDK_q: return keymap::q; - case GDK_r: return keymap::r; - case GDK_s: return keymap::s; - case GDK_t: return keymap::t; - case GDK_u: return keymap::u; - case GDK_v: return keymap::v; - case GDK_w: return keymap::w; - case GDK_x: return keymap::x; - case GDK_y: return keymap::y; - case GDK_z: return keymap::z; - - case GDK_A: return keymap::A; - case GDK_B: return keymap::B; - case GDK_C: return keymap::C; - case GDK_D: return keymap::D; - case GDK_E: return keymap::E; - case GDK_F: return keymap::F; - case GDK_G: return keymap::G; - case GDK_H: return keymap::H; - case GDK_I: return keymap::I; - case GDK_J: return keymap::J; - case GDK_K: return keymap::K; - case GDK_L: return keymap::L; - case GDK_M: return keymap::M; - case GDK_N: return keymap::N; - case GDK_O: return keymap::O; - case GDK_P: return keymap::P; - case GDK_Q: return keymap::Q; - case GDK_R: return keymap::R; - case GDK_S: return keymap::S; - case GDK_T: return keymap::T; - case GDK_U: return keymap::U; - case GDK_V: return keymap::V; - case GDK_W: return keymap::W; - case GDK_X: return keymap::X; - case GDK_Y: return keymap::Y; - case GDK_Z: return keymap::Z; - - case GDK_bracketleft: return keymap::lbracket; - case GDK_bracketright: return keymap::rbracket; - case GDK_backslash: return keymap::backslash; - case GDK_semicolon: return keymap::semicolon; - case GDK_apostrophe: return keymap::apostrophe; - case GDK_comma: return keymap::comma; - case GDK_period: return keymap::period; - case GDK_slash: return keymap::slash; - - case GDK_braceleft: return keymap::lbrace; - case GDK_braceright: return keymap::rbrace; - case GDK_bar: return keymap::pipe; - case GDK_colon: return keymap::colon; - case GDK_quotedbl: return keymap::quote; - case GDK_less: return keymap::lcaret; - case GDK_greater: return keymap::rcaret; - case GDK_question: return keymap::question; - - case GDK_KP_1: return keymap::kp_1; - case GDK_KP_2: return keymap::kp_2; - case GDK_KP_3: return keymap::kp_3; - case GDK_KP_4: return keymap::kp_4; - case GDK_KP_5: return keymap::kp_5; - case GDK_KP_6: return keymap::kp_6; - case GDK_KP_7: return keymap::kp_7; - case GDK_KP_8: return keymap::kp_8; - case GDK_KP_9: return keymap::kp_9; - case GDK_KP_0: return keymap::kp_0; - case GDK_KP_Decimal: return keymap::kp_decimal; - - case GDK_KP_End: return keymap::kp_end; - case GDK_KP_Down: return keymap::kp_down; - case GDK_KP_Page_Down: return keymap::kp_page_down; - case GDK_KP_Left: return keymap::kp_left; - case GDK_KP_Begin: return keymap::kp_center; - case GDK_KP_Right: return keymap::kp_right; - case GDK_KP_Home: return keymap::kp_home; - case GDK_KP_Up: return keymap::kp_up; - case GDK_KP_Page_Up: return keymap::kp_page_up; - case GDK_KP_Insert: return keymap::kp_insert; - case GDK_KP_Delete: return keymap::kp_delete; - - case GDK_KP_Add: return keymap::kp_plus; - case GDK_KP_Subtract: return keymap::kp_minus; - case GDK_KP_Multiply: return keymap::kp_mul; - case GDK_KP_Divide: return keymap::kp_div; - case GDK_KP_Enter: return keymap::kp_enter; - - case GDK_Num_Lock: return keymap::num_lock; - case GDK_Caps_Lock: return keymap::caps_lock; - - case GDK_Up: return keymap::up; - case GDK_Down: return keymap::down; - case GDK_Left: return keymap::left; - case GDK_Right: return keymap::right; - - case GDK_Tab: return keymap::tab; - case GDK_Return: return keymap::enter; - case GDK_space: return keymap::space; - - case GDK_Control_L: return keymap::lctrl; - case GDK_Control_R: return keymap::rctrl; - case GDK_Alt_L: return keymap::lalt; - case GDK_Alt_R: return keymap::ralt; - case GDK_Shift_L: return keymap::lshift; - case GDK_Shift_R: return keymap::rshift; - case GDK_Super_L: return keymap::lsuper; - case GDK_Super_R: return keymap::rsuper; - case GDK_Menu: return keymap::menu; - - } - - return keymap::none; -} - -}; diff --git a/src/lib/libui_gtk.h b/src/lib/libui_gtk.h deleted file mode 100644 index 45ac93b5..00000000 --- a/src/lib/libui_gtk.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - libui_gtk ~byuu (2007-06-06) - license: public domain -*/ - -#ifndef LIBUI_H -#define LIBUI_H - -#include "libbase.h" -#include "libarray.h" -#include "libvector.h" -#include "libstring.h" -#include "libkeymap.h" - -//TODO: hide this if possible -#include - -namespace libui { - -class Window; -#include "libui_gtk_control.h" - -void init(); -void term(); -bool run(); -bool events_pending(); - -uint get_screen_width(); -uint get_screen_height(); - -bool file_load(Window *owner, char *filename, const char *filter, const char *path = ""); -bool file_save(Window *owner, char *filename, const char *filter, const char *path = ""); - -uint16 translate_key(uint key); - -namespace Message { - enum { - Invalid = 0, - Close, - Block, - KeyUp, - KeyDown, - Clicked, - DoubleClicked, - Changed, - }; -}; - -class Window { public: -enum Style { - Center = 1, -}; - -MenuBar menu; - void create(uint style, uint width, uint height, const char *caption = ""); - void set_text(const char *str); - void set_background_color(uint8 r, uint8 g, uint8 b); - void focus(); - bool focused(); - void move(uint x, uint y); - void resize(uint width, uint height); - virtual void show(); - virtual void hide(); - void show(bool state); - bool visible(); - void fullscreen(); - void unfullscreen(); - void fullscreen(bool state); - bool is_fullscreen(); - - virtual bool message(uint id, uintptr_t param = 0) { return true; } - -//private: -struct { - GtkWidget *window, *menubar; - GtkWidget *vcontainer, *container; -} info; - -public: - Window() { - info.menubar = 0; - } -}; - -}; - -#endif diff --git a/src/lib/libui_gtk_control.cpp b/src/lib/libui_gtk_control.cpp deleted file mode 100644 index 8f42e877..00000000 --- a/src/lib/libui_gtk_control.cpp +++ /dev/null @@ -1,676 +0,0 @@ -namespace libui { - -/***** - * Control - *****/ - -void Control::move(uint x, uint y) { - gtk_fixed_move(GTK_FIXED(owner->info.container), widget, x, y); -} - -void Control::resize(uint width, uint height) { - gtk_widget_set_size_request(widget, width, height); -} - -void Control::focus() { - gtk_widget_grab_focus(widget); -} - -void Control::show() { - gtk_widget_show(widget); -} - -void Control::hide() { - gtk_widget_hide(widget); -} - -void Control::show(bool state) { - (state == true) ? show() : hide(); -} - -bool Control::visible() { - return GTK_WIDGET_VISIBLE(widget); -} - -void Control::enable() { - gtk_widget_set_sensitive(widget, true); -} - -void Control::disable() { - gtk_widget_set_sensitive(widget, false); -} - -void Control::enable(bool state) { - (state == true) ? enable() : disable(); -} - -bool Control::enabled() { - return GTK_WIDGET_SENSITIVE(widget); -} - -/***** - * MenuBar - *****/ - -void MenuBar::create(Window &r_owner) { - type = ControlType::MenuBar; - widget = r_owner.info.menubar; - owner = &r_owner; - show(); -} - -void MenuBar::finish() { -} - -/***** - * MenuGroup - *****/ - -void MenuGroup::create(MenuBar &r_owner, const char *caption) { - type = ControlType::MenuGroup; - widget = gtk_menu_new(); - item = gtk_menu_item_new_with_label(caption ? caption : "?"); - owner = r_owner.owner; - parent = r_owner.widget; -} - -void MenuGroup::create(MenuGroup &r_owner, const char *caption) { - type = ControlType::MenuGroup; - widget = gtk_menu_new(); - item = gtk_menu_item_new_with_label(caption ? caption : "?"); - owner = r_owner.owner; - parent = r_owner.widget; -} - -void MenuGroup::finish() { - gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), widget); - gtk_menu_bar_append(parent, item); - gtk_widget_show(item); -} - -/***** - * MenuItem - *****/ - -void MenuItem::create(MenuGroup &r_owner, const char *caption) { - type = ControlType::MenuItem; - widget = gtk_menu_item_new_with_label(caption ? caption : "?"); - owner = r_owner.owner; - parent = r_owner.widget; - gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); - g_signal_connect_swapped(G_OBJECT(widget), "activate", - G_CALLBACK(libui_control_clicked), (gpointer)this); - gtk_widget_show(widget); -} - -/***** - * MenuCheckItem - *****/ - -void MenuCheckItem::create(MenuGroup &r_owner, const char *caption) { - type = ControlType::MenuCheckItem; - widget = gtk_check_menu_item_new_with_label(caption ? caption : "?"); - owner = r_owner.owner; - parent = r_owner.widget; - gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); - g_signal_connect_swapped(G_OBJECT(widget), "activate", - G_CALLBACK(libui_control_clicked), (gpointer)this); - gtk_widget_show(widget); -} - -void MenuCheckItem::check() { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE); -} - -void MenuCheckItem::uncheck() { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), FALSE); -} - -void MenuCheckItem::check(bool state) { - (state == true) ? check() : uncheck(); -} - -bool MenuCheckItem::checked() { - return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); -} - -/***** - * MenuRadioItem - *****/ - -void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) { - if(list.count() == 0)throw; - type = ControlType::MenuRadioItem; - widget = (&list[0] == this) ? - gtk_radio_menu_item_new_with_label(0, caption ? caption : "?") : - gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(list[0].widget), caption ? caption : ""); - owner = r_owner.owner; - parent = r_owner.widget; - gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); - g_signal_connect_swapped(G_OBJECT(widget), "activate", - G_CALLBACK(libui_control_clicked), (gpointer)this); - gtk_widget_show(widget); -} - -void MenuRadioItem::check() { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), TRUE); -} - -bool MenuRadioItem::checked() { - return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); -} - -/***** - * MenuSeparator - *****/ - -void MenuSeparator::create(MenuGroup &r_owner) { - type = ControlType::MenuSeparator; - widget = gtk_separator_menu_item_new(); - owner = r_owner.owner; - parent = r_owner.widget; - gtk_menu_shell_append(GTK_MENU_SHELL(parent), widget); - gtk_widget_show(widget); -} - -/***** - * Panel - *****/ - -void Panel::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Panel; - widget = gtk_fixed_new(); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Panel::attach(Window &window) { - if(attached) { //detach existing child window, return to toplevel window - gtk_widget_reparent(attached->info.vcontainer, attached->info.window); - } - attached = &window; - window.hide(); - gtk_widget_reparent(window.info.vcontainer, widget); -} - -void Panel::detach() { - if(attached) { - gtk_widget_reparent(attached->info.vcontainer, attached->info.window); - } - attached = 0; -} - -/***** - * Container - *****/ - -void Container::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Container; - widget = gtk_drawing_area_new(); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Container::set_background_color(uint8 r, uint8 g, uint8 b) { -GdkColor color; - color.pixel = (r << 16) | (g << 8) | (b); - color.red = (r << 8) | (r); - color.green = (g << 8) | (g); - color.blue = (b << 8) | (b); - gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color); -} - -unsigned long Container::x_handle() { - return GDK_WINDOW_XWINDOW(widget->window); -} - -GtkWidget *Container::handle() { - return widget; -} - -/***** - * Canvas - * - * Note: for reasons that defy any notion of logic, the GTK+ developers decided to - * store color in semi-reversed format (XBGR) rather than conventional format (XRGB). - * This is not an endian issue. - * As a result, we are forced to perform manual conversion to XBGR format, at the - * cost of significant overhead. - *****/ - -void libui_canvas_expose(GtkWidget *widget, GdkEventAny *any, Canvas *canvas) { -uint32 *d = canvas->rbuffer; -uint32 *s = canvas->buffer; - for(uint y = widget->allocation.height; y; y--) { - for(uint x = widget->allocation.width; x; x--) { - uint32 p = *s++; - *d++ = ((p << 16) & 0xff0000) + (p & 0x00ff00) + ((p >> 16) & 0x0000ff); - } - } - - gdk_draw_rgb_32_image(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], - 0, 0, widget->allocation.width, widget->allocation.height, - GDK_RGB_DITHER_NONE, (guchar*)canvas->rbuffer, canvas->pitch); -} - -void Canvas::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Canvas; - widget = gtk_drawing_area_new(); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); - - pitch = width * sizeof(uint32); - rbuffer = (uint32*)malloc(pitch * height); - buffer = (uint32*)malloc(pitch * height); - memset(buffer, 0, pitch * height); - memset(rbuffer, 0, pitch * height); - g_signal_connect(G_OBJECT(widget), "expose_event", G_CALLBACK(libui_canvas_expose), this); -} - -void Canvas::redraw() { - if(!widget->window)return; - -GdkRectangle rect; - rect.x = 0; - rect.y = 0; - rect.width = widget->allocation.width; - rect.height = widget->allocation.height; - gdk_window_invalidate_rect(widget->window, &rect, true); -} - -Canvas::Canvas() { - buffer = 0; -} - -Canvas::~Canvas() { - safe_free(rbuffer); - safe_free(buffer); -} - -/***** - * Frame - *****/ - -void Frame::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Frame; - widget = gtk_frame_new(caption ? caption : ""); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -/***** - * Label - *****/ - -void Label::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Label; - widget = gtk_label_new(caption ? caption : ""); - owner = &r_owner; - gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.0); - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Label::set_text(const char *str) { - gtk_label_set_label(GTK_LABEL(widget), str); -} - -/***** - * Button - *****/ - -void Button::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Button; - widget = gtk_button_new_with_label(caption ? caption : ""); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); - - g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this); -} - -void Button::set_text(const char *str) { - gtk_button_set_label(GTK_BUTTON(widget), str); -} - -/***** - * Checkbox - *****/ - -void Checkbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Checkbox; - widget = gtk_check_button_new_with_label(caption ? caption : ""); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); - - g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this); -} - -void Checkbox::check() { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); -} - -void Checkbox::uncheck() { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); -} - -void Checkbox::check(bool state) { - (state == true) ? check() : uncheck(); -} - -bool Checkbox::checked() { - return (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) ? true : false; -} - -/***** - * Radiobox - *****/ - -void Radiobox::create(Window &r_owner, ControlGroup &group, uint style, uint x, uint y, uint width, uint height, const char *caption) { - if(group.count() == 0)throw; - type = ControlType::Radiobox; - widget = (&group[0] == this) ? - gtk_radio_button_new_with_label(0, caption ? caption : "") : - gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0].widget), caption ? caption : ""); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); - - g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(libui_control_clicked), (gpointer)this); -} - -void Radiobox::check() { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); -} - -bool Radiobox::checked() { - return (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) ? true : false; -} - -/***** - * Editbox - *****/ - -void Editbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - owner = &r_owner; - type = ControlType::Editbox; - multiline = bool(style & Multiline); - - if(multiline == false) { - widget = gtk_entry_new(); - if(style & Editbox::Readonly) { gtk_entry_set_editable(GTK_ENTRY(widget), false); } - gtk_entry_set_text(GTK_ENTRY(widget), caption ? caption : ""); - } else { - GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS : - (style & Editbox::HorizontalScrollNever) ? GTK_POLICY_NEVER : - GTK_POLICY_AUTOMATIC; - GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS : - (style & Editbox::VerticalScrollNever) ? GTK_POLICY_NEVER : - GTK_POLICY_AUTOMATIC; - widget = gtk_scrolled_window_new(0, 0); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), hscroll, vscroll); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), GTK_SHADOW_ETCHED_IN); - subwidget = gtk_text_view_new(); - gtk_container_add(GTK_CONTAINER(widget), subwidget); - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subwidget)); - if(style & Editbox::Readonly) { gtk_text_view_set_editable(GTK_TEXT_VIEW(subwidget), false); } - gtk_text_buffer_set_text(buffer, caption ? caption : "", -1); - gtk_widget_show(subwidget); - } - - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Editbox::set_text(const char *str) { - if(multiline == false) { - gtk_entry_set_text(GTK_ENTRY(widget), str); - } else { - gtk_text_buffer_set_text(buffer, str, -1); - } -} - -uint Editbox::get_text(char *str, uint length) { - if(multiline == false) { - const char *temp = gtk_entry_get_text(GTK_ENTRY(widget)); - return strlcpy(str, temp ? temp : "", length); - } else { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - return strlcpy(str, gtk_text_buffer_get_text(buffer, &start, &end, true), length); - } -} - -/***** - * Listbox - *****/ - -/***** - * GTK+'s implementation of list boxes was apparently someone's idea of a very, very cruel joke ... - * Attempt to understand the below code at the risk of your own sanity. - *****/ - -void Listbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *columns) { - owner = &r_owner; - type = ControlType::Listbox; - -bool header = bool(style & Header); - -stringarray list, part; - split(part, "|", columns); - -GType *v = (GType*)malloc(count(part) * sizeof(GType)); - for(uint i = 0; i < count(part); i++) { v[i] = G_TYPE_STRING; } - store = gtk_list_store_newv(count(part), v); - safe_free(v); - - widget = gtk_scrolled_window_new(0, 0); -GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS : - (style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER : - GTK_POLICY_AUTOMATIC; -GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS : - (style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER : - GTK_POLICY_AUTOMATIC; - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), hscroll, vscroll); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), GTK_SHADOW_ETCHED_IN); - subwidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_container_add(GTK_CONTAINER(widget), subwidget); - g_object_unref(G_OBJECT(store)); - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(subwidget); - gtk_widget_show(widget); - - split(list, "|", columns); -//alternate colors for each listbox entry if there are multiple columns ... - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(subwidget), (count(list) >= 2) ? true : false); - for(uint i = 0; i < count(list); i++) { - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(strptr(list[i]), renderer, "text", i, 0); - column_list[column_list.size()] = column; - gtk_tree_view_append_column(GTK_TREE_VIEW(subwidget), column); - } - - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(subwidget), header); - autosize_columns(); - - g_signal_connect_swapped(G_OBJECT(subwidget), "cursor-changed", G_CALLBACK(libui_control_changed), (gpointer)this); - g_signal_connect_swapped(G_OBJECT(subwidget), "row-activated", G_CALLBACK(libui_control_double_clicked), (gpointer)this); -} - -void Listbox::autosize_columns() { - gtk_tree_view_columns_autosize(GTK_TREE_VIEW(subwidget)); -} - -void Listbox::set_column_width(uint column, uint width) { - gtk_tree_view_column_set_min_width(column_list[column], width); - gtk_tree_view_column_set_max_width(column_list[column], width); -} - -void Listbox::add_item(const char *data) { -stringarray part; - split(part, "|", data); - gtk_list_store_append(store, &iter); - for(uint i = 0; i < count(part); i++) { - gtk_list_store_set(store, &iter, i, strptr(part[i]), -1); - } -} - -void Listbox::set_item(uint index, const char *data) { -GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget)); - for(uint i = 0; i <= index; i++) { - (i == 0) ? - gtk_tree_model_get_iter_first(model, &iter) : - gtk_tree_model_iter_next(model, &iter); - } - -stringarray part; - split(part, "|", data); - for(uint i = 0; i < count(part); i++) { - gtk_list_store_set(store, &iter, i, strptr(part[i]), -1); - } -} - -//... because gtk_tree_view_get_selected_row(GTK_TREE_VIEW(subwidget)) would be too easy ... -int Listbox::get_selection() { -GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget)); -GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget)); - if(gtk_tree_model_get_iter_first(model, &iter) == false) { return -1; } - if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return 0; } - for(uint i = 1; i < 100000; i++) { - if(gtk_tree_model_iter_next(model, &iter) == false) { return -1; } - if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return i; } - } - return -1; -} - -//... because gtk_tree_view_set_selected_row(GTK_TREE_VIEW(subwidget), index) would be too easy ... -void Listbox::set_selection(int index) { -int current = get_selection(); -GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subwidget)); -GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subwidget)); - gtk_tree_selection_unselect_all(selection); - if(index < 0) { goto end; } - if(gtk_tree_model_get_iter_first(model, &iter) == false) { goto end; } - if(index == 0) { gtk_tree_selection_select_iter(selection, &iter); goto end; } - for(uint i = 1; i < 100000; i++) { - if(gtk_tree_model_iter_next(model, &iter) == false) { goto end; } - if(index == i) { gtk_tree_selection_select_iter(selection, &iter); goto end; } - } -end: - if(current != index) { owner->message(Message::Changed, (uintptr_t)this); } -} - -void Listbox::reset() { - gtk_list_store_clear(GTK_LIST_STORE(store)); - gtk_tree_view_set_model(GTK_TREE_VIEW(subwidget), GTK_TREE_MODEL(store)); -} - -/***** - * Combobox - *****/ - -void Combobox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Combobox; - widget = gtk_combo_box_new_text(); //gtk_combo_box_entry_new_text(); /* alternate style */ - owner = &r_owner; - counter = 0; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Combobox::add_item(const char *data) { - gtk_combo_box_append_text(GTK_COMBO_BOX(widget), data); - if(counter++ == 0) { set_selection(0); } -} - -int Combobox::get_selection() { - return gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); -} - -void Combobox::set_selection(int index) { - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), index); -} - -void Combobox::reset() { - if(counter == 0) { return; } - for(int i = (counter - 1); i >= 0; i--) { - gtk_combo_box_remove_text(GTK_COMBO_BOX(widget), i); - } - counter = 0; -} - -/***** - * Progressbar - *****/ - -void Progressbar::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Progressbar; - widget = gtk_progress_bar_new(); - owner = &r_owner; - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); -} - -void Progressbar::set_progress(uint progress) { - progress = minmax<0, 100>(progress); -double p = (double)progress / 100.0; - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(widget), p); -} - -uint Progressbar::get_progress() { -uint p = (uint)(gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(widget)) * 100.0); - return (uint)minmax<0, 100>(p); -} - -/***** - * Slider - *****/ - -void Slider::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, uint range) { - type = ControlType::Slider; - orientation = (style & Vertical) ? 1 : 0; - - if(range < 1)range = 1; - if(orientation == 0) { - widget = gtk_hscale_new_with_range(0, range - 1, 1); - } else { - widget = gtk_vscale_new_with_range(0, range - 1, 1); - } - - owner = &r_owner; - gtk_scale_set_draw_value(GTK_SCALE(widget), FALSE); - gtk_widget_set_size_request(widget, width, height); - gtk_fixed_put(GTK_FIXED(owner->info.container), widget, x, y); - gtk_widget_show(widget); - - g_signal_connect_swapped(G_OBJECT(widget), "value-changed", G_CALLBACK(libui_control_changed), (gpointer)this); -} - -void Slider::set_position(uint position) { - gtk_range_set_value(GTK_RANGE(widget), position); -} - -uint Slider::get_position() { - return (int)gtk_range_get_value(GTK_RANGE(widget)); -} - -}; diff --git a/src/lib/libui_gtk_control.h b/src/lib/libui_gtk_control.h deleted file mode 100644 index f1b1f639..00000000 --- a/src/lib/libui_gtk_control.h +++ /dev/null @@ -1,265 +0,0 @@ -namespace ControlType { - enum { - Invalid, - MenuBar, - MenuGroup, - MenuItem, - MenuCheckItem, - MenuRadioItem, - MenuSeparator, - Panel, - Container, - Canvas, - Frame, - Label, - Button, - Checkbox, - Radiobox, - Editbox, - Listbox, - Combobox, - Progressbar, - Slider, - }; -}; - -class Control { public: -uint type; - void move(uint x, uint y); - void resize(uint width, uint height); - - void focus(); - - void show(bool state); - void show(); - void hide(); - bool visible(); - - void enable(bool state); - void enable(); - void disable(); - bool enabled(); - -//protected: -Window *owner; -GtkWidget *widget; -uint id; - -public: - Control() : owner(0), widget(0), id(0), type(ControlType::Invalid) {} -}; - -class ControlGroup { public: - uint count() { return list.size(); } - void add(Control &control) { list[list.size()] = &control; } - void reset() { list.reset(); } - ControlGroup &operator=(ControlGroup &source) { list = source.list; return *this; } - Control &operator[](int index) { return *list[index]; } - -private: -array list; -}; - -class MenuBar : public Control { public: - void create(Window &owner); - void finish(); -}; - -class MenuGroup : public Control { public: - void create(MenuBar &owner, const char *caption); - void create(MenuGroup &owner, const char *caption); - void finish(); - -private: -GtkWidget *parent, *item; -}; - -class MenuItem : public Control { public: - void create(MenuGroup &owner, const char *caption); - -private: -GtkWidget *parent; -}; - -class MenuCheckItem : public Control { public: - void create(MenuGroup &owner, const char *caption); - void check(); - void uncheck(); - void check(bool state); - bool checked(); - -private: -GtkWidget *parent; -}; - -class MenuRadioItem : public Control { public: - void create(MenuGroup &owner, ControlGroup &list, const char *caption); - void check(); - bool checked(); - -private: -GtkWidget *parent; -}; - -class MenuSeparator : public Control { public: - void create(MenuGroup &owner); - -private: -GtkWidget *parent; -}; - -class Panel : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void attach(Window &window); - void detach(); - -private: -Window *attached; - -public: - Panel() : attached(0) {} -}; - -class Container : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void set_background_color(uint8 r, uint8 g, uint8 b); - -//platform-dependent: - unsigned long x_handle(); - GtkWidget *handle(); -}; - -class Canvas : public Control { public: -uint32 *buffer; -uint pitch; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void redraw(); - Canvas(); - ~Canvas(); - -private: -uint32 *rbuffer; - friend void libui_canvas_expose(GtkWidget *widget, GdkEventAny *any, Canvas *canvas); -}; - -class Frame : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); -}; - -class Label : public Control { public: -enum { ideal_height = 18 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void set_text(const char *str); -}; - -class Button : public Control { public: -enum { ideal_height = 30 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void set_text(const char *str); -}; - -class Checkbox : public Control { public: -enum { ideal_height = 18 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void check(); - void uncheck(); - void check(bool state); - bool checked(); -}; - -class Radiobox : public Control { public: -enum { ideal_height = 18 }; - void create(Window &owner, ControlGroup &group, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void check(); - bool checked(); -}; - -class Editbox : public Control { public: -enum { ideal_height = 30 }; -enum { - Multiline = (1 << 1), - Readonly = (1 << 2), - - HorizontalScrollAuto = 0, - HorizontalScrollAlways = (1 << 3), - HorizontalScrollNever = (1 << 4), - - VerticalScrollAuto = 0, - VerticalScrollAlways = (1 << 5), - VerticalScrollNever = (1 << 6), -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void set_text(const char *str); - uint get_text(char *str, uint length); - -private: -GtkWidget *subwidget; -GtkTextBuffer *buffer; -bool multiline; -}; - -class Listbox : public Control { public: -enum { - Header = (1 << 1), - - HorizontalScrollAuto = 0, - HorizontalScrollAlways = (1 << 2), - HorizontalScrollNever = (1 << 3), - - VerticalScrollAuto = 0, - VerticalScrollAlways = (1 << 4), - VerticalScrollNever = (1 << 5), -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *columns = ""); - void autosize_columns(); - void set_column_width(uint column, uint width); - void add_item(const char *data); - void set_item(uint index, const char *data); - int get_selection(); - void set_selection(int index); - void reset(); - -private: -GtkWidget *subwidget; -GtkListStore *store; -GtkCellRenderer *renderer; -GtkTreeViewColumn *column; -array column_list; -GtkTreeIter iter; -}; - -class Combobox : public Control { public: -enum { ideal_height = 30 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void add_item(const char *data); - int get_selection(); - void set_selection(int index); - void reset(); - -private: -uint counter; -}; - -class Progressbar : public Control { public: -enum { ideal_height = 30 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void set_progress(uint progress); - uint get_progress(); -}; - -class Slider : public Control { public: -enum { ideal_height = 25 }; -enum { - Horizontal = 0, - Vertical = 1, -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, uint range); - void set_position(uint position); - uint get_position(); - -private: -bool orientation; -}; diff --git a/src/lib/libui_gtk_window.cpp b/src/lib/libui_gtk_window.cpp deleted file mode 100644 index 496c361a..00000000 --- a/src/lib/libui_gtk_window.cpp +++ /dev/null @@ -1,119 +0,0 @@ -namespace libui { - -gint libui_window_close(GtkWidget *w, GdkEventAny *any, Window *window) { - if(window) { return !window->message(Message::Close); } - return FALSE; //destroy window by default -} - -gint libui_window_keydown(GtkWidget *w, GdkEventKey *key, Window *window) { - if(window) { window->message(Message::KeyDown, libui::translate_key(key->keyval)); } - return FALSE; -} - -gint libui_window_keyup(GtkWidget *w, GdkEventKey *key, Window *window) { - if(window) { window->message(Message::KeyUp, libui::translate_key(key->keyval)); } - return FALSE; -} - -void libui_control_clicked(Control *control) { - if(control && control->owner) { control->owner->message(Message::Clicked, (uintptr_t)control); } -} - -void libui_control_changed(Control *control) { - if(control && control->owner) { control->owner->message(Message::Changed, (uintptr_t)control); } -} - -void libui_control_double_clicked(Control *control) { - if(control && control->owner) { control->owner->message(Message::DoubleClicked, (uintptr_t)control); } -} - -void Window::create(uint style, uint width, uint height, const char *caption) { - info.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(info.window), caption ? caption : ""); - gtk_window_set_resizable(GTK_WINDOW(info.window), false); - g_signal_connect(G_OBJECT(info.window), "delete_event", G_CALLBACK(libui_window_close), (gpointer)this); - g_signal_connect(G_OBJECT(info.window), "key_press_event", G_CALLBACK(libui_window_keydown), (gpointer)this); - g_signal_connect(G_OBJECT(info.window), "key_release_event", G_CALLBACK(libui_window_keyup), (gpointer)this); - - if(style & Center) { gtk_window_set_position(GTK_WINDOW(info.window), GTK_WIN_POS_CENTER_ALWAYS); } - - info.vcontainer = gtk_vbox_new(false, 0); - gtk_container_add(GTK_CONTAINER(info.window), info.vcontainer); - gtk_widget_show(info.vcontainer); - -//always create menubar, only display it when MenuBar type is created -//this is needed to setup box packing before menubar is defined - info.menubar = gtk_menu_bar_new(); - gtk_box_pack_start(GTK_BOX(info.vcontainer), info.menubar, false, false, 0); - - info.container = gtk_fixed_new(); - gtk_widget_set_size_request(info.container, width, height); - gtk_box_pack_end(GTK_BOX(info.vcontainer), info.container, true, true, 0); - gtk_widget_show(info.container); -} - -void Window::focus() { - gtk_window_present(GTK_WINDOW(info.window)); -} - -bool Window::focused() { - return gtk_window_is_active(GTK_WINDOW(info.window)); -} - -void Window::move(uint x, uint y) { -//if window was centered before, GTK+ will ignore move requests, -//therfore we must turn off auto-centering. - gtk_window_set_position(GTK_WINDOW(info.window), GTK_WIN_POS_NONE); - gtk_window_move(GTK_WINDOW(info.window), x, y); -} - -void Window::resize(uint width, uint height) { - gtk_widget_set_size_request(info.container, width, height); -} - -void Window::show() { - gtk_widget_show(info.window); -} - -void Window::hide() { - gtk_widget_hide(info.window); -} - -void Window::show(bool state) { - (state == true) ? show() : hide(); -} - -bool Window::visible() { - return GTK_WIDGET_VISIBLE(info.window); -} - -void Window::fullscreen() { - gtk_window_fullscreen(GTK_WINDOW(info.window)); -} - -void Window::unfullscreen() { - gtk_window_unfullscreen(GTK_WINDOW(info.window)); -} - -void Window::fullscreen(bool state) { - (state == true) ? fullscreen() : unfullscreen(); -} - -bool Window::is_fullscreen() { - return false; -}; - -void Window::set_text(const char *str) { - gtk_window_set_title(GTK_WINDOW(info.window), str); -} - -void Window::set_background_color(uint8 r, uint8 g, uint8 b) { -GdkColor color; - color.pixel = (r << 16) | (g << 8) | (b); - color.red = (r << 8) | (r); - color.green = (g << 8) | (g); - color.blue = (b << 8) | (b); - gtk_widget_modify_bg(info.window, GTK_STATE_NORMAL, &color); -} - -}; diff --git a/src/lib/libui_win.cpp b/src/lib/libui_win.cpp deleted file mode 100644 index 23f3c2e3..00000000 --- a/src/lib/libui_win.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#define _WIN32_IE 0x0600 - -#include "libui_win.h" -#include "libui_win_window.cpp" -#include "libui_win_control.cpp" - -namespace libui { - -long __stdcall canvas_wndproc(HWND, UINT, WPARAM, LPARAM); -long __stdcall label_wndproc (HWND, UINT, WPARAM, LPARAM); - -HFONT create_font(const char *name, uint size) { -HDC hdc = GetDC(0); -HFONT font = CreateFont(-MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72), - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name); - ReleaseDC(0, hdc); - return font; -} - -void init() { - InitCommonControls(); - -WNDCLASS wc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = libui_wndproc; - wc.lpszClassName = "libui_class"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - - font.variable = create_font("Tahoma", 8); - font.fixed = create_font("Courier New", 8); - - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = canvas_wndproc; - wc.lpszClassName = "canvas_class"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = label_wndproc; - wc.lpszClassName = "label_class"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); -} - -void term() { -} - -bool run() { -MSG msg; - if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return events_pending(); -} - -bool events_pending() { -MSG msg; - return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); -} - -uint get_screen_width() { return GetSystemMetrics(SM_CXSCREEN); } -uint get_screen_height() { return GetSystemMetrics(SM_CYSCREEN); } - -// - -bool file_load(Window *owner, char *filename, const char *filter, const char *path) { -string dir, f; - strcpy(dir, path ? path : ""); - replace(dir, "/", "\\"); - -stringarray type, part; - strcpy(f, ""); - split(type, "|", filter); - for(int i = 0; i < count(type); i++) { - split(part, ";", type[i]); - if(count(part) != 2)continue; - - strcat(f, part[0]); - strcat(f, " ("); - strcat(f, part[1]); - strcat(f, ")|"); - replace(part[1], ",", ";"); - strcat(f, part[1]); - strcat(f, "|"); - } - -char *pf = strptr(f); - for(int i = strlen(pf) - 1; i >= 0; i--) { - if(pf[i] == '|')pf[i] = '\0'; - } - -OPENFILENAME ofn; - strcpy(filename, ""); - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = owner ? owner->info.hwnd : 0; - ofn.lpstrFilter = pf; - ofn.lpstrInitialDir = strptr(dir); - ofn.lpstrFile = filename; - ofn.nMaxFile = MAX_PATH; - ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; - ofn.lpstrDefExt = ""; - - return GetOpenFileName(&ofn); -} - -bool file_save(Window *owner, char *filename, const char *filter, const char *path) { -string dir, f; - strcpy(dir, path ? path : ""); - replace(dir, "/", "\\"); - -stringarray type, part; - strcpy(f, ""); - split(type, "|", filter); - for(int i = 0; i < count(type); i++) { - split(part, ";", type[i]); - if(count(part) != 2)continue; - - strcat(f, part[0]); - strcat(f, " ("); - strcat(f, part[1]); - strcat(f, ")|"); - replace(part[1], ",", ";"); - strcat(f, part[1]); - strcat(f, "|"); - } - -char *pf = strptr(f); - for(int i = strlen(pf) - 1; i >= 0; i--) { - if(pf[i] == '|')pf[i] = '\0'; - } - -OPENFILENAME ofn; - strcpy(filename, ""); - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = owner ? owner->info.hwnd : 0; - ofn.lpstrFilter = pf; - ofn.lpstrInitialDir = strptr(dir); - ofn.lpstrFile = filename; - ofn.nMaxFile = MAX_PATH; - ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; - ofn.lpstrDefExt = ""; - - return GetSaveFileName(&ofn); -} - -// - -uint16 translate_key(uint key) { - switch(key) { - - case VK_ESCAPE: return keymap::esc; - - case VK_F1: return keymap::f1; - case VK_F2: return keymap::f2; - case VK_F3: return keymap::f3; - case VK_F4: return keymap::f4; - case VK_F5: return keymap::f5; - case VK_F6: return keymap::f6; - case VK_F7: return keymap::f7; - case VK_F8: return keymap::f8; - case VK_F9: return keymap::f9; - case VK_F10: return keymap::f10; - case VK_F11: return keymap::f11; - case VK_F12: return keymap::f12; - - case VK_TAB: return keymap::tab; - case VK_RETURN: return keymap::enter; - case VK_SPACE: return keymap::space; - - case '0': return keymap::num_0; - case '1': return keymap::num_1; - case '2': return keymap::num_2; - case '3': return keymap::num_3; - case '4': return keymap::num_4; - case '5': return keymap::num_5; - case '6': return keymap::num_6; - case '7': return keymap::num_7; - case '8': return keymap::num_8; - case '9': return keymap::num_9; - - case 'A': return keymap::a; - case 'B': return keymap::b; - case 'C': return keymap::c; - case 'D': return keymap::d; - case 'E': return keymap::e; - case 'F': return keymap::f; - case 'G': return keymap::g; - case 'H': return keymap::h; - case 'I': return keymap::i; - case 'J': return keymap::j; - case 'K': return keymap::k; - case 'L': return keymap::l; - case 'M': return keymap::m; - case 'N': return keymap::n; - case 'O': return keymap::o; - case 'P': return keymap::p; - case 'Q': return keymap::q; - case 'R': return keymap::r; - case 'S': return keymap::s; - case 'T': return keymap::t; - case 'U': return keymap::u; - case 'V': return keymap::v; - case 'W': return keymap::w; - case 'X': return keymap::x; - case 'Y': return keymap::y; - case 'Z': return keymap::z; - - case VK_UP: return keymap::up; - case VK_DOWN: return keymap::down; - case VK_LEFT: return keymap::left; - case VK_RIGHT: return keymap::right; - - } - return keymap::none; -} - -}; diff --git a/src/lib/libui_win.h b/src/lib/libui_win.h deleted file mode 100644 index 26ec2645..00000000 --- a/src/lib/libui_win.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - libui_win ~byuu (2007-06-10) - license: public domain -*/ - -#ifndef LIBUI_H -#define LIBUI_H - -#include "libbase.h" -#include "libarray.h" -#include "libvector.h" -#include "libstring.h" -#include "libkeymap.h" - -#undef WINVER -#undef _WIN32_WINNT -#define WINVER 0x0500 -#define _WIN32_WINNT 0x0500 -#include -#include - -namespace libui { - -class Window; -#include "libui_win_control.h" - -void init(); -void term(); -bool run(); -bool events_pending(); - -uint get_screen_width(); -uint get_screen_height(); - -bool file_load(Window *owner, char *filename, const char *filter, const char *path = ""); -bool file_save(Window *owner, char *filename, const char *filter, const char *path = ""); - -uint16 translate_key(uint key); - -namespace Message { - enum { - Invalid = 0, - Close, - Block, - KeyUp, - KeyDown, - Clicked, - DoubleClicked, - Changed, - }; -}; - -class Window { public: -enum Style { - Center = 1, -}; - -MenuBar menu; - void create(uint style, uint width, uint height, const char *caption = ""); - void set_text(const char *str, ...); - void set_background_color(uint8 r, uint8 g, uint8 b); - void focus(); - bool focused(); - void move(uint x, uint y); - void resize(uint width, uint height); - virtual void show(); - virtual void hide(); - void show(bool state); - bool visible(); - void fullscreen(); - void unfullscreen(); - void fullscreen(bool state); - bool is_fullscreen(); - - virtual bool message(uint id, uintptr_t param = 0) { return true; } - - void move(Control &control, uint x, uint y); - void attach(Control &control); - - Window(); - -//platform-dependent: - HWND handle(); - -//private: -struct { - uint width, height; - bool fullscreen; - - HWND hwnd; - HWND hwnd_resize; - HBRUSH background; - HMENU menubar; - bool center; - array control; - uint control_index; - - array menu_check_list; -} info; - long wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam); -}; - -//platform-dependent: - -static uint window_count = 0; - -static struct { - HFONT variable; - HFONT fixed; -} font; - -HFONT create_font(const char *name, uint size); - -}; - -#endif diff --git a/src/lib/libui_win_control.cpp b/src/lib/libui_win_control.cpp deleted file mode 100644 index 1594467b..00000000 --- a/src/lib/libui_win_control.cpp +++ /dev/null @@ -1,710 +0,0 @@ -namespace libui { - -/***** - * Control - *****/ - -void Control::move(uint x, uint y) { - SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); -} - -void Control::resize(uint width, uint height) { - SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE); -} - -void Control::focus() { - if(hwnd) { SetFocus(hwnd); } -} - -void Control::show() { - ShowWindow(hwnd, SW_NORMAL); -} - -void Control::hide() { - ShowWindow(hwnd, SW_HIDE); -} - -void Control::show(bool state) { - (state == true) ? show() : hide(); -} - -bool Control::visible() { - return (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) ? true : false; -} - -void Control::enable() { - EnableWindow(hwnd, true); -} - -void Control::disable() { - EnableWindow(hwnd, false); -} - -void Control::enable(bool state) { - (state == true) ? enable() : disable(); -} - -bool Control::enabled() { - return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED); -} - -/***** - * MenuBar - *****/ - -void MenuBar::create(Window &r_owner) { - type = ControlType::MenuBar; - group = CreateMenu(); - r_owner.attach(*this); - owner->info.menu_check_list.reset(); -} - -void MenuBar::finish() { - show(); - -//check all menu radio items that need to be ... - for(uint i = 0; i < owner->info.menu_check_list.size(); i++) { - CheckMenuItem(owner->info.menu_check_list[i]->parent, owner->info.menu_check_list[i]->id, MF_CHECKED); - } - owner->info.menu_check_list.reset(); -} - -void MenuBar::show() { - SetMenu(owner->info.hwnd_resize, group); - SetMenu(owner->info.hwnd, group); - owner->resize(owner->info.width, owner->info.height); -} - -void MenuBar::hide() { - SetMenu(owner->info.hwnd_resize, 0); - SetMenu(owner->info.hwnd, 0); - owner->resize(owner->info.width, owner->info.height); -} - -void MenuBar::show(bool state) { - (state == true) ? show() : hide(); -} - -bool MenuBar::visible() { - return GetMenu(owner->info.hwnd); -} - -/***** - * MenuGroup - *****/ - -void MenuGroup::create(MenuBar &r_owner, const char *_caption) { - type = ControlType::MenuGroup; - owner = r_owner.owner; - parent = r_owner.group; - group = CreatePopupMenu(); - caption = strdup(_caption); - owner->attach(*this); -} - -void MenuGroup::create(MenuGroup &r_owner, const char *_caption) { - type = ControlType::MenuGroup; - owner = r_owner.owner; - parent = r_owner.group; - group = CreatePopupMenu(); - caption = strdup(_caption); - owner->attach(*this); -} - -void MenuGroup::finish() { - AppendMenu(parent, MF_STRING | MF_POPUP, (uint)group, caption); -} - -/***** - * MenuItem - *****/ - -void MenuItem::create(MenuGroup &r_owner, const char *caption) { - type = ControlType::MenuItem; - owner = r_owner.owner; - owner->attach(*this); - AppendMenu(r_owner.group, MF_STRING, (uint)id, caption); -} - -/***** - * MenuCheckItem - *****/ - -void MenuCheckItem::create(MenuGroup &r_owner, const char *caption) { - type = ControlType::MenuCheckItem; - owner = r_owner.owner; - parent = r_owner.group; - owner->attach(*this); - AppendMenu(r_owner.group, MF_STRING, (uint)id, caption); -} - -void MenuCheckItem::check() { - if(checked() == true)return; - CheckMenuItem(parent, id, MF_CHECKED); - owner->message(Message::Clicked, (uintptr_t)this); -} - -void MenuCheckItem::uncheck() { - if(checked() == false)return; - CheckMenuItem(parent, id, MF_UNCHECKED); - owner->message(Message::Clicked, (uintptr_t)this); -} - -void MenuCheckItem::check(bool state) { - (state == true) ? check() : uncheck(); -} - -bool MenuCheckItem::checked() { -MENUITEMINFO info; - memset(&info, 0, sizeof(info)); - info.cbSize = sizeof(info); - info.fMask = MIIM_STATE; - GetMenuItemInfo(parent, id, false, &info); - return (info.fState & MFS_CHECKED); -} - -/***** - * MenuRadioItem - *****/ - -void MenuRadioItem::create(MenuGroup &r_owner, ControlGroup &list, const char *caption) { - if(list.count() == 0)throw; - type = ControlType::MenuRadioItem; - owner = r_owner.owner; - parent = r_owner.group; - owner->attach(*this); - AppendMenu(r_owner.group, MF_STRING, (uint)id, caption); - group = list; - if(&group[0] == this) { owner->info.menu_check_list[owner->info.menu_check_list.size()] = this; } -} - -void MenuRadioItem::check() { - if(checked() == true)return; -//uncheck all items in group except for current item ... - for(uint i = 0; i < group.count(); i++) { - CheckMenuItem(parent, group[i].id, (id == group[i].id) ? MF_CHECKED : MF_UNCHECKED); - } - owner->message(Message::Clicked, (uintptr_t)this); -} - -bool MenuRadioItem::checked() { -MENUITEMINFO info; - memset(&info, 0, sizeof(info)); - info.cbSize = sizeof(info); - info.fMask = MIIM_STATE; - GetMenuItemInfo(parent, id, false, &info); - return (info.fState & MFS_CHECKED); -} - -/***** - * MenuSeparator - *****/ - -void MenuSeparator::create(MenuGroup &r_owner) { - AppendMenu(r_owner.group, MF_SEPARATOR, 0, ""); -} - -/***** - * Panel - *****/ - -void Panel::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Panel; - hwnd = CreateWindow("libui_class", "", WS_CHILD | WS_VISIBLE, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - r_owner.attach(*this); -} - -void Panel::attach(Window &window) { - if(attached) { detach(); } - attached = &window; - SetParent(attached->info.hwnd, hwnd); - SetWindowLong(attached->info.hwnd, GWL_STYLE, WS_CHILD); - SetWindowPos(attached->info.hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE); - ShowWindow(attached->info.hwnd, SW_NORMAL); -} - -void Panel::detach() { - if(!attached) { return; } - ShowWindow(attached->info.hwnd, SW_HIDE); - SetWindowLong(attached->info.hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX); - SetParent(attached->info.hwnd, NULL); - attached = 0; -} - -/***** - * Container - *****/ - -void Container::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Container; - -char classname[4096]; - sprintf(classname, "libui_class_%d", window_count++); -WNDCLASS wc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = libui_wndproc; - wc.lpszClassName = classname; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - RegisterClass(&wc); - - hwnd = CreateWindow(classname, "", WS_CHILD | WS_VISIBLE, - 0, 0, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); -} - -void Container::set_background_color(uint8 r, uint8 g, uint8 b) { -HBRUSH old_brush = background; - background = (HBRUSH)CreateSolidBrush(RGB(r, g, b)); - SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)background); - InvalidateRect(hwnd, 0, TRUE); - if(old_brush) { DeleteObject((HGDIOBJ)old_brush); } -} - -HWND Container::handle() { - return hwnd; -} - -Container::Container() { - background = 0; -} - -/***** - * Canvas - *****/ - -long __stdcall canvas_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - switch(msg) { - - case WM_PAINT: { - Canvas *canvas = (Canvas*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if(canvas) { canvas->blit(); } - } break; - - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -void Canvas::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - _w = width; - _h = height; - - type = ControlType::Canvas; - hwnd = CreateWindow("canvas_class", "", WS_CHILD | WS_VISIBLE, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); - - pitch = width * sizeof(uint32); - buffer = (uint32*)malloc(pitch * height); - memset(buffer, 0, pitch * height); - - memset(&bmi, 0, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; //use negative height to tell GDI not to flip bitmap vertically - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = pitch * height; - - r_owner.attach(*this); -} - -void Canvas::blit() { -PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - SetDIBitsToDevice(ps.hdc, 0, 0, _w, _h, 0, 0, 0, _h, (void*)buffer, &bmi, DIB_RGB_COLORS); - EndPaint(hwnd, &ps); -} - -void Canvas::redraw() { - InvalidateRect(hwnd, 0, FALSE); -} - -Canvas::Canvas() { - buffer = 0; -} - -Canvas::~Canvas() { - safe_free(buffer); -} - -/***** - * Frame - *****/ - -void Frame::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Frame; - hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -/***** - * Label - *****/ - -long __stdcall label_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - switch(msg) { - - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hwnd, &ps); - RECT rc; - char t[4096]; - GetWindowText(hwnd, t, 4095); //TODO: use internal buffer, so length is not limited ... - GetClientRect(hwnd, &rc); - SetTextColor(ps.hdc, RGB(0, 0, 0)); - SetBkMode(ps.hdc, TRANSPARENT); - SelectObject(ps.hdc, (HGDIOBJ)libui::font.variable); - //center text if text height < control height, otherwise draw from top left corner - RECT trc; - GetClientRect(hwnd, &trc); - DrawText(ps.hdc, t, strlen(t), &trc, DT_CALCRECT); - if(trc.bottom < rc.bottom) { - rc.top = (rc.bottom - trc.bottom) / 2; - rc.bottom = rc.top + trc.bottom; - } - // - DrawText(ps.hdc, t, strlen(t), &rc, DT_END_ELLIPSIS | DT_NOPREFIX); - EndPaint(hwnd, &ps); - } break; - - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -void Label::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { -string t; - strcpy(t, caption ? caption : ""); - replace(t, "\r", ""); - replace(t, "\n", "\r\n"); - - type = ControlType::Label; - hwnd = CreateWindow("label_class", strptr(t), WS_CHILD | WS_VISIBLE, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -void Label::set_text(const char *str, ...) { -va_list args; - va_start(args, str); -string temp; - vsprintf(temp, str, args); - va_end(args); - SetWindowText(hwnd, strptr(temp)); - InvalidateRect(hwnd, 0, TRUE); -} - -/***** - * Button - *****/ - -void Button::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Button; - hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -/***** - * Checkbox - *****/ - -void Checkbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Checkbox; - hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_CHECKBOX, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -void Checkbox::check() { - if(checked() == true)return; - SendMessage(hwnd, BM_SETCHECK, (WPARAM)TRUE, 0); - owner->message(Message::Clicked, (uintptr_t)this); -} - -void Checkbox::uncheck() { - if(checked() == false)return; - SendMessage(hwnd, BM_SETCHECK, (WPARAM)FALSE, 0); - owner->message(Message::Clicked, (uintptr_t)this); -} - -void Checkbox::check(bool state) { - (state == true) ? check() : uncheck(); -} - -bool Checkbox::checked() { - return SendMessage(hwnd, BM_GETCHECK, 0, 0); -} - -/***** - * Radiobox - *****/ - -void Radiobox::create(Window &r_owner, ControlGroup &list, uint style, uint x, uint y, uint width, uint height, const char *caption) { - if(list.count() == 0)throw; - type = ControlType::Radiobox; - group = list; - hwnd = CreateWindow("BUTTON", caption ? caption : "", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); - if(this == &group[0])check(); -} - -void Radiobox::check() { - if(checked() == true)return; - for(uint i = 0; i < group.count(); i++) { - SendMessage(group[i].hwnd, BM_SETCHECK, (group[i].hwnd == hwnd) ? (WPARAM)TRUE : (WPARAM)FALSE, 0); - } - owner->message(Message::Clicked, (uintptr_t)this); -} - -bool Radiobox::checked() { - return SendMessage(hwnd, BM_GETCHECK, 0, 0); -} - -/***** - * Editbox - *****/ - -void Editbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *caption) { - type = ControlType::Editbox; - multiline = (style & Multiline); - readonly = (style & Readonly); - vscroll = false; - hscroll = false; - -uint hscroll = (style & HorizontalScrollAlways) ? WS_HSCROLL : - (style & HorizontalScrollNever) ? 0 : - ES_AUTOHSCROLL; -uint vscroll = (style & VerticalScrollAlways) ? WS_VSCROLL : - (style & VerticalScrollNever) ? 0 : - ES_AUTOVSCROLL; - -string data = caption; - replace(data, "\r", ""); - replace(data, "\n", "\r\n"); - hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", strptr(data), - WS_CHILD | WS_VISIBLE | vscroll | hscroll | - (multiline == true ? ES_MULTILINE : 0) | - (readonly == true ? ES_READONLY : 0), - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -void Editbox::set_text(const char *str, ...) { -va_list args; - va_start(args, str); -string data; - vsprintf(data, str, args); - va_end(args); - - replace(data, "\r", ""); - replace(data, "\n", "\r\n"); - SetWindowText(hwnd, strptr(data)); -} - -uint Editbox::get_text(char *str, uint length) { - GetWindowText(hwnd, str, length); - return strlen(str); -} - -/***** - * Listbox - *****/ - -void Listbox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, const char *columns) { -stringarray part; - header = (style & Header); - -uint hscroll = (style & HorizontalScrollAlways) ? WS_HSCROLL : - (style & HorizontalScrollNever) ? 0 : - 0; -uint vscroll = (style & VerticalScrollAlways) ? WS_VSCROLL : - (style & VerticalScrollNever) ? 0 : - 0; - - type = ControlType::Listbox; - hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "", - WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll | - (header == true ? 0 : LVS_NOCOLUMNHEADER), - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT); - - split(part, "|", columns); - column_count = count(part); - for(uint i = 0; i < column_count; i++) { - LVCOLUMN column; - column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM; - column.fmt = LVCFMT_LEFT; - column.iSubItem = count(part); - column.pszText = (LPSTR)strptr(part[i]); - ListView_InsertColumn(hwnd, i, &column); - } - - autosize_columns(); - r_owner.attach(*this); -} - -void Listbox::autosize_columns() { - for(uint i = 0; i < column_count; i++) { - ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER); - } -} - -void Listbox::set_column_width(uint column, uint width) { - ListView_SetColumnWidth(hwnd, column, width); -} - -void Listbox::add_item(const char *data, ...) { -va_list args; - va_start(args, data); -string temp; - vsprintf(temp, data, args); - va_end(args); - -stringarray part; - split(part, "|", temp); - -LVITEM item; -uint pos = ListView_GetItemCount(hwnd); - item.mask = LVIF_TEXT; - item.iItem = pos; - item.iSubItem = 0; - item.pszText = (LPSTR)strptr(part[0]); - ListView_InsertItem(hwnd, &item); - - for(uint i = 1; i < count(part); i++) { - ListView_SetItemText(hwnd, pos, i, (LPSTR)strptr(part[i])); - } -} - -void Listbox::set_item(uint index, const char *data, ...) { -va_list args; - va_start(args, data); -string temp; - vsprintf(temp, data, args); - va_end(args); - -stringarray part; - split(part, "|", temp); - - for(uint i = 0; i < count(part); i++) { - ListView_SetItemText(hwnd, index, i, strptr(part[i])); - } -} - -int Listbox::get_selection() { -uint count = ListView_GetItemCount(hwnd); - for(uint i = 0; i < count; i++) { - if(ListView_GetItemState(hwnd, i, LVIS_SELECTED))return i; - } - return -1; -} - -void Listbox::set_selection(int index) { -uint count = ListView_GetItemCount(hwnd); - for(uint i = 0; i < count; i++) { - ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0); - ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0); - } -} - -void Listbox::reset() { - ListView_DeleteAllItems(hwnd); -} - -/***** - * Combobox - *****/ - -void Combobox::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Combobox; - hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "", - WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS, - x, y, width, 200, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, WM_SETFONT, (WPARAM)libui::font.variable, 0); - r_owner.attach(*this); -} - -void Combobox::add_item(const char *data) { - SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)data); - if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) { set_selection(0); } -} - -void Combobox::set_selection(int index) { - SendMessage(hwnd, CB_SETCURSEL, index, 0); -} - -int Combobox::get_selection() { - return SendMessage(hwnd, CB_GETCURSEL, 0, 0); -} - -void Combobox::reset() { - SendMessage(hwnd, CB_RESETCONTENT, 0, 0); -} - -/***** - * Progressbar - *****/ - -void Progressbar::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height) { - type = ControlType::Progressbar; - hwnd = CreateWindow(PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | PBS_SMOOTH, - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); - SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); - r_owner.attach(*this); -} - -void Progressbar::set_progress(uint progress) { - progress = minmax<0, 100>(progress); - SendMessage(hwnd, PBM_SETPOS, (WPARAM)progress, 0); -} - -uint Progressbar::get_progress() { - return minmax<0, 100>(SendMessage(hwnd, PBM_GETPOS, 0, 0)); -} - -/***** - * Slider - *****/ - -void Slider::create(Window &r_owner, uint style, uint x, uint y, uint width, uint height, uint range) { - type = ControlType::Slider; - orientation = (style & Vertical) ? 1 : 0; - if(range < 1)range = 1; - - hwnd = CreateWindow(TRACKBAR_CLASS, "", - WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_BOTH | (orientation == 0 ? TBS_HORZ : TBS_VERT), - x, y, width, height, r_owner.info.hwnd, (HMENU)0, GetModuleHandle(0), 0); - SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, range - 1)); - SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(range >> 3)); - SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)0); - r_owner.attach(*this); -} - -void Slider::set_position(uint position) { - SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)position); -} - -uint Slider::get_position() { - return SendMessage(hwnd, TBM_GETPOS, 0, 0); -} - -}; diff --git a/src/lib/libui_win_control.h b/src/lib/libui_win_control.h deleted file mode 100644 index 07883449..00000000 --- a/src/lib/libui_win_control.h +++ /dev/null @@ -1,271 +0,0 @@ -namespace ControlType { - enum { - Invalid, - MenuBar, - MenuGroup, - MenuItem, - MenuCheckItem, - MenuRadioItem, - MenuSeparator, - Panel, - Container, - Canvas, - Frame, - Label, - Button, - Checkbox, - Radiobox, - Editbox, - Listbox, - Combobox, - Progressbar, - Slider, - }; -}; - -class Control { public: -uint type; - void move(uint x, uint y); - void resize(uint width, uint height); - - void focus(); - - virtual void show(); - virtual void hide(); - virtual void show(bool state); - virtual bool visible(); - - void enable(); - void disable(); - void enable(bool state); - bool enabled(); - -//private: -Window *owner; -HWND hwnd; -uint id; - -public: - Control() : owner(0), hwnd(0), id(0), type(ControlType::Invalid) {} -}; - -class ControlGroup { public: - uint count() { return list.size(); } - void add(Control &control) { list[list.size()] = &control; } - void reset() { list.reset(); } - ControlGroup &operator=(ControlGroup &source) { list = source.list; return *this; } - Control &operator[](int index) { return *list[index]; } - -//private: -array list; -}; - -// - -class MenuBar : public Control { public: - void create(Window &owner); - void finish(); - - void show(); - void hide(); - void show(bool state); - bool visible(); - -//private: -HMENU group; -}; - -class MenuGroup : public Control { public: - void create(MenuBar &owner, const char *caption); - void create(MenuGroup &owner, const char *caption); - void finish(); - -//private: -HMENU parent, group; -char *caption; - ~MenuGroup() { safe_free(caption); } -}; - -class MenuItem : public Control { public: - void create(MenuGroup &owner, const char *caption); -}; - -class MenuCheckItem : public Control { public: - void create(MenuGroup &owner, const char *caption); - void check(); - void uncheck(); - void check(bool state); - bool checked(); - -//private: -HMENU parent; -}; - -class MenuRadioItem : public Control { public: - void create(MenuGroup &owner, ControlGroup &list, const char *caption); - void check(); - bool checked(); - -//private: -HMENU parent; -ControlGroup group; -}; - -class MenuSeparator : public Control { public: - void create(MenuGroup &owner); -}; - -// - -class Panel : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void attach(Window &window); - void detach(); - -//private: -Window *attached; - Panel() : attached(0) {} -}; - -class Container : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void set_background_color(uint8 r, uint8 g, uint8 b); - -//platform-dependent: - HWND handle(); - -//private: -HBRUSH background; - Container(); -}; - -class Canvas : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void redraw(); - -//private: -BITMAPINFO bmi; -uint32 *buffer; -uint pitch, _w, _h; - void blit(); - Canvas(); - ~Canvas(); -}; - -class Frame : public Control { public: - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); -}; - -class Label : public Control { public: -enum { ideal_height = 16 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void set_text(const char *str, ...); -}; - -class Button : public Control { public: -enum { ideal_height = 21 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); -}; - -class Checkbox : public Control { public: -enum { ideal_height = 15 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void check(); - void uncheck(); - void check(bool state); - bool checked(); -}; - -class Radiobox : public Control { public: -enum { ideal_height = 15 }; - void create(Window &owner, ControlGroup &list, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void check(); - bool checked(); - -//private: -ControlGroup group; -}; - -class Editbox : public Control { public: -enum { ideal_height = 21 }; -enum { - Multiline = (1 << 1), - Readonly = (1 << 2), - - HorizontalScrollAuto = 0, - HorizontalScrollAlways = (1 << 3), - HorizontalScrollNever = (1 << 4), - - VerticalScrollAuto = 0, - VerticalScrollAlways = (1 << 5), - VerticalScrollNever = (1 << 6), -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *caption = ""); - void set_text(const char *str, ...); - uint get_text(char *str, uint length); - -//private: -bool multiline; -bool readonly; -bool vscroll; -bool hscroll; -}; - -class Listbox : public Control { public: -enum { - Header = (1 << 1), - - HorizontalScrollAuto = 0, - HorizontalScrollAlways = (1 << 2), - HorizontalScrollNever = (1 << 3), - - VerticalScrollAuto = 0, - VerticalScrollAlways = (1 << 4), - VerticalScrollNever = (1 << 5), -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, const char *columns = ""); - void autosize_columns(); - void set_column_width(uint column, uint width); - void add_item(const char *data, ...); - void set_item(uint index, const char *data, ...); - int get_selection(); - void set_selection(int index); - void reset(); - -//private: -bool header; -uint column_count; -}; - -class Combobox : public Control { public: -enum { ideal_height = 21 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void add_item(const char *data); - void set_selection(int index); - int get_selection(); - void reset(); -}; - -class Progressbar : public Control { public: -enum { ideal_height = 30 }; - void create(Window &owner, uint style, uint x, uint y, uint width, uint height); - void set_progress(uint progress); - uint get_progress(); -}; - -class Slider : public Control { public: -enum { ideal_height = 25 }; -enum Style { - Horizontal = 0, - Vertical = 1, -}; - - void create(Window &owner, uint style, uint x, uint y, uint width, uint height, uint range); - void set_position(uint position); - uint get_position(); - -//private: -bool orientation; -}; diff --git a/src/lib/libui_win_window.cpp b/src/lib/libui_win_window.cpp deleted file mode 100644 index b2e814fd..00000000 --- a/src/lib/libui_win_window.cpp +++ /dev/null @@ -1,290 +0,0 @@ -namespace libui { - -long __stdcall libui_wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) { -Window *window = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - if(window) { return window->wndproc(hwnd, msg, wparam, lparam); } - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -long Window::wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) { - switch(msg) { - - case WM_CLOSE: { - if(message(Message::Close) == false) { return TRUE; } - } break; - - case WM_ENTERMENULOOP: { - message(Message::Block); - } - - case WM_PAINT: { - uint16 i = LOWORD(wparam); - if(!i || !info.control[i])break; - Control &control = *info.control[i]; - if(control.id != i)break; //this should never happen - - switch(control.type) { - - case ControlType::Canvas: { - ((Canvas&)control).redraw(); - } break; - - } - } break; - - case WM_KEYDOWN: { - message(Message::KeyDown, libui::translate_key(wparam)); - } break; - - case WM_KEYUP: { - message(Message::KeyUp, libui::translate_key(wparam)); - } break; - - case WM_COMMAND: { - uint16 i = LOWORD(wparam); - if(!i || !info.control[i])break; - Control &control = *info.control[i]; - if(control.id != i)break; //this should never happen - - switch(control.type) { - - //emit Message::Clicked message indirectly, through control.check() - case ControlType::MenuCheckItem: { - ((MenuCheckItem&)control).check(!((MenuCheckItem&)control).checked()); //toggle checked status - } break; - - case ControlType::MenuRadioItem: { - ((MenuRadioItem&)control).check(); - } break; - - case ControlType::Checkbox: { - ((Checkbox&)control).check(!((Checkbox&)control).checked()); //toggle checked status - } break; - - case ControlType::Radiobox: { - ((Radiobox&)control).check(); - } break; - - //emit Message::Clicked message directly - case ControlType::MenuItem: - case ControlType::Button: { - message(Message::Clicked, (uintptr_t)&control); - } break; - - } - } break; - - case WM_HSCROLL: - case WM_VSCROLL: { - uint16 i = GetDlgCtrlID((HWND)lparam); - if(!i || !info.control[i])break; - Control &control = *info.control[i]; - if(control.id != i)break; - - switch(control.type) { - - case ControlType::Slider: { - message(Message::Changed, (uintptr_t)&control); - } break; - - } - } break; - - case WM_NOTIFY: { - uint16 i = (uint16)wparam; - if(!i || !info.control[i])break; - Control &control = *info.control[i]; - if(control.id != i)break; - - switch(control.type) { - - case ControlType::Listbox: { - Listbox &listbox = ((Listbox&)control); - if(((LPNMHDR)lparam)->code == LVN_ITEMCHANGED) { - if(((LPNMLISTVIEW)lparam)->uChanged & LVIF_STATE) { - if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_FOCUSED)) { - if(ListView_GetItemState(listbox.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_SELECTED)) { - message(Message::Changed, (uintptr_t)&control); - } - } - } - } else if(((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) { - message(Message::DoubleClicked, (uintptr_t)&control); - } - } break; - - } - } break; - - } - - return DefWindowProc(hwnd, msg, wparam, lparam); -} - -void Window::attach(Control &control) { - info.control[info.control_index] = &control; - control.id = info.control_index++; - control.owner = this; - -//menu items will not have HWND, and do not require GWL_ID to be set - if(control.hwnd) { SetWindowLong(control.hwnd, GWL_ID, control.id); } -} - -void Window::focus() { - if(!visible()) { show(); } - SetFocus(info.hwnd); -} - -bool Window::focused() { - return (GetForegroundWindow() == info.hwnd); -} - -void Window::move(Control &control, uint x, uint y) { - SetWindowPos(control.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); -} - -void Window::create(uint style, uint width, uint height, const char *caption) { - info.center = bool(style & Center); - -char classname[4096]; - sprintf(classname, "libui_class_%d", window_count++); -WNDCLASS wc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = libui_wndproc; - wc.lpszClassName = classname; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - -RECT rc; - SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); - - info.hwnd = CreateWindowEx(0, classname, caption ? caption : "", - WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, - rc.left, rc.top, width, height, 0, 0, GetModuleHandle(0), 0); - info.hwnd_resize = CreateWindowEx(0, "libui_class", "", - WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, - rc.left, rc.top, width, height, 0, 0, GetModuleHandle(0), 0); - SetWindowLongPtr(info.hwnd, GWLP_USERDATA, (LONG_PTR)this); - - resize(width, height); -} - -void Window::move(uint x, uint y) { -RECT rc; - SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); - if(x < rc.left) { x = rc.left; } - if(y < rc.top ) { y = rc.top; } - SetWindowPos(info.hwnd, 0, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE); -} - -void Window::resize(uint width, uint height) { - if(info.fullscreen == true) { - info.width = GetSystemMetrics(SM_CXSCREEN); - info.height = GetSystemMetrics(SM_CYSCREEN); - SetWindowPos(info.hwnd, 0, 0, 0, info.width, info.height, SWP_NOZORDER); - return; - } - - info.width = width; - info.height = height; - -//set requested window size to hidden window, calculate the difference between requested and actual client -//size area, and then adjust width so that new width, height values will set requested client area size. -//AdjustWindowRect() does not properly calculate the height of multi-line menus, and thusly is not used. - SetWindowPos(info.hwnd_resize, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE); -RECT rc; - GetClientRect(info.hwnd_resize, &rc); - width += width - (rc.right - rc.left); - height += height - (rc.bottom - rc.top); - -int x = (GetSystemMetrics(SM_CXSCREEN) - int(width)) / 2; -int y = (GetSystemMetrics(SM_CYSCREEN) - int(height)) / 2; - -//do not allow window to be placed offscreen, force to top-left if window is larger than screen size - SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); - if(x < rc.left) { x = rc.left; } - if(y < rc.top) { y = rc.top; } - - SetWindowPos(info.hwnd, 0, x, y, width, height, SWP_NOZORDER | (info.center == true ? 0 : SWP_NOMOVE)); -} - -void Window::show() { - ShowWindow(info.hwnd, SW_NORMAL); - SetFocus(info.hwnd); -} - -void Window::hide() { - ShowWindow(info.hwnd, SW_HIDE); -} - -void Window::show(bool state) { - (state == true) ? show() : hide(); -} - -bool Window::visible() { - return GetWindowLong(info.hwnd, GWL_STYLE) & WS_VISIBLE; -} - -void Window::fullscreen() { - if(info.fullscreen)return; - info.fullscreen = true; - SetWindowLong(info.hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); - resize(get_screen_width(), get_screen_height()); -} - -void Window::unfullscreen() { - if(!info.fullscreen)return; - info.fullscreen = false; - SetWindowLong(info.hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE); - resize(info.width, info.height); -} - -void Window::fullscreen(bool state) { - (state == true) ? fullscreen() : unfullscreen(); -} - -bool Window::is_fullscreen() { - return info.fullscreen; -} - -// - -void Window::set_text(const char *str, ...) { -va_list args; - va_start(args, str); -string temp; - vsprintf(temp, str, args); - va_end(args); - SetWindowText(info.hwnd, strptr(temp)); -} - -void Window::set_background_color(uint8 r, uint8 g, uint8 b) { -HBRUSH old_brush = info.background; - info.background = (HBRUSH)CreateSolidBrush(RGB(r, g, b)); - SetClassLong(info.hwnd, GCL_HBRBACKGROUND, (LONG)info.background); - InvalidateRect(info.hwnd, 0, TRUE); - if(old_brush) { DeleteObject((HGDIOBJ)old_brush); } -} - -// - -Window::Window() { - info.fullscreen = false; - info.background = 0; - info.center = false; - info.control_index = 1; -} - -//platform-dependent: - -HWND Window::handle() { - return info.hwnd; -} - -}; diff --git a/src/lib/miu.cpp b/src/lib/miu.cpp new file mode 100644 index 00000000..56208806 --- /dev/null +++ b/src/lib/miu.cpp @@ -0,0 +1,253 @@ +#include "miu.h" + +namespace ns_miu { + +/* Miu (singleton) */ + +void Miu::init() { p.init(); } +void Miu::term() { p.term(); } +bool Miu::run() { return p.run(); } +bool Miu::pending() { return p.pending(); } +bool Miu::file_load(Window *focus, char *filename, const char *filter, const char *path) { return p.file_load(focus, filename, filter, path); } +bool Miu::file_save(Window *focus, char *filename, const char *filter, const char *path) { return p.file_save(focus, filename, filter, path); } +uint Miu::screen_width() { return p.screen_width(); } +uint Miu::screen_height() { return p.screen_height(); } +Miu& Miu::handle() { static Miu miu; return miu; } +Miu::Miu() : p(*new pMiu(*this)) {} +Miu::~Miu() { delete &p; } +Miu& miu() { return Miu::handle(); } + +/* Widget */ + +void Widget::show(bool state) { p.show(state); } +void Widget::hide() { p.hide(); } +bool Widget::visible() { return p.visible(); } +uintptr_t Widget::handle() { return p.handle(); } +Widget::Widget() : p(*new pWidget(*this)) { type = WidgetType; } +Widget::Widget(pWidget &p_) : p(p_) { type = WidgetType; } +Widget::~Widget() { delete &p; } + +/* Widget -> Window */ + +void Window::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Window::close() { p.close(); } +void Window::move(uint x, uint y) { p.move(x, y); } +void Window::resize(uint width, uint height) { p.resize(width, height); } +void Window::focus() { p.focus(); } +bool Window::focused() { return p.focused(); } +void Window::fullscreen() { p.fullscreen(); } +void Window::unfullscreen() { p.unfullscreen(); } +void Window::set_background_color(uint8 r, uint8 g, uint8 b) { p.set_background_color(r, g, b); } +void Window::set_text(const char *text) { p.set_text(text); } +void Window::attach(Window &window, uint x, uint y) { p.attach(window, x, y); } +void Window::attach(MenuGroup &menugroup) { p.attach(menugroup); } +void Window::attach(FormControl &formcontrol, uint x, uint y) { p.attach(formcontrol, x, y); } +void Window::move(Window &window, uint x, uint y) { p.move(window, x, y); } +void Window::move(FormControl &formcontrol, uint x, uint y) { p.move(formcontrol, x, y); } +void Window::menu_show(bool state) { p.menu_show(state); } +void Window::menu_hide() { p.menu_hide(); } +bool Window::menu_visible() { return p.menu_visible(); } +Window::Window() : + base_from_member(*new pWindow(*this)), + Widget(base_from_member::value), + p(base_from_member::value) { type = WindowType; } +Window::Window(pWindow &p_) : + base_from_member(p_), + Widget(base_from_member::value), + p(base_from_member::value) { type = WindowType; } + +/* Widget -> MenuControl */ + +void MenuControl::enable(bool state) { p.enable(state); } +void MenuControl::disable() { p.disable(); } +bool MenuControl::enabled() { return p.enabled(); } +MenuControl::MenuControl() : + base_from_member(*new pMenuControl(*this)), + Widget(base_from_member::value), + p(base_from_member::value) { type = MenuControlType; } +MenuControl::MenuControl(pMenuControl &p_) : + base_from_member(p_), + Widget(base_from_member::value), + p(base_from_member::value) { type = MenuControlType; } + +/* Widget -> MenuControl -> MenuGroup */ + +MenuGroup& MenuGroup::create(const char *text) { p.create(text); return *this; } +void MenuGroup::attach(MenuControl &menucontrol) { p.attach(menucontrol); } +MenuGroup::MenuGroup() : + base_from_member(*new pMenuGroup(*this)), + MenuControl(base_from_member::value), + p(base_from_member::value) { type = MenuGroupType; } + +/* Widget -> MenuControl -> MenuItem */ + +MenuItem& MenuItem::create(const char *text) { p.create(text); return *this; } +MenuItem::MenuItem() : + base_from_member(*new pMenuItem(*this)), + MenuControl(base_from_member::value), + p(base_from_member::value) { type = MenuItemType; } + +/* Widget -> MenuControl -> MenuCheckItem */ + +MenuCheckItem& MenuCheckItem::create(const char *text) { p.create(text); return *this; } +void MenuCheckItem::check(bool state) { state ? p.check() : p.uncheck(); } +void MenuCheckItem::uncheck() { p.uncheck(); } +bool MenuCheckItem::checked() { return p.checked(); } +MenuCheckItem::MenuCheckItem() : + base_from_member(*new pMenuCheckItem(*this)), + MenuControl(base_from_member::value), + p(base_from_member::value) { type = MenuCheckItemType; } + +/* Widget -> MenuControl -> MenuRadioItem */ + +MenuRadioItem& MenuRadioItem::create(MenuRadioItemGroup &group, const char *text) { p.create(group, text); return *this; } +void MenuRadioItem::check() { p.check(); } +bool MenuRadioItem::checked() { return p.checked(); } +MenuRadioItem::MenuRadioItem() : + base_from_member(*new pMenuRadioItem(*this)), + MenuControl(base_from_member::value), + p(base_from_member::value) { type = MenuRadioItemType; } + +/* Widget -> MenuControl -> MenuSeparator */ + +MenuSeparator& MenuSeparator::create() { p.create(); return *this; } +MenuSeparator::MenuSeparator() : + base_from_member(*new pMenuSeparator(*this)), + MenuControl(base_from_member::value), + p(base_from_member::value) { type = MenuSeparatorType; } + +/* Widget -> FormControl */ + +void FormControl::resize(uint width, uint height) { p.resize(width, height); } +void FormControl::focus() { p.focus(); } +bool FormControl::focused() { return p.focused(); } +void FormControl::enable(bool state) { p.enable(state); } +void FormControl::disable() { p.disable(); } +bool FormControl::enabled() { return p.enabled(); } +FormControl::FormControl() : + base_from_member(*new pFormControl(*this)), + Widget(base_from_member::value), + p(base_from_member::value) { type = FormControlType; } +FormControl::FormControl(pFormControl &p_) : + base_from_member(p_), + Widget(base_from_member::value), + p(base_from_member::value) { type = FormControlType; } + +/* Widget -> FormControl -> Frame */ + +void Frame::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Frame::set_text(const char *text) { p.set_text(text); } +Frame::Frame() : + base_from_member(*new pFrame(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = FrameType; } + +/* Widget -> FormControl -> Canvas */ + +void Canvas::create(uint style, uint width, uint height) { p.create(style, width, height); } +void Canvas::redraw() { p.redraw(); } +uint32* Canvas::buffer() { return p.buffer(); } +Canvas::Canvas() : + base_from_member(*new pCanvas(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = CanvasType; } + +/* Widget -> FormControl -> Label */ + +void Label::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Label::set_text(const char *text) { p.set_text(text); } +Label::Label() : + base_from_member(*new pLabel(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = LabelType; } + +/* Widget -> FormControl -> Button */ + +void Button::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Button::set_text(const char *text) { p.set_text(text); } +Button::Button() : + base_from_member(*new pButton(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = ButtonType; } + +/* Widget -> FormControl -> Checkbox */ + +void Checkbox::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Checkbox::set_text(const char *text) { p.set_text(text); } +void Checkbox::check(bool state) { state ? p.check() : p.uncheck(); } +void Checkbox::uncheck() { p.uncheck(); } +bool Checkbox::checked() { return p.checked(); } +Checkbox::Checkbox() : + base_from_member(*new pCheckbox(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = CheckboxType; } + +/* Widget -> FormControl -> Radiobox */ + +void Radiobox::create(RadioboxGroup &group, uint style, uint width, uint height, const char *text) { p.create(group, style, width, height, text); } +void Radiobox::set_text(const char *text) { p.set_text(text); } +void Radiobox::check() { p.check(); } +bool Radiobox::checked() { return p.checked(); } +Radiobox::Radiobox() : + base_from_member(*new pRadiobox(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = RadioboxType; } + +/* Widget -> FormControl -> Editbox */ + +void Editbox::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +uint Editbox::get_text(char *text, uint length) { return p.get_text(text, length); } +void Editbox::set_text(const char *text) { p.set_text(text); } +Editbox::Editbox() : + base_from_member(*new pEditbox(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = EditboxType; } + +/* Widget -> FormControl -> Listbox */ + +void Listbox::create(uint style, uint width, uint height, const char *columns, const char *text) { p.create(style, width, height, columns, text); } +void Listbox::autosize_columns() { p.autosize_columns(); } +void Listbox::set_column_width(uint column, uint width) { p.set_column_width(column, width); } +void Listbox::add_item(const char *text) { p.add_item(text); } +void Listbox::set_item(uint index, const char *text) { p.set_item(index, text); } +int Listbox::get_selection() { return p.get_selection(); } +void Listbox::set_selection(int index) { p.set_selection(index); } +void Listbox::reset() { p.reset(); } +Listbox::Listbox() : + base_from_member(*new pListbox(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = ListboxType; } + +/* Widget -> FormControl -> Combobox */ + +void Combobox::create(uint style, uint width, uint height, const char *text) { p.create(style, width, height, text); } +void Combobox::add_item(const char *text) { p.add_item(text); } +int Combobox::get_selection() { return p.get_selection(); } +void Combobox::set_selection(int index) { p.set_selection(index); } +void Combobox::reset() { p.reset(); } +Combobox::Combobox() : + base_from_member(*new pCombobox(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = ComboboxType; } + +/* Widget -> FormControl -> Progressbar */ + +void Progressbar::create(uint style, uint width, uint height) { p.create(style, width, height); } +uint Progressbar::get_progress() { return p.get_progress(); } +void Progressbar::set_progress(uint progress) { p.set_progress(progress); } +Progressbar::Progressbar() : + base_from_member(*new pProgressbar(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = ProgressbarType; } + +/* Widget -> FormControl -> Slider */ + +void Slider::create(uint style, uint width, uint height, uint length) { p.create(style, width, height, length); } +uint Slider::get_position() { return p.get_position(); } +void Slider::set_position(uint position) { p.set_position(position); } +Slider::Slider() : + base_from_member(*new pSlider(*this)), + FormControl(base_from_member::value), + p(base_from_member::value) { type = SliderType; } + +} //namespace ns_miu diff --git a/src/lib/miu.gtk/miu.gtk.button.cpp b/src/lib/miu.gtk/miu.gtk.button.cpp new file mode 100644 index 00000000..06523dac --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.button.cpp @@ -0,0 +1,25 @@ +void miu_pbutton_tick(pButton *p) { + if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self)); +} + +void pButton::create(uint style, uint width, uint height, const char *text) { + button = gtk_button_new_with_label(text ? text : ""); + gtk_widget_set_size_request(button, width, height); + gtk_widget_show(button); + g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(miu_pbutton_tick), (gpointer)this); +} + +void pButton::set_text(const char *text) { + if(!button) return; + gtk_button_set_label(GTK_BUTTON(button), text ? text : ""); +} + +pButton::pButton(Button &self_) : pFormControl(self_), self(self_) { + button = 0; +} + +/* internal */ + +GtkWidget* pButton::gtk_handle() { + return button; +} diff --git a/src/lib/miu.gtk/miu.gtk.button.h b/src/lib/miu.gtk/miu.gtk.button.h new file mode 100644 index 00000000..10bab078 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.button.h @@ -0,0 +1,12 @@ +class pButton : public pFormControl { +public: + Button &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pButton(Button&); + +/* internal */ + GtkWidget *button; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.canvas.cpp b/src/lib/miu.gtk/miu.gtk.canvas.cpp new file mode 100644 index 00000000..42454289 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.canvas.cpp @@ -0,0 +1,72 @@ +void miu_pcanvas_expose(pCanvas *p) { +uint32 *f = p->fbuffer; +uint32 *r = p->rbuffer; + for(uint y = p->canvas->allocation.height; y; y--) { + for(uint x = p->canvas->allocation.width; x; x--) { + uint32 p = *f++; + *r++ = ((p << 16) & 0xff0000) + (p & 0x00ff00) + ((p >> 16) & 0x0000ff); + } + } + + gdk_draw_rgb_32_image(p->canvas->window, + p->canvas->style->fg_gc[GTK_WIDGET_STATE(p->canvas)], + 0, 0, p->canvas->allocation.width, p->canvas->allocation.height, + GDK_RGB_DITHER_NONE, (guchar*)p->rbuffer, p->bpitch); +} + +void pCanvas::create(uint style, uint width, uint height) { + canvas = gtk_drawing_area_new(); + resize(width, height); +GdkColor color; + color.pixel = color.red = color.green = color.blue = 0; + gtk_widget_modify_bg(canvas, GTK_STATE_NORMAL, &color); + gtk_widget_show(canvas); + + g_signal_connect_swapped(G_OBJECT(canvas), "expose_event", G_CALLBACK(miu_pcanvas_expose), (gpointer)this); +} + +void pCanvas::redraw() { + if(!canvas || !canvas->window) return; + +GdkRectangle rect; + rect.x = 0; + rect.y = 0; + rect.width = canvas->allocation.width; + rect.height = canvas->allocation.height; + gdk_window_invalidate_rect(canvas->window, &rect, true); +} + +uint32* pCanvas::buffer() { + return fbuffer; +} + +pCanvas::pCanvas(Canvas &self_) : pFormControl(self_), self(self_) { + canvas = 0; + fbuffer = 0; + rbuffer = 0; + bpitch = 0; +} + +pCanvas::~pCanvas() { + safe_free(fbuffer); + safe_free(rbuffer); +} + +/* internal */ + +void pCanvas::resize(uint width, uint height) { + safe_free(fbuffer); + safe_free(rbuffer); + + bpitch = width * sizeof(uint32); + fbuffer = (uint32*)malloc(bpitch * height); + rbuffer = (uint32*)malloc(bpitch * height); + memset(fbuffer, 0, bpitch * height); + memset(rbuffer, 0, bpitch * height); + + pFormControl::resize(width, height); +} + +GtkWidget* pCanvas::gtk_handle() { + return canvas; +} diff --git a/src/lib/miu.gtk/miu.gtk.canvas.h b/src/lib/miu.gtk/miu.gtk.canvas.h new file mode 100644 index 00000000..5e334e93 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.canvas.h @@ -0,0 +1,19 @@ +class pCanvas : public pFormControl { +public: + void create(uint style, uint width, uint height); + void redraw(); + uint32* buffer(); + + Canvas &self; + pCanvas(Canvas&); + ~pCanvas(); + +/* internal */ + GtkWidget *canvas; +//GTK+ RGB drawing function draws in xBGR format, so two buffers are needed ... + uint32 *fbuffer; //one for the xRGB image + uint32 *rbuffer; //one for the xBGR image + uint bpitch; + void resize(uint width, uint height); + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.checkbox.cpp b/src/lib/miu.gtk/miu.gtk.checkbox.cpp new file mode 100644 index 00000000..17012664 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.checkbox.cpp @@ -0,0 +1,37 @@ +void miu_pcheckbox_tick(pCheckbox *p) { + if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self)); +} + +void pCheckbox::create(uint style, uint width, uint height, const char *text) { + checkbox = gtk_check_button_new_with_label(text ? text : ""); + gtk_widget_set_size_request(checkbox, width, height); + gtk_widget_show(checkbox); + g_signal_connect_swapped(G_OBJECT(checkbox), "toggled", G_CALLBACK(miu_pcheckbox_tick), (gpointer)this); +} + +void pCheckbox::set_text(const char *text) { + if(!checkbox) return; + gtk_button_set_label(GTK_BUTTON(checkbox), text ? text : ""); +} + +void pCheckbox::check(bool state) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), state ? TRUE : FALSE); +} + +void pCheckbox::uncheck() { + check(false); +} + +bool pCheckbox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox)); +} + +pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) { + checkbox = 0; +} + +/* internal */ + +GtkWidget* pCheckbox::gtk_handle() { + return checkbox; +} diff --git a/src/lib/miu.gtk/miu.gtk.checkbox.h b/src/lib/miu.gtk/miu.gtk.checkbox.h new file mode 100644 index 00000000..c22b8496 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.checkbox.h @@ -0,0 +1,15 @@ +class pCheckbox : public pFormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(bool state = true); + void uncheck(); + bool checked(); + + Checkbox &self; + pCheckbox(Checkbox&); + +/* internal */ + GtkWidget *checkbox; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.combobox.cpp b/src/lib/miu.gtk/miu.gtk.combobox.cpp new file mode 100644 index 00000000..f7d1012b --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.combobox.cpp @@ -0,0 +1,44 @@ +void miu_pcombobox_change(pCombobox *p) { + if(p->self.on_change) p->self.on_change(Event(Event::Change, p->get_selection(), &p->self)); +} + +void pCombobox::create(uint style, uint width, uint height, const char *text) { + combobox = gtk_combo_box_new_text(); + gtk_widget_set_size_request(combobox, width, height); + gtk_widget_show(combobox); + + g_signal_connect_swapped(G_OBJECT(combobox), "changed", G_CALLBACK(miu_pcombobox_change), (gpointer)this); +} + +void pCombobox::add_item(const char *text) { + if(!combobox) return; + gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), text ? text : "?"); + if(counter++ == 0) set_selection(0); +} + +int pCombobox::get_selection() { + return gtk_combo_box_get_active(GTK_COMBO_BOX(combobox)); +} + +void pCombobox::set_selection(int index) { + gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index); +} + +void pCombobox::reset() { + if(counter == 0) return; + for(int i = counter - 1; i >= 0; i--) { + gtk_combo_box_remove_text(GTK_COMBO_BOX(combobox), i); + } + counter = 0; +} + +pCombobox::pCombobox(Combobox &self_) : pFormControl(self_), self(self_) { + combobox = 0; + counter = 0; +} + +/* internal */ + +GtkWidget* pCombobox::gtk_handle() { + return combobox; +} diff --git a/src/lib/miu.gtk/miu.gtk.combobox.h b/src/lib/miu.gtk/miu.gtk.combobox.h new file mode 100644 index 00000000..7a209027 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.combobox.h @@ -0,0 +1,16 @@ +class pCombobox : public pFormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void add_item(const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + Combobox &self; + pCombobox(Combobox&); + +/* internal */ + GtkWidget *combobox; + uint counter; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.cpp b/src/lib/miu.gtk/miu.gtk.cpp new file mode 100644 index 00000000..f5391c13 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.cpp @@ -0,0 +1,118 @@ +#include "miu.gtk.h" +#include "../miu.cpp" + +namespace ns_miu { + +#include "miu.gtk.keymap.cpp" +#include "miu.gtk.widget.cpp" + #include "miu.gtk.window.cpp" + #include "miu.gtk.menucontrol.cpp" + #include "miu.gtk.menugroup.cpp" + #include "miu.gtk.menuitem.cpp" + #include "miu.gtk.menucheckitem.cpp" + #include "miu.gtk.menuradioitem.cpp" + #include "miu.gtk.menuseparator.cpp" + #include "miu.gtk.formcontrol.cpp" + #include "miu.gtk.frame.cpp" + #include "miu.gtk.canvas.cpp" + #include "miu.gtk.label.cpp" + #include "miu.gtk.button.cpp" + #include "miu.gtk.checkbox.cpp" + #include "miu.gtk.radiobox.cpp" + #include "miu.gtk.editbox.cpp" + #include "miu.gtk.listbox.cpp" + #include "miu.gtk.combobox.cpp" + #include "miu.gtk.progressbar.cpp" + #include "miu.gtk.slider.cpp" + +void pMiu::init() { +//simulate passing argc, argv to gtk_init() +int argc = 1; +char **argv; + argv = (char**)malloc(1 * sizeof(char*)); + argv[0] = (char*)malloc(64 * sizeof(char)); + strcpy(argv[0], "./miu"); + gtk_init(&argc, &argv); + safe_free(argv[0]); + safe_free(argv); +} + +void pMiu::term() { +} + +bool pMiu::run() { + gtk_main_iteration_do(false); + return pending(); +} + +bool pMiu::pending() { + return gtk_events_pending(); +} + +bool pMiu::file_load(Window *focus, char *filename, const char *filter, const char *path) { + if(!filename) return false; + strcpy(filename, ""); + +GtkWidget *dialog = gtk_file_chooser_dialog_new("Load File", + focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0); + + if(path && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + strcpy(filename, fn); + g_free(fn); + } + + gtk_widget_destroy(dialog); + return strcmp(filename, ""); //return true if filename exists +} + +bool pMiu::file_save(Window *focus, char *filename, const char *filter, const char *path) { + if(!filename) return false; + strcpy(filename, ""); + +GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File", + focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + (const gchar*)0); + + if(path && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + strcpy(filename, fn); + g_free(fn); + } + + gtk_widget_destroy(dialog); + return strcmp(filename, ""); //return true if filename exists +} + +uint pMiu::screen_width() { + return gdk_screen_width(); +} + +uint pMiu::screen_height() { + return gdk_screen_height(); +} + +pMiu& pMiu::handle() { + return miu().p; +} + +pMiu::pMiu(Miu &self_) : self(self_) { +} + +pMiu& pmiu() { + return pMiu::handle(); +} + +} //namespace ns_miu diff --git a/src/lib/miu.gtk/miu.gtk.editbox.cpp b/src/lib/miu.gtk/miu.gtk.editbox.cpp new file mode 100644 index 00000000..a27655f5 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.editbox.cpp @@ -0,0 +1,62 @@ +void pEditbox::create(uint style, uint width, uint height, const char *text) { + multiline = bool(style & Editbox::Multiline); + + if(multiline == false) { + editbox = gtk_entry_new(); + if(style & Editbox::Readonly) { gtk_entry_set_editable(GTK_ENTRY(editbox), false); } + gtk_entry_set_text(GTK_ENTRY(editbox), text ? text : ""); + gtk_widget_set_size_request(editbox, width, height); + gtk_widget_show(editbox); + } else { + GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS : + (style & Editbox::HorizontalScrollNever) ? GTK_POLICY_NEVER : + GTK_POLICY_AUTOMATIC; + GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS : + (style & Editbox::VerticalScrollNever) ? GTK_POLICY_NEVER : + GTK_POLICY_AUTOMATIC; + scrollbox = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN); + gtk_widget_set_size_request(scrollbox, width, height); + editbox = gtk_text_view_new(); + gtk_container_add(GTK_CONTAINER(scrollbox), editbox); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(editbox)); + if(style & Editbox::Readonly) { gtk_text_view_set_editable(GTK_TEXT_VIEW(editbox), false); } + gtk_text_buffer_set_text(buffer, text ? text : "", -1); + gtk_widget_show(editbox); + gtk_widget_show(scrollbox); + } +} + +void pEditbox::set_text(const char *text) { + if(multiline == false) { + gtk_entry_set_text(GTK_ENTRY(editbox), text); + } else { + gtk_text_buffer_set_text(buffer, text, -1); + } +} + +uint pEditbox::get_text(char *text, uint length) { + if(multiline == false) { + const char *temp = gtk_entry_get_text(GTK_ENTRY(editbox)); + return strlcpy(text, temp ? temp : "", length); + } else { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + return strlcpy(text, gtk_text_buffer_get_text(buffer, &start, &end, true), length); + } +} + +pEditbox::pEditbox(Editbox &self_) : pFormControl(self_), self(self_) { + scrollbox = 0; + editbox = 0; + buffer = 0; + multiline = false; +} + +/* internal */ + +GtkWidget* pEditbox::gtk_handle() { + return multiline ? scrollbox : editbox; +} diff --git a/src/lib/miu.gtk/miu.gtk.editbox.h b/src/lib/miu.gtk/miu.gtk.editbox.h new file mode 100644 index 00000000..682f2ce1 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.editbox.h @@ -0,0 +1,16 @@ +class pEditbox : public pFormControl { +public: + Editbox &self; + void create(uint style, uint width, uint height, const char *text = ""); + uint get_text(char *text, uint length = -1U); + void set_text(const char *text = ""); + + pEditbox(Editbox&); + +/* internal */ + GtkWidget *scrollbox; + GtkWidget *editbox; + GtkTextBuffer *buffer; + bool multiline; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.formcontrol.cpp b/src/lib/miu.gtk/miu.gtk.formcontrol.cpp new file mode 100644 index 00000000..cc9d8cda --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.formcontrol.cpp @@ -0,0 +1,32 @@ +void pFormControl::resize(uint width, uint height) { + gtk_widget_set_size_request(gtk_handle(), width, height); +} + +void pFormControl::focus() { + gtk_widget_grab_focus(gtk_handle()); +} + +bool pFormControl::focused() { + return GTK_WIDGET_HAS_FOCUS(gtk_handle()); +} + +void pFormControl::enable(bool state) { + gtk_widget_set_sensitive(gtk_handle(), state); +} + +void pFormControl::disable() { + enable(false); +} + +bool pFormControl::enabled() { + return GTK_WIDGET_SENSITIVE(gtk_handle()); +} + +pFormControl::pFormControl(FormControl &self_) : pWidget(self_), self(self_) { +} + +/* internal */ + +GtkWidget* pFormControl::gtk_handle() { + return 0; +} diff --git a/src/lib/miu.gtk/miu.gtk.formcontrol.h b/src/lib/miu.gtk/miu.gtk.formcontrol.h new file mode 100644 index 00000000..b775632b --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.formcontrol.h @@ -0,0 +1,15 @@ +class pFormControl : public pWidget { +public: + virtual void resize(uint width, uint height); + void focus(); + bool focused(); + void enable(bool = true); + void disable(); + bool enabled(); + + FormControl &self; + pFormControl(FormControl&); + +/* internal */ + virtual GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.frame.cpp b/src/lib/miu.gtk/miu.gtk.frame.cpp new file mode 100644 index 00000000..f378bb9e --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.frame.cpp @@ -0,0 +1,19 @@ +void pFrame::create(uint style, uint width, uint height, const char *text) { + frame = gtk_frame_new(text ? text : ""); + gtk_widget_set_size_request(frame, width, height); + gtk_widget_show(frame); +} + +void pFrame::set_text(const char *text) { + gtk_frame_set_label(GTK_FRAME(frame), text ? text : ""); +} + +pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) { + frame = 0; +} + +/* internal */ + +GtkWidget* pFrame::gtk_handle() { + return frame; +} diff --git a/src/lib/miu.gtk/miu.gtk.frame.h b/src/lib/miu.gtk/miu.gtk.frame.h new file mode 100644 index 00000000..446f016e --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.frame.h @@ -0,0 +1,12 @@ +class pFrame : public pFormControl { +public: + Frame &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pFrame(Frame&); + +/* internal */ + GtkWidget *frame; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.h b/src/lib/miu.gtk/miu.gtk.h new file mode 100644 index 00000000..9aba9374 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.h @@ -0,0 +1,58 @@ +#ifndef MIU_GTK_H +#define MIU_GTK_H + +#include "../miu.h" + +#include +#include +#include + +namespace ns_miu { + +#include "miu.gtk.widget.h" + #include "miu.gtk.window.h" + #include "miu.gtk.menucontrol.h" + #include "miu.gtk.menugroup.h" + #include "miu.gtk.menuitem.h" + #include "miu.gtk.menucheckitem.h" + #include "miu.gtk.menuradioitem.h" + #include "miu.gtk.menuseparator.h" + #include "miu.gtk.formcontrol.h" + #include "miu.gtk.frame.h" + #include "miu.gtk.canvas.h" + #include "miu.gtk.label.h" + #include "miu.gtk.button.h" + #include "miu.gtk.checkbox.h" + #include "miu.gtk.radiobox.h" + #include "miu.gtk.editbox.h" + #include "miu.gtk.listbox.h" + #include "miu.gtk.combobox.h" + #include "miu.gtk.progressbar.h" + #include "miu.gtk.slider.h" + +class pMiu { +public: + Miu &self; + void init(); + void term(); + bool run(); + bool pending(); + + bool file_load(Window *focus, char *filename, const char *filter, const char *path); + bool file_save(Window *focus, char *filename, const char *filter, const char *path); + + uint screen_width(); + uint screen_height(); + + static pMiu& handle(); + pMiu(Miu&); + +/* internal */ + uint16 translate_key(uint key); +}; + +pMiu& pmiu(); + +} //namespace ns_miu + +#endif //ifndef MIU_GTK_H diff --git a/src/lib/miu.gtk/miu.gtk.keymap.cpp b/src/lib/miu.gtk/miu.gtk.keymap.cpp new file mode 100644 index 00000000..621f8e0f --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.keymap.cpp @@ -0,0 +1,188 @@ +uint16 pMiu::translate_key(uint key) { + switch(key) { + case GDK_Escape: return keymap::esc; + + case GDK_F1: return keymap::f1; + case GDK_F2: return keymap::f2; + case GDK_F3: return keymap::f3; + case GDK_F4: return keymap::f4; + case GDK_F5: return keymap::f5; + case GDK_F6: return keymap::f6; + case GDK_F7: return keymap::f7; + case GDK_F8: return keymap::f8; + case GDK_F9: return keymap::f9; + case GDK_F10: return keymap::f10; + case GDK_F11: return keymap::f11; + case GDK_F12: return keymap::f12; + + case GDK_Print: return keymap::print_screen; + case GDK_Sys_Req: return keymap::sys_req; + case GDK_Scroll_Lock: return keymap::scroll_lock; + case GDK_Pause: return keymap::pause; + case GDK_Break: return keymap::brk; + + case GDK_grave: return keymap::grave; + case GDK_asciitilde: return keymap::tilde; + + case GDK_1: return keymap::num_1; + case GDK_2: return keymap::num_2; + case GDK_3: return keymap::num_3; + case GDK_4: return keymap::num_4; + case GDK_5: return keymap::num_5; + case GDK_6: return keymap::num_6; + case GDK_7: return keymap::num_7; + case GDK_8: return keymap::num_8; + case GDK_9: return keymap::num_9; + case GDK_0: return keymap::num_0; + + case GDK_exclam: return keymap::exclamation; + case GDK_at: return keymap::at; + case GDK_numbersign: return keymap::pound; + case GDK_dollar: return keymap::dollar; + case GDK_percent: return keymap::percent; + case GDK_asciicircum: return keymap::power; + case GDK_ampersand: return keymap::ampersand; + case GDK_asterisk: return keymap::asterisk; + case GDK_parenleft: return keymap::lparenthesis; + case GDK_parenright: return keymap::rparenthesis; + + case GDK_minus: return keymap::minus; + case GDK_underscore: return keymap::underscore; + case GDK_equal: return keymap::equal; + case GDK_plus: return keymap::plus; + case GDK_BackSpace: return keymap::backspace; + + case GDK_Insert: return keymap::ins; + case GDK_Delete: return keymap::del; + case GDK_Home: return keymap::home; + case GDK_End: return keymap::end; + case GDK_Page_Up: return keymap::page_up; + case GDK_Page_Down: return keymap::page_down; + + case GDK_a: return keymap::a; + case GDK_b: return keymap::b; + case GDK_c: return keymap::c; + case GDK_d: return keymap::d; + case GDK_e: return keymap::e; + case GDK_f: return keymap::f; + case GDK_g: return keymap::g; + case GDK_h: return keymap::h; + case GDK_i: return keymap::i; + case GDK_j: return keymap::j; + case GDK_k: return keymap::k; + case GDK_l: return keymap::l; + case GDK_m: return keymap::m; + case GDK_n: return keymap::n; + case GDK_o: return keymap::o; + case GDK_p: return keymap::p; + case GDK_q: return keymap::q; + case GDK_r: return keymap::r; + case GDK_s: return keymap::s; + case GDK_t: return keymap::t; + case GDK_u: return keymap::u; + case GDK_v: return keymap::v; + case GDK_w: return keymap::w; + case GDK_x: return keymap::x; + case GDK_y: return keymap::y; + case GDK_z: return keymap::z; + + case GDK_A: return keymap::A; + case GDK_B: return keymap::B; + case GDK_C: return keymap::C; + case GDK_D: return keymap::D; + case GDK_E: return keymap::E; + case GDK_F: return keymap::F; + case GDK_G: return keymap::G; + case GDK_H: return keymap::H; + case GDK_I: return keymap::I; + case GDK_J: return keymap::J; + case GDK_K: return keymap::K; + case GDK_L: return keymap::L; + case GDK_M: return keymap::M; + case GDK_N: return keymap::N; + case GDK_O: return keymap::O; + case GDK_P: return keymap::P; + case GDK_Q: return keymap::Q; + case GDK_R: return keymap::R; + case GDK_S: return keymap::S; + case GDK_T: return keymap::T; + case GDK_U: return keymap::U; + case GDK_V: return keymap::V; + case GDK_W: return keymap::W; + case GDK_X: return keymap::X; + case GDK_Y: return keymap::Y; + case GDK_Z: return keymap::Z; + + case GDK_bracketleft: return keymap::lbracket; + case GDK_bracketright: return keymap::rbracket; + case GDK_backslash: return keymap::backslash; + case GDK_semicolon: return keymap::semicolon; + case GDK_apostrophe: return keymap::apostrophe; + case GDK_comma: return keymap::comma; + case GDK_period: return keymap::period; + case GDK_slash: return keymap::slash; + + case GDK_braceleft: return keymap::lbrace; + case GDK_braceright: return keymap::rbrace; + case GDK_bar: return keymap::pipe; + case GDK_colon: return keymap::colon; + case GDK_quotedbl: return keymap::quote; + case GDK_less: return keymap::lcaret; + case GDK_greater: return keymap::rcaret; + case GDK_question: return keymap::question; + + case GDK_KP_1: return keymap::kp_1; + case GDK_KP_2: return keymap::kp_2; + case GDK_KP_3: return keymap::kp_3; + case GDK_KP_4: return keymap::kp_4; + case GDK_KP_5: return keymap::kp_5; + case GDK_KP_6: return keymap::kp_6; + case GDK_KP_7: return keymap::kp_7; + case GDK_KP_8: return keymap::kp_8; + case GDK_KP_9: return keymap::kp_9; + case GDK_KP_0: return keymap::kp_0; + case GDK_KP_Decimal: return keymap::kp_decimal; + + case GDK_KP_End: return keymap::kp_end; + case GDK_KP_Down: return keymap::kp_down; + case GDK_KP_Page_Down: return keymap::kp_page_down; + case GDK_KP_Left: return keymap::kp_left; + case GDK_KP_Begin: return keymap::kp_center; + case GDK_KP_Right: return keymap::kp_right; + case GDK_KP_Home: return keymap::kp_home; + case GDK_KP_Up: return keymap::kp_up; + case GDK_KP_Page_Up: return keymap::kp_page_up; + case GDK_KP_Insert: return keymap::kp_insert; + case GDK_KP_Delete: return keymap::kp_delete; + + case GDK_KP_Add: return keymap::kp_plus; + case GDK_KP_Subtract: return keymap::kp_minus; + case GDK_KP_Multiply: return keymap::kp_mul; + case GDK_KP_Divide: return keymap::kp_div; + case GDK_KP_Enter: return keymap::kp_enter; + + case GDK_Num_Lock: return keymap::num_lock; + case GDK_Caps_Lock: return keymap::caps_lock; + + case GDK_Up: return keymap::up; + case GDK_Down: return keymap::down; + case GDK_Left: return keymap::left; + case GDK_Right: return keymap::right; + + case GDK_Tab: return keymap::tab; + case GDK_Return: return keymap::enter; + case GDK_space: return keymap::space; + + case GDK_Control_L: return keymap::lctrl; + case GDK_Control_R: return keymap::rctrl; + case GDK_Alt_L: return keymap::lalt; + case GDK_Alt_R: return keymap::ralt; + case GDK_Shift_L: return keymap::lshift; + case GDK_Shift_R: return keymap::rshift; + case GDK_Super_L: return keymap::lsuper; + case GDK_Super_R: return keymap::rsuper; + case GDK_Menu: return keymap::menu; + } + + return keymap::none; +} diff --git a/src/lib/miu.gtk/miu.gtk.label.cpp b/src/lib/miu.gtk/miu.gtk.label.cpp new file mode 100644 index 00000000..809a8561 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.label.cpp @@ -0,0 +1,21 @@ +void pLabel::create(uint style, uint width, uint height, const char *text) { + label = gtk_label_new(text ? text : ""); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + gtk_widget_set_size_request(label, width, height); + gtk_widget_show(label); +} + +void pLabel::set_text(const char *text) { + if(!label) return; + gtk_label_set_label(GTK_LABEL(label), text ? text : ""); +} + +pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) { + label = 0; +} + +/* internal */ + +GtkWidget* pLabel::gtk_handle() { + return label; +} diff --git a/src/lib/miu.gtk/miu.gtk.label.h b/src/lib/miu.gtk/miu.gtk.label.h new file mode 100644 index 00000000..e08540ea --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.label.h @@ -0,0 +1,12 @@ +class pLabel : public pFormControl { +public: + Label &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pLabel(Label&); + +/* internal */ + GtkWidget *label; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.listbox.cpp b/src/lib/miu.gtk/miu.gtk.listbox.cpp new file mode 100644 index 00000000..f90e01c3 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.listbox.cpp @@ -0,0 +1,135 @@ +void miu_plistbox_change(pListbox *p) { + if(p->listbox_selection == p->get_selection()) return; + if(p->self.on_change) p->self.on_change(Event(Event::Change, p->listbox_selection = p->get_selection(), &p->self)); +} + +void miu_plistbox_activate(pListbox *p) { + if(p->self.on_activate) p->self.on_activate(Event(Event::Activate, p->listbox_selection = p->get_selection(), &p->self)); +} + +void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) { +bool header = style & Listbox::Header; +GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS : + (style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER : + GTK_POLICY_AUTOMATIC; +GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS : + (style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER : + GTK_POLICY_AUTOMATIC; + + scrollbox = gtk_scrolled_window_new(0, 0); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN); + +lstring list; + split(list, "\t", columns); + +GType *v = (GType*)malloc(count(list) * sizeof(GType)); + for(uint i = 0; i < count(list); i++) v[i] = G_TYPE_STRING; + store = gtk_list_store_newv(count(list), v); + safe_free(v); + + listbox = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + gtk_container_add(GTK_CONTAINER(scrollbox), listbox); + g_object_unref(G_OBJECT(store)); + gtk_widget_set_size_request(scrollbox, width, height); + gtk_widget_show(listbox); + gtk_widget_show(scrollbox); + +//alternate colors for each listbox entry if there are multiple columns ... + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(listbox), count(list) >= 2 ? true : false); + for(uint i = 0; i < count(list); i++) { + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(list[i], renderer, "text", i, 0); + column_list[column_list.size()] = column; + gtk_tree_view_append_column(GTK_TREE_VIEW(listbox), column); + } + + if(text && *text) { + split(list, "\n", text); + for(uint i = 0; i < count(list); i++) add_item(list[i]); + } + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(listbox), header); + autosize_columns(); + + g_signal_connect_swapped(G_OBJECT(listbox), "cursor-changed", G_CALLBACK(miu_plistbox_change), (gpointer)this); + g_signal_connect_swapped(G_OBJECT(listbox), "row-activated", G_CALLBACK(miu_plistbox_activate), (gpointer)this); +} + +void pListbox::autosize_columns() { + gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listbox)); +} + +void pListbox::set_column_width(uint column, uint width) { + gtk_tree_view_column_set_min_width(column_list[column], width); + gtk_tree_view_column_set_max_width(column_list[column], width); +} + +void pListbox::add_item(const char *text) { +lstring list; + split(list, "\t", text); + gtk_list_store_append(store, &iter); + for(uint i = 0; i < count(list); i++) { + gtk_list_store_set(store, &iter, i, list[i](), -1); + } +} + +void pListbox::set_item(uint index, const char *text) { +GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox)); + for(uint i = 0; i <= index; i++) { + i == 0 ? + gtk_tree_model_get_iter_first(model, &iter) : + gtk_tree_model_iter_next(model, &iter); + } + +lstring list; + split(list, "\t", text); + for(uint i = 0; i < count(list); i++) { + gtk_list_store_set(store, &iter, i, list[i](), -1); + } +} + +int pListbox::get_selection() { +GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listbox)); +GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox)); + if(gtk_tree_model_get_iter_first(model, &iter) == false) { return -1; } + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return 0; } + for(uint i = 1; i < 100000; i++) { + if(gtk_tree_model_iter_next(model, &iter) == false) { return -1; } + if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) { return i; } + } + return -1; +} + +void pListbox::set_selection(int index) { +int current = get_selection(); +GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listbox)); +GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox)); + gtk_tree_selection_unselect_all(selection); + if(index < 0) { goto end; } + if(gtk_tree_model_get_iter_first(model, &iter) == false) { goto end; } + if(index == 0) { gtk_tree_selection_select_iter(selection, &iter); goto end; } + for(uint i = 1; i < 100000; i++) { + if(gtk_tree_model_iter_next(model, &iter) == false) { goto end; } + if(index == i) { gtk_tree_selection_select_iter(selection, &iter); goto end; } + } +end: + if(current != index) ;//{ owner->message(Message::Changed, (uintptr_t)this); } +} + +void pListbox::reset() { + gtk_list_store_clear(GTK_LIST_STORE(store)); + gtk_tree_view_set_model(GTK_TREE_VIEW(listbox), GTK_TREE_MODEL(store)); +} + +pListbox::pListbox(Listbox &self_) : pFormControl(self_), self(self_) { + scrollbox = 0; + listbox = 0; + listbox_selection = -1; +} + +/* internal */ + +GtkWidget* pListbox::gtk_handle() { + return scrollbox; +} diff --git a/src/lib/miu.gtk/miu.gtk.listbox.h b/src/lib/miu.gtk/miu.gtk.listbox.h new file mode 100644 index 00000000..faeae4cf --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.listbox.h @@ -0,0 +1,25 @@ +class pListbox : public pFormControl { +public: + void create(uint style, uint width, uint height, const char *columns = "", const char *text = ""); + void autosize_columns(); + void set_column_width(uint column, uint width); + void add_item(const char *text); + void set_item(uint index, const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + Listbox &self; + pListbox(Listbox&); + +/* internal */ + GtkWidget *scrollbox; + GtkWidget *listbox; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + array column_list; + GtkTreeIter iter; + int listbox_selection; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menucheckitem.cpp b/src/lib/miu.gtk/miu.gtk.menucheckitem.cpp new file mode 100644 index 00000000..c185d497 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menucheckitem.cpp @@ -0,0 +1,31 @@ +void miu_pmenucheckitem_tick(pMenuCheckItem *p) { + if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self)); +} + +void pMenuCheckItem::create(const char *text) { + item = gtk_check_menu_item_new_with_label(text ? text : "?"); + gtk_widget_show(item); + g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(miu_pmenucheckitem_tick), (gpointer)this); +} + +void pMenuCheckItem::check(bool state) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state ? TRUE : FALSE); +} + +void pMenuCheckItem::uncheck() { + check(false); +} + +bool pMenuCheckItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)); +} + +pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) { + item = 0; +} + +/* internal */ + +GtkWidget* pMenuCheckItem::gtk_handle() { + return item; +} diff --git a/src/lib/miu.gtk/miu.gtk.menucheckitem.h b/src/lib/miu.gtk/miu.gtk.menucheckitem.h new file mode 100644 index 00000000..a161249e --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menucheckitem.h @@ -0,0 +1,14 @@ +class pMenuCheckItem : public pMenuControl { +public: + void create(const char *text = ""); + void check(bool state = true); + void uncheck(); + bool checked(); + + MenuCheckItem &self; + pMenuCheckItem(MenuCheckItem&); + +/* internal */ + GtkWidget *item; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menucontrol.cpp b/src/lib/miu.gtk/miu.gtk.menucontrol.cpp new file mode 100644 index 00000000..de6281bb --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menucontrol.cpp @@ -0,0 +1,20 @@ +void pMenuControl::enable(bool state) { + gtk_widget_set_sensitive(gtk_handle(), state); +} + +void pMenuControl::disable() { + enable(false); +} + +bool pMenuControl::enabled() { + return GTK_WIDGET_SENSITIVE(gtk_handle()); +} + +pMenuControl::pMenuControl(MenuControl &self_) : pWidget(self_), self(self_) { +} + +/* internal */ + +GtkWidget* pMenuControl::gtk_handle() { + return 0; +} diff --git a/src/lib/miu.gtk/miu.gtk.menucontrol.h b/src/lib/miu.gtk/miu.gtk.menucontrol.h new file mode 100644 index 00000000..0204eacd --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menucontrol.h @@ -0,0 +1,12 @@ +class pMenuControl : public pWidget { +public: + void enable(bool = true); + void disable(); + bool enabled(); + + MenuControl &self; + pMenuControl(MenuControl&); + +/* internal */ + virtual GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menugroup.cpp b/src/lib/miu.gtk/miu.gtk.menugroup.cpp new file mode 100644 index 00000000..74c2d499 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menugroup.cpp @@ -0,0 +1,21 @@ +void pMenuGroup::create(const char *text) { + group = gtk_menu_new(); + item = gtk_menu_item_new_with_label(text ? text : ""); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), group); + gtk_widget_show(item); +} + +void pMenuGroup::attach(MenuControl &menucontrol) { + gtk_menu_shell_append(GTK_MENU_SHELL(group), menucontrol.p.gtk_handle()); +} + +pMenuGroup::pMenuGroup(MenuGroup &self_) : pMenuControl(self_), self(self_) { + group = 0; + item = 0; +} + +/* internal */ + +GtkWidget* pMenuGroup::gtk_handle() { + return item; +} diff --git a/src/lib/miu.gtk/miu.gtk.menugroup.h b/src/lib/miu.gtk/miu.gtk.menugroup.h new file mode 100644 index 00000000..594ba51f --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menugroup.h @@ -0,0 +1,13 @@ +class pMenuGroup : public pMenuControl { +public: + MenuGroup &self; + void create(const char *text); + void attach(MenuControl &menucontrol); + + pMenuGroup(MenuGroup&); + +/* internal */ + GtkWidget *group; + GtkWidget *item; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menuitem.cpp b/src/lib/miu.gtk/miu.gtk.menuitem.cpp new file mode 100644 index 00000000..64699dba --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuitem.cpp @@ -0,0 +1,19 @@ +void miu_pmenuitem_tick(pMenuItem *p) { + if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self)); +} + +void pMenuItem::create(const char *text) { + item = gtk_menu_item_new_with_label(text ? text : ""); + g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(miu_pmenuitem_tick), (gpointer)this); + gtk_widget_show(item); +} + +pMenuItem::pMenuItem(MenuItem &self_) : pMenuControl(self_), self(self_) { + item = 0; +} + +/* internal */ + +GtkWidget* pMenuItem::gtk_handle() { + return item; +} diff --git a/src/lib/miu.gtk/miu.gtk.menuitem.h b/src/lib/miu.gtk/miu.gtk.menuitem.h new file mode 100644 index 00000000..55d02bca --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuitem.h @@ -0,0 +1,11 @@ +class pMenuItem : public pMenuControl { +public: + void create(const char *text = ""); + + MenuItem &self; + pMenuItem(MenuItem&); + +/* internal */ + GtkWidget *item; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menuradioitem.cpp b/src/lib/miu.gtk/miu.gtk.menuradioitem.cpp new file mode 100644 index 00000000..0e9a436b --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuradioitem.cpp @@ -0,0 +1,33 @@ +void miu_pmenuradioitem_tick(pMenuRadioItem *p) { +//GTK+ sends two messages: one for the activated radio item, +//and one for the deactivated radio item. ignore the latter. + if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self)); +} + +void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) { + if(group.size() == 0 || group[0] == &self) { + item = gtk_radio_menu_item_new_with_label(0, text ? text : "?"); + } else { + item = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(group[0]->p.gtk_handle()), text ? text : ""); + } + gtk_widget_show(item); + g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(miu_pmenuradioitem_tick), (gpointer)this); +} + +void pMenuRadioItem::check() { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); +} + +bool pMenuRadioItem::checked() { + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)); +} + +pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) { + item = 0; +} + +/* internal */ + +GtkWidget* pMenuRadioItem::gtk_handle() { + return item; +} diff --git a/src/lib/miu.gtk/miu.gtk.menuradioitem.h b/src/lib/miu.gtk/miu.gtk.menuradioitem.h new file mode 100644 index 00000000..bd020cb2 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuradioitem.h @@ -0,0 +1,13 @@ +class pMenuRadioItem : public pMenuControl { +public: + void create(MenuRadioItemGroup &group, const char *text = ""); + void check(); + bool checked(); + + MenuRadioItem &self; + pMenuRadioItem(MenuRadioItem&); + +/* internal */ + GtkWidget *item; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.menuseparator.cpp b/src/lib/miu.gtk/miu.gtk.menuseparator.cpp new file mode 100644 index 00000000..a03ba421 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuseparator.cpp @@ -0,0 +1,14 @@ +void pMenuSeparator::create() { + item = gtk_separator_menu_item_new(); + gtk_widget_show(item); +} + +pMenuSeparator::pMenuSeparator(MenuSeparator &self_) : pMenuControl(self_), self(self_) { + item = 0; +} + +/* internal */ + +GtkWidget* pMenuSeparator::gtk_handle() { + return item; +} diff --git a/src/lib/miu.gtk/miu.gtk.menuseparator.h b/src/lib/miu.gtk/miu.gtk.menuseparator.h new file mode 100644 index 00000000..54d8d151 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.menuseparator.h @@ -0,0 +1,11 @@ +class pMenuSeparator : public pMenuControl { +public: + MenuSeparator &self; + void create(); + + pMenuSeparator(MenuSeparator&); + +/* internal */ + GtkWidget *item; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.progressbar.cpp b/src/lib/miu.gtk/miu.gtk.progressbar.cpp new file mode 100644 index 00000000..2cef9fc0 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.progressbar.cpp @@ -0,0 +1,25 @@ +void pProgressbar::create(uint style, uint width, uint height) { + progressbar = gtk_progress_bar_new(); + gtk_widget_set_size_request(progressbar, width, height); + gtk_widget_show(progressbar); +} + +uint pProgressbar::get_progress() { +uint progress = (uint)(gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(progressbar)) * 100.0); + return max(0, min(progress, 100)); +} + +void pProgressbar::set_progress(uint progress) { + progress = max(0, min(progress, 100)); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), (double)progress / 100.0); +} + +pProgressbar::pProgressbar(Progressbar &self_) : pFormControl(self_), self(self_) { + progressbar = 0; +} + +/* internal */ + +GtkWidget* pProgressbar::gtk_handle() { + return progressbar; +} diff --git a/src/lib/miu.gtk/miu.gtk.progressbar.h b/src/lib/miu.gtk/miu.gtk.progressbar.h new file mode 100644 index 00000000..251c47dc --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.progressbar.h @@ -0,0 +1,13 @@ +class pProgressbar : public pFormControl { +public: + Progressbar &self; + void create(uint style, uint width, uint height); + uint get_progress(); + void set_progress(uint progress); + + pProgressbar(Progressbar&); + +/* internal */ + GtkWidget *progressbar; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.radiobox.cpp b/src/lib/miu.gtk/miu.gtk.radiobox.cpp new file mode 100644 index 00000000..1e7ec75d --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.radiobox.cpp @@ -0,0 +1,39 @@ +void miu_pradiobox_tick(pRadiobox *p) { +//GTK+ sends two messages: one for the activated radiobox, +//and one for the deactivated radiobox. ignore the latter. + if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self)); +} + +void pRadiobox::create(RadioboxGroup &group, uint style, uint width, uint height, const char *text) { + if(group.size() == 0 || group[0] == &self) { + radiobox = gtk_radio_button_new_with_label(0, text ? text : ""); + } else { + radiobox = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0]->p.gtk_handle()), text ? text : ""); + } + gtk_widget_set_size_request(radiobox, width, height); + gtk_widget_show(radiobox); + g_signal_connect_swapped(G_OBJECT(radiobox), "toggled", G_CALLBACK(miu_pradiobox_tick), (gpointer)this); +} + +void pRadiobox::set_text(const char *text) { + if(!radiobox) return; + gtk_button_set_label(GTK_BUTTON(radiobox), text ? text : ""); +} + +void pRadiobox::check() { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radiobox), TRUE); +} + +bool pRadiobox::checked() { + return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobox)); +} + +pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self), self(self_) { + radiobox = 0; +} + +/* internal */ + +GtkWidget* pRadiobox::gtk_handle() { + return radiobox; +} diff --git a/src/lib/miu.gtk/miu.gtk.radiobox.h b/src/lib/miu.gtk/miu.gtk.radiobox.h new file mode 100644 index 00000000..ea45c369 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.radiobox.h @@ -0,0 +1,14 @@ +class pRadiobox : public pFormControl { +public: + void create(RadioboxGroup &group, uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(); + bool checked(); + + Radiobox &self; + pRadiobox(Radiobox&); + +/* internal */ + GtkWidget *radiobox; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.slider.cpp b/src/lib/miu.gtk/miu.gtk.slider.cpp new file mode 100644 index 00000000..c1f40b2c --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.slider.cpp @@ -0,0 +1,36 @@ +void miu_pslider_change(pSlider *p) { + if(p->slider_position == p->get_position()) return; + if(p->self.on_change) p->self.on_change(Event(Event::Change, p->slider_position = p->get_position(), &p->self)); +} + +void pSlider::create(uint style, uint width, uint height, uint length) { + if(length < 1) length = 1; + if(style & Slider::Vertical) { + slider = gtk_vscale_new_with_range(0, length - 1, 1); + } else { + slider = gtk_hscale_new_with_range(0, length - 1, 1); + } + gtk_scale_set_draw_value(GTK_SCALE(slider), FALSE); + gtk_widget_set_size_request(slider, width, height); + gtk_widget_show(slider); + g_signal_connect_swapped(G_OBJECT(slider), "value-changed", G_CALLBACK(miu_pslider_change), (gpointer)this); +} + +uint pSlider::get_position() { + return (uint)gtk_range_get_value(GTK_RANGE(slider)); +} + +void pSlider::set_position(uint position) { + gtk_range_set_value(GTK_RANGE(slider), position); +} + +pSlider::pSlider(Slider &self_) : pFormControl(self_), self(self_) { + slider = 0; + slider_position = 0; +} + +/* internal */ + +GtkWidget* pSlider::gtk_handle() { + return slider; +} diff --git a/src/lib/miu.gtk/miu.gtk.slider.h b/src/lib/miu.gtk/miu.gtk.slider.h new file mode 100644 index 00000000..9b2d02c1 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.slider.h @@ -0,0 +1,14 @@ +class pSlider : public pFormControl { +public: + void create(uint style, uint width, uint height, uint length); + uint get_position(); + void set_position(uint position); + + Slider &self; + pSlider(Slider&); + +/* internal */ + GtkWidget *slider; + uint slider_position; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.widget.cpp b/src/lib/miu.gtk/miu.gtk.widget.cpp new file mode 100644 index 00000000..464351d0 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.widget.cpp @@ -0,0 +1,24 @@ +void pWidget::show(bool state) { + state ? gtk_widget_show(gtk_handle()) : gtk_widget_hide(gtk_handle()); +} + +void pWidget::hide() { + show(false); +} + +bool pWidget::visible() { + return GTK_WIDGET_VISIBLE(gtk_handle()); +} + +uintptr_t pWidget::handle() { + return GDK_WINDOW_XWINDOW(gtk_handle()->window); +} + +pWidget::pWidget(Widget &self_) : self(self_) { +} + +/* internal */ + +GtkWidget* pWidget::gtk_handle() { + return 0; +} diff --git a/src/lib/miu.gtk/miu.gtk.widget.h b/src/lib/miu.gtk/miu.gtk.widget.h new file mode 100644 index 00000000..dfdec8c1 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.widget.h @@ -0,0 +1,13 @@ +class pWidget { +public: + void show(bool = true); + void hide(); + bool visible(); + uintptr_t handle(); + + Widget &self; + pWidget(Widget&); + +/* internal */ + virtual GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.gtk/miu.gtk.window.cpp b/src/lib/miu.gtk/miu.gtk.window.cpp new file mode 100644 index 00000000..5fd71962 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.window.cpp @@ -0,0 +1,135 @@ +gint miu_pwindow_close(pWindow *p) { +uintptr_t r = p->self.on_close ? p->self.on_close(Event(Event::Close, 0, &p->self)) : true; + return !bool(r); +} + +gint miu_pwindow_keydown(GtkWidget *w, GdkEventKey *key, pWindow *p) { + if(p && p->self.on_keydown) p->self.on_keydown(Event(Event::KeyDown, pmiu().translate_key(key->keyval), &p->self)); + return FALSE; +} + +gint miu_pwindow_keyup(GtkWidget *w, GdkEventKey *key, pWindow *p) { + if(p && p->self.on_keyup) p->self.on_keyup(Event(Event::KeyUp, pmiu().translate_key(key->keyval), &p->self)); + return FALSE; +} + +void pWindow::create(uint style, uint width, uint height, const char *text) { + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), text ? text : ""); + gtk_window_set_resizable(GTK_WINDOW(window), false); + if(style & Window::AutoCenter) gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS); + g_signal_connect_swapped(G_OBJECT(window), "delete_event", G_CALLBACK(miu_pwindow_close), (gpointer)this); + g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(miu_pwindow_keydown), (gpointer)this); + g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(miu_pwindow_keyup), (gpointer)this); + + menucontainer = gtk_vbox_new(false, 0); + gtk_container_add(GTK_CONTAINER(window), menucontainer); + gtk_widget_show(menucontainer); + + menubar = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(menucontainer), menubar, false, false, 0); + + formcontainer = gtk_fixed_new(); + gtk_widget_set_size_request(formcontainer, width, height); + gtk_box_pack_end(GTK_BOX(menucontainer), formcontainer, true, true, 0); + gtk_widget_show(formcontainer); +} + +void pWindow::close() { + gtk_widget_destroy(window); +} + +void pWindow::move(uint x, uint y) { + gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE); + gtk_window_move(GTK_WINDOW(window), x, y); +} + +void pWindow::resize(uint width, uint height) { + gtk_widget_set_size_request(formcontainer, width, height); +} + +void pWindow::focus() { + gtk_window_present(GTK_WINDOW(window)); +} + +bool pWindow::focused() { + return gtk_window_is_active(GTK_WINDOW(window)); +} + +void pWindow::fullscreen() { + gtk_window_fullscreen(GTK_WINDOW(window)); +} + +void pWindow::unfullscreen() { + gtk_window_unfullscreen(GTK_WINDOW(window)); +} + +void pWindow::set_background_color(uint8 r, uint8 g, uint8 b) { +GdkColor color; + color.pixel = (r << 16) | (g << 8) | b; + color.red = (r << 8) | r; + color.green = (g << 8) | g; + color.blue = (b << 8) | b; + gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); + gtk_widget_modify_bg(formcontainer, GTK_STATE_NORMAL, &color); +} + +void pWindow::set_text(const char *text) { + gtk_window_set_title(GTK_WINDOW(window), text ? text : ""); +} + +void pWindow::attach(Window &window, uint x, uint y) { + window.p.owner = this; +//GTK+ does not support attaching a window to another window, +//so instead reparent the container from the child window to +//the parent window, and reposition the child window's container + gtk_widget_hide(window.p.window); + gtk_widget_hide(window.p.formcontainer); + gtk_widget_reparent(window.p.formcontainer, formcontainer); + gtk_fixed_move(GTK_FIXED(formcontainer), window.p.formcontainer, x, y); + gtk_widget_show(window.p.formcontainer); +} + +void pWindow::attach(MenuGroup &menugroup) { + gtk_menu_bar_append(menubar, menugroup.p.item); + gtk_widget_show(menubar); +} + +void pWindow::attach(FormControl &formcontrol, uint x, uint y) { + gtk_fixed_put(GTK_FIXED(formcontainer), formcontrol.p.gtk_handle(), x, y); +} + +void pWindow::move(Window &window, uint x, uint y) { + gtk_fixed_move(GTK_FIXED(formcontainer), window.p.gtk_handle(), x, y); +} + +void pWindow::move(FormControl &formcontrol, uint x, uint y) { + gtk_fixed_move(GTK_FIXED(formcontainer), formcontrol.p.gtk_handle(), x, y); +} + +void pWindow::menu_show(bool state) { + if(!menubar) return; + state ? gtk_widget_show(menubar) : gtk_widget_hide(menubar); +} + +void pWindow::menu_hide() { + menu_show(false); +} + +bool pWindow::menu_visible() { + return GTK_WIDGET_VISIBLE(menubar); +} + +pWindow::pWindow(Window &self_) : pWidget(self_), self(self_) { + owner = 0; + window = 0; + menubar = 0; + menucontainer = 0; + formcontainer = 0; +} + +/* internal */ + +GtkWidget* pWindow::gtk_handle() { + return owner ? formcontainer : window; +} diff --git a/src/lib/miu.gtk/miu.gtk.window.h b/src/lib/miu.gtk/miu.gtk.window.h new file mode 100644 index 00000000..6b2c28a4 --- /dev/null +++ b/src/lib/miu.gtk/miu.gtk.window.h @@ -0,0 +1,32 @@ +class pWindow : public pWidget { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void close(); + void move(uint x, uint y); + void resize(uint width, uint height); + void focus(); + bool focused(); + void fullscreen(); + void unfullscreen(); + void set_background_color(uint8 r, uint8 g, uint8 b); + void set_text(const char *text = ""); + void attach(Window &window, uint x, uint y); + void attach(MenuGroup &menugroup); + void attach(FormControl &formcontrol, uint x, uint y); + void move(Window &window, uint x, uint y); + void move(FormControl &formcontrol, uint x, uint y); + void menu_show(bool state = true); + void menu_hide(); + bool menu_visible(); + + Window &self; + pWindow(Window&); + +/* internal */ + pWindow *owner; //0 = no owner (default) + GtkWidget *window; + GtkWidget *menubar; + GtkWidget *menucontainer; + GtkWidget *formcontainer; + GtkWidget* gtk_handle(); +}; diff --git a/src/lib/miu.h b/src/lib/miu.h new file mode 100644 index 00000000..8ce90101 --- /dev/null +++ b/src/lib/miu.h @@ -0,0 +1,506 @@ +/* + miu + version: 0.012 (2007-12-22) + author: byuu + license: public domain +*/ + +#ifndef MIU_H +#define MIU_H + +#include "bbase.h" +#include "barray.h" +#include "bfunction.h" +#include "bkeymap.h" +#include "bstring.h" + +namespace ns_miu { + +class pMiu; +class pWidget; + class pWindow; + class pMenuControl; + class pMenuGroup; + class pMenuItem; + class pMenuCheckItem; + class pMenuRadioItem; + class pMenuSeparator; + class pFormControl; + class pFrame; + class pCanvas; + class pLabel; + class pButton; + class pCheckbox; + class pRadiobox; + class pEditbox; + class pListbox; + class pCombobox; + class pProgressbar; + class pSlider; + +#define pFriends \ + friend class pMiu; \ + friend class pWidget; \ + friend class pWindow; \ + friend class pMenuControl; \ + friend class pMenuGroup; \ + friend class pMenuItem; \ + friend class pMenuCheckItem; \ + friend class pMenuRadioItem; \ + friend class pMenuSeparator; \ + friend class pFormControl; \ + friend class pFrame; \ + friend class pCanvas; \ + friend class pLabel; \ + friend class pButton; \ + friend class pCheckbox; \ + friend class pRadiobox; \ + friend class pEditbox; \ + friend class pListbox; \ + friend class pCombobox; \ + friend class pProgressbar; \ + friend class pSlider + +class Miu; +class Widget; + class Window; + class MenuControl; + class MenuGroup; + class MenuItem; + class MenuCheckItem; + class MenuRadioItem; + class MenuSeparator; + class FormControl; + class Frame; + class Canvas; + class Label; + class Button; + class Checkbox; + class Radiobox; + class Editbox; + class Listbox; + class Combobox; + class Progressbar; + class Slider; + +typedef array MenuRadioItemGroup; +typedef array RadioboxGroup; + +struct Event { + enum Type { + Close, + Block, + KeyDown, + KeyUp, + Change, + Tick, + Activate, + } type; + uintptr_t param; + Widget *widget; + + Event(Type type_, uintptr_t param_ = 0, Widget *widget_ = 0) : + type(type_), param(param_), widget(widget_) {} +}; + +class Miu : noncopyable { +public: + void init(); + void term(); + bool run(); + bool pending(); + + bool file_load(Window *focus, char *filename, const char *filter, const char *path); + bool file_save(Window *focus, char *filename, const char *filter, const char *path); + + uint screen_width(); + uint screen_height(); + + static Miu& handle(); + Miu(); + ~Miu(); + +private: + pFriends; + pMiu &p; +}; + +Miu& miu(); + +class Widget : noncopyable { +public: + enum Type { + WidgetType, + WindowType, + MenuControlType, + MenuGroupType, + MenuItemType, + MenuCheckItemType, + MenuRadioItemType, + MenuSeparatorType, + FormControlType, + FrameType, + CanvasType, + LabelType, + ButtonType, + CheckboxType, + RadioboxType, + EditboxType, + ListboxType, + ComboboxType, + ProgressbarType, + SliderType, + } type; + + void show(bool = true); + void hide(); + bool visible(); + + uintptr_t handle(); + + Widget(); + ~Widget(); + +protected: + Widget(pWidget&); + +private: + pFriends; + pWidget &p; +}; + +class Window : private base_from_member, public Widget { +public: + enum Style { + AutoCenter = 1 << 1, + }; + + void create(uint style, uint width, uint height, const char *text = ""); + void close(); + void move(uint x, uint y); + void resize(uint width, uint height); + void focus(); + bool focused(); + void fullscreen(); + void unfullscreen(); + void set_background_color(uint8 r, uint8 g, uint8 b); + void set_text(const char *text = ""); + void attach(Window &window, uint x, uint y); + void attach(MenuGroup &menugroup); + void attach(FormControl &formcontrol, uint x, uint y); + void move(Window &window, uint x, uint y); + void move(FormControl &formcontrol, uint x, uint y); + void menu_show(bool = true); + void menu_hide(); + bool menu_visible(); + + function on_close; + function on_block; + function on_keydown; + function on_keyup; + + Window(); + +protected: + Window(pWindow&); + +private: + pFriends; + pWindow &p; +}; + +class MenuControl : public base_from_member, public Widget { +public: + void enable(bool = true); + void disable(); + bool enabled(); + + MenuControl(); + +protected: + MenuControl(pMenuControl&); + +private: + pFriends; + pMenuControl &p; +}; + +class MenuGroup : public base_from_member, public MenuControl { +public: + MenuGroup& create(const char *text); + void attach(MenuControl &menucontrol); + MenuGroup(); + +private: + pFriends; + pMenuGroup &p; +}; + +class MenuItem : public base_from_member, public MenuControl { +public: + MenuItem& create(const char *text); + MenuItem(); + + function on_tick; + +private: + pFriends; + pMenuItem &p; +}; + +class MenuCheckItem : public base_from_member, public MenuControl { +public: + MenuCheckItem& create(const char *text); + void check(bool = true); + void uncheck(); + bool checked(); + MenuCheckItem(); + + function on_tick; + +private: + pFriends; + pMenuCheckItem &p; +}; + +class MenuRadioItem : public base_from_member, public MenuControl { +public: + MenuRadioItem& create(MenuRadioItemGroup &group, const char *text); + void check(); + bool checked(); + MenuRadioItem(); + + function on_tick; + +private: + pFriends; + pMenuRadioItem &p; +}; + +class MenuSeparator : public base_from_member, public MenuControl { +public: + MenuSeparator& create(); + MenuSeparator(); + +private: + pFriends; + pMenuSeparator &p; +}; + +class FormControl : private base_from_member, public Widget { +public: + void resize(uint width, uint height); + void focus(); + bool focused(); + void enable(bool = true); + void disable(); + bool enabled(); + + FormControl(); + +protected: + FormControl(pFormControl&); + +private: + pFriends; + pFormControl &p; +}; + +class Frame : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + Frame(); + +private: + pFriends; + pFrame &p; +}; + +class Canvas : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height); + void redraw(); + uint32* buffer(); + + Canvas(); + +private: + pFriends; + pCanvas &p; +}; + +class Label : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + Label(); + +private: + pFriends; + pLabel &p; +}; + +class Button : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + function on_tick; + + Button(); + +private: + pFriends; + pButton &p; +}; + +class Checkbox : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(bool = true); + void uncheck(); + bool checked(); + + function on_tick; + + Checkbox(); + +private: + pFriends; + pCheckbox &p; +}; + +class Radiobox : private base_from_member, public FormControl { +public: + void create(RadioboxGroup &group, uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(); + bool checked(); + + function on_tick; + + Radiobox(); + +private: + pFriends; + pRadiobox &p; +}; + +class Editbox : private base_from_member, public FormControl { +public: + enum Style { + Multiline = 1 << 1, + Readonly = 1 << 2, + + HorizontalScrollAuto = 0, + HorizontalScrollAlways = 1 << 3, + HorizontalScrollNever = 1 << 4, + + VerticalScrollAuto = 0, + VerticalScrollAlways = 1 << 5, + VerticalScrollNever = 1 << 6, + }; + + void create(uint style, uint width, uint height, const char *text = ""); + uint get_text(char *text, uint length = -1U); + void set_text(const char *text = ""); + + Editbox(); + +private: + pFriends; + pEditbox &p; +}; + +class Listbox : private base_from_member, public FormControl { +public: + enum Style { + Header = 1 << 1, + + HorizontalScrollAuto = 0, + HorizontalScrollAlways = 1 << 2, + HorizontalScrollNever = 1 << 3, + + VerticalScrollAuto = 0, + VerticalScrollAlways = 1 << 4, + VerticalScrollNever = 1 << 5, + }; + + void create(uint style, uint width, uint height, const char *columns = "", const char *text = ""); + void autosize_columns(); + void set_column_width(uint column, uint width); + void add_item(const char *text); + void set_item(uint index, const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + function on_change; + function on_activate; + + Listbox(); + +private: + pFriends; + pListbox &p; +}; + +class Combobox : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void add_item(const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + function on_change; + + Combobox(); + +private: + pFriends; + pCombobox &p; +}; + +class Progressbar : private base_from_member, public FormControl { +public: + void create(uint style, uint width, uint height); + uint get_progress(); + void set_progress(uint progress); + + Progressbar(); + +private: + pFriends; + pProgressbar &p; +}; + +class Slider : private base_from_member, public FormControl { +public: + enum Style { + Horizontal = 0, + Vertical = 1 << 1, + }; + + void create(uint style, uint width, uint height, uint length); + uint get_position(); + void set_position(uint position); + + function on_change; + + Slider(); + +private: + pFriends; + pSlider &p; +}; + +#undef pFriends + +} //namespace ns_miu + +#endif //ifndef MIU_H diff --git a/src/lib/miu.win/miu.win.button.cpp b/src/lib/miu.win/miu.win.button.cpp new file mode 100644 index 00000000..618b70a3 --- /dev/null +++ b/src/lib/miu.win/miu.win.button.cpp @@ -0,0 +1,14 @@ +void pButton::create(uint style, uint width, uint height, const char *text) { + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); +} + +void pButton::set_text(const char *text) { + SetWindowText(hwnd, text ? text : ""); +} + +pButton::pButton(Button &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.button.h b/src/lib/miu.win/miu.win.button.h new file mode 100644 index 00000000..ee125e68 --- /dev/null +++ b/src/lib/miu.win/miu.win.button.h @@ -0,0 +1,8 @@ +class pButton : public pFormControl { +public: + Button &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pButton(Button&); +}; diff --git a/src/lib/miu.win/miu.win.canvas.cpp b/src/lib/miu.win/miu.win.canvas.cpp new file mode 100644 index 00000000..5431934d --- /dev/null +++ b/src/lib/miu.win/miu.win.canvas.cpp @@ -0,0 +1,54 @@ +void pCanvas::create(uint style, uint width, uint height) { + hwnd = CreateWindow("miu_window", "", WS_CHILD, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); + resize(width, height); + ShowWindow(hwnd, SW_NORMAL); +} + +void pCanvas::redraw() { +} + +uint32* pCanvas::buffer() { + return ibuffer; +} + +pCanvas::pCanvas(Canvas &self_) : pFormControl(self_), self(self_) { + ibuffer = 0; + ipitch = 0; + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; +} + +pCanvas::~pCanvas() { + safe_free(ibuffer); +} + +/* internal */ + +void pCanvas::blit() { +PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS); + EndPaint(hwnd, &ps); +} + +void pCanvas::resize(uint width, uint height) { + safe_free(ibuffer); + + ipitch = width * sizeof(uint32); + iwidth = width; + iheight = height; + ibuffer = (uint32*)malloc(ipitch * height); + memset(ibuffer, 0, ipitch * height); + + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; //use negative height to tell GDI not to flip bitmap vertically + bmi.bmiHeader.biSizeImage = ipitch * height; + + pFormControl::resize(width, height); +} diff --git a/src/lib/miu.win/miu.win.canvas.h b/src/lib/miu.win/miu.win.canvas.h new file mode 100644 index 00000000..9b39f6fb --- /dev/null +++ b/src/lib/miu.win/miu.win.canvas.h @@ -0,0 +1,17 @@ +class pCanvas : public pFormControl { +public: + void create(uint style, uint width, uint height); + void redraw(); + uint32* buffer(); + + Canvas &self; + pCanvas(Canvas&); + ~pCanvas(); + +/* internal */ + BITMAPINFO bmi; + uint32 *ibuffer; + uint ipitch, iwidth, iheight; + void blit(); + void resize(uint width, uint height); +}; diff --git a/src/lib/miu.win/miu.win.checkbox.cpp b/src/lib/miu.win/miu.win.checkbox.cpp new file mode 100644 index 00000000..db7caf3b --- /dev/null +++ b/src/lib/miu.win/miu.win.checkbox.cpp @@ -0,0 +1,29 @@ +void pCheckbox::create(uint style, uint width, uint height, const char *text) { + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_CHECKBOX, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); +} + +void pCheckbox::set_text(const char *text) { + SetWindowText(hwnd, text ? text : ""); +} + +void pCheckbox::check(bool state) { +bool prev = checked(); + SendMessage(hwnd, BM_SETCHECK, (WPARAM)(state ? TRUE : FALSE), 0); + if(prev != state) { + if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self)); + } +} + +void pCheckbox::uncheck() { + check(false); +} + +bool pCheckbox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.checkbox.h b/src/lib/miu.win/miu.win.checkbox.h new file mode 100644 index 00000000..8334b9a5 --- /dev/null +++ b/src/lib/miu.win/miu.win.checkbox.h @@ -0,0 +1,11 @@ +class pCheckbox : public pFormControl { +public: + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(bool state = true); + void uncheck(); + bool checked(); + + Checkbox &self; + pCheckbox(Checkbox&); +}; diff --git a/src/lib/miu.win/miu.win.combobox.cpp b/src/lib/miu.win/miu.win.combobox.cpp new file mode 100644 index 00000000..458d416b --- /dev/null +++ b/src/lib/miu.win/miu.win.combobox.cpp @@ -0,0 +1,28 @@ +void pCombobox::create(uint style, uint width, uint height, const char *text) { + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "", + WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, 0, width, 200, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); +} + +void pCombobox::add_item(const char *text) { + SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)text); + if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) set_selection(0); +} + +int pCombobox::get_selection() { + return SendMessage(hwnd, CB_GETCURSEL, 0, 0); +} + +void pCombobox::set_selection(int index) { + SendMessage(hwnd, CB_SETCURSEL, combobox_selection = index, 0); +} + +void pCombobox::reset() { + SendMessage(hwnd, CB_RESETCONTENT, 0, 0); +} + +pCombobox::pCombobox(Combobox &self_) : pFormControl(self_), self(self_) { + combobox_selection = 0; +} diff --git a/src/lib/miu.win/miu.win.combobox.h b/src/lib/miu.win/miu.win.combobox.h new file mode 100644 index 00000000..f7b7713d --- /dev/null +++ b/src/lib/miu.win/miu.win.combobox.h @@ -0,0 +1,14 @@ +class pCombobox : public pFormControl { +public: + Combobox &self; + void create(uint style, uint width, uint height, const char *text = ""); + void add_item(const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + pCombobox(Combobox&); + +/* internal */ + int combobox_selection; +}; diff --git a/src/lib/miu.win/miu.win.cpp b/src/lib/miu.win/miu.win.cpp new file mode 100644 index 00000000..81025313 --- /dev/null +++ b/src/lib/miu.win/miu.win.cpp @@ -0,0 +1,318 @@ +#include "miu.win.h" +#include "../miu.cpp" + +namespace ns_miu { + +long __stdcall pmiu_wndproc(HWND, UINT, WPARAM, LPARAM); + +#include "miu.win.keymap.cpp" +#include "miu.win.widget.cpp" + #include "miu.win.window.cpp" + #include "miu.win.menucontrol.cpp" + #include "miu.win.menugroup.cpp" + #include "miu.win.menuitem.cpp" + #include "miu.win.menucheckitem.cpp" + #include "miu.win.menuradioitem.cpp" + #include "miu.win.menuseparator.cpp" + #include "miu.win.formcontrol.cpp" + #include "miu.win.frame.cpp" + #include "miu.win.canvas.cpp" + #include "miu.win.label.cpp" + #include "miu.win.button.cpp" + #include "miu.win.checkbox.cpp" + #include "miu.win.radiobox.cpp" + #include "miu.win.editbox.cpp" + #include "miu.win.listbox.cpp" + #include "miu.win.combobox.cpp" + #include "miu.win.progressbar.cpp" + #include "miu.win.slider.cpp" + +void pMiu::init() { +WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = pmiu_wndproc; + wc.lpszClassName = "miu_window"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + InitCommonControls(); + default_hwnd = CreateWindow("miu_window", "", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0); + default_font = create_font("Tahoma", 9); + black_brush = CreateSolidBrush(RGB(0, 0, 0)); +} + +void pMiu::term() { + DeleteObject(black_brush); +} + +bool pMiu::run() { +MSG msg; + if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return pending(); +} + +bool pMiu::pending() { +MSG msg; + return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); +} + +bool pMiu::file_load(Window *focus, char *filename, const char *filter, const char *path) { +string dir, f; + strcpy(dir, path ? path : ""); + replace(dir, "/", "\\"); + +lstring type, part; + strcpy(f, ""); + split(type, "|", filter); + for(int i = 0; i < count(type); i++) { + split(part, ";", type[i]); + if(count(part) != 2)continue; + + strcat(f, part[0]); + strcat(f, " ("); + strcat(f, part[1]); + strcat(f, ")|"); + replace(part[1], ",", ";"); + strcat(f, part[1]); + strcat(f, "|"); + } + +char *pf = f(); + for(int i = strlen(pf) - 1; i >= 0; i--) { + if(pf[i] == '|') pf[i] = '\0'; + } + +OPENFILENAME ofn; + strcpy(filename, ""); + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = focus ? focus->p.hwnd : 0; + ofn.lpstrFilter = pf; + ofn.lpstrInitialDir = dir; + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; + ofn.lpstrDefExt = ""; + + return GetOpenFileName(&ofn); +} + +bool pMiu::file_save(Window *focus, char *filename, const char *filter, const char *path) { +string dir, f; + strcpy(dir, path ? path : ""); + replace(dir, "/", "\\"); + +lstring type, part; + strcpy(f, ""); + split(type, "|", filter); + for(int i = 0; i < count(type); i++) { + split(part, ";", type[i]); + if(count(part) != 2)continue; + + strcat(f, part[0]); + strcat(f, " ("); + strcat(f, part[1]); + strcat(f, ")|"); + replace(part[1], ",", ";"); + strcat(f, part[1]); + strcat(f, "|"); + } + +char *pf = f(); + for(int i = strlen(pf) - 1; i >= 0; i--) { + if(pf[i] == '|') pf[i] = '\0'; + } + +OPENFILENAME ofn; + strcpy(filename, ""); + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = focus ? focus->p.hwnd : 0; + ofn.lpstrFilter = pf; + ofn.lpstrInitialDir = dir; + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; + ofn.lpstrDefExt = ""; + + return GetSaveFileName(&ofn); +} + +uint pMiu::screen_width() { + return GetSystemMetrics(SM_CXSCREEN); +} + +uint pMiu::screen_height() { + return GetSystemMetrics(SM_CYSCREEN); +} + +pMiu& pMiu::handle() { + return miu().p; +} + +pMiu::pMiu(Miu &self_) : self(self_) { +} + +pMiu& pmiu() { + return pMiu::handle(); +} + +/* internal */ + +HFONT pMiu::create_font(const char *name, uint size) { +HDC hdc = GetDC(0); +HFONT font = CreateFont(-MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name); + ReleaseDC(0, hdc); + return font; +} + +Widget* pMiu::get_widget(uint instance) { +Widget *widget = 0; + for(uint i = 0; i < widget_list.size(); i++) { + if(widget_list[i]->p.instance != instance) continue; + widget = widget_list[i]; + break; + } + return widget; +} + +long __stdcall pmiu_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + return pmiu().wndproc(hwnd, msg, wparam, lparam); +} + +long pMiu::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { +pWidget *p = (pWidget*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch(msg) { + case WM_CLOSE: { + if(!p || p->self.type != Widget::WindowType) break; + Window &w = ((pWindow*)p)->self; + if(w.on_close) return (bool)w.on_close(Event(Event::Close, 0, &w)); + return TRUE; //true = destroy window + } break; + + case WM_ENTERMENULOOP: { + if(!p || p->self.type != Widget::WindowType) break; + Window &w = ((pWindow*)p)->self; + if(w.on_block) w.on_block(Event(Event::Block, 0, &w)); + } break; + + case WM_KEYDOWN: { + if(!p || p->self.type != Widget::WindowType) break; + Window &w = ((pWindow*)p)->self; + if(w.on_keydown) w.on_keydown(Event(Event::KeyDown, translate_key(wparam), &w)); + } break; + + case WM_KEYUP: { + if(!p || p->self.type != Widget::WindowType) break; + Window &w = ((pWindow*)p)->self; + if(w.on_keyup) w.on_keyup(Event(Event::KeyUp, translate_key(wparam), &w)); + } break; + + case WM_ERASEBKGND: { + if(!p) break; + HBRUSH brush = 0; + if(p->self.type == Widget::WindowType) brush = ((pWindow*)p)->background; + if(p->self.type == Widget::CanvasType) brush = pmiu().black_brush; + if(!brush) break; + RECT rc; + GetClientRect(hwnd, &rc); + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + FillRect(ps.hdc, &rc, brush); + EndPaint(hwnd, &ps); + return TRUE; + } break; + + case WM_PAINT: { + if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->blit(); + } break; + + case WM_COMMAND: { + Widget *widget = get_widget(LOWORD(wparam)); + if(!widget) break; + + switch(widget->type) { + case Widget::MenuItemType: { + MenuItem &w = (MenuItem&)*widget; + if(w.on_tick) w.on_tick(Event(Event::Tick, 0, &w)); + } break; + case Widget::MenuCheckItemType: { + MenuCheckItem &w = (MenuCheckItem&)*widget; + w.check(!w.checked()); //invert check state + } break; + case Widget::MenuRadioItemType: { + MenuRadioItem &w = (MenuRadioItem&)*widget; + w.check(); + } break; + case Widget::ButtonType: { + Button &w = (Button&)*widget; + if(w.on_tick) w.on_tick(Event(Event::Tick, 0, &w)); + } break; + case Widget::CheckboxType: { + Checkbox &w = (Checkbox&)*widget; + w.check(!w.checked()); //invert check state + } break; + case Widget::RadioboxType: { + Radiobox &w = (Radiobox&)*widget; + w.check(); + } break; + case Widget::ComboboxType: { + Combobox &combobox = (Combobox&)*widget; + if(HIWORD(wparam) == CBN_SELCHANGE) { + if(combobox.p.combobox_selection == combobox.get_selection()) break; + if(combobox.on_change) combobox.on_change(Event(Event::Change, combobox.p.combobox_selection = combobox.get_selection(), &combobox)); + } + } break; + } + } break; + + case WM_HSCROLL: + case WM_VSCROLL: { + Widget *widget = get_widget(GetDlgCtrlID((HWND)lparam)); + if(!widget) break; + + switch(widget->type) { + case Widget::SliderType: { + Slider &slider = (Slider&)*widget; + if(slider.p.slider_position == slider.get_position()) break; + if(slider.on_change) slider.on_change(Event(Event::Change, slider.p.slider_position = slider.get_position(), &slider)); + } break; + } + } break; + + case WM_NOTIFY: { + Widget *widget = get_widget(LOWORD(wparam)); + if(!widget) break; + + switch(widget->type) { + case Widget::ListboxType: { + Listbox &listbox = (Listbox&)*widget; + if(((LPNMHDR)lparam)->code == LVN_ITEMCHANGED + && ((LPNMLISTVIEW)lparam)->uChanged & LVIF_STATE + && ListView_GetItemState(listbox.p.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_FOCUSED) + && ListView_GetItemState(listbox.p.hwnd, ((LPNMLISTVIEW)lparam)->iItem, LVIS_SELECTED) + ) { + if(listbox.on_change) listbox.on_change(Event(Event::Change, listbox.get_selection(), &listbox)); + } else if(((LPNMHDR)lparam)->code == LVN_ITEMACTIVATE) { + if(listbox.on_activate) listbox.on_activate(Event(Event::Activate, listbox.get_selection(), &listbox)); + } + } break; + } + } break; + } + + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +} //namespace ns_miu diff --git a/src/lib/miu.win/miu.win.editbox.cpp b/src/lib/miu.win/miu.win.editbox.cpp new file mode 100644 index 00000000..76388572 --- /dev/null +++ b/src/lib/miu.win/miu.win.editbox.cpp @@ -0,0 +1,37 @@ +void pEditbox::create(uint style, uint width, uint height, const char *text) { +bool multiline = style & Editbox::Multiline; +bool readonly = style & Editbox::Readonly; +uint vscroll = (style & Editbox::VerticalScrollAlways) ? WS_VSCROLL : + (style & Editbox::VerticalScrollNever) ? 0 : + ES_AUTOVSCROLL; +uint hscroll = (style & Editbox::HorizontalScrollAlways) ? WS_HSCROLL : + (style & Editbox::HorizontalScrollNever) ? 0 : + ES_AUTOHSCROLL; + + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | vscroll | hscroll | + (multiline == true ? ES_MULTILINE : 0) | + (readonly == true ? ES_READONLY : 0), + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); + set_text(text); +} + +void pEditbox::set_text(const char *text) { +string temp = text ? text : ""; + replace(temp, "\r", ""); + replace(temp, "\n", "\r\n"); + SetWindowText(hwnd, temp); +} + +uint pEditbox::get_text(char *text, uint length) { + GetWindowText(hwnd, text, length); +string temp = text; + replace(temp, "\r", ""); + strcpy(text, temp); + return strlen(text); +} + +pEditbox::pEditbox(Editbox &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.editbox.h b/src/lib/miu.win/miu.win.editbox.h new file mode 100644 index 00000000..6cd3f5a6 --- /dev/null +++ b/src/lib/miu.win/miu.win.editbox.h @@ -0,0 +1,9 @@ +class pEditbox : public pFormControl { +public: + Editbox &self; + void create(uint style, uint width, uint height, const char *text = ""); + uint get_text(char *text, uint length = -1U); + void set_text(const char *text = ""); + + pEditbox(Editbox&); +}; diff --git a/src/lib/miu.win/miu.win.formcontrol.cpp b/src/lib/miu.win/miu.win.formcontrol.cpp new file mode 100644 index 00000000..3f96e298 --- /dev/null +++ b/src/lib/miu.win/miu.win.formcontrol.cpp @@ -0,0 +1,31 @@ +void pFormControl::resize(uint width, uint height) { + SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE); +} + +void pFormControl::focus() { + SetFocus(hwnd); +} + +bool pFormControl::focused() { + return true; //fixme +} + +void pFormControl::enable(bool state) { + EnableWindow(hwnd, state); +} + +void pFormControl::disable() { + enable(false); +} + +bool pFormControl::enabled() { + return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED); +} + +uintptr_t pFormControl::handle() { + return (uintptr_t)hwnd; +} + +pFormControl::pFormControl(FormControl &self_) : pWidget(self_), self(self_) { + hwnd = 0; +} diff --git a/src/lib/miu.win/miu.win.formcontrol.h b/src/lib/miu.win/miu.win.formcontrol.h new file mode 100644 index 00000000..7d4e119a --- /dev/null +++ b/src/lib/miu.win/miu.win.formcontrol.h @@ -0,0 +1,16 @@ +class pFormControl : public pWidget { +public: + virtual void resize(uint width, uint height); + void focus(); + bool focused(); + void enable(bool = true); + void disable(); + bool enabled(); + uintptr_t handle(); + + FormControl &self; + pFormControl(FormControl&); + +/* internal */ + HWND hwnd; +}; diff --git a/src/lib/miu.win/miu.win.frame.cpp b/src/lib/miu.win/miu.win.frame.cpp new file mode 100644 index 00000000..e7386977 --- /dev/null +++ b/src/lib/miu.win/miu.win.frame.cpp @@ -0,0 +1,13 @@ +void pFrame::create(uint style, uint width, uint height, const char *text) { + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); +} + +void pFrame::set_text(const char *text) { + SetWindowText(hwnd, text ? text : ""); +} + +pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.frame.h b/src/lib/miu.win/miu.win.frame.h new file mode 100644 index 00000000..742afcc9 --- /dev/null +++ b/src/lib/miu.win/miu.win.frame.h @@ -0,0 +1,8 @@ +class pFrame : public pFormControl { +public: + Frame &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pFrame(Frame&); +}; diff --git a/src/lib/miu.win/miu.win.h b/src/lib/miu.win/miu.win.h new file mode 100644 index 00000000..5cf41e29 --- /dev/null +++ b/src/lib/miu.win/miu.win.h @@ -0,0 +1,73 @@ +#ifndef MIU_WIN_H +#define MIU_WIN_H + +#undef WINVER +#undef _WIN32_WINNT +#undef _WIN32_IE + +#define WINVER 0x0501 +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0600 + +#include +#include + +#include "../miu.h" + +namespace ns_miu { + +#include "miu.win.widget.h" + #include "miu.win.window.h" + #include "miu.win.menucontrol.h" + #include "miu.win.menugroup.h" + #include "miu.win.menuitem.h" + #include "miu.win.menucheckitem.h" + #include "miu.win.menuradioitem.h" + #include "miu.win.menuseparator.h" + #include "miu.win.formcontrol.h" + #include "miu.win.frame.h" + #include "miu.win.canvas.h" + #include "miu.win.label.h" + #include "miu.win.button.h" + #include "miu.win.checkbox.h" + #include "miu.win.radiobox.h" + #include "miu.win.editbox.h" + #include "miu.win.listbox.h" + #include "miu.win.combobox.h" + #include "miu.win.progressbar.h" + #include "miu.win.slider.h" + +class pMiu { +public: + Miu &self; + void init(); + void term(); + bool run(); + bool pending(); + + bool file_load(Window *focus, char *filename, const char *filter, const char *path); + bool file_save(Window *focus, char *filename, const char *filter, const char *path); + + uint screen_width(); + uint screen_height(); + + static pMiu& handle(); + pMiu(Miu&); + +/* internal */ + HWND default_hwnd; //default parent window for all windowless controls + HFONT default_font; //default font for all controls + HBRUSH black_brush; //used for Canvas background + HFONT create_font(const char *name, uint size); + + array widget_list; + Widget* get_widget(uint instance); + long wndproc(HWND, UINT, WPARAM, LPARAM); + uint16 translate_key(uint key); +}; + +pMiu& pmiu(); + +} //namsepace ns_miu + +#endif //ifndef MIU_WIN_H diff --git a/src/lib/miu.win/miu.win.keymap.cpp b/src/lib/miu.win/miu.win.keymap.cpp new file mode 100644 index 00000000..221a2894 --- /dev/null +++ b/src/lib/miu.win/miu.win.keymap.cpp @@ -0,0 +1,67 @@ +uint16 pMiu::translate_key(uint key) { + switch(key) { + case VK_ESCAPE: return keymap::esc; + + case VK_F1: return keymap::f1; + case VK_F2: return keymap::f2; + case VK_F3: return keymap::f3; + case VK_F4: return keymap::f4; + case VK_F5: return keymap::f5; + case VK_F6: return keymap::f6; + case VK_F7: return keymap::f7; + case VK_F8: return keymap::f8; + case VK_F9: return keymap::f9; + case VK_F10: return keymap::f10; + case VK_F11: return keymap::f11; + case VK_F12: return keymap::f12; + + case VK_TAB: return keymap::tab; + case VK_RETURN: return keymap::enter; + case VK_SPACE: return keymap::space; + + case '0': return keymap::num_0; + case '1': return keymap::num_1; + case '2': return keymap::num_2; + case '3': return keymap::num_3; + case '4': return keymap::num_4; + case '5': return keymap::num_5; + case '6': return keymap::num_6; + case '7': return keymap::num_7; + case '8': return keymap::num_8; + case '9': return keymap::num_9; + + case 'A': return keymap::a; + case 'B': return keymap::b; + case 'C': return keymap::c; + case 'D': return keymap::d; + case 'E': return keymap::e; + case 'F': return keymap::f; + case 'G': return keymap::g; + case 'H': return keymap::h; + case 'I': return keymap::i; + case 'J': return keymap::j; + case 'K': return keymap::k; + case 'L': return keymap::l; + case 'M': return keymap::m; + case 'N': return keymap::n; + case 'O': return keymap::o; + case 'P': return keymap::p; + case 'Q': return keymap::q; + case 'R': return keymap::r; + case 'S': return keymap::s; + case 'T': return keymap::t; + case 'U': return keymap::u; + case 'V': return keymap::v; + case 'W': return keymap::w; + case 'X': return keymap::x; + case 'Y': return keymap::y; + case 'Z': return keymap::z; + + case VK_UP: return keymap::up; + case VK_DOWN: return keymap::down; + case VK_LEFT: return keymap::left; + case VK_RIGHT: return keymap::right; + } + + return keymap::none; +} diff --git a/src/lib/miu.win/miu.win.label.cpp b/src/lib/miu.win/miu.win.label.cpp new file mode 100644 index 00000000..48d34ea7 --- /dev/null +++ b/src/lib/miu.win/miu.win.label.cpp @@ -0,0 +1,13 @@ +void pLabel::create(uint style, uint width, uint height, const char *text) { + hwnd = CreateWindow("STATIC", text ? text : "", WS_CHILD | WS_VISIBLE, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); +} + +void pLabel::set_text(const char *text) { + SetWindowText(hwnd, text ? text : ""); +} + +pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.label.h b/src/lib/miu.win/miu.win.label.h new file mode 100644 index 00000000..5c4368b7 --- /dev/null +++ b/src/lib/miu.win/miu.win.label.h @@ -0,0 +1,8 @@ +class pLabel : public pFormControl { +public: + Label &self; + void create(uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + + pLabel(Label&); +}; diff --git a/src/lib/miu.win/miu.win.listbox.cpp b/src/lib/miu.win/miu.win.listbox.cpp new file mode 100644 index 00000000..b97fb647 --- /dev/null +++ b/src/lib/miu.win/miu.win.listbox.cpp @@ -0,0 +1,92 @@ +void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) { +bool header = style & Listbox::Header; +uint hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL : + (style & Listbox::HorizontalScrollNever) ? 0 : + 0; +uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL : + (style & Listbox::VerticalScrollNever) ? 0 : + 0; + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "", + WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll | + (header ? 0 : LVS_NOCOLUMNHEADER), + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); + ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT); + +lstring list; + split(list, "\t", columns ? columns : ""); + column_count = count(list); + for(uint i = 0; i < count(list); i++) { + LVCOLUMN column; + column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM; + column.fmt = LVCFMT_LEFT; + column.iSubItem = count(list); + column.pszText = (LPSTR)list[i](); + ListView_InsertColumn(hwnd, i, &column); + } + + if(text && *text) { + split(list, "\n", text); + for(uint i = 0; i < count(list); i++) add_item(list[i]); + } + autosize_columns(); +} + +void pListbox::autosize_columns() { + for(uint i = 0; i < column_count; i++) { + ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER); + } +} + +void pListbox::set_column_width(uint column, uint width) { + ListView_SetColumnWidth(hwnd, column, width); +} + +void pListbox::add_item(const char *text) { +lstring list; + split(list, "\t", text ? text : ""); +LVITEM item; +uint pos = ListView_GetItemCount(hwnd); + item.mask = LVIF_TEXT; + item.iItem = pos; + item.iSubItem = 0; + item.pszText = (LPSTR)list[0](); + ListView_InsertItem(hwnd, &item); + + for(uint i = 1; i < count(list); i++) { + ListView_SetItemText(hwnd, pos, i, (LPSTR)list[i]()); + } +} + +void pListbox::set_item(uint index, const char *text) { +lstring list; + split(list, "\t", text ? text : ""); + for(uint i = 0; i < count(list); i++) { + ListView_SetItemText(hwnd, index, i, list[i]()); + } +} + +int pListbox::get_selection() { +uint count = ListView_GetItemCount(hwnd); + for(uint i = 0; i < count; i++) { + if(ListView_GetItemState(hwnd, i, LVIS_SELECTED)) return i; + } + return -1; +} + +void pListbox::set_selection(int index) { +uint count = ListView_GetItemCount(hwnd); + for(uint i = 0; i < count; i++) { + ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0); + ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0); + } +} + +void pListbox::reset() { + ListView_DeleteAllItems(hwnd); +} + +pListbox::pListbox(Listbox &self_) : pFormControl(self_), self(self_) { + column_count = 0; +} diff --git a/src/lib/miu.win/miu.win.listbox.h b/src/lib/miu.win/miu.win.listbox.h new file mode 100644 index 00000000..e36b3a4d --- /dev/null +++ b/src/lib/miu.win/miu.win.listbox.h @@ -0,0 +1,17 @@ +class pListbox : public pFormControl { +public: + Listbox &self; + void create(uint style, uint width, uint height, const char *columns = "", const char *text = ""); + void autosize_columns(); + void set_column_width(uint column, uint width); + void add_item(const char *text); + void set_item(uint index, const char *text); + int get_selection(); + void set_selection(int index); + void reset(); + + pListbox(Listbox&); + +/* internal */ + uint column_count; +}; diff --git a/src/lib/miu.win/miu.win.menucheckitem.cpp b/src/lib/miu.win/miu.win.menucheckitem.cpp new file mode 100644 index 00000000..b327ce8f --- /dev/null +++ b/src/lib/miu.win/miu.win.menucheckitem.cpp @@ -0,0 +1,27 @@ +void pMenuCheckItem::create(const char *text_) { + text = strdup(text_); +} + +void pMenuCheckItem::check(bool state) { +bool prev = checked(); + CheckMenuItem(parent, instance, state ? MF_CHECKED : MF_UNCHECKED); + if(prev != state) { + if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self)); + } +} + +void pMenuCheckItem::uncheck() { + check(false); +} + +bool pMenuCheckItem::checked() { +MENUITEMINFO info; + memset(&info, 0, sizeof info); + info.cbSize = sizeof info; + info.fMask = MIIM_STATE; + GetMenuItemInfo(parent, instance, false, &info); + return info.fState & MFS_CHECKED; +} + +pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.menucheckitem.h b/src/lib/miu.win/miu.win.menucheckitem.h new file mode 100644 index 00000000..9bcacade --- /dev/null +++ b/src/lib/miu.win/miu.win.menucheckitem.h @@ -0,0 +1,10 @@ +class pMenuCheckItem : public pMenuControl { +public: + void create(const char *text = ""); + void check(bool state = true); + void uncheck(); + bool checked(); + + MenuCheckItem &self; + pMenuCheckItem(MenuCheckItem&); +}; diff --git a/src/lib/miu.win/miu.win.menucontrol.cpp b/src/lib/miu.win/miu.win.menucontrol.cpp new file mode 100644 index 00000000..9e118af3 --- /dev/null +++ b/src/lib/miu.win/miu.win.menucontrol.cpp @@ -0,0 +1,25 @@ +void pMenuControl::enable(bool state) { + EnableMenuItem(parent, instance, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED)); +} + +void pMenuControl::disable() { + enable(false); +} + +bool pMenuControl::enabled() { +MENUITEMINFO info; + memset(&info, 0, sizeof info); + info.cbSize = sizeof info; + info.fMask = MIIM_STATE; + GetMenuItemInfo(parent, instance, false, &info); + return info.fState & MFS_ENABLED; +} + +pMenuControl::pMenuControl(MenuControl &self_) : pWidget(self_), self(self_) { + parent = 0; + text = 0; +} + +pMenuControl::~pMenuControl() { + safe_free(text); +} diff --git a/src/lib/miu.win/miu.win.menucontrol.h b/src/lib/miu.win/miu.win.menucontrol.h new file mode 100644 index 00000000..5dc179b9 --- /dev/null +++ b/src/lib/miu.win/miu.win.menucontrol.h @@ -0,0 +1,14 @@ +class pMenuControl : public pWidget { +public: + void enable(bool = true); + void disable(); + bool enabled(); + + MenuControl &self; + pMenuControl(MenuControl&); + virtual ~pMenuControl(); + +/* internal */ + HMENU parent; + char *text; +}; diff --git a/src/lib/miu.win/miu.win.menugroup.cpp b/src/lib/miu.win/miu.win.menugroup.cpp new file mode 100644 index 00000000..b1b4a2a7 --- /dev/null +++ b/src/lib/miu.win/miu.win.menugroup.cpp @@ -0,0 +1,31 @@ +void pMenuGroup::create(const char *text_) { + group = CreatePopupMenu(); + text = strdup(text_); +} + +void pMenuGroup::attach(MenuControl &menucontrol) { + switch(menucontrol.type) { + case Widget::MenuGroupType: { + AppendMenu(group, MF_STRING | MF_POPUP, (uint)((MenuGroup&)menucontrol).p.group, menucontrol.p.text); + } break; + + case Widget::MenuItemType: + case Widget::MenuCheckItemType: + case Widget::MenuRadioItemType: { + AppendMenu(group, MF_STRING, menucontrol.p.instance, menucontrol.p.text); + if(menucontrol.type == Widget::MenuRadioItemType && ((MenuRadioItem&)menucontrol).p.create_checked) { + CheckMenuItem(group, menucontrol.p.instance, MF_CHECKED); + } + } break; + + case Widget::MenuSeparatorType: { + AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, ""); + } break; + } + + menucontrol.p.parent = group; +} + +pMenuGroup::pMenuGroup(MenuGroup &self_) : pMenuControl(self_), self(self_) { + group = 0; +} diff --git a/src/lib/miu.win/miu.win.menugroup.h b/src/lib/miu.win/miu.win.menugroup.h new file mode 100644 index 00000000..da3bdaed --- /dev/null +++ b/src/lib/miu.win/miu.win.menugroup.h @@ -0,0 +1,11 @@ +class pMenuGroup : public pMenuControl { +public: + MenuGroup &self; + void create(const char *text); + void attach(MenuControl &menucontrol); + + pMenuGroup(MenuGroup&); + +/* internal */ + HMENU group; +}; diff --git a/src/lib/miu.win/miu.win.menuitem.cpp b/src/lib/miu.win/miu.win.menuitem.cpp new file mode 100644 index 00000000..98ea66c2 --- /dev/null +++ b/src/lib/miu.win/miu.win.menuitem.cpp @@ -0,0 +1,6 @@ +void pMenuItem::create(const char *text_) { + text = strdup(text_); +} + +pMenuItem::pMenuItem(MenuItem &self_) : pMenuControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.menuitem.h b/src/lib/miu.win/miu.win.menuitem.h new file mode 100644 index 00000000..715f8cc3 --- /dev/null +++ b/src/lib/miu.win/miu.win.menuitem.h @@ -0,0 +1,7 @@ +class pMenuItem : public pMenuControl { +public: + void create(const char *text = ""); + + MenuItem &self; + pMenuItem(MenuItem&); +}; diff --git a/src/lib/miu.win/miu.win.menuradioitem.cpp b/src/lib/miu.win/miu.win.menuradioitem.cpp new file mode 100644 index 00000000..0b69f6b3 --- /dev/null +++ b/src/lib/miu.win/miu.win.menuradioitem.cpp @@ -0,0 +1,26 @@ +void pMenuRadioItem::create(MenuRadioItemGroup &group_, const char *text_) { + group = group_; + text = strdup(text_); + create_checked = (group[0] == &self); +} + +void pMenuRadioItem::check() { +bool prev = checked(); + for(uint i = 0; i < group.size(); i++) { + CheckMenuItem(parent, group[i]->p.instance, (group[i] == &self) ? MF_CHECKED : MF_UNCHECKED); + } + if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self)); +} + +bool pMenuRadioItem::checked() { +MENUITEMINFO info; + memset(&info, 0, sizeof info); + info.cbSize = sizeof info; + info.fMask = MIIM_STATE; + GetMenuItemInfo(parent, instance, false, &info); + return info.fState & MFS_CHECKED; +} + +pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) { + create_checked = false; +} diff --git a/src/lib/miu.win/miu.win.menuradioitem.h b/src/lib/miu.win/miu.win.menuradioitem.h new file mode 100644 index 00000000..2776ff64 --- /dev/null +++ b/src/lib/miu.win/miu.win.menuradioitem.h @@ -0,0 +1,13 @@ +class pMenuRadioItem : public pMenuControl { +public: + void create(MenuRadioItemGroup &group, const char *text = ""); + void check(); + bool checked(); + + MenuRadioItem &self; + pMenuRadioItem(MenuRadioItem&); + +/* internal */ + MenuRadioItemGroup group; + bool create_checked; +}; diff --git a/src/lib/miu.win/miu.win.menuseparator.cpp b/src/lib/miu.win/miu.win.menuseparator.cpp new file mode 100644 index 00000000..4fa3e0c1 --- /dev/null +++ b/src/lib/miu.win/miu.win.menuseparator.cpp @@ -0,0 +1,5 @@ +void pMenuSeparator::create() { +} + +pMenuSeparator::pMenuSeparator(MenuSeparator &self_) : pMenuControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.menuseparator.h b/src/lib/miu.win/miu.win.menuseparator.h new file mode 100644 index 00000000..c270b58b --- /dev/null +++ b/src/lib/miu.win/miu.win.menuseparator.h @@ -0,0 +1,7 @@ +class pMenuSeparator : public pMenuControl { +public: + MenuSeparator &self; + void create(); + + pMenuSeparator(MenuSeparator&); +}; diff --git a/src/lib/miu.win/miu.win.progressbar.cpp b/src/lib/miu.win/miu.win.progressbar.cpp new file mode 100644 index 00000000..6518b28e --- /dev/null +++ b/src/lib/miu.win/miu.win.progressbar.cpp @@ -0,0 +1,20 @@ +void pProgressbar::create(uint style, uint width, uint height) { + hwnd = CreateWindow(PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | PBS_SMOOTH, + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); +} + +uint pProgressbar::get_progress() { +uint progress = SendMessage(hwnd, PBM_GETPOS, 0, 0); + return max(0, min(progress, 100)); +} + +void pProgressbar::set_progress(uint progress) { + progress = max(0, min(progress, 100)); + SendMessage(hwnd, PBM_SETPOS, (WPARAM)progress, 0); +} + +pProgressbar::pProgressbar(Progressbar &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.progressbar.h b/src/lib/miu.win/miu.win.progressbar.h new file mode 100644 index 00000000..d3ca64c4 --- /dev/null +++ b/src/lib/miu.win/miu.win.progressbar.h @@ -0,0 +1,9 @@ +class pProgressbar : public pFormControl { +public: + Progressbar &self; + void create(uint style, uint width, uint height); + uint get_progress(); + void set_progress(uint progress); + + pProgressbar(Progressbar&); +}; diff --git a/src/lib/miu.win/miu.win.radiobox.cpp b/src/lib/miu.win/miu.win.radiobox.cpp new file mode 100644 index 00000000..f857db1d --- /dev/null +++ b/src/lib/miu.win/miu.win.radiobox.cpp @@ -0,0 +1,26 @@ +void pRadiobox::create(RadioboxGroup &group_, uint style, uint width, uint height, const char *text) { + group = group_; + hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON, + 0, 0, width, height, miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, WM_SETFONT, (WPARAM)miu().p.default_font, 0); + if(group[0] == &self) check(); +} + +void pRadiobox::set_text(const char *text) { + SetWindowText(hwnd, text); +} + +void pRadiobox::check() { +bool prev = checked(); + for(uint i = 0; i < group.size(); i++) { + SendMessage(group[i]->p.hwnd, BM_SETCHECK, (WPARAM)(group[i] == &self), 0); + } + if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self)); +} + +bool pRadiobox::checked() { + return SendMessage(hwnd, BM_GETCHECK, 0, 0); +} + +pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self_), self(self_) { +} diff --git a/src/lib/miu.win/miu.win.radiobox.h b/src/lib/miu.win/miu.win.radiobox.h new file mode 100644 index 00000000..40dae4f7 --- /dev/null +++ b/src/lib/miu.win/miu.win.radiobox.h @@ -0,0 +1,13 @@ +class pRadiobox : public pFormControl { +public: + void create(RadioboxGroup &group, uint style, uint width, uint height, const char *text = ""); + void set_text(const char *text = ""); + void check(); + bool checked(); + + Radiobox &self; + pRadiobox(Radiobox&); + +/* internal */ + RadioboxGroup group; +}; diff --git a/src/lib/miu.win/miu.win.slider.cpp b/src/lib/miu.win/miu.win.slider.cpp new file mode 100644 index 00000000..e41ad000 --- /dev/null +++ b/src/lib/miu.win/miu.win.slider.cpp @@ -0,0 +1,24 @@ +void pSlider::create(uint style, uint width, uint height, uint length) { + if(length < 1) length = 1; + + hwnd = CreateWindow(TRACKBAR_CLASS, "", + WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_BOTH | + (style & Slider::Vertical ? TBS_VERT : TBS_HORZ), + 0, 0, width, height, + miu().p.default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); + SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1)); + SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3)); + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)0); +} + +uint pSlider::get_position() { + return SendMessage(hwnd, TBM_GETPOS, 0, 0); +} + +void pSlider::set_position(uint position) { + SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)(slider_position = position)); +} + +pSlider::pSlider(Slider &self_) : pFormControl(self_), self(self_) { + slider_position = 0; +} diff --git a/src/lib/miu.win/miu.win.slider.h b/src/lib/miu.win/miu.win.slider.h new file mode 100644 index 00000000..17b11e57 --- /dev/null +++ b/src/lib/miu.win/miu.win.slider.h @@ -0,0 +1,12 @@ +class pSlider : public pFormControl { +public: + Slider &self; + void create(uint style, uint width, uint height, uint length); + uint get_position(); + void set_position(uint position); + + pSlider(Slider&); + +/* internal */ + uint slider_position; +}; diff --git a/src/lib/miu.win/miu.win.widget.cpp b/src/lib/miu.win/miu.win.widget.cpp new file mode 100644 index 00000000..ea6b74a5 --- /dev/null +++ b/src/lib/miu.win/miu.win.widget.cpp @@ -0,0 +1,27 @@ +void pWidget::show(bool state) { +} + +void pWidget::hide() { +} + +bool pWidget::visible() { + return true; +} + +uintptr_t pWidget::handle() { + return 0; +} + +pWidget::pWidget(Widget &self_) : self(self_) { + instance = instance_counter++; + miu().p.widget_list.add(&self); +} + +pWidget::~pWidget() { +} + +/* internal */ + +//100 is the standard start index for control IDs in the Windows API +//avoids duplicate IDs when they are not explicitly set (and are thus 0) +uint pWidget::instance_counter = 100; diff --git a/src/lib/miu.win/miu.win.widget.h b/src/lib/miu.win/miu.win.widget.h new file mode 100644 index 00000000..5354a262 --- /dev/null +++ b/src/lib/miu.win/miu.win.widget.h @@ -0,0 +1,19 @@ +class pWidget { +public: + Widget &self; + virtual void show(bool = true); + virtual void hide(); + virtual bool visible(); + virtual uintptr_t handle(); + + pWidget(Widget&); + virtual ~pWidget(); + +/* internal */ + +//Windows API controls often require a unique ID for each control to identify it +//Simulate this with an instance counter, so that each Widget has a unique ID +//In each pWidget() constructor, instance = instance_counter++; is called + static uint instance_counter; + uint instance; +}; diff --git a/src/lib/miu.win/miu.win.window.cpp b/src/lib/miu.win/miu.win.window.cpp new file mode 100644 index 00000000..460a37d1 --- /dev/null +++ b/src/lib/miu.win/miu.win.window.cpp @@ -0,0 +1,183 @@ +void pWindow::create(uint style, uint width_, uint height_, const char *text) { + auto_center = style & Window::AutoCenter; + +RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + + hwnd = CreateWindowEx(0, "miu_window", text ? text : "", + WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, + rc.left, rc.top, width_, height_, + 0, 0, GetModuleHandle(0), 0); + hwndr = CreateWindowEx(0, "miu_window", text ? text : "", + WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, + rc.left, rc.top, width_, height_, + 0, 0, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this); + menu = CreateMenu(); + + resize(width_, height_); +} + +void pWindow::close() { + CloseWindow(hwnd); +} + +void pWindow::move(uint x, uint y) { + if(is_fullscreen == true) return; + SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +void pWindow::resize(uint width_, uint height_) { + if(is_fullscreen == true) { + width_ = GetSystemMetrics(SM_CXSCREEN); + height_ = GetSystemMetrics(SM_CYSCREEN); + SetWindowPos(hwnd, 0, 0, 0, width_, height_, SWP_NOZORDER | SWP_FRAMECHANGED); + return; + } + + width = width_; + height = height_; + +//set requested window size to hidden window, calculate the difference between +//requested and actual client size area, and then adjust width so that new +//width, height values will set requested client area size. +//AdjustWindowRect() does not properly calculate the height of multi-line menus, +//and thusly is not used. + SetWindowPos(hwndr, 0, 0, 0, width_, height_, SWP_NOMOVE | SWP_NOZORDER); +RECT rc; + GetClientRect(hwndr, &rc); + width_ += width_ - (rc.right - rc.left); + height_ += height_ - (rc.bottom - rc.top); + +int x = (GetSystemMetrics(SM_CXSCREEN) - width_) / 2; +int y = (GetSystemMetrics(SM_CYSCREEN) - height_) / 2; + +//if window is larger than screen, force window to top-left corner + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + if(x < rc.left) x = rc.left; + if(y < rc.top) y = rc.top; + + SetWindowPos(hwnd, 0, x, y, width_, height_, (auto_center ? 0 : SWP_NOMOVE) | SWP_NOZORDER | SWP_FRAMECHANGED); +} + +void pWindow::focus() { + if(visible() == false) show(); + SetFocus(hwnd); +} + +bool pWindow::focused() { + return GetForegroundWindow() == hwnd; +} + +void pWindow::show(bool state) { + if(state == true) { + ShowWindow(hwnd, SW_NORMAL); + SetFocus(hwnd); + } else { + ShowWindow(hwnd, SW_HIDE); + } +} + +void pWindow::hide() { + show(false); +} + +bool pWindow::visible() { + return GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE; +} + +void pWindow::fullscreen() { + if(is_fullscreen == true) return; + is_fullscreen = true; + SetWindowLong(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); + resize(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); +} + +void pWindow::unfullscreen() { + if(is_fullscreen == false) return; + is_fullscreen = false; + SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE); + resize(width, height); +} + +void pWindow::set_background_color(uint8 r, uint8 g, uint8 b) { + if(background) DeleteObject(background); + background = CreateSolidBrush(RGB(r, g, b)); +} + +void pWindow::set_text(const char *text) { + SetWindowText(hwnd, text); +} + +void pWindow::attach(Window &window, uint x, uint y) { + if(!window.p.hwnd) return; + +//toplevel window size is larger, because it includes window borders +//read size of window without window borders, and resize upon attach +RECT rc; + GetClientRect(window.p.hwnd, &rc); + + ShowWindow(window.p.hwnd, SW_HIDE); + SetWindowLong(window.p.hwnd, GWL_STYLE, WS_CHILD); + SetParent(window.p.hwnd, hwnd); + SetWindowPos(window.p.hwnd, 0, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_FRAMECHANGED); + ShowWindow(window.p.hwnd, SW_NORMAL); +} + +void pWindow::attach(MenuGroup &menugroup) { + AppendMenu(menu, MF_STRING | MF_POPUP, (uint)menugroup.p.group, menugroup.p.text); + if(menu_visible() == false) menu_show(); +} + +void pWindow::attach(FormControl &formcontrol, uint x, uint y) { + SetWindowPos(formcontrol.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetParent(formcontrol.p.hwnd, hwnd); +} + +void pWindow::move(Window &window, uint x, uint y) { + SetWindowPos(window.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +void pWindow::move(FormControl &formcontrol, uint x, uint y) { + SetWindowPos(formcontrol.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +void pWindow::menu_show(bool state) { + if(!menu) return; + if(state) { + SetMenu(hwnd, menu); + SetMenu(hwndr, menu); + } else { + SetMenu(hwnd, 0); + SetMenu(hwndr, 0); + } + resize(width, height); +} + +void pWindow::menu_hide() { + menu_show(false); +} + +bool pWindow::menu_visible() { + if(!menu) return false; + return GetMenu(hwnd); +} + +uintptr_t pWindow::handle() { + return (uintptr_t)hwnd; +} + +pWindow::pWindow(Window &self_) : pWidget(self_), self(self_) { + hwnd = 0; + hwndr = 0; + menu = 0; + background = 0; + is_fullscreen = false; + auto_center = false; + width = 0; + height = 0; +} + +pWindow::~pWindow() { + if(background) DeleteObject(background); +} diff --git a/src/lib/miu.win/miu.win.window.h b/src/lib/miu.win/miu.win.window.h new file mode 100644 index 00000000..eeefebc2 --- /dev/null +++ b/src/lib/miu.win/miu.win.window.h @@ -0,0 +1,39 @@ +class pWindow : public pWidget { +public: + Window &self; + void create(uint style, uint width, uint height, const char *text = ""); + void close(); + void move(uint x, uint y); + void resize(uint width, uint height); + void focus(); + bool focused(); + void fullscreen(); + void unfullscreen(); + void set_background_color(uint8 r, uint8 g, uint8 b); + void set_text(const char *text = ""); + void attach(Window &window, uint x, uint y); + void attach(MenuGroup &menugroup); + void attach(FormControl &formcontrol, uint x, uint y); + void move(Window &window, uint x, uint y); + void move(FormControl &formcontrol, uint x, uint y); + void menu_show(bool = true); + void menu_hide(); + bool menu_visible(); + uintptr_t handle(); + + pWindow(Window&); + ~pWindow(); + +/* internal */ + HWND hwnd; + HWND hwndr; //hidden window, used as resize assistant + HMENU menu; + HBRUSH background; + bool is_fullscreen; + bool auto_center; + uint width, height; + + void show(bool = true); + void hide(); + bool visible(); +}; diff --git a/src/lib/opgen.cpp b/src/lib/tool/opgen.cpp similarity index 94% rename from src/lib/opgen.cpp rename to src/lib/tool/opgen.cpp index 487631a6..ed50771d 100644 --- a/src/lib/opgen.cpp +++ b/src/lib/tool/opgen.cpp @@ -1,3 +1,5 @@ +/* broken -- need to port libstring to bstring */ + #include "libbase.h" #include "libstring.h" #include "libstring.cpp" diff --git a/src/lib/opgen_s.cpp b/src/lib/tool/opgen_s.cpp similarity index 93% rename from src/lib/opgen_s.cpp rename to src/lib/tool/opgen_s.cpp index 054b705d..2ffd360d 100644 --- a/src/lib/opgen_s.cpp +++ b/src/lib/tool/opgen_s.cpp @@ -1,3 +1,5 @@ +/* broken -- need to port libstring to bstring */ + #include "libbase.h" #include "libstring.h" #include "libstring.cpp" diff --git a/src/lib/opgen_so.cpp b/src/lib/tool/opgen_so.cpp similarity index 94% rename from src/lib/opgen_so.cpp rename to src/lib/tool/opgen_so.cpp index 13d0bdd2..1f948bd9 100644 --- a/src/lib/opgen_so.cpp +++ b/src/lib/tool/opgen_so.cpp @@ -1,3 +1,5 @@ +/* broken -- need to port libstring to bstring */ + #include "libbase.h" #include "libstring.h" #include "libstring.cpp" diff --git a/src/memory/memory.h b/src/memory/memory.h index 904d41c6..eb33ff44 100644 --- a/src/memory/memory.h +++ b/src/memory/memory.h @@ -76,9 +76,17 @@ enum MapMode { MapDirect, MapLinear, MapShadow }; Memory &access, uint offset = 0, uint size = 0); alwaysinline uint8 read(uint addr) { + #if defined(CHEAT_SYSTEM) + if(cheat.enabled() && cheat.exists(addr)) { + uint8 r; + if(cheat.read(addr, r)) return r; + } + #endif + Page &p = page[addr >> 8]; return p.access->read(p.offset + addr); } + alwaysinline void write(uint addr, uint8 data) { Page &p = page[addr >> 8]; return p.access->write(p.offset + addr, data); diff --git a/src/ui/audio/ao.cpp b/src/ui/audio/ao.cpp deleted file mode 100644 index d962b147..00000000 --- a/src/ui/audio/ao.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "ao.h" - -uint AudioAO::object_count = 0; - -void AudioAO::sample(uint16 l_sample, uint16 r_sample) { -uint32 samp = (l_sample << 0) + (r_sample << 16); - ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian -} - -void AudioAO::update_frequency() { - Audio::update_frequency(); - driver_format.rate = frequency; - if(audio_device) { - term(); - init(); - } -} - -void AudioAO::init() { - audio_device = ao_open_live(driver_id, &driver_format, 0); - if(audio_device) { - ao_info *di = ao_driver_info(driver_id); - } else { - dprintf("libao: failed to open audio device.\n"); - } -} - -void AudioAO::term() { - if(audio_device) { - ao_close(audio_device); - audio_device = 0; - } -} - -AudioAO::AudioAO(const char *driver) { - if(!object_count++) { - ao_initialize(); - } - - driver_id = (driver && *driver) ? ao_driver_id(driver) : ao_default_driver_id(); - if(driver_id < 0) { driver_id = ao_default_driver_id(); } //fallback on default if driver doesn't exist - driver_format.bits = 16; - driver_format.channels = 2; - driver_format.rate = frequency; - driver_format.byte_format = AO_FMT_LITTLE; - audio_device = 0; -} - -AudioAO::~AudioAO() { - if(audio_device) { - ao_close(audio_device); - } - if(!--object_count) { - ao_shutdown(); - } -} diff --git a/src/ui/audio/ao.h b/src/ui/audio/ao.h deleted file mode 100644 index 1f44f82e..00000000 --- a/src/ui/audio/ao.h +++ /dev/null @@ -1,19 +0,0 @@ -#include - -class AudioAO : public Audio { -private: -static uint object_count; - -int driver_id; -ao_sample_format driver_format; -ao_device *audio_device; - -public: - void sample(uint16 l_sample, uint16 r_sample); - void update_frequency(); - void init(); - void term(); - - AudioAO(const char *driver = 0); - ~AudioAO(); -}; diff --git a/src/ui/audio/audio.cpp b/src/ui/audio/audio.cpp deleted file mode 100644 index 2201b46f..00000000 --- a/src/ui/audio/audio.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "audio.h" - -void Audio::update_frequency() { -uint freq = config::audio.frequency; -uint speed = config::system.speed_normal; - switch(uint(config::system.speed)) { - case 1: speed = config::system.speed_slowest; break; - case 2: speed = config::system.speed_slow; break; - case 3: speed = config::system.speed_normal; break; - case 4: speed = config::system.speed_fast; break; - case 5: speed = config::system.speed_fastest; break; - } -//convert speed setting from integer to fp-percentage and adjust default frequency by this value - frequency = uint( double(speed) * 0.01 * double(freq) ); -//convert latency from time in ms to time in samples, divide by 3 for ring buffers - latency = uint( (double(frequency) / 1000.0) * (double(config::audio.latency) / 3.0) ); -} - -Audio::Audio() { - update_frequency(); -} diff --git a/src/ui/audio/audio.h b/src/ui/audio/audio.h deleted file mode 100644 index 8086e6db..00000000 --- a/src/ui/audio/audio.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef AUDIO_H -#define AUDIO_H - -class Audio { -public: -uint frequency, latency; - virtual void sample(uint16 l_sample, uint16 r_sample) {} - virtual void update_frequency(); - virtual void clear_audio() {} - virtual void init() {} - virtual void term() {} - - Audio(); -} *uiAudio; - -#endif diff --git a/src/ui/audio/dsound.cpp b/src/ui/audio/dsound.cpp deleted file mode 100644 index 5e3ac2b2..00000000 --- a/src/ui/audio/dsound.cpp +++ /dev/null @@ -1,143 +0,0 @@ -void AudioDS::sample(uint16 l_sample, uint16 r_sample) { - data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16); - if(data.buffer_pos < latency)return; - -DWORD ring_pos, pos, size; - for(;;) { - dsb_b->GetCurrentPosition(&pos, 0); - ring_pos = pos / data.ring_size; - if( - config::system.regulate_speed == false || - config::audio.synchronize == false || - ring_pos != data.ring_pos - ) break; - Sleep(1); - } - - data.ring_pos = ring_pos; -void *output; - if(dsb_b->Lock(((data.ring_pos + 2) % 3) * data.ring_size, - data.ring_size, &output, &size, 0, 0, 0) == DS_OK) { - //Audio::resample_hermite((uint32*)output, data.buffer, latency, data.buffer_pos); - memcpy(output, data.buffer, data.ring_size); - dsb_b->Unlock(output, size, 0, 0); - } - - data.buffer_pos = 0; -} - -/*void AudioDS::sample(uint16 l_sample, uint16 r_sample) { - data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16); -//if(data.buffer_pos & 15)return; - -DWORD ring_pos, pos, size; - dsb_b->GetCurrentPosition(&pos, 0); - ring_pos = pos / data.ring_size; - if(ring_pos == data.ring_pos)return; - data.ring_pos = ring_pos; - -void *output; - if(dsb_b->Lock(((data.ring_pos + 2) % 3) * data.ring_size, - data.ring_size, &output, &size, 0, 0, 0) == DS_OK) { - Audio::resample_hermite((uint32*)output, data.buffer, latency, data.buffer_pos); - //memcpy(output, data.buffer, data.ring_size); - dsb_b->Unlock(output, size, 0, 0); - } - - dprintf("* %10d -> %10d / %10I64d", data.buffer_pos, latency, scheduler.clock.cpusmp); - - data.buffer_pos = 0; -}*/ - -void AudioDS::update_frequency() { - Audio::update_frequency(); - init(); -} - -void AudioDS::clear_audio() { - data.buffer_pos = 0; - data.ring_pos = 0; - if(data.buffer) { - memset(data.buffer, 0, data.buffer_size); - } - - if(!dsb_b)return; - - dsb_b->Stop(); - dsb_b->SetCurrentPosition(0); - -DWORD size; -void *output; - dsb_b->Lock(0, data.ring_size * 3, &output, &size, 0, 0, 0); - memset(output, 0, size); - dsb_b->Unlock(output, size, 0, 0); - - dsb_b->Play(0, 0, DSBPLAY_LOOPING); -} - -void AudioDS::init() { - clear_audio(); - term(); - - data.ring_size = latency * sizeof(uint32); - data.buffer_size = data.ring_size * 16; - data.buffer = (uint32*)malloc(data.buffer_size); - data.buffer_pos = 0; - - DirectSoundCreate(0, &ds, 0); - ds->SetCooperativeLevel(hwnd, DSSCL_PRIORITY); - - memset(&dsbd, 0, sizeof(dsbd)); - dsbd.dwSize = sizeof(dsbd); - dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; - dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = 0; - ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); - - memset(&wfx, 0, sizeof(wfx)); - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = 2; - wfx.nSamplesPerSec = frequency; - wfx.wBitsPerSample = 16; - wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; - wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; - dsb_p->SetFormat(&wfx); - - memset(&dsbd, 0, sizeof(dsbd)); - dsbd.dwSize = sizeof(dsbd); - dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | - DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; - dsbd.dwBufferBytes = data.ring_size * 3; - dsbd.guid3DAlgorithm = GUID_NULL; - dsbd.lpwfxFormat = &wfx; - ds->CreateSoundBuffer(&dsbd, &dsb_b, 0); - dsb_b->SetFrequency(frequency); - dsb_b->SetCurrentPosition(0); - - clear_audio(); -} - -void AudioDS::term() { - safe_free(data.buffer); - - if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; } - if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; } - if(ds) { ds->Release(); ds = 0; } -} - -AudioDS::AudioDS(HWND handle) { - hwnd = handle ? handle : GetDesktopWindow(); - ds = 0; - dsb_p = 0; - dsb_b = 0; - - data.buffer = 0; - data.buffer_pos = 0; - data.ring_pos = 0; - data.buffer_size = 0; - data.ring_size = 0; -} - -AudioDS::~AudioDS() { - term(); -} diff --git a/src/ui/audio/dsound.h b/src/ui/audio/dsound.h deleted file mode 100644 index 453b66b9..00000000 --- a/src/ui/audio/dsound.h +++ /dev/null @@ -1,25 +0,0 @@ -#include - -class AudioDS : public Audio { -public: -HWND hwnd; -LPDIRECTSOUND ds; -LPDIRECTSOUNDBUFFER dsb_p, dsb_b; -DSBUFFERDESC dsbd; -WAVEFORMATEX wfx; - -struct { - uint32 *buffer; - uint buffer_pos, ring_pos; - uint buffer_size, ring_size; -} data; - - void sample(uint16 l_sample, uint16 r_sample); - void update_frequency(); - void clear_audio(); - void init(); - void term(); - - AudioDS(HWND handle = 0); - ~AudioDS(); -}; diff --git a/src/ui/config.cpp b/src/ui/config.cpp index 5db727be..a670bf26 100644 --- a/src/ui/config.cpp +++ b/src/ui/config.cpp @@ -4,26 +4,15 @@ char filename[PATH_MAX + 16] = "bsnes.cfg"; struct System { static StringSetting video, audio, input; - static StringSetting video_flags, audio_flags, input_flags; - static IntegerSetting regulate_speed, speed; - static IntegerSetting speed_slowest, speed_slow, speed_normal, speed_fast, speed_fastest; } system; + StringSetting System::video(&config(), "system.video", "Video hardware interface", ""); StringSetting System::audio(&config(), "system.audio", "Audio hardware interface", ""); StringSetting System::input(&config(), "system.input", "Input hardware interface", ""); -StringSetting System::video_flags(&config(), "system.video_flags", "Video hardware interface flags", ""); -StringSetting System::audio_flags(&config(), "system.audio_flags", "Audio hardware interface flags", ""); -StringSetting System::input_flags(&config(), "system.input_flags", "Input hardware interface flags", ""); - IntegerSetting System::regulate_speed(&config(), "system.regulate_speed", "Regulate speed to 60hz (NTSC) / 50hz (PAL)", IntegerSetting::Boolean, true); -IntegerSetting System::speed (0, "system.speed", "Current speed regulation setting (1-5)", IntegerSetting::Decimal, 3); -IntegerSetting System::speed_slowest (&config(), "system.speed_slowest", "Slowest speed setting", IntegerSetting::Decimal, 50); -IntegerSetting System::speed_slow (&config(), "system.speed_slow", "Slow speed setting", IntegerSetting::Decimal, 75); -IntegerSetting System::speed_normal (&config(), "system.speed_normal", "Normal speed setting", IntegerSetting::Decimal, 100); -IntegerSetting System::speed_fast (&config(), "system.speed_fast", "Fast speed setting", IntegerSetting::Decimal, 150); -IntegerSetting System::speed_fastest (&config(), "system.speed_fastest", "Fastest speed setting", IntegerSetting::Decimal, 200); +IntegerSetting System::speed(0, "system.speed", "Current speed regulation setting (1-5)", IntegerSetting::Decimal, 3); struct Video { static IntegerSetting mode; @@ -86,16 +75,9 @@ IntegerSetting Video::use_vram(&config(), "video.use_vram", "Use Video RAM inste struct Audio { static IntegerSetting synchronize; static IntegerSetting frequency; - static IntegerSetting latency; } audio; IntegerSetting Audio::synchronize(&config(), "audio.synchronize", "Synchronize to audio sample rate.", IntegerSetting::Boolean, true); IntegerSetting Audio::frequency(&config(), "audio.frequency", "Default audio playback frequency.", IntegerSetting::Decimal, 32000); -IntegerSetting Audio::latency(&config(), "audio.latency", "Audio playback latency in milliseconds.\n" - "Specifies how long audio playback is delayed compared to a real SNES.\n" - "A delay is necessary to allow smooth audio playback via buffering.\n" - "Raising this value may help with audio playback problems, but will decrease\n" - "audio responsiveness.", - IntegerSetting::Decimal, 75); struct Input { static IntegerSetting axis_resistance; diff --git a/src/ui/input/dinput.cpp b/src/ui/input/dinput.cpp deleted file mode 100644 index 0f9f946f..00000000 --- a/src/ui/input/dinput.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "dinput.h" - -void InputDI::clear_input() { - memset(keystate, 0, sizeof keystate); -} - -void InputDI::poll() { - clear_input(); - -HRESULT hr; -DIJOYSTATE2 js; - if(di_key) { - hr = di_key->GetDeviceState(256, keystate); - if(FAILED(hr)) { - di_key->Acquire(); - hr = di_key->GetDeviceState(256, keystate); - } - } - - for(int i = 0; i < di_joy_count; i++) { - if(!di_joy[i])continue; - - memset(js.rgbButtons, 0, 128); - - hr = di_joy[i]->Poll(); - if(FAILED(hr)) { - di_joy[i]->Acquire(); - di_joy[i]->Poll(); - } - di_joy[i]->GetDeviceState(sizeof(DIJOYSTATE2), &js); - - uint index = keymap::joypad_flag | (i << 8); //joypad index - memcpy(keystate + index, js.rgbButtons, 128); - - //map d-pad axes - int resistance = config::input.axis_resistance; - if(resistance < 1)resistance = 1; - if(resistance > 99)resistance = 99; - resistance = int32(double(resistance) * 32768.0 / 100.0); - int resistance_lo = 0x7fff - resistance; - int resistance_hi = 0x8000 + resistance; - keystate[index + keymap::joypad_up] = (js.lY <= resistance_lo) ? 0x80 : 0x00; - keystate[index + keymap::joypad_down] = (js.lY >= resistance_hi) ? 0x80 : 0x00; - keystate[index + keymap::joypad_left] = (js.lX <= resistance_lo) ? 0x80 : 0x00; - keystate[index + keymap::joypad_right] = (js.lX >= resistance_hi) ? 0x80 : 0x00; - - //map analog POV (analog directional pad) as well - uint pov = js.rgdwPOV[0]; - keystate[index + keymap::joypad_up] |= (pov == 0 || pov == 31500 || pov == 4500) ? 0x80 : 0x00; - keystate[index + keymap::joypad_down] |= (pov == 18000 || pov == 13500 || pov == 22500) ? 0x80 : 0x00; - keystate[index + keymap::joypad_left] |= (pov == 27000 || pov == 22500 || pov == 31500) ? 0x80 : 0x00; - keystate[index + keymap::joypad_right] |= (pov == 9000 || pov == 4500 || pov == 13500) ? 0x80 : 0x00; - } -} - -BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *context) { - return static_cast(uiInput)->enum_joypads(instance); -} - -bool InputDI::enum_joypads(const DIDEVICEINSTANCE *instance) { -HRESULT hr = di->CreateDevice(instance->guidInstance, &di_joy[di_joy_count], 0); - if(FAILED(hr)) { - return DIENUM_CONTINUE; - } - - di_joy[di_joy_count]->SetDataFormat(&c_dfDIJoystick2); - di_joy[di_joy_count]->SetCooperativeLevel(owner, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - - if(++di_joy_count >= DIRECTINPUT_JOYMAX) { - //too many joypads? - return DIENUM_STOP; - } - - return DIENUM_CONTINUE; -} - -void InputDI::init() { - di_key = 0; - for(int i = 0; i < DIRECTINPUT_JOYMAX; i++)di_joy[i] = 0; - di = 0; - di_joy_count = 0; - - DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION, - IID_IDirectInput8, (void**)&di, 0); - di->CreateDevice(GUID_SysKeyboard, &di_key, 0); - - di_key->SetDataFormat(&c_dfDIKeyboard); - di_key->SetCooperativeLevel(owner, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); - di_key->Acquire(); - - di->EnumDevices(DI8DEVCLASS_GAMECTRL, DI_EnumJoypadsCallback, 0, DIEDFL_ATTACHEDONLY); - - Input::init(); -} - -void InputDI::term() { - if(di_key) { di_key->Unacquire(); di_key->Release(); di_key = 0; } - for(int i = 0; i < DIRECTINPUT_JOYMAX; i++) { - if(di_joy[i]) { di_joy[i]->Unacquire(); di_joy[i]->Release(); di_joy[i] = 0; } - } - if(di) { di->Release(); di = 0; } - di_joy_count = 0; - - Input::term(); -} - -bool InputDI::key_down(uint16 key) { - return keystate[translate(key)] & 0x80; -} - -//translate keymap code to DirectInput code, to lookup key status in DI status table -uint16 InputDI::translate(uint16 key) { -//DI joypad codes share 1:1 mapping with keymap codes - if(key & keymap::joypad_flag) { return key; } - - switch(key) { - case keymap::esc: return 0x01; - - case keymap::f1: return 0x3b; - case keymap::f2: return 0x3c; - case keymap::f3: return 0x3d; - case keymap::f4: return 0x3e; - case keymap::f5: return 0x3f; - case keymap::f6: return 0x40; - case keymap::f7: return 0x41; - case keymap::f8: return 0x42; - case keymap::f9: return 0x43; - case keymap::f10: return 0x44; - case keymap::f11: return 0x57; - case keymap::f12: return 0x58; - - case keymap::print_screen: return 0xb7; - case keymap::scroll_lock: return 0x46; - case keymap::pause: return 0xc5; - - case keymap::grave: return 0x29; - - case keymap::num_1: return 0x02; - case keymap::num_2: return 0x03; - case keymap::num_3: return 0x04; - case keymap::num_4: return 0x05; - case keymap::num_5: return 0x06; - case keymap::num_6: return 0x07; - case keymap::num_7: return 0x08; - case keymap::num_8: return 0x09; - case keymap::num_9: return 0x0a; - case keymap::num_0: return 0x0b; - - case keymap::minus: return 0x0c; - case keymap::equal: return 0x0d; - case keymap::backspace: return 0x0e; - - case keymap::ins: return 0xd2; - case keymap::del: return 0xd3; - case keymap::home: return 0xc7; - case keymap::end: return 0xcf; - case keymap::page_up: return 0xc9; - case keymap::page_down: return 0xd1; - - case keymap::a: return 0x1e; - case keymap::b: return 0x30; - case keymap::c: return 0x2e; - case keymap::d: return 0x20; - case keymap::e: return 0x12; - case keymap::f: return 0x21; - case keymap::g: return 0x22; - case keymap::h: return 0x23; - case keymap::i: return 0x17; - case keymap::j: return 0x24; - case keymap::k: return 0x25; - case keymap::l: return 0x26; - case keymap::m: return 0x32; - case keymap::n: return 0x31; - case keymap::o: return 0x18; - case keymap::p: return 0x19; - case keymap::q: return 0x10; - case keymap::r: return 0x13; - case keymap::s: return 0x1f; - case keymap::t: return 0x14; - case keymap::u: return 0x16; - case keymap::v: return 0x2f; - case keymap::w: return 0x11; - case keymap::x: return 0x2d; - case keymap::y: return 0x15; - case keymap::z: return 0x2c; - - case keymap::lbracket: return 0x1a; - case keymap::rbracket: return 0x1b; - case keymap::backslash: return 0x2b; - case keymap::semicolon: return 0x27; - case keymap::apostrophe: return 0x28; - case keymap::comma: return 0x33; - case keymap::period: return 0x34; - case keymap::slash: return 0x35; - - case keymap::kp_1: return 0x4f; - case keymap::kp_2: return 0x50; - case keymap::kp_3: return 0x51; - case keymap::kp_4: return 0x4b; - case keymap::kp_5: return 0x4c; - case keymap::kp_6: return 0x4d; - case keymap::kp_7: return 0x47; - case keymap::kp_8: return 0x48; - case keymap::kp_9: return 0x49; - case keymap::kp_0: return 0x52; - case keymap::kp_decimal: return 0x53; - - case keymap::kp_plus: return 0x4e; - case keymap::kp_minus: return 0x4a; - case keymap::kp_mul: return 0x37; - case keymap::kp_div: return 0xb5; - case keymap::kp_enter: return 0x9c; - - case keymap::num_lock : return 0x45; - case keymap::caps_lock: return 0x3a; - - case keymap::up: return 0xc8; - case keymap::down: return 0xd0; - case keymap::left: return 0xcb; - case keymap::right: return 0xcd; - - case keymap::tab: return 0x0f; - case keymap::enter: return 0x1c; - case keymap::space: return 0x39; - - case keymap::lctrl : return 0x1d; - case keymap::rctrl : return 0x9d; - case keymap::lalt : return 0x38; - case keymap::ralt : return 0xb8; - case keymap::lshift: return 0x2a; - case keymap::rshift: return 0x36; - case keymap::lsuper: return 0xdb; - case keymap::rsuper: return 0xdc; - case keymap::menu: return 0xdd; - } - - return 0x00; -} diff --git a/src/ui/input/dinput.h b/src/ui/input/dinput.h deleted file mode 100644 index 8acf8cc7..00000000 --- a/src/ui/input/dinput.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DINPUT_H -#define DINPUT_H - -#define DIRECTINPUT_VERSION 0x0800 -#define DIRECTINPUT_JOYMAX 16 -#include - -class InputDI : public Input { -private: -uint8 keystate[65536]; - -public: -HWND owner; -LPDIRECTINPUT8 di; -LPDIRECTINPUTDEVICE8 di_key, di_joy[DIRECTINPUT_JOYMAX]; -uint32 di_joy_count; - - void clear_input(); - void poll(); - void init(); - void term(); - bool key_down(uint16 key); - -// - uint16 translate(uint16 key); - bool enum_joypads(const DIDEVICEINSTANCE *instance); - - InputDI(HWND hwnd) { - owner = hwnd; - di = 0; - di_key = 0; - for(int i = 0; i < DIRECTINPUT_JOYMAX; i++)di_joy[i] = 0; - } - - ~InputDI() { term(); } -}; - -#endif diff --git a/src/ui/input/input.cpp b/src/ui/input/input.cpp deleted file mode 100644 index 018d9c79..00000000 --- a/src/ui/input/input.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "input.h" diff --git a/src/ui/input/input.h b/src/ui/input/input.h deleted file mode 100644 index 6bc9801a..00000000 --- a/src/ui/input/input.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef INPUT_H -#define INPUT_H - -class Input { public: - virtual bool key_down(uint16 key) { return false; } - virtual bool key_up (uint16 key) { return !key_down(key); } - - virtual void clear_input() {} - virtual void poll() {} - virtual void init() {} - virtual void term() {} -} *uiInput; - -#endif diff --git a/src/ui/input/xinput.cpp b/src/ui/input/xinput.cpp deleted file mode 100644 index b420d705..00000000 --- a/src/ui/input/xinput.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "xinput.h" - -bool InputX::key_down(uint16 key) { -#define map(i) (keymap[i >> 3] & (1 << (i & 7))) - switch(key) { - case keymap::esc: return map(0x09); - - case keymap::f1: return map(0x43); - case keymap::f2: return map(0x44); - case keymap::f3: return map(0x45); - case keymap::f4: return map(0x46); - case keymap::f5: return map(0x47); - case keymap::f6: return map(0x48); - case keymap::f7: return map(0x49); - case keymap::f8: return map(0x4a); - case keymap::f9: return map(0x4b); - case keymap::f10: return map(0x4c); - case keymap::f11: return map(0x5f); - case keymap::f12: return map(0x60); - - case keymap::print_screen: return map(0x6f); - case keymap::scroll_lock: return map(0x4e); - case keymap::pause: return map(0x6e); - - case keymap::grave: return map(0x31); - - case keymap::num_1: return map(0x0a); - case keymap::num_2: return map(0x0b); - case keymap::num_3: return map(0x0c); - case keymap::num_4: return map(0x0d); - case keymap::num_5: return map(0x0e); - case keymap::num_6: return map(0x0f); - case keymap::num_7: return map(0x10); - case keymap::num_8: return map(0x11); - case keymap::num_9: return map(0x12); - case keymap::num_0: return map(0x13); - - case keymap::minus: return map(0x14); - case keymap::equal: return map(0x15); - case keymap::backspace: return map(0x16); - - case keymap::ins: return map(0x6a); - case keymap::del: return map(0x6b); - case keymap::home: return map(0x61); - case keymap::end: return map(0x67); - case keymap::page_up: return map(0x63); - case keymap::page_down: return map(0x69); - - case keymap::a: return map(0x26); - case keymap::b: return map(0x38); - case keymap::c: return map(0x36); - case keymap::d: return map(0x28); - case keymap::e: return map(0x1a); - case keymap::f: return map(0x29); - case keymap::g: return map(0x2a); - case keymap::h: return map(0x2b); - case keymap::i: return map(0x1f); - case keymap::j: return map(0x2c); - case keymap::k: return map(0x2d); - case keymap::l: return map(0x2e); - case keymap::m: return map(0x3a); - case keymap::n: return map(0x39); - case keymap::o: return map(0x20); - case keymap::p: return map(0x21); - case keymap::q: return map(0x18); - case keymap::r: return map(0x1b); - case keymap::s: return map(0x27); - case keymap::t: return map(0x1c); - case keymap::u: return map(0x1e); - case keymap::v: return map(0x37); - case keymap::w: return map(0x19); - case keymap::x: return map(0x35); - case keymap::y: return map(0x1d); - case keymap::z: return map(0x34); - - case keymap::lbracket: return map(0x22); - case keymap::rbracket: return map(0x23); - case keymap::backslash: return map(0x33); - case keymap::semicolon: return map(0x2f); - case keymap::apostrophe: return map(0x30); - case keymap::comma: return map(0x3b); - case keymap::period: return map(0x3c); - case keymap::slash: return map(0x3d); - - case keymap::kp_1: return map(0x57); - case keymap::kp_2: return map(0x58); - case keymap::kp_3: return map(0x59); - case keymap::kp_4: return map(0x53); - case keymap::kp_5: return map(0x54); - case keymap::kp_6: return map(0x55); - case keymap::kp_7: return map(0x4f); - case keymap::kp_8: return map(0x50); - case keymap::kp_9: return map(0x51); - - case keymap::kp_plus: return map(0x56); - case keymap::kp_minus: return map(0x52); - case keymap::kp_mul: return map(0x3f); - case keymap::kp_div: return map(0x70); - case keymap::kp_enter: return map(0x6c); - - case keymap::num_lock: return map(0x4d); - case keymap::caps_lock: return map(0x42); - - case keymap::up: return map(0x62); - case keymap::down: return map(0x68); - case keymap::left: return map(0x64); - case keymap::right: return map(0x66); - - case keymap::tab: return map(0x17); - case keymap::enter: return map(0x24); - case keymap::space: return map(0x41); - - case keymap::lctrl: return map(0x25); - case keymap::rctrl: return map(0x6d); - case keymap::lalt: return map(0x40); - case keymap::ralt: return map(0x71); - case keymap::lshift: return map(0x32); - case keymap::rshift: return map(0x3e); - case keymap::lsuper: return map(0x73); - case keymap::rsuper: return map(0x74); - case keymap::menu: return map(0x75); - } -#undef map - - return false; -} - -void InputX::clear_input() { - memset(keymap, 0, sizeof keymap); -} - -void InputX::poll() { - XQueryKeymap(display, keymap); -} - -void InputX::init() { - Input::init(); - display = XOpenDisplay(0); -} - -void InputX::term() { - Input::term(); -} diff --git a/src/ui/input/xinput.h b/src/ui/input/xinput.h deleted file mode 100644 index 772a12ba..00000000 --- a/src/ui/input/xinput.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef XINPUT_H -#define XINPUT_H - -#include -#include -#include -#include -#include -#include -#include -#include - -class InputX : public Input { public: - bool key_down(uint16 key); - - void clear_input(); - void poll(); - void init(); - void term(); - -private: -Display *display; -char keymap[32]; -}; - -#endif diff --git a/src/ui/lui/loader/ui_bsxloader.cpp b/src/ui/lui/loader/ui_bsxloader.cpp deleted file mode 100644 index a7f1fe68..00000000 --- a/src/ui/lui/loader/ui_bsxloader.cpp +++ /dev/null @@ -1,81 +0,0 @@ -bool BSXLoaderWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Close) { - hide(); - return false; - } - - if(id == ui::Message::Clicked) { - if(control == &bbase) { - char fn[PATH_MAX]; - if(event::load_rom(fn) == true) tbase.set_text(fn); - } - - if(control == &bslot) { - char fn[PATH_MAX]; - if(event::load_rom(fn) == true) tslot.set_text(fn); - } - - if(control == &cbase) tbase.set_text(""); - if(control == &cslot) tslot.set_text(""); - - if(control == &load) { - char base[PATH_MAX], slot[PATH_MAX]; - tbase.get_text(base, PATH_MAX); - tslot.get_text(slot, PATH_MAX); - - if(mode == ModeBSX) { - config::path.bsx = base; - event::load_cart_bsx(base, slot); - } else if(mode == ModeBSC) { - event::load_cart_bsc(base, slot); - } - - tbase.set_text(""); - tslot.set_text(""); - hide(); - } - - if(control == &cancel) { - tbase.set_text(""); - tslot.set_text(""); - hide(); - } - } - - return true; -} - -void BSXLoaderWindow::setup() { - create(ui::Window::Center, 640, 200, "Load BS-X Cartridge"); - -uint bh = ui::Button::ideal_height; -uint eh = ui::Editbox::ideal_height; -uint lh = ui::Label::ideal_height; -uint mh = max(bh, eh); - -uint y = 5; - lbase.create(*this, 0, 5, y, 630, lh, "Base cartridge:"); - y += lh; - tbase.create(*this, 0, 5, y, 420, mh); - bbase.create(*this, 0, 430, y, 100, mh, "Browse ..."); - cbase.create(*this, 0, 535, y, 100, mh, "Clear"); - y += mh + 5; - - lslot.create(*this, 0, 5, y, 630, lh, "Slot cartridge:"); - y += lh; - tslot.create(*this, 0, 5, y, 420, mh); - bslot.create(*this, 0, 430, y, 100, mh, "Browse ..."); - cslot.create(*this, 0, 535, y, 100, mh, "Clear"); - y += mh + lh; - - load.create(*this, 0, 5, y, 312, mh, "Load"); - cancel.create(*this, 0, 323, y, 312, mh, "Cancel"); - y += mh + 5; - - resize(640, y); -} - -BSXLoaderWindow::BSXLoaderWindow() { - mode = ModeBSX; -} diff --git a/src/ui/lui/loader/ui_bsxloader.h b/src/ui/lui/loader/ui_bsxloader.h deleted file mode 100644 index 92c39207..00000000 --- a/src/ui/lui/loader/ui_bsxloader.h +++ /dev/null @@ -1,24 +0,0 @@ -class BSXLoaderWindow : public ui::Window { -public: - enum Mode { - ModeBSX, //BS-X cartridge - ModeBSC, //BS-X slotted cartridge - }; - - Mode mode; - - ui::Label lbase; - ui::Editbox tbase; - ui::Button bbase, cbase; - - ui::Label lslot; - ui::Editbox tslot; - ui::Button bslot, cslot; - - ui::Button load, cancel; - - bool message(uint id, uintptr_t param = 0); - void setup(); - - BSXLoaderWindow(); -} window_bsxloader; diff --git a/src/ui/lui/loader/ui_stloader.cpp b/src/ui/lui/loader/ui_stloader.cpp deleted file mode 100644 index 7a92c79c..00000000 --- a/src/ui/lui/loader/ui_stloader.cpp +++ /dev/null @@ -1,89 +0,0 @@ -bool STLoaderWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Close) { - hide(); - return false; - } - - if(id == ui::Message::Clicked) { - if(control == &bbase) { - char fn[PATH_MAX]; - if(event::load_rom(fn) == true) tbase.set_text(fn); - } - - if(control == &bslotA) { - char fn[PATH_MAX]; - if(event::load_rom(fn) == true) tslotA.set_text(fn); - } - - if(control == &bslotB) { - char fn[PATH_MAX]; - if(event::load_rom(fn) == true) tslotB.set_text(fn); - } - - if(control == &cbase) tbase.set_text(""); - if(control == &cslotA) tslotA.set_text(""); - if(control == &cslotB) tslotB.set_text(""); - - if(control == &load) { - char base[PATH_MAX], slotA[PATH_MAX], slotB[PATH_MAX]; - tbase.get_text(base, PATH_MAX); - tslotA.get_text(slotA, PATH_MAX); - tslotB.get_text(slotB, PATH_MAX); - - config::path.st = base; - event::load_cart_st(base, slotA, slotB); - - tbase.set_text(""); - tslotA.set_text(""); - tslotB.set_text(""); - hide(); - } - - if(control == &cancel) { - tbase.set_text(""); - tslotA.set_text(""); - tslotB.set_text(""); - hide(); - } - } - - return true; -} - -void STLoaderWindow::setup() { - create(ui::Window::Center, 640, 200, "Load Sufami Turbo Cartridge"); - -uint bh = ui::Button::ideal_height; -uint eh = ui::Editbox::ideal_height; -uint lh = ui::Label::ideal_height; -uint mh = max(bh, eh); - -uint y = 5; - lbase.create(*this, 0, 5, y, 630, lh, "Base cartridge:"); - y += lh; - tbase.create(*this, 0, 5, y, 420, mh); - bbase.create(*this, 0, 430, y, 100, mh, "Browse ..."); - cbase.create(*this, 0, 535, y, 100, mh, "Clear"); - y += mh + 5; - - lslotA.create(*this, 0, 5, y, 630, lh, "Slot A cartridge:"); - y += lh; - tslotA.create(*this, 0, 5, y, 420, mh); - bslotA.create(*this, 0, 430, y, 100, mh, "Browse ..."); - cslotA.create(*this, 0, 535, y, 100, mh, "Clear"); - y += mh + 5; - - lslotB.create(*this, 0, 5, y, 630, lh, "Slot B cartridge:"); - y += lh; - tslotB.create(*this, 0, 5, y, 420, mh); - bslotB.create(*this, 0, 430, y, 100, mh, "Browse ..."); - cslotB.create(*this, 0, 535, y, 100, mh, "Clear"); - y += mh + lh; - - load.create(*this, 0, 5, y, 312, mh, "Load"); - cancel.create(*this, 0, 323, y, 312, mh, "Cancel"); - y += mh + 5; - - resize(640, y); -} diff --git a/src/ui/lui/loader/ui_stloader.h b/src/ui/lui/loader/ui_stloader.h deleted file mode 100644 index d9648781..00000000 --- a/src/ui/lui/loader/ui_stloader.h +++ /dev/null @@ -1,19 +0,0 @@ -class STLoaderWindow : public ui::Window { -public: - ui::Label lbase; - ui::Editbox tbase; - ui::Button bbase, cbase; - - ui::Label lslotA; - ui::Editbox tslotA; - ui::Button bslotA, cslotA; - - ui::Label lslotB; - ui::Editbox tslotB; - ui::Button bslotB, cslotB; - - ui::Button load, cancel; - - bool message(uint id, uintptr_t param = 0); - void setup(); -} window_stloader; diff --git a/src/ui/lui/settings/ui_advanced.cpp b/src/ui/lui/settings/ui_advanced.cpp deleted file mode 100644 index f971111f..00000000 --- a/src/ui/lui/settings/ui_advanced.cpp +++ /dev/null @@ -1,83 +0,0 @@ -bool AdvancedWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Changed && control == &list) { - int pos = list.get_selection(); - set_val.enable(pos >= 0); - set_def.enable(pos >= 0); - if(pos >= 0 && pos < config::config().list_count) { - desc.set_text(string() << "(default = " << config::config().list[pos]->def << ")\n" << config::config().list[pos]->desc); - string val; - config::config().list[pos]->get(val); - edit_val.set_text(strptr(val)); - } - } else if(id == ui::Message::Clicked && control == &set_val) { - char t[4096]; - edit_val.get_text(t, sizeof(t)); - update(list.get_selection(), t); - } else if(id == ui::Message::Clicked && control == &set_def) { - update(list.get_selection(), 0); - } - - return true; -} - -void AdvancedWindow::read_config(uint pos, string &data) { - strcpy(data, "?|?|?"); - if(pos >= config::config().list_count)return; -string name, val; - name = config::config().list[pos]->name; - config::config().list[pos]->get(val); - if(val != config::config().list[pos]->def) { strcat(name, " (*)"); } - sprintf(data, "%s|%s|%s", - strptr(name), - config::config().list[pos]->type == Setting::String ? "String" : "Integer", - strptr(val) - ); -} - -void AdvancedWindow::update(uint pos, const char *data) { - if(pos >= config::config().list_count)return; - config::config().list[pos]->set(data ? data : config::config().list[pos]->def); -string val; - config::config().list[pos]->get(val); - edit_val.set_text(strptr(val)); - read_config(pos, val); - list.set_item(pos, strptr(val)); - list.autosize_columns(); -} - -void AdvancedWindow::setup() { - create(0, 475, 355); - -int x = 0, y = 0; -int bh = ui::Button::ideal_height; -int eh = ui::Editbox::ideal_height; - bh = max(bh, eh); //set both editbox and button to same size, as they are on the same line -int th = 80; -int lh = 355 - th - bh - 10; - list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lh, "Name|Type|Value"); - y += lh + 5; - - desc.create(*this, ui::Editbox::Multiline | ui::Editbox::Readonly, x, y, 475, th, - "\n" - "Warning: modifification of certain variables will not take effect until\n" - "bsnes is restarted, and corresponding UI elements will not be updated\n" - "to reflect changes here. (*) = modified" - ); - y += th + 5; - - edit_val.create(*this, 0, x, y, 265, bh, ""); - set_val.create(*this, 0, x + 270, y, 100, bh, "Set"); - set_def.create(*this, 0, x + 375, y, 100, bh, "Default"); - - for(int i = 0; i < config::config().list_count; i++) { - string val; - read_config(i, val); - list.add_item(strptr(val)); - } - - list.autosize_columns(); - - set_val.disable(); - set_def.disable(); -} diff --git a/src/ui/lui/settings/ui_advanced.h b/src/ui/lui/settings/ui_advanced.h deleted file mode 100644 index 5c9a97bc..00000000 --- a/src/ui/lui/settings/ui_advanced.h +++ /dev/null @@ -1,11 +0,0 @@ -class AdvancedWindow : public ui::Window { public: -ui::Listbox list; -ui::Editbox desc; -ui::Editbox edit_val; -ui::Button set_val; -ui::Button set_def; - bool message(uint id, uintptr_t param); - void read_config(uint pos, string &data); - void update(uint pos, const char *data); - void setup(); -} window_advanced; diff --git a/src/ui/lui/settings/ui_cheateditor.cpp b/src/ui/lui/settings/ui_cheateditor.cpp deleted file mode 100644 index cc68ad8a..00000000 --- a/src/ui/lui/settings/ui_cheateditor.cpp +++ /dev/null @@ -1,82 +0,0 @@ -void CheatEditorWindow::refresh() { - list.reset(); - - for(uint i = 0; i < cheat.count(); i++) { - bool enabled; - uint32 addr; - uint8 data; - char s_code[256], s_desc[256], s_result[1024]; - cheat.get(i, enabled, addr, data, s_code, s_desc); - sprintf(s_result, "%s|%s|%s", enabled ? "Enabled" : "Disabled", s_code, s_desc); - list.add_item(s_result); - } - - list.autosize_columns(); - -//enable controls only if cartridge is loaded -bool loaded = cartridge.loaded(); - add_code.enable(loaded); - toggle_code.enable(loaded); - delete_code.enable(loaded); -} - -bool CheatEditorWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - - if(id == ui::Message::Clicked && control == &add_code) { - char s_code[256], s_desc[256]; - code.get_text(s_code, sizeof s_code); - desc.get_text(s_desc, sizeof s_desc); - cheat.add(false, s_code, s_desc); //param 0 = new codes disabled by default - refresh(); - return true; - } - - if((id == ui::Message::Clicked && control == &toggle_code) || - (id == ui::Message::DoubleClicked && control == &list)) { - int index = list.get_selection(); - if(index >= 0 && index < cheat.count()) { - cheat.enabled(index) ? cheat.disable(index) : cheat.enable(index); - bool enabled; - uint32 addr; - uint8 data; - char s_code[256], s_desc[256], s_result[1024]; - cheat.get(index, enabled, addr, data, s_code, s_desc); - sprintf(s_result, "%s|%s|%s", enabled ? "Enabled" : "Disabled", s_code, s_desc); - list.set_item(index, s_result); - } - return true; - } - - if(id == ui::Message::Clicked && control == &delete_code) { - int index = list.get_selection(); - if(index >= 0 && index < cheat.count()) { - cheat.remove(index); - refresh(); - } - return true; - } - - return true; -} - -void CheatEditorWindow::setup() { - create(0, 475, 355); - -int x = 0, y = 0; -int bh = ui::Button::ideal_height; -int eh = ui::Editbox::ideal_height; -int lh = 355 - bh - eh - 10; - list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lh, "Status|Code|Description"); - y += lh + 5; - - add_code.create (*this, 0, x, y, 155, bh, "Add Code"); - toggle_code.create(*this, 0, x + 160, y, 155, bh, "Toggle Status"); - delete_code.create(*this, 0, x + 320, y, 155, bh, "Delete Code"); - y += bh + 5; - - code.create(*this, 0, x, y, 155, eh, ""); - desc.create(*this, 0, x + 160, y, 315, eh, ""); - - refresh(); -} diff --git a/src/ui/lui/settings/ui_cheateditor.h b/src/ui/lui/settings/ui_cheateditor.h deleted file mode 100644 index b6d2f26e..00000000 --- a/src/ui/lui/settings/ui_cheateditor.h +++ /dev/null @@ -1,12 +0,0 @@ -class CheatEditorWindow : public ui::Window { public: -ui::Listbox list; -ui::Button add_code; -ui::Button toggle_code; -ui::Button delete_code; -ui::Editbox code; -ui::Editbox desc; - bool message(uint id, uintptr_t param); - void setup(); - - void refresh(); -} window_cheat_editor; diff --git a/src/ui/lui/settings/ui_inputconfig.cpp b/src/ui/lui/settings/ui_inputconfig.cpp deleted file mode 100644 index 98739590..00000000 --- a/src/ui/lui/settings/ui_inputconfig.cpp +++ /dev/null @@ -1,211 +0,0 @@ -const char InputConfigWindow::list_index[][64] = { - "Joypad 1 Up", - "Joypad 1 Down", - "Joypad 1 Left", - "Joypad 1 Right", - "Joypad 1 A", - "Joypad 1 B", - "Joypad 1 X", - "Joypad 1 Y", - "Joypad 1 L", - "Joypad 1 R", - "Joypad 1 Select", - "Joypad 1 Start", - - "Joypad 2 Up", - "Joypad 2 Down", - "Joypad 2 Left", - "Joypad 2 Right", - "Joypad 2 A", - "Joypad 2 B", - "Joypad 2 X", - "Joypad 2 Y", - "Joypad 2 L", - "Joypad 2 R", - "Joypad 2 Select", - "Joypad 2 Start", -}; - -uint InputConfigWindow::get_value(uint index) { - switch(index) { - case 0: return keymap::find(config::input.joypad1.up); - case 1: return keymap::find(config::input.joypad1.down); - case 2: return keymap::find(config::input.joypad1.left); - case 3: return keymap::find(config::input.joypad1.right); - case 4: return keymap::find(config::input.joypad1.a); - case 5: return keymap::find(config::input.joypad1.b); - case 6: return keymap::find(config::input.joypad1.x); - case 7: return keymap::find(config::input.joypad1.y); - case 8: return keymap::find(config::input.joypad1.l); - case 9: return keymap::find(config::input.joypad1.r); - case 10: return keymap::find(config::input.joypad1.select); - case 11: return keymap::find(config::input.joypad1.start); - - case 12: return keymap::find(config::input.joypad2.up); - case 13: return keymap::find(config::input.joypad2.down); - case 14: return keymap::find(config::input.joypad2.left); - case 15: return keymap::find(config::input.joypad2.right); - case 16: return keymap::find(config::input.joypad2.a); - case 17: return keymap::find(config::input.joypad2.b); - case 18: return keymap::find(config::input.joypad2.x); - case 19: return keymap::find(config::input.joypad2.y); - case 20: return keymap::find(config::input.joypad2.l); - case 21: return keymap::find(config::input.joypad2.r); - case 22: return keymap::find(config::input.joypad2.select); - case 23: return keymap::find(config::input.joypad2.start); - } - - return keymap::none; -} - -void InputConfigWindow::set_value(uint index, uint16 value) { - switch(index) { - case 0: config::input.joypad1.up = keymap::find(value); break; - case 1: config::input.joypad1.down = keymap::find(value); break; - case 2: config::input.joypad1.left = keymap::find(value); break; - case 3: config::input.joypad1.right = keymap::find(value); break; - case 4: config::input.joypad1.a = keymap::find(value); break; - case 5: config::input.joypad1.b = keymap::find(value); break; - case 6: config::input.joypad1.x = keymap::find(value); break; - case 7: config::input.joypad1.y = keymap::find(value); break; - case 8: config::input.joypad1.l = keymap::find(value); break; - case 9: config::input.joypad1.r = keymap::find(value); break; - case 10: config::input.joypad1.select = keymap::find(value); break; - case 11: config::input.joypad1.start = keymap::find(value); break; - - case 12: config::input.joypad2.up = keymap::find(value); break; - case 13: config::input.joypad2.down = keymap::find(value); break; - case 14: config::input.joypad2.left = keymap::find(value); break; - case 15: config::input.joypad2.right = keymap::find(value); break; - case 16: config::input.joypad2.a = keymap::find(value); break; - case 17: config::input.joypad2.b = keymap::find(value); break; - case 18: config::input.joypad2.x = keymap::find(value); break; - case 19: config::input.joypad2.y = keymap::find(value); break; - case 20: config::input.joypad2.l = keymap::find(value); break; - case 21: config::input.joypad2.r = keymap::find(value); break; - case 22: config::input.joypad2.select = keymap::find(value); break; - case 23: config::input.joypad2.start = keymap::find(value); break; - } - - input_manager.bind(); -} - -void InputConfigWindow::refresh_list() { - for(uint i = 0; i < 24; i++) { - list.set_item(i, string() << list_index[i] << "|" << keymap::find(get_value(i))); - } - list.autosize_columns(); -} - -bool InputConfigWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Changed && control == &list) { - int pos = list.get_selection(); - setkey.enable(pos >= 0); - clrkey.enable(pos >= 0); - return true; - } - - if((id == ui::Message::DoubleClicked && control == &list) || - (id == ui::Message::Clicked && control == &setkey)) { - int pos = list.get_selection(); - if(pos < 0) { return true; } - window_input_capture.index = pos; - window_input_capture.label.set_text(string() << "Please press a key to assign to " << list_index[pos] << " ..."); - window_input_capture.show(); - return true; - } - - if(id == ui::Message::Clicked && control == &clrkey) { - int pos = list.get_selection(); - if(pos < 0) { return true; } - set_value(pos, keymap::none); - refresh_list(); - return true; - } - - return true; -} - -void InputConfigWindow::setup() { - create(0, 475, 355); - -int x = 0, y = 0; -int lh = ui::Label::ideal_height; -int ch = ui::Combobox::ideal_height; -int bh = ui::Button::ideal_height; -int lbh = 355 - lh - ch - bh - 10; - lportA.create(*this, 0, x, y, 235, lh, "Controller Port A:"); - lportB.create(*this, 0, x + 240, y, 235, lh, "Controller Port B:"); - y += lh; - - portA.create (*this, 0, x, y, 235, ch); - portA.add_item("None"); - portA.add_item("Joypad 1"); - portA.add_item("Joypad 2"); - portA.set_selection(1); - portA.disable(); - - portB.create (*this, 0, x + 240, y, 235, ch); - portB.add_item("None"); - portB.add_item("Joypad 1"); - portB.add_item("Joypad 2"); - portB.set_selection(2); - portB.disable(); - y += ch + 5; - - list.create(*this, ui::Listbox::Header | ui::Listbox::VerticalScrollAlways, x, y, 475, lbh, "Name|Value"); - for(uint i = 0; i < 24; i++) { list.add_item("???|???"); } - y += lbh + 5; - - setkey.create(*this, 0, x, y, 235, bh, "Assign Key"); - clrkey.create(*this, 0, x + 240, y, 235, bh, "Unassign Key"); - - refresh_list(); - window_input_capture.setup(); - - setkey.disable(); - clrkey.disable(); -} - -// - -bool InputCaptureWindow::message(uint id, uintptr_t param) { - if(id == ui::Message::Close) { - hide(); - return false; - } - - return true; -} - -void InputCaptureWindow::show() { - uiInput->clear_input(); - -//enter and spacebar can be used to activate key capture, -//set lock on these keys if they are held down to prevent -//them from being instantly assigned to selected entry ... - uiInput->poll(); - key_lock = (uiInput->key_down(keymap::enter) || uiInput->key_down(keymap::space)); - Window::show(); - Window::focus(); - - while(_term_ == false && visible() == true) { - run(); - uint16 key = input_manager.scan(); - if(key == keymap::none) { key_lock = false; continue; } - if(key_lock && (key == keymap::enter || key == keymap::space)) { continue; } - hide(); - window_input_config.set_value(index, key); - window_input_config.refresh_list(); - break; - } - - uiInput->clear_input(); -} - -void InputCaptureWindow::setup() { -int lh = ui::Label::ideal_height; - create(ui::Window::Center, 350, lh * 3, "bsnes Key Capture"); - label.create(*this, 0, 5, lh, 340, lh); -} diff --git a/src/ui/lui/settings/ui_inputconfig.h b/src/ui/lui/settings/ui_inputconfig.h deleted file mode 100644 index 5d562228..00000000 --- a/src/ui/lui/settings/ui_inputconfig.h +++ /dev/null @@ -1,27 +0,0 @@ -class InputCaptureWindow : public ui::Window { public: -ui::Label label; -uint index; -bool key_lock; - bool message(uint id, uintptr_t param = 0); - void show(); - void setup(); - InputCaptureWindow() : index(0) {} -} window_input_capture; - -class InputConfigWindow : public ui::Window { public: -ui::Label lportA; -ui::Label lportB; -ui::Combobox portA; -ui::Combobox portB; -ui::Listbox list; -ui::Button setkey; -ui::Button clrkey; - -static const char list_index[][64]; - - bool message(uint id, uintptr_t param = 0); - uint get_value(uint index); - void set_value(uint index, uint16 value); - void refresh_list(); - void setup(); -} window_input_config; diff --git a/src/ui/lui/settings/ui_rastersettings.cpp b/src/ui/lui/settings/ui_rastersettings.cpp deleted file mode 100644 index 4c99f9b5..00000000 --- a/src/ui/lui/settings/ui_rastersettings.cpp +++ /dev/null @@ -1,119 +0,0 @@ -bool RasterSettingsWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Changed) { - if(control == &contrast) { - if(config::snes.contrast != contrast.get_position() - 96) { - config::snes.contrast = contrast.get_position() - 96; - lcontrast.set_text(string() << "Contrast: " << config::snes.contrast); - snes.update_color_lookup_table(); - } - } else if(control == &brightness) { - if(config::snes.brightness != brightness.get_position() - 96) { - config::snes.brightness = brightness.get_position() - 96; - lbrightness.set_text(string() << "Brightness: " << config::snes.brightness); - snes.update_color_lookup_table(); - } - } else if(control == &gamma) { - if(config::snes.gamma != gamma.get_position() + 10) { - config::snes.gamma = gamma.get_position() + 10; - lgamma.set_text(string() << "Gamma: " << config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0 - snes.update_color_lookup_table(); - } - } - return true; - } - - if(id == ui::Message::Clicked) { - if(control == &gamma_ramp) { - if(config::snes.gamma_ramp != gamma_ramp.checked()) { - config::snes.gamma_ramp = gamma_ramp.checked(); - snes.update_color_lookup_table(); - } - } else if(control == &sepia) { - if(config::snes.sepia != sepia.checked()) { - config::snes.sepia = sepia.checked(); - snes.update_color_lookup_table(); - } - } else if(control == &grayscale) { - if(config::snes.grayscale != grayscale.checked()) { - config::snes.grayscale = grayscale.checked(); - snes.update_color_lookup_table(); - } - } else if(control == &invert) { - if(config::snes.invert != invert.checked()) { - config::snes.invert = invert.checked(); - snes.update_color_lookup_table(); - } - } else if(control == &preset_optimal) { - config::snes.contrast = 0; - config::snes.brightness = 0; - config::snes.gamma = 80; - config::snes.gamma_ramp = true; - config::snes.sepia = false; - config::snes.grayscale = false; - config::snes.invert = false; - sync_ui(); - } else if(control == &preset_standard) { - config::snes.contrast = 0; - config::snes.brightness = 0; - config::snes.gamma = 100; - config::snes.gamma_ramp = false; - config::snes.sepia = false; - config::snes.grayscale = false; - config::snes.invert = false; - sync_ui(); - } - return true; - } - - return true; -} - -//update all UI controls to match config file values ... -void RasterSettingsWindow::sync_ui() { - contrast.set_position(config::snes.contrast + 96); - lcontrast.set_text(string() << "Contrast: " << config::snes.contrast); - brightness.set_position(config::snes.brightness + 96); - lbrightness.set_text(string() << "Brightness: " << config::snes.brightness); - gamma.set_position(config::snes.gamma - 10); - lgamma.set_text(string() << "Gamma: " << config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0 - gamma_ramp.check(config::snes.gamma_ramp); - sepia.check(config::snes.sepia); - grayscale.check(config::snes.grayscale); - invert.check(config::snes.invert); - snes.update_color_lookup_table(); -} - -void RasterSettingsWindow::setup() { - create(0, 475, 355); - -int x = 0, y = 0; -int sh = ui::Slider::ideal_height; -int kh = ui::Checkbox::ideal_height; -int bh = ui::Button::ideal_height; - lcontrast.create(*this, 0, x, y, 100, sh); - contrast.create (*this, 0, x + 100, y, 375, sh, 192); - y += sh; - - lbrightness.create(*this, 0, x, y, 100, sh); - brightness.create (*this, 0, x + 100, y, 375, sh, 192); - y += sh; - - lgamma.create(*this, 0, x, y, 100, sh); - gamma.create (*this, 0, x + 100, y, 375, sh, 191); - y += sh; - - gamma_ramp.create(*this, 0, x, y, 235, kh, "Gamma ramp"); - sepia.create(*this, 0, x + 240, y, 235, kh, "Sepia"); - y += kh; - - grayscale.create(*this, 0, x, y, 235, kh, "Grayscale"); - invert.create(*this, 0, x + 240, y, 235, kh, "Invert colors"); - y += kh + 5; - - preset_optimal.create (*this, 0, x, y, 235, bh, "Optimal Preset"); - preset_standard.create(*this, 0, x + 240, y, 235, bh, "Standard Preset"); - y += bh; - - sync_ui(); -} diff --git a/src/ui/lui/settings/ui_rastersettings.h b/src/ui/lui/settings/ui_rastersettings.h deleted file mode 100644 index 46e4ba4d..00000000 --- a/src/ui/lui/settings/ui_rastersettings.h +++ /dev/null @@ -1,20 +0,0 @@ -class RasterSettingsWindow : public ui::Window { public: -ui::Label lcontrast; -ui::Label lbrightness; -ui::Label lgamma; -ui::Slider contrast; -ui::Slider brightness; -ui::Slider gamma; - -ui::Checkbox gamma_ramp; -ui::Checkbox sepia; -ui::Checkbox grayscale; -ui::Checkbox invert; - -ui::Button preset_optimal; -ui::Button preset_standard; - - bool message(uint id, uintptr_t param); - void setup(); - void sync_ui(); -} window_raster_settings; diff --git a/src/ui/lui/settings/ui_settings.cpp b/src/ui/lui/settings/ui_settings.cpp deleted file mode 100644 index 8bda1988..00000000 --- a/src/ui/lui/settings/ui_settings.cpp +++ /dev/null @@ -1,38 +0,0 @@ -void SettingsWindow::setup() { - create(ui::Window::Center, 640, 365, "bsnes Configuration Settings"); - panel_list.create(*this, 0, 5, 5, 150, 355); -//panel_list.add_item("Video Settings"); - panel_list.add_item("Raster Settings"); - panel_list.add_item("Input Configuration"); - panel_list.add_item("Cheat Code Editor"); - panel_list.add_item("Advanced"); - panel.create(*this, 0, 160, 5, 475, 355); - - panel_list.set_selection(0); -} - -void SettingsWindow::show() { - Window::show(); - panel_list.focus(); -} - -bool SettingsWindow::message(uint id, uintptr_t param) { - if(id == ui::Message::Close) { - hide(); - return false; - } - - if(id == ui::Message::Changed && (ui::Control*)param == &panel_list) { - switch(panel_list.get_selection()) { - //case 0: panel.attach(window_video_settings); break; - case 0: panel.attach(window_raster_settings); break; - case 1: panel.attach(window_input_config); break; - case 2: panel.attach(window_cheat_editor); break; - case 3: panel.attach(window_advanced); break; - } - panel_list.focus(); - return true; - } - - return true; -} diff --git a/src/ui/lui/settings/ui_settings.h b/src/ui/lui/settings/ui_settings.h deleted file mode 100644 index ff6b9eab..00000000 --- a/src/ui/lui/settings/ui_settings.h +++ /dev/null @@ -1,7 +0,0 @@ -class SettingsWindow : public ui::Window { public: -ui::Listbox panel_list; -ui::Panel panel; - bool message(uint id, uintptr_t param = 0); - void show(); - void setup(); -} window_settings; diff --git a/src/ui/lui/settings/ui_videosettings.cpp b/src/ui/lui/settings/ui_videosettings.cpp deleted file mode 100644 index 0fabc663..00000000 --- a/src/ui/lui/settings/ui_videosettings.cpp +++ /dev/null @@ -1,59 +0,0 @@ -bool VideoSettingsWindow::message(uint id, uintptr_t param) { - return true; -} - -void VideoSettingsWindow::setup() { - create(0, 475, 355); - -int x = 0, y = 0; -int lh = ui::Label::ideal_height; -int ch = ui::Combobox::ideal_height; -int kh = ui::Checkbox::ideal_height; -int eh = ui::Editbox::ideal_height; - label_select.create(*this, 0, x, y, 475, lh, "Select video mode to configure:"); - y += lh; - mode_select.create(*this, 0, x, y, 475, ch); - mode_select.add_item("Windowed mode"); - mode_select.add_item("Pseudo-fullscreen mode"); - mode_select.add_item("Fullscreen mode"); - y += ch + 5; - - label_region.create(*this, 0, x, y, 235, lh, "Region:"); - label_scalar.create(*this, 0, x + 240, y, 235, lh, "Scale:"); - y += lh; - region.create(*this, 0, x, y, 235, ch); - region.add_item("NTSC"); - region.add_item("PAL"); - scalar.create(*this, 0, x + 240, y, 235, ch); - scalar.add_item("100%"); - scalar.add_item("200%"); - scalar.add_item("300%"); - scalar.add_item("400%"); - scalar.add_item("500%"); - y += ch; - - label_hwfilter.create(*this, 0, x, y, 235, lh, "Hardware filter:"); - label_swfilter.create(*this, 0, x + 240, y, 235, lh, "Software filter:"); - y += lh; - hwfilter.create(*this, 0, x, y, 235, ch); - hwfilter.add_item("Point"); - hwfilter.add_item("Linear"); - swfilter.create(*this, 0, x + 240, y, 235, ch); - swfilter.add_item("None"); - swfilter.add_item("NTSC"); - swfilter.add_item("HQ2x"); - swfilter.add_item("Scale2x"); - y += ch + 5; - - aspect.create(*this, 0, x, y, 235, kh, "Correct aspect ratio"); - vsync.create(*this, 0, x + 240, y, 235, kh, "Sync to vertical retrace"); - y += kh + 5; - - label_fsmode.create(*this, 0, x, y, 475, lh, "Fullscreen mode (width x height x refresh rate):"); - y += lh; - - fs_width.create(*this, 0, x, y, 155, eh, ""); - fs_height.create(*this, 0, x + 160, y, 155, eh, ""); - fs_refresh.create(*this, 0, x + 320, y, 155, eh, ""); - y += eh + 5; -} diff --git a/src/ui/lui/settings/ui_videosettings.h b/src/ui/lui/settings/ui_videosettings.h deleted file mode 100644 index eb4fed9a..00000000 --- a/src/ui/lui/settings/ui_videosettings.h +++ /dev/null @@ -1,14 +0,0 @@ -class VideoSettingsWindow : public ui::Window { public: -ui::Label label_select; -ui::Combobox mode_select; - -ui::Label label_region, label_scalar, label_hwfilter, label_swfilter; -ui::Combobox region, scalar, hwfilter, swfilter; - -ui::Checkbox aspect, vsync; - -ui::Label label_fsmode; -ui::Editbox fs_width, fs_height, fs_refresh; - bool message(uint, uintptr_t); - void setup(); -} window_video_settings; diff --git a/src/ui/lui/ui.cpp b/src/ui/lui/ui.cpp deleted file mode 100644 index d9052325..00000000 --- a/src/ui/lui/ui.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "ui_main.cpp" -#include "ui_about.cpp" - -#include "loader/ui_bsxloader.cpp" -#include "loader/ui_stloader.cpp" - -#include "settings/ui_settings.cpp" -#include "settings/ui_videosettings.cpp" -#include "settings/ui_rastersettings.cpp" -#include "settings/ui_inputconfig.cpp" -#include "settings/ui_cheateditor.cpp" -#include "settings/ui_advanced.cpp" - -#if defined(PLATFORM_WIN) - #include "../video/d3d.h" - #include "../video/d3d.cpp" - #include "../video/ddraw.h" - #include "../video/ddraw.cpp" - #include "../video/gdi.cpp" - #include "../audio/dsound.h" - #include "../audio/dsound.cpp" - #include "../input/dinput.cpp" -#elif defined(PLATFORM_X) - #include "../video/xv.cpp" - #include "../video/gtk.cpp" - #include "../audio/ao.cpp" - #include "../input/xinput.cpp" -#endif - -void ui_init() { - window_main.setup(); - window_about.setup(); - - window_bsxloader.setup(); - window_stloader.setup(); - - window_video_settings.setup(); - window_raster_settings.setup(); - window_input_config.setup(); - window_cheat_editor.setup(); - window_advanced.setup(); - window_settings.setup(); - - event::update_video_settings(); //call first time to resize main window and update menubar - window_main.show(); - while(ui::events_pending()) { ui::run(); } - -#if defined(PLATFORM_WIN) - uiVideo = - config::system.video == "none" ? (Video*)new Video() : - config::system.video == "gdi" ? (Video*)new VideoGDI(window_main.view.handle()) : - config::system.video == "dd" ? (Video*)new VideoDD(window_main.view.handle()) : - (Video*)new VideoD3D(window_main.view.handle()); - uiAudio = - config::system.audio == "none" ? (Audio*)new Audio() : - (Audio*)new AudioDS(window_main.handle()); - uiInput = - config::system.input == "none" ? (Input*)new Input() : - (Input*)new InputDI(window_main.handle()); -#elif defined(PLATFORM_X) - uiVideo = - config::system.video == "none" ? (Video*)new Video() : - config::system.video == "gtk" ? (Video*)new VideoGTK(window_main.view.handle()) : - (Video*)new VideoXv((unsigned long)window_main.view.x_handle()); - uiAudio = - config::system.audio == "none" ? (Audio*)new Audio() : - (Audio*)new AudioAO(config::system.audio_flags); - uiInput = - config::system.input == "none" ? (Input*)new Input() : - (Input*)new InputX(); -#endif - - uiVideo->init(); - uiAudio->init(); - uiInput->init(); - - event::update_video_settings(); //call second time to update uiVideo->settings -} - -void ui_term() { - window_main.hide(); - - uiVideo->term(); - uiAudio->term(); - uiInput->term(); - - safe_delete(uiVideo); - safe_delete(uiAudio); - safe_delete(uiInput); -} diff --git a/src/ui/lui/ui_about.h b/src/ui/lui/ui_about.h deleted file mode 100644 index 11d2df03..00000000 --- a/src/ui/lui/ui_about.h +++ /dev/null @@ -1,6 +0,0 @@ -class AboutWindow : public ui::Window { public: -ui::Label about; -static const char about_text[4096]; - bool message(uint id, uintptr_t param = 0); - void setup(); -} window_about; diff --git a/src/ui/lui/ui_main.cpp b/src/ui/lui/ui_main.cpp deleted file mode 100644 index b0f2508b..00000000 --- a/src/ui/lui/ui_main.cpp +++ /dev/null @@ -1,304 +0,0 @@ -bool MainWindow::input_ready() { -//only allow input when main window is focused - return focused() == true; -} - -bool MainWindow::message(uint id, uintptr_t param) { -ui::Control *control = (ui::Control*)param; - if(id == ui::Message::Close) { - _term_ = true; - hide(); - return false; - } - - if(id == ui::Message::Block) { - if(uiAudio) { uiAudio->clear_audio(); } - return true; - } - - if(id == ui::Message::KeyDown) { - if(param == keymap::esc) { event::toggle_menu(); } - if(param == keymap::f11) { event::toggle_fullscreen(); } - return true; - } - - if(id == ui::Message::Clicked) { - if(control == &menu_file_load) { - event::load_rom(); - } - - if(control == &menu_file_load_bsx) { - window_bsxloader.mode = BSXLoaderWindow::ModeBSX; - window_bsxloader.set_text("Load BS-X Cartridge"); - window_bsxloader.tbase.set_text(config::path.bsx); - window_bsxloader.show(); - } - - if(control == &menu_file_load_bsc) { - window_bsxloader.mode = BSXLoaderWindow::ModeBSC; - window_bsxloader.set_text("Load BS-X Slotted Cartridge"); - window_bsxloader.tbase.set_text(""); - window_bsxloader.show(); - } - - if(control == &menu_file_load_st) { - window_stloader.tbase.set_text(config::path.st); - window_stloader.show(); - } - - if(control == &menu_file_unload) { - event::unload_rom(); - } - - if(control == &menu_file_reset) { - event::reset(); - } - - if(control == &menu_file_power) { - event::power(); - } - - if(control == &menu_file_exit) { - message(ui::Message::Close); - } - - if(locked == false) { - //set locked to true to update below menu item check statuses without triggering events - if(control == &menu_settings_videomode_1x) { event::update_multiplier(1); } - if(control == &menu_settings_videomode_2x) { event::update_multiplier(2); } - if(control == &menu_settings_videomode_3x) { event::update_multiplier(3); } - if(control == &menu_settings_videomode_4x) { event::update_multiplier(4); } - if(control == &menu_settings_videomode_5x) { event::update_multiplier(5); } - - if(control == &menu_settings_videomode_aspect_correction) { - event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked()); - } - - if(control == &menu_settings_videomode_ntsc) { event::update_region(0); } - if(control == &menu_settings_videomode_pal) { event::update_region(1); } - - if(control == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); } - if(control == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); } - - if(control == &menu_settings_videofilter_swnone) { event::update_software_filter(0); } - if(control == &menu_settings_videofilter_swntsc) { event::update_software_filter(1); } - if(control == &menu_settings_videofilter_swhq2x) { event::update_software_filter(2); } - if(control == &menu_settings_videofilter_swscale2x) { event::update_software_filter(3); } - - if(control == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } - if(control == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } - if(control == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } - if(control == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } - if(control == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } - if(control == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } - if(control == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } - if(control == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } - if(control == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } - if(control == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } - - if(control == &menu_settings_mute) { - config::snes.mute = menu_settings_mute.checked(); - } - - if(control == &menu_settings_speedreg_enable) { - config::system.regulate_speed = menu_settings_speedreg_enable.checked(); - } - - if(control == &menu_settings_speedreg_slowest) { config::system.speed = 1; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_slow) { config::system.speed = 2; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_normal) { config::system.speed = 3; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_fast) { config::system.speed = 4; uiAudio->update_frequency(); } - if(control == &menu_settings_speedreg_fastest) { config::system.speed = 5; uiAudio->update_frequency(); } - } - - if(control == &menu_settings_config) { window_settings.show(); } - - if(control == &menu_misc_logaudio) { - (menu_misc_logaudio.checked() == true) ? snes.log_audio_enable() : snes.log_audio_disable(); - } - - if(control == &menu_misc_showfps) { - config::misc.show_frame_counter = menu_misc_showfps.checked(); - if(config::misc.show_frame_counter == false) { - set_text(BSNES_TITLE); - } - } - - if(control == &menu_misc_about) { - window_about.focus(); - } - - return true; - } - - return true; -} - -void MainWindow::setup() { - snesinterface.input_ready = bind(&MainWindow::input_ready, this); - - locked = true; - -ui::ControlGroup group; - create(ui::Window::Center, 256, 224, BSNES_TITLE); - set_background_color(0, 0, 0); - - menu.create(*this); - menu_file.create(menu, "File"); - menu_file_load.create(menu_file, "Load Cartridge ..."); - menu_file_load_special.create(menu_file, "Load Special"); - menu_file_load_bsx.create(menu_file_load_special, "Load BS-X Cartridge ..."); - menu_file_load_bsc.create(menu_file_load_special, "Load BS-X Slotted Cartridge ..."); - menu_file_load_st.create(menu_file_load_special, "Load ST Cartridge ..."); - menu_file_load_special.finish(); - menu_file_unload.create(menu_file, "Unload Cartridge"); - menu_file_sep1.create(menu_file); - menu_file_reset.create(menu_file, "Reset System"); - menu_file_power.create(menu_file, "Power Cycle System"); - menu_file_sep2.create(menu_file); - menu_file_exit.create(menu_file, "Exit"); - menu_file.finish(); - - menu_settings.create(menu, "Settings"); - menu_settings_videomode.create(menu_settings, "Video Mode"); - group.add(menu_settings_videomode_1x); - group.add(menu_settings_videomode_2x); - group.add(menu_settings_videomode_3x); - group.add(menu_settings_videomode_4x); - group.add(menu_settings_videomode_5x); - menu_settings_videomode_1x.create(menu_settings_videomode, group, "Scale 1x"); - menu_settings_videomode_2x.create(menu_settings_videomode, group, "Scale 2x"); - menu_settings_videomode_3x.create(menu_settings_videomode, group, "Scale 3x"); - menu_settings_videomode_4x.create(menu_settings_videomode, group, "Scale 4x"); - menu_settings_videomode_5x.create(menu_settings_videomode, group, "Scale 5x"); - group.reset(); - menu_settings_videomode_sep1.create(menu_settings_videomode); - menu_settings_videomode_aspect_correction.create(menu_settings_videomode, "Correct Aspect Ratio"); - menu_settings_videomode_sep2.create(menu_settings_videomode); - group.add(menu_settings_videomode_ntsc); - group.add(menu_settings_videomode_pal); - menu_settings_videomode_ntsc.create(menu_settings_videomode, group, "NTSC"); - menu_settings_videomode_pal.create(menu_settings_videomode, group, "PAL"); - group.reset(); - menu_settings_videomode.finish(); - - menu_settings_videofilter.create(menu_settings, "Video Filter"); - group.add(menu_settings_videofilter_hwpoint); - group.add(menu_settings_videofilter_hwlinear); - menu_settings_videofilter_hwpoint.create(menu_settings_videofilter, group, "Point"); - menu_settings_videofilter_hwlinear.create(menu_settings_videofilter, group, "Linear"); - group.reset(); - menu_settings_videofilter_sep1.create(menu_settings_videofilter); - group.add(menu_settings_videofilter_swnone); - group.add(menu_settings_videofilter_swntsc); - group.add(menu_settings_videofilter_swhq2x); - group.add(menu_settings_videofilter_swscale2x); - menu_settings_videofilter_swnone.create(menu_settings_videofilter, group, "None"); - menu_settings_videofilter_swntsc.create(menu_settings_videofilter, group, "NTSC"); - menu_settings_videofilter_swhq2x.create(menu_settings_videofilter, group, "HQ2x"); - menu_settings_videofilter_swscale2x.create(menu_settings_videofilter, group, "Scale2x"); - group.reset(); - menu_settings_videofilter.finish(); - - menu_settings_videoframeskip.create(menu_settings, "Video Frameskip"); - group.add(menu_settings_videoframeskip_0); - group.add(menu_settings_videoframeskip_1); - group.add(menu_settings_videoframeskip_2); - group.add(menu_settings_videoframeskip_3); - group.add(menu_settings_videoframeskip_4); - group.add(menu_settings_videoframeskip_5); - group.add(menu_settings_videoframeskip_6); - group.add(menu_settings_videoframeskip_7); - group.add(menu_settings_videoframeskip_8); - group.add(menu_settings_videoframeskip_9); - menu_settings_videoframeskip_0.create(menu_settings_videoframeskip, group, "0"); - menu_settings_videoframeskip_sep1.create(menu_settings_videoframeskip); - menu_settings_videoframeskip_1.create(menu_settings_videoframeskip, group, "1"); - menu_settings_videoframeskip_2.create(menu_settings_videoframeskip, group, "2"); - menu_settings_videoframeskip_3.create(menu_settings_videoframeskip, group, "3"); - menu_settings_videoframeskip_4.create(menu_settings_videoframeskip, group, "4"); - menu_settings_videoframeskip_5.create(menu_settings_videoframeskip, group, "5"); - menu_settings_videoframeskip_6.create(menu_settings_videoframeskip, group, "6"); - menu_settings_videoframeskip_7.create(menu_settings_videoframeskip, group, "7"); - menu_settings_videoframeskip_8.create(menu_settings_videoframeskip, group, "8"); - menu_settings_videoframeskip_9.create(menu_settings_videoframeskip, group, "9"); - group.reset(); - menu_settings_videoframeskip.finish(); - - menu_settings_sep1.create(menu_settings); - menu_settings_mute.create(menu_settings, "Mute Sound Output"); - menu_settings_sep2.create(menu_settings); - - menu_settings_speedreg.create(menu_settings, "Speed Regulation"); - menu_settings_speedreg_enable.create(menu_settings_speedreg, "Enable"); - menu_settings_speedreg_sep1.create(menu_settings_speedreg); - group.add(menu_settings_speedreg_slowest); - group.add(menu_settings_speedreg_slow); - group.add(menu_settings_speedreg_normal); - group.add(menu_settings_speedreg_fast); - group.add(menu_settings_speedreg_fastest); - menu_settings_speedreg_slowest.create(menu_settings_speedreg, group, "Slowest"); - menu_settings_speedreg_slow.create(menu_settings_speedreg, group, "Slow"); - menu_settings_speedreg_normal.create(menu_settings_speedreg, group, "Normal"); - menu_settings_speedreg_fast.create(menu_settings_speedreg, group, "Fast"); - menu_settings_speedreg_fastest.create(menu_settings_speedreg, group, "Fastest"); - group.reset(); - menu_settings_speedreg.finish(); - - menu_settings_sep3.create(menu_settings); - menu_settings_config.create(menu_settings, "Configuration ..."); - menu_settings.finish(); - - menu_misc.create(menu, "Misc"); - menu_misc_logaudio.create(menu_misc, "Log Audio Data"); - menu_misc_showfps.create(menu_misc, "Show FPS"); - menu_misc_sep1.create(menu_misc); - menu_misc_about.create(menu_misc, "About ..."); - menu_misc.finish(); - menu.finish(); - - view.create(*this, 0, 0, 0, 256, 224); - view.set_background_color(0, 0, 0); -} - -void MainWindow::update_menu_settings() { - locked = true; - - event::load_video_settings(); - - switch(event::video_settings.multiplier) { default: - case 1: menu_settings_videomode_1x.check(); break; - case 2: menu_settings_videomode_2x.check(); break; - case 3: menu_settings_videomode_3x.check(); break; - case 4: menu_settings_videomode_4x.check(); break; - case 5: menu_settings_videomode_5x.check(); break; - } - - menu_settings_videomode_aspect_correction.check(event::video_settings.aspect_correction); - - switch(event::video_settings.region) { default: - case 0: menu_settings_videomode_ntsc.check(); break; - case 1: menu_settings_videomode_pal.check(); break; - } - - switch(event::video_settings.hardware_filter) { default: - case 0: menu_settings_videofilter_hwpoint.check(); break; - case 1: menu_settings_videofilter_hwlinear.check(); break; - } - - switch(event::video_settings.software_filter) { default: - case 0: menu_settings_videofilter_swnone.check(); break; - case 1: menu_settings_videofilter_swntsc.check(); break; - case 2: menu_settings_videofilter_swhq2x.check(); break; - case 3: menu_settings_videofilter_swscale2x.check(); break; - } - - menu_settings_mute.check(config::snes.mute); - - menu_settings_speedreg_enable.check(config::system.regulate_speed); - menu_settings_speedreg_normal.check(); - - menu_misc_showfps.check(config::misc.show_frame_counter); - - locked = false; -} diff --git a/src/ui/lui/ui_main.h b/src/ui/lui/ui_main.h deleted file mode 100644 index 46c61fc5..00000000 --- a/src/ui/lui/ui_main.h +++ /dev/null @@ -1,74 +0,0 @@ -class MainWindow : public ui::Window { public: -ui::MenuGroup menu_file; - ui::MenuItem menu_file_load; - ui::MenuGroup menu_file_load_special; - ui::MenuItem menu_file_load_bsx; - ui::MenuItem menu_file_load_bsc; - ui::MenuItem menu_file_load_st; - ui::MenuItem menu_file_unload; - ui::MenuSeparator menu_file_sep1; - ui::MenuItem menu_file_reset; - ui::MenuItem menu_file_power; - ui::MenuSeparator menu_file_sep2; - ui::MenuItem menu_file_exit; -ui::MenuGroup menu_settings; - ui::MenuGroup menu_settings_videomode; - ui::MenuRadioItem menu_settings_videomode_1x; - ui::MenuRadioItem menu_settings_videomode_2x; - ui::MenuRadioItem menu_settings_videomode_3x; - ui::MenuRadioItem menu_settings_videomode_4x; - ui::MenuRadioItem menu_settings_videomode_5x; - ui::MenuSeparator menu_settings_videomode_sep1; - ui::MenuCheckItem menu_settings_videomode_aspect_correction; - ui::MenuSeparator menu_settings_videomode_sep2; - ui::MenuRadioItem menu_settings_videomode_ntsc; - ui::MenuRadioItem menu_settings_videomode_pal; - ui::MenuGroup menu_settings_videofilter; - ui::MenuRadioItem menu_settings_videofilter_hwpoint; - ui::MenuRadioItem menu_settings_videofilter_hwlinear; - ui::MenuSeparator menu_settings_videofilter_sep1; - ui::MenuRadioItem menu_settings_videofilter_swnone; - ui::MenuRadioItem menu_settings_videofilter_swntsc; - ui::MenuRadioItem menu_settings_videofilter_swhq2x; - ui::MenuRadioItem menu_settings_videofilter_swscale2x; - ui::MenuGroup menu_settings_videoframeskip; - ui::MenuRadioItem menu_settings_videoframeskip_0; - ui::MenuSeparator menu_settings_videoframeskip_sep1; - ui::MenuRadioItem menu_settings_videoframeskip_1; - ui::MenuRadioItem menu_settings_videoframeskip_2; - ui::MenuRadioItem menu_settings_videoframeskip_3; - ui::MenuRadioItem menu_settings_videoframeskip_4; - ui::MenuRadioItem menu_settings_videoframeskip_5; - ui::MenuRadioItem menu_settings_videoframeskip_6; - ui::MenuRadioItem menu_settings_videoframeskip_7; - ui::MenuRadioItem menu_settings_videoframeskip_8; - ui::MenuRadioItem menu_settings_videoframeskip_9; - ui::MenuSeparator menu_settings_sep1; - ui::MenuCheckItem menu_settings_mute; - ui::MenuSeparator menu_settings_sep2; - ui::MenuGroup menu_settings_speedreg; - ui::MenuCheckItem menu_settings_speedreg_enable; - ui::MenuSeparator menu_settings_speedreg_sep1; - ui::MenuRadioItem menu_settings_speedreg_slowest; - ui::MenuRadioItem menu_settings_speedreg_slow; - ui::MenuRadioItem menu_settings_speedreg_normal; - ui::MenuRadioItem menu_settings_speedreg_fast; - ui::MenuRadioItem menu_settings_speedreg_fastest; - ui::MenuSeparator menu_settings_sep3; - ui::MenuItem menu_settings_config; -ui::MenuGroup menu_misc; - ui::MenuCheckItem menu_misc_logaudio; - ui::MenuCheckItem menu_misc_showfps; - ui::MenuSeparator menu_misc_sep1; - ui::MenuItem menu_misc_about; - -ui::Container view; -// - - bool input_ready(); - -bool locked; - bool message(uint id, uintptr_t param = 0); - void setup(); - void update_menu_settings(); -} window_main; diff --git a/src/ui/main.cpp b/src/ui/main.cpp index acdb2fe3..7a8e43bd 100644 --- a/src/ui/main.cpp +++ b/src/ui/main.cpp @@ -1,7 +1,6 @@ #define INTERFACE_MAIN #include "../base.h" -#include "main.h" #include "config.cpp" void init_snes(); @@ -11,9 +10,13 @@ void term_snes(); * hardware abstraction layer *****/ -#include "video/video.cpp" -#include "audio/audio.cpp" -#include "input/input.cpp" +#include "vai/video.h" +#include "vai/audio.h" +#include "vai/input.h" + +Video *uiVideo; +Audio *uiAudio; +Input *uiInput; #include "inputmgr.cpp" #include "interface.cpp" @@ -22,12 +25,10 @@ void term_snes(); * platform abstraction layer *****/ -#if defined(UI_LUI) - #include "lui/main.cpp" -#elif defined(UI_WIN) - #include "win/main.cpp" -#elif defined(UI_SDL) - #include "sdl/main.cpp" +#if defined(UI_MIU) + #include "../lib/miu.h" + using namespace ns_miu; + #include "miu/main.cpp" #else #error "unsupported platform" #endif diff --git a/src/ui/main.h b/src/ui/main.h deleted file mode 100644 index a05798f9..00000000 --- a/src/ui/main.h +++ /dev/null @@ -1 +0,0 @@ -#include "../lib/libkeymap.h" diff --git a/src/ui/lui/event.cpp b/src/ui/miu/event.cpp similarity index 67% rename from src/ui/lui/event.cpp rename to src/ui/miu/event.cpp index 8ed45970..70a10036 100644 --- a/src/ui/lui/event.cpp +++ b/src/ui/miu/event.cpp @@ -24,44 +24,57 @@ void load_video_settings() { void update_aspect_correction(bool aspect_correction) { switch(config::video.mode) { default: - case 0: config::video.windowed.aspect_correction = aspect_correction; break; - case 1: config::video.fullscreen.aspect_correction = aspect_correction; break; + case 0: config::video.windowed.aspect_correction = aspect_correction; break; + case 1: config::video.fullscreen.aspect_correction = aspect_correction; break; } update_video_settings(); } void update_multiplier(uint multiplier) { switch(config::video.mode) { default: - case 0: config::video.windowed.multiplier = multiplier; break; - case 1: config::video.fullscreen.multiplier = multiplier; break; + case 0: config::video.windowed.multiplier = multiplier; break; + case 1: config::video.fullscreen.multiplier = multiplier; break; } update_video_settings(); } void update_region(uint region) { switch(config::video.mode) { default: - case 0: config::video.windowed.region = region; break; - case 1: config::video.fullscreen.region = region; break; + case 0: config::video.windowed.region = region; break; + case 1: config::video.fullscreen.region = region; break; } update_video_settings(); } void update_hardware_filter(uint hardware_filter) { switch(config::video.mode) { default: - case 0: config::video.windowed.hardware_filter = hardware_filter; break; - case 1: config::video.fullscreen.hardware_filter = hardware_filter; break; + case 0: config::video.windowed.hardware_filter = hardware_filter; break; + case 1: config::video.fullscreen.hardware_filter = hardware_filter; break; } update_video_settings(); } void update_software_filter(uint software_filter) { switch(config::video.mode) { default: - case 0: config::video.windowed.software_filter = software_filter; break; - case 1: config::video.fullscreen.software_filter = software_filter; break; + case 0: config::video.windowed.software_filter = software_filter; break; + case 1: config::video.fullscreen.software_filter = software_filter; break; } update_video_settings(); } +void update_speed_regulation(uint speed) { + config::system.speed = max(1, min(speed, 5)); + if(uiAudio && uiAudio->cap(Audio::Frequency)) { + switch(config::system.speed) { + case 1: uiAudio->set(Audio::Frequency, 16000); break; + case 2: uiAudio->set(Audio::Frequency, 24000); break; + case 3: uiAudio->set(Audio::Frequency, 32000); break; + case 4: uiAudio->set(Audio::Frequency, 48000); break; + case 5: uiAudio->set(Audio::Frequency, 64000); break; + } + } +} + void update_frame_counter() { if(ppu.status.frames_updated) { ppu.status.frames_updated = false; @@ -88,39 +101,40 @@ uint multiplier = minmax<1, 5>(video_settings.multiplier); } switch(video_settings.mode) { default: - case 0: //windowed - window_main.unfullscreen(); - window_main.resize(width, height); - window_main.view.move(0, 0); - window_main.view.resize(width, height); - break; - case 1: //fullscreen - window_main.fullscreen(); - window_main.view.move((ui::get_screen_width() - width) / 2, (ui::get_screen_height() - height) / 2); - window_main.view.resize(width, height); - break; + case 0: { //windowed + window_main.unfullscreen(); + window_main.resize(width, height); + window_main.move(window_main.view, 0, 0); + window_main.view.resize(width, height); + } break; + case 1: { //fullscreen + window_main.fullscreen(); + window_main.move(window_main.view, + (miu().screen_width() - width) / 2, + (miu().screen_height() - height) / 2); + window_main.view.resize(width, height); + } break; } uint filter, standard; switch(video_settings.software_filter) { default: - case 0: filter = VIDEOFILTER_DIRECT; break; - case 1: filter = VIDEOFILTER_NTSC; break; - case 2: filter = VIDEOFILTER_HQ2X; break; - case 3: filter = VIDEOFILTER_SCALE2X; break; + case 0: filter = VIDEOFILTER_DIRECT; break; + case 1: filter = VIDEOFILTER_NTSC; break; + case 2: filter = VIDEOFILTER_HQ2X; break; + case 3: filter = VIDEOFILTER_SCALE2X; break; } switch(video_settings.region) { default: - case 0: standard = SNES::VIDEOSTANDARD_NTSC; break; - case 1: standard = SNES::VIDEOSTANDARD_PAL; break; + case 0: standard = SNES::VIDEOSTANDARD_NTSC; break; + case 1: standard = SNES::VIDEOSTANDARD_PAL; break; } snes.set_video_filter(filter); snes.set_video_standard(standard); if(uiVideo) { - uiVideo->settings.synchronize = video_settings.synchronize; - uiVideo->settings.filter = video_settings.hardware_filter; - uiVideo->update_settings(); + uiVideo->set(Video::Synchronize, video_settings.synchronize); + uiVideo->set(Video::Filter, video_settings.hardware_filter); } //update main window video mode checkbox settings @@ -128,7 +142,7 @@ uint filter, standard; } void toggle_menu() { - window_main.menu.show(!window_main.menu.visible()); + window_main.menu_show(!window_main.menu_visible()); update_video_settings(); } @@ -144,21 +158,21 @@ void toggle_fullscreen() { // bool load_rom(char *fn) { -stringarray dir; +lstring dir; strcpy(fn, ""); - strcpy(dir, config::path.rom); - replace(dir, "\\", "/"); - if(strlen(dir) && !strend(dir, "/")) { strcat(dir, "/"); } + strcpy(dir[0], config::path.rom); + replace(dir[0], "\\", "/"); + if(strlen(dir[0]) && !strend(dir[0], "/")) strcat(dir[0], "/"); //append base path if rom path is relative - if(strbegin(dir, "./")) { - strltrim(dir, "./"); + if(strbegin(dir[0], "./")) { + ltrim(dir[0], "./"); strcpy(dir[1], dir[0]); strcpy(dir[0], config::path.base); strcat(dir[0], dir[1]); } - return ui::file_load(0, fn, + return miu().file_load(0, fn, "SNES images;*.smc,*.sfc,*.swc,*.fig,*.bs,*.st" #if defined(GZIP_SUPPORT) ",*.gz,*.z,*.zip" @@ -167,7 +181,7 @@ stringarray dir; ",*.jma" #endif "|All files;*.*", - strptr(dir)); + dir[0]); } void load_rom() { diff --git a/src/ui/lui/event.h b/src/ui/miu/event.h similarity index 90% rename from src/ui/lui/event.h rename to src/ui/miu/event.h index e9bb2646..250f414f 100644 --- a/src/ui/lui/event.h +++ b/src/ui/miu/event.h @@ -11,13 +11,14 @@ struct VideoSettings { } video_settings; void load_video_settings(); -//change video settings for active video mode void update_aspect_correction(bool); void update_multiplier(uint); void update_region(uint); void update_hardware_filter(uint); void update_software_filter(uint); +void update_speed_regulation(uint); + void update_frame_counter(); void update_video_settings(); void toggle_menu(); diff --git a/src/ui/miu/loader/ui_bsxloader.cpp b/src/ui/miu/loader/ui_bsxloader.cpp new file mode 100644 index 00000000..00853038 --- /dev/null +++ b/src/ui/miu/loader/ui_bsxloader.cpp @@ -0,0 +1,92 @@ +uintptr_t BSXLoaderWindow::close(Event) { + hide(); + return false; +} + +uintptr_t BSXLoaderWindow::bbase_tick(Event) { +char fn[PATH_MAX]; + if(event::load_rom(fn) == true) tbase.set_text(fn); + return true; +} + +uintptr_t BSXLoaderWindow::cbase_tick(Event) { + tbase.set_text(""); + return true; +} + +uintptr_t BSXLoaderWindow::bslot_tick(Event) { +char fn[PATH_MAX]; + if(event::load_rom(fn) == true) tslot.set_text(fn); + return true; +} + +uintptr_t BSXLoaderWindow::cslot_tick(Event) { + tslot.set_text(""); + return true; +} + +uintptr_t BSXLoaderWindow::load_tick(Event) { +char base[PATH_MAX], slot[PATH_MAX]; + tbase.get_text(base, PATH_MAX); + tslot.get_text(slot, PATH_MAX); + + if(mode == ModeBSX) { + config::path.bsx = base; + event::load_cart_bsx(base, slot); + } else if(mode == ModeBSC) { + event::load_cart_bsc(base, slot); + } + + tbase.set_text(""); + tslot.set_text(""); + hide(); + return true; +} + +uintptr_t BSXLoaderWindow::cancel_tick(Event) { + tbase.set_text(""); + tslot.set_text(""); + hide(); + return true; +} + +void BSXLoaderWindow::setup() { + create(Window::AutoCenter, 640, 150, "Load BS-X Cartridge"); + + lbase.create(0, 630, 20, "Base cartridge:"); + tbase.create(0, 420, 30); + bbase.create(0, 100, 30, "Browse ..."); + cbase.create(0, 100, 30, "Clear"); + + lslot.create(0, 630, 20, "Slot cartridge:"); + tslot.create(0, 420, 30); + bslot.create(0, 100, 30, "Browse ..."); + cslot.create(0, 100, 30, "Clear"); + + load.create (0, 312, 30, "Load"); + cancel.create(0, 312, 30, "Cancel"); + +uint y = 5; + attach(lbase, 5, y); y += 20; + attach(tbase, 5, y); + attach(bbase, 430, y); + attach(cbase, 535, y); y += 30 + 5; + attach(lslot, 5, y); y += 20; + attach(tslot, 5, y); + attach(bslot, 430, y); + attach(cslot, 535, y); y += 30 + 5; + attach(load, 5, y); + attach(cancel, 323, y); y += 30 + 5; + + on_close = bind(&BSXLoaderWindow::close, this); + bbase.on_tick = bind(&BSXLoaderWindow::bbase_tick, this); + cbase.on_tick = bind(&BSXLoaderWindow::cbase_tick, this); + bslot.on_tick = bind(&BSXLoaderWindow::bslot_tick, this); + cslot.on_tick = bind(&BSXLoaderWindow::cslot_tick, this); + load.on_tick = bind(&BSXLoaderWindow::load_tick, this); + cancel.on_tick = bind(&BSXLoaderWindow::cancel_tick, this); +} + +BSXLoaderWindow::BSXLoaderWindow() { + mode = ModeBSX; +} diff --git a/src/ui/miu/loader/ui_bsxloader.h b/src/ui/miu/loader/ui_bsxloader.h new file mode 100644 index 00000000..e5d7e3c4 --- /dev/null +++ b/src/ui/miu/loader/ui_bsxloader.h @@ -0,0 +1,28 @@ +class BSXLoaderWindow : public Window { +public: + enum Mode { + ModeBSX, //BS-X cartridge + ModeBSC, //BS-X slotted cartridge + } mode; + + Label lbase; + Editbox tbase; + Button bbase, cbase; + + Label lslot; + Editbox tslot; + Button bslot, cslot; + + Button load, cancel; + + void setup(); + uintptr_t close(Event); + uintptr_t bbase_tick(Event); + uintptr_t cbase_tick(Event); + uintptr_t bslot_tick(Event); + uintptr_t cslot_tick(Event); + uintptr_t load_tick(Event); + uintptr_t cancel_tick(Event); + + BSXLoaderWindow(); +} window_bsxloader; diff --git a/src/ui/miu/loader/ui_stloader.cpp b/src/ui/miu/loader/ui_stloader.cpp new file mode 100644 index 00000000..a133b5ad --- /dev/null +++ b/src/ui/miu/loader/ui_stloader.cpp @@ -0,0 +1,109 @@ +uintptr_t STLoaderWindow::close(Event) { + hide(); + return false; +} + +uintptr_t STLoaderWindow::bbase_tick(Event) { +char fn[PATH_MAX]; + if(event::load_rom(fn) == true) tbase.set_text(fn); + return true; +} + +uintptr_t STLoaderWindow::cbase_tick(Event) { + tbase.set_text(""); + return true; +} + +uintptr_t STLoaderWindow::bslotA_tick(Event) { +char fn[PATH_MAX]; + if(event::load_rom(fn) == true) tslotA.set_text(fn); + return true; +} + +uintptr_t STLoaderWindow::cslotA_tick(Event) { + tslotA.set_text(""); + return true; +} + +uintptr_t STLoaderWindow::bslotB_tick(Event) { +char fn[PATH_MAX]; + if(event::load_rom(fn) == true) tslotB.set_text(fn); + return true; +} + +uintptr_t STLoaderWindow::cslotB_tick(Event) { + tslotB.set_text(""); + return true; +} + +uintptr_t STLoaderWindow::load_tick(Event) { +char base[PATH_MAX], slotA[PATH_MAX], slotB[PATH_MAX]; + tbase.get_text(base, PATH_MAX); + tslotA.get_text(slotA, PATH_MAX); + tslotB.get_text(slotB, PATH_MAX); + + config::path.st = base; + event::load_cart_st(base, slotA, slotB); + + tbase.set_text(""); + tslotA.set_text(""); + tslotB.set_text(""); + hide(); + return true; +} + +uintptr_t STLoaderWindow::cancel_tick(Event) { + tbase.set_text(""); + tslotA.set_text(""); + tslotB.set_text(""); + hide(); + return true; +} + +void STLoaderWindow::setup() { + create(Window::AutoCenter, 640, 205, "Load Sufami Turbo Cartridge"); + + lbase.create(0, 630, 20, "Base cartridge:"); + tbase.create(0, 420, 30); + bbase.create(0, 100, 30, "Browse ..."); + cbase.create(0, 100, 30, "Clear"); + + lslotA.create(0, 630, 20, "Slot A cartridge:"); + tslotA.create(0, 420, 30); + bslotA.create(0, 100, 30, "Browse ..."); + cslotA.create(0, 100, 30, "Clear"); + + lslotB.create(0, 630, 20, "Slot B cartridge:"); + tslotB.create(0, 420, 30); + bslotB.create(0, 100, 30, "Browse ..."); + cslotB.create(0, 100, 30, "Clear"); + + load.create (0, 312, 30, "Load"); + cancel.create(0, 312, 30, "Cancel"); + +uint y = 5; + attach(lbase, 5, y); y += 20; + attach(tbase, 5, y); + attach(bbase, 430, y); + attach(cbase, 535, y); y += 30 + 5; + attach(lslotA, 5, y); y += 20; + attach(tslotA, 5, y); + attach(bslotA, 430, y); + attach(cslotA, 535, y); y += 30 + 5; + attach(lslotB, 5, y); y += 20; + attach(tslotB, 5, y); + attach(bslotB, 430, y); + attach(cslotB, 535, y); y += 30 + 5; + attach(load, 5, y); + attach(cancel, 323, y); y += 30 + 5; + + on_close = bind(&STLoaderWindow::close, this); + bbase.on_tick = bind(&STLoaderWindow::bbase_tick, this); + cbase.on_tick = bind(&STLoaderWindow::cbase_tick, this); + bslotA.on_tick = bind(&STLoaderWindow::bslotA_tick, this); + cslotA.on_tick = bind(&STLoaderWindow::cslotA_tick, this); + bslotB.on_tick = bind(&STLoaderWindow::bslotB_tick, this); + cslotB.on_tick = bind(&STLoaderWindow::cslotB_tick, this); + load.on_tick = bind(&STLoaderWindow::load_tick, this); + cancel.on_tick = bind(&STLoaderWindow::cancel_tick, this); +} diff --git a/src/ui/miu/loader/ui_stloader.h b/src/ui/miu/loader/ui_stloader.h new file mode 100644 index 00000000..3d8dd476 --- /dev/null +++ b/src/ui/miu/loader/ui_stloader.h @@ -0,0 +1,27 @@ +class STLoaderWindow : public Window { +public: + Label lbase; + Editbox tbase; + Button bbase, cbase; + + Label lslotA; + Editbox tslotA; + Button bslotA, cslotA; + + Label lslotB; + Editbox tslotB; + Button bslotB, cslotB; + + Button load, cancel; + + void setup(); + uintptr_t close(Event); + uintptr_t bbase_tick(Event); + uintptr_t cbase_tick(Event); + uintptr_t bslotA_tick(Event); + uintptr_t cslotA_tick(Event); + uintptr_t bslotB_tick(Event); + uintptr_t cslotB_tick(Event); + uintptr_t load_tick(Event); + uintptr_t cancel_tick(Event); +} window_stloader; diff --git a/src/ui/lui/main.cpp b/src/ui/miu/main.cpp similarity index 82% rename from src/ui/lui/main.cpp rename to src/ui/miu/main.cpp index c7c0452b..e3cfc836 100644 --- a/src/ui/lui/main.cpp +++ b/src/ui/miu/main.cpp @@ -1,15 +1,4 @@ void run(); - -#if defined(PLATFORM_WIN) - #include "../../lib/libui_win.h" -#elif defined(PLATFORM_X) - #include "../../lib/libui_gtk.h" -#else - #error "unsupported platform" -#endif - -namespace ui = libui; - bool _term_ = false; #include "ui.h" @@ -68,21 +57,23 @@ char full_name[PATH_MAX] = ""; string t = full_name; if(strlen(t) != 0) { //remove program name + //TODO: rewrite this to be cleaner ... replace(t, "\\", "/"); for(int i = strlen(t) - 1; i >= 0; i--) { - if(strptr(t)[i] == '/' || strptr(t)[i] == '\\') { - strptr(t)[i] = 0; + if(t()[i] == '/' || t()[i] == '\\') { + t()[i] = 0; break; } } } if(strend(t, "/") == false) { strcat(t, "/"); } - config::path.base = strptr(t); + config::path.base = t; } void run() { - while(ui::events_pending() == true) { ui::run(); } + while(miu().pending()) miu().run(); + if(cartridge.loaded() == true) { snes.runtoframe(); event::update_frame_counter(); @@ -107,7 +98,7 @@ int main(int argc, char *argv[]) { set_config_filename(); get_base_path(argv[0]); - ui::init(); + miu().init(); config::config().load(config::filename); if(fexists(config::filename) == false) { //in case program crashes on first run, save config file @@ -131,6 +122,6 @@ int main(int argc, char *argv[]) { config::config().save(config::filename); snes.term(); ui_term(); - ui::term(); + miu().term(); return 0; } diff --git a/src/ui/miu/settings/ui_advanced.cpp b/src/ui/miu/settings/ui_advanced.cpp new file mode 100644 index 00000000..2a49cd2d --- /dev/null +++ b/src/ui/miu/settings/ui_advanced.cpp @@ -0,0 +1,85 @@ +uintptr_t AdvancedWindow::list_change(Event) { +int pos = list.get_selection(); + set_val.enable(pos >= 0); + set_def.enable(pos >= 0); + if(pos >= 0 && pos < config::config().list_count) { + desc.set_text(string() << "(default = " << config::config().list[pos]->def << ")\n" << config::config().list[pos]->desc); + string val; + config::config().list[pos]->get(val); + edit_val.set_text(val); + } +} + +uintptr_t AdvancedWindow::setval_tick(Event) { +char t[4096]; + edit_val.get_text(t, sizeof t); + update(list.get_selection(), t); +} + +uintptr_t AdvancedWindow::setdef_tick(Event) { + update(list.get_selection(), 0); + return true; +} + +void AdvancedWindow::read_config(uint pos, string &data) { + data = "?\t?\t?"; + if(pos >= config::config().list_count) return; + +string name, val; + name = config::config().list[pos]->name; + config::config().list[pos]->get(val); + if(val != config::config().list[pos]->def) { strcat(name, " (*)"); } + data = string() + << name << "\t" + << (config::config().list[pos]->type == Setting::String ? "String" : "Integer") << "\t" + << val; +} + +void AdvancedWindow::update(uint pos, const char *data) { + if(pos >= config::config().list_count) return; + + config::config().list[pos]->set(data ? data : config::config().list[pos]->def); +string val; + config::config().list[pos]->get(val); + edit_val.set_text(val); + read_config(pos, val); + list.set_item(pos, val); + list.autosize_columns(); +} + +void AdvancedWindow::setup() { + create(0, 475, 355); + + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 475, 235, "Name\tType\tValue"); + desc.create(Editbox::Multiline | Editbox::VerticalScrollAlways | Editbox::Readonly, 475, 80, + "\n" + "Warning: modifification of certain variables will not take effect until\n" + "bsnes is restarted, and corresponding UI elements will not be updated\n" + "to reflect changes here. (*) = modified" + ); + edit_val.create(0, 265, 30, ""); + set_val.create (0, 100, 30, "Set"); + set_def.create (0, 100, 30, "Default"); + +uint y = 0; + attach(list, 0, y); y += 235 + 5; + attach(desc, 0, y); y += 80 + 5; + attach(edit_val, 0, y); + attach(set_val, 270, y); + attach(set_def, 375, y); y += 30 + 5; + + for(int i = 0; i < config::config().list_count; i++) { + string val; + read_config(i, val); + list.add_item(val); + } + + list.autosize_columns(); + + set_val.disable(); + set_def.disable(); + + list.on_change = bind(&AdvancedWindow::list_change, this); + set_val.on_tick = bind(&AdvancedWindow::setval_tick, this); + set_def.on_tick = bind(&AdvancedWindow::setdef_tick, this); +} diff --git a/src/ui/miu/settings/ui_advanced.h b/src/ui/miu/settings/ui_advanced.h new file mode 100644 index 00000000..561d0514 --- /dev/null +++ b/src/ui/miu/settings/ui_advanced.h @@ -0,0 +1,15 @@ +class AdvancedWindow : public Window { +public: + Listbox list; + Editbox desc; + Editbox edit_val; + Button set_val; + Button set_def; + + void read_config(uint pos, string &data); + void update(uint pos, const char *data); + void setup(); + uintptr_t list_change(Event); + uintptr_t setval_tick(Event); + uintptr_t setdef_tick(Event); +} window_advanced; diff --git a/src/ui/miu/settings/ui_cheateditor.cpp b/src/ui/miu/settings/ui_cheateditor.cpp new file mode 100644 index 00000000..ea1ce934 --- /dev/null +++ b/src/ui/miu/settings/ui_cheateditor.cpp @@ -0,0 +1,91 @@ +void CheatEditorWindow::setup() { + create(0, 475, 355); + + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 475, 285, "Status\tCode\tDescription"); + add_code.create (0, 155, 30, "Add Code"); + toggle_code.create(0, 155, 30, "Toggle Status"); + delete_code.create(0, 155, 30, "Delete Code"); + code.create(0, 155, 30, ""); + desc.create(0, 315, 30, ""); + +uint y = 0; + attach(list, 0, y); y += 285 + 5; + attach(add_code, 0, y); + attach(toggle_code, 160, y); + attach(delete_code, 320, y); y += 30 + 5; + attach(code, 0, y); + attach(desc, 160, y); y += 30 + 5; + + list.on_activate = bind(&CheatEditorWindow::toggle_event, this); + add_code.on_tick = bind(&CheatEditorWindow::add_tick, this); + toggle_code.on_tick = bind(&CheatEditorWindow::toggle_event, this); + delete_code.on_tick = bind(&CheatEditorWindow::delete_tick, this); + + refresh(); +} + +void CheatEditorWindow::refresh() { + list.reset(); + + for(uint i = 0; i < cheat.count(); i++) { + bool enabled; + uint32 addr; + uint8 data; + char s_code[256], s_desc[256]; + cheat.get(i, enabled, addr, data, s_code, s_desc); + list.add_item(string() + << (enabled ? "Enabled" : "Disabled") << "\t" + << s_code << "\t" + << s_desc); + } + + list.autosize_columns(); + +//enable controls only if cartridge is loaded +bool loaded = cartridge.loaded(); + add_code.enable(loaded); + toggle_code.enable(loaded); + delete_code.enable(loaded); +} + +uintptr_t CheatEditorWindow::toggle_event(Event) { +int index = list.get_selection(); + if(index >= 0 && index < cheat.count()) { + cheat.enabled(index) ? cheat.disable(index) : cheat.enable(index); + bool enabled; + uint32 addr; + uint8 data; + char s_code[256], s_desc[256]; + cheat.get(index, enabled, addr, data, s_code, s_desc); + list.set_item(index, string() + << (enabled ? "Enabled" : "Disabled") << "\t" + << s_code << "\t" + << s_desc); + } + return true; +} + +uintptr_t CheatEditorWindow::add_tick(Event) { +char s_code[256], s_desc[256]; + code.get_text(s_code, sizeof s_code); + desc.get_text(s_desc, sizeof s_desc); + cheat.add(false, s_code, s_desc); //param 0 = false, meaning: new codes disabled by default + refresh(); + return true; +} + +uintptr_t CheatEditorWindow::delete_tick(Event) { +int index = list.get_selection(); + if(index >= 0 && index < cheat.count()) { + cheat.remove(index); + refresh(); + } + return true; +} + +/* +bool CheatEditorWindow::message(uint id, uintptr_t param) { + if((id == ui::Message::Clicked && control == &toggle_code) || + (id == ui::Message::DoubleClicked && control == &list)) {} +} +*/ diff --git a/src/ui/miu/settings/ui_cheateditor.h b/src/ui/miu/settings/ui_cheateditor.h new file mode 100644 index 00000000..c385e61c --- /dev/null +++ b/src/ui/miu/settings/ui_cheateditor.h @@ -0,0 +1,16 @@ +class CheatEditorWindow : public Window { +public: + Listbox list; + Button add_code; + Button toggle_code; + Button delete_code; + Editbox code; + Editbox desc; + + void setup(); + void refresh(); + + uintptr_t toggle_event(Event); + uintptr_t add_tick(Event); + uintptr_t delete_tick(Event); +} window_cheat_editor; diff --git a/src/ui/miu/settings/ui_inputconfig.cpp b/src/ui/miu/settings/ui_inputconfig.cpp new file mode 100644 index 00000000..d201e42c --- /dev/null +++ b/src/ui/miu/settings/ui_inputconfig.cpp @@ -0,0 +1,214 @@ +/* InputConfigWindow */ + +void InputConfigWindow::setup() { + create(0, 475, 355); + + lportA.create(0, 235, 20, "Controller Port A:"); + lportB.create(0, 235, 20, "Controller Port B:"); + + portA.create(0, 235, 30); + portA.add_item("None"); + portA.add_item("Joypad 1"); + portA.add_item("Joypad 2"); + portA.set_selection(1); + portA.disable(); + + portB.create(0, 235, 30); + portB.add_item("None"); + portB.add_item("Joypad 1"); + portB.add_item("Joypad 2"); + portB.set_selection(2); + portB.disable(); + + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 475, 265, "Name\tValue"); + setkey.create(0, 235, 30, "Assign Key"); + setkey.disable(); + clrkey.create(0, 235, 30, "Unassign Key"); + clrkey.disable(); + +uint y = 0; + attach(lportA, 0, y); + attach(lportB, 240, y); y += 20; + attach(portA, 0, y); + attach(portB, 240, y); y += 30 + 5; + attach(list, 0, y); y += 265 + 5; + attach(setkey, 0, y); + attach(clrkey, 240, y); y += 30 + 5; + + list.on_change = bind(&InputConfigWindow::list_change, this); + list.on_activate = bind(&InputConfigWindow::set_tick, this); + setkey.on_tick = bind(&InputConfigWindow::set_tick, this); + clrkey.on_tick = bind(&InputConfigWindow::clr_tick, this); + + for(uint i = 0; i < 24; i++) list.add_item("???\t???"); + refresh_list(); + window_input_capture.setup(); +} + +void InputConfigWindow::refresh_list() { + for(uint i = 0; i < 24; i++) { + list.set_item(i, string() << list_index[i] << "\t" << keymap::find(get_value(i))); + } + list.autosize_columns(); +} + +uintptr_t InputConfigWindow::list_change(Event) { +int pos = list.get_selection(); + setkey.enable(pos >= 0); + clrkey.enable(pos >= 0); + return true; +} + +uintptr_t InputConfigWindow::set_tick(Event) { +int pos = list.get_selection(); + if(pos < 0) return true; + window_input_capture.index = pos; + window_input_capture.label.set_text(string() << "Press a key to assign to " << list_index[pos] << " ..."); + window_input_capture.show(); + return true; +} + +uintptr_t InputConfigWindow::clr_tick(Event) { +int pos = list.get_selection(); + if(pos < 0) return true; + set_value(pos, keymap::none); + refresh_list(); + return true; +} + +/* InputCaptureWindow */ + +void InputCaptureWindow::setup() { + create(Window::AutoCenter, 350, 100, "bsnes Key Capture"); + label.create(0, 340, 90); + attach(label, 5, 5); + on_close = bind(&InputCaptureWindow::close, this); +} + +void InputCaptureWindow::show() { + uiInput->clear_input(); + +//enter and spacebar can be used to activate key capture, +//set lock on these keys if they are held down to prevent +//them from being instantly assigned to selected entry ... + uiInput->poll(); + key_lock = (uiInput->key_down(keymap::enter) || uiInput->key_down(keymap::space)); + Window::focus(); + + while(_term_ == false && visible() == true) { + run(); + uint16 key = input_manager.scan(); + if(key == keymap::none) { key_lock = false; continue; } + if(key_lock && (key == keymap::enter || key == keymap::space)) { continue; } + hide(); + window_input_config.set_value(index, key); + window_input_config.refresh_list(); + break; + } + + uiInput->clear_input(); +} + +uintptr_t InputCaptureWindow::close(Event) { + hide(); + return false; +} + +InputCaptureWindow::InputCaptureWindow() { + index = 0; + key_lock = false; +} + +/* Misc */ + +const char InputConfigWindow::list_index[][64] = { + "Joypad 1 Up", + "Joypad 1 Down", + "Joypad 1 Left", + "Joypad 1 Right", + "Joypad 1 A", + "Joypad 1 B", + "Joypad 1 X", + "Joypad 1 Y", + "Joypad 1 L", + "Joypad 1 R", + "Joypad 1 Select", + "Joypad 1 Start", + + "Joypad 2 Up", + "Joypad 2 Down", + "Joypad 2 Left", + "Joypad 2 Right", + "Joypad 2 A", + "Joypad 2 B", + "Joypad 2 X", + "Joypad 2 Y", + "Joypad 2 L", + "Joypad 2 R", + "Joypad 2 Select", + "Joypad 2 Start", +}; + +uint InputConfigWindow::get_value(uint index) { + switch(index) { + case 0: return keymap::find(config::input.joypad1.up); + case 1: return keymap::find(config::input.joypad1.down); + case 2: return keymap::find(config::input.joypad1.left); + case 3: return keymap::find(config::input.joypad1.right); + case 4: return keymap::find(config::input.joypad1.a); + case 5: return keymap::find(config::input.joypad1.b); + case 6: return keymap::find(config::input.joypad1.x); + case 7: return keymap::find(config::input.joypad1.y); + case 8: return keymap::find(config::input.joypad1.l); + case 9: return keymap::find(config::input.joypad1.r); + case 10: return keymap::find(config::input.joypad1.select); + case 11: return keymap::find(config::input.joypad1.start); + + case 12: return keymap::find(config::input.joypad2.up); + case 13: return keymap::find(config::input.joypad2.down); + case 14: return keymap::find(config::input.joypad2.left); + case 15: return keymap::find(config::input.joypad2.right); + case 16: return keymap::find(config::input.joypad2.a); + case 17: return keymap::find(config::input.joypad2.b); + case 18: return keymap::find(config::input.joypad2.x); + case 19: return keymap::find(config::input.joypad2.y); + case 20: return keymap::find(config::input.joypad2.l); + case 21: return keymap::find(config::input.joypad2.r); + case 22: return keymap::find(config::input.joypad2.select); + case 23: return keymap::find(config::input.joypad2.start); + } + + return keymap::none; +} + +void InputConfigWindow::set_value(uint index, uint16 value) { + switch(index) { + case 0: config::input.joypad1.up = keymap::find(value); break; + case 1: config::input.joypad1.down = keymap::find(value); break; + case 2: config::input.joypad1.left = keymap::find(value); break; + case 3: config::input.joypad1.right = keymap::find(value); break; + case 4: config::input.joypad1.a = keymap::find(value); break; + case 5: config::input.joypad1.b = keymap::find(value); break; + case 6: config::input.joypad1.x = keymap::find(value); break; + case 7: config::input.joypad1.y = keymap::find(value); break; + case 8: config::input.joypad1.l = keymap::find(value); break; + case 9: config::input.joypad1.r = keymap::find(value); break; + case 10: config::input.joypad1.select = keymap::find(value); break; + case 11: config::input.joypad1.start = keymap::find(value); break; + + case 12: config::input.joypad2.up = keymap::find(value); break; + case 13: config::input.joypad2.down = keymap::find(value); break; + case 14: config::input.joypad2.left = keymap::find(value); break; + case 15: config::input.joypad2.right = keymap::find(value); break; + case 16: config::input.joypad2.a = keymap::find(value); break; + case 17: config::input.joypad2.b = keymap::find(value); break; + case 18: config::input.joypad2.x = keymap::find(value); break; + case 19: config::input.joypad2.y = keymap::find(value); break; + case 20: config::input.joypad2.l = keymap::find(value); break; + case 21: config::input.joypad2.r = keymap::find(value); break; + case 22: config::input.joypad2.select = keymap::find(value); break; + case 23: config::input.joypad2.start = keymap::find(value); break; + } + + input_manager.bind(); +} diff --git a/src/ui/miu/settings/ui_inputconfig.h b/src/ui/miu/settings/ui_inputconfig.h new file mode 100644 index 00000000..cb2b05a0 --- /dev/null +++ b/src/ui/miu/settings/ui_inputconfig.h @@ -0,0 +1,36 @@ +class InputConfigWindow : public Window { +public: + Label lportA; + Label lportB; + Combobox portA; + Combobox portB; + Listbox list; + Button setkey; + Button clrkey; + + void setup(); + void refresh_list(); + + uintptr_t list_change(Event); + uintptr_t set_tick(Event); + uintptr_t clr_tick(Event); + + static const char list_index[][64]; + uint get_value(uint index); + void set_value(uint index, uint16 value); +} window_input_config; + +class InputCaptureWindow : public Window { +public: + Label label; + + uint index; + bool key_lock; + + void setup(); + void show(); + + uintptr_t close(Event); + + InputCaptureWindow(); +} window_input_capture; diff --git a/src/ui/miu/settings/ui_rastersettings.cpp b/src/ui/miu/settings/ui_rastersettings.cpp new file mode 100644 index 00000000..edd35b3d --- /dev/null +++ b/src/ui/miu/settings/ui_rastersettings.cpp @@ -0,0 +1,140 @@ +void RasterSettingsWindow::setup() { + create(0, 475, 355); + + lcontrast.create (0, 475, 20); + contrast.create (0, 475, 30, 192); + lbrightness.create (0, 475, 20); + brightness.create (0, 475, 30, 192); + lgamma.create (0, 475, 20); + gamma.create (0, 475, 30, 191); + gamma_ramp.create (0, 235, 20, "Gamma ramp"); + sepia.create (0, 235, 20, "Sepia"); + grayscale.create (0, 235, 20, "Grayscale"); + invert.create (0, 235, 20, "Invert colors"); + preset_optimal.create (0, 235, 30, "Optimal Preset"); + preset_standard.create(0, 235, 30, "Standard Preset"); + sync_ui(); + +uint y = 0; + attach(lcontrast, 0, y); y += 20; + attach(contrast, 0, y); y += 30; + attach(lbrightness, 0, y); y += 20; + attach(brightness, 0, y); y += 30; + attach(lgamma, 0, y); y += 20; + attach(gamma, 0, y); y += 30; + attach(gamma_ramp, 0, y); + attach(sepia, 240, y); y += 20; + attach(grayscale, 0, y); + attach(invert, 240, y); y += 20; + attach(preset_optimal, 0, y); + attach(preset_standard, 240, y); y += 30; + + contrast.on_change = bind(&RasterSettingsWindow::contrast_change, this); + brightness.on_change = bind(&RasterSettingsWindow::brightness_change, this); + gamma.on_change = bind(&RasterSettingsWindow::gamma_change, this); + gamma_ramp.on_tick = bind(&RasterSettingsWindow::gammaramp_tick, this); + sepia.on_tick = bind(&RasterSettingsWindow::sepia_tick, this); + grayscale.on_tick = bind(&RasterSettingsWindow::grayscale_tick, this); + invert.on_tick = bind(&RasterSettingsWindow::invert_tick, this); + preset_optimal.on_tick = bind(&RasterSettingsWindow::optimal_tick, this); + preset_standard.on_tick = bind(&RasterSettingsWindow::standard_tick, this); +} + +//update all UI controls to match config file values ... +void RasterSettingsWindow::sync_ui() { + ui_lock = true; //supress event messages while syncing UI elements, prevents infinite recursion + contrast.set_position(config::snes.contrast + 96); + lcontrast.set_text(string() << "Contrast: " << config::snes.contrast); + brightness.set_position(config::snes.brightness + 96); + lbrightness.set_text(string() << "Brightness: " << config::snes.brightness); + gamma.set_position(config::snes.gamma - 10); + lgamma.set_text(string() << "Gamma: " << config::snes.gamma); //TODO: print gamma as "%0.2f" / 100.0 + gamma_ramp.check(config::snes.gamma_ramp); + sepia.check(config::snes.sepia); + grayscale.check(config::snes.grayscale); + invert.check(config::snes.invert); + snes.update_color_lookup_table(); + ui_lock = false; +} + +uintptr_t RasterSettingsWindow::contrast_change(Event) { + if(!ui_lock && config::snes.contrast != contrast.get_position() - 96) { + config::snes.contrast = contrast.get_position() - 96; + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::brightness_change(Event) { + if(!ui_lock && config::snes.brightness != brightness.get_position() - 96) { + config::snes.brightness = brightness.get_position() - 96; + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::gamma_change(Event) { + if(!ui_lock && config::snes.gamma != gamma.get_position() + 10) { + config::snes.gamma = gamma.get_position() + 10; + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::gammaramp_tick(Event) { + if(!ui_lock && config::snes.gamma_ramp != gamma_ramp.checked()) { + config::snes.gamma_ramp = gamma_ramp.checked(); + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::sepia_tick(Event) { + if(!ui_lock && config::snes.sepia != sepia.checked()) { + config::snes.sepia = sepia.checked(); + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::grayscale_tick(Event) { + if(!ui_lock && config::snes.grayscale != grayscale.checked()) { + config::snes.grayscale = grayscale.checked(); + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::invert_tick(Event) { + if(!ui_lock && config::snes.invert != invert.checked()) { + config::snes.invert = invert.checked(); + sync_ui(); + } + return true; +} + +uintptr_t RasterSettingsWindow::optimal_tick(Event) { + config::snes.contrast = 0; + config::snes.brightness = 0; + config::snes.gamma = 80; + config::snes.gamma_ramp = true; + config::snes.sepia = false; + config::snes.grayscale = false; + config::snes.invert = false; + sync_ui(); +} + +uintptr_t RasterSettingsWindow::standard_tick(Event) { + config::snes.contrast = 0; + config::snes.brightness = 0; + config::snes.gamma = 100; + config::snes.gamma_ramp = false; + config::snes.sepia = false; + config::snes.grayscale = false; + config::snes.invert = false; + sync_ui(); +} + +RasterSettingsWindow::RasterSettingsWindow() { + ui_lock = false; +} diff --git a/src/ui/miu/settings/ui_rastersettings.h b/src/ui/miu/settings/ui_rastersettings.h new file mode 100644 index 00000000..9d924efd --- /dev/null +++ b/src/ui/miu/settings/ui_rastersettings.h @@ -0,0 +1,33 @@ +class RasterSettingsWindow : public Window { +public: + Label lcontrast; + Label lbrightness; + Label lgamma; + Slider contrast; + Slider brightness; + Slider gamma; + + Checkbox gamma_ramp; + Checkbox sepia; + Checkbox grayscale; + Checkbox invert; + + Button preset_optimal; + Button preset_standard; + + void setup(); + void sync_ui(); + + bool ui_lock; + uintptr_t contrast_change(Event); + uintptr_t brightness_change(Event); + uintptr_t gamma_change(Event); + uintptr_t gammaramp_tick(Event); + uintptr_t sepia_tick(Event); + uintptr_t grayscale_tick(Event); + uintptr_t invert_tick(Event); + uintptr_t optimal_tick(Event); + uintptr_t standard_tick(Event); + + RasterSettingsWindow(); +} window_raster_settings; diff --git a/src/ui/miu/settings/ui_settings.cpp b/src/ui/miu/settings/ui_settings.cpp new file mode 100644 index 00000000..f88a3eae --- /dev/null +++ b/src/ui/miu/settings/ui_settings.cpp @@ -0,0 +1,47 @@ +void SettingsWindow::setup() { + create(Window::AutoCenter, 640, 365, "bsnes Configuration Settings"); + + panel_list.create(0, 150, 355); + panel_list.add_item("Raster Settings"); + panel_list.add_item("Input Configuration"); + panel_list.add_item("Cheat Code Editor"); + panel_list.add_item("Advanced"); + + attach(panel_list, 5, 5); + attach(window_raster_settings, 160, 5); + attach(window_input_config, 160, 5); + attach(window_cheat_editor, 160, 5); + attach(window_advanced, 160, 5); + + on_close = bind(&SettingsWindow::close, this); + panel_list.on_change = bind(&SettingsWindow::list_change, this); + + panel_list.set_selection(0); +} + +uintptr_t SettingsWindow::close(Event) { + hide(); + return false; +} + +uintptr_t SettingsWindow::list_change(Event) { + window_raster_settings.hide(); + window_input_config.hide(); + window_cheat_editor.hide(); + window_advanced.hide(); + + switch(panel_list.get_selection()) { + case 0: window_raster_settings.show(); break; + case 1: window_input_config.show(); break; + case 2: window_cheat_editor.show(); break; + case 3: window_advanced.show(); break; + } + + panel_list.focus(); + return true; +} + +void SettingsWindow::show() { + Window::show(); + panel_list.focus(); +} diff --git a/src/ui/miu/settings/ui_settings.h b/src/ui/miu/settings/ui_settings.h new file mode 100644 index 00000000..968ee741 --- /dev/null +++ b/src/ui/miu/settings/ui_settings.h @@ -0,0 +1,9 @@ +class SettingsWindow : public Window { +public: + Listbox panel_list; + + void setup(); + void show(); + uintptr_t close(Event); + uintptr_t list_change(Event); +} window_settings; diff --git a/src/ui/miu/ui.cpp b/src/ui/miu/ui.cpp new file mode 100644 index 00000000..93bb4e5c --- /dev/null +++ b/src/ui/miu/ui.cpp @@ -0,0 +1,114 @@ +#include "ui_main.cpp" +#include "ui_about.cpp" + +#include "loader/ui_bsxloader.cpp" +#include "loader/ui_stloader.cpp" + +#include "settings/ui_settings.cpp" +#include "settings/ui_rastersettings.cpp" +#include "settings/ui_inputconfig.cpp" +#include "settings/ui_cheateditor.cpp" +#include "settings/ui_advanced.cpp" + +#if defined(PLATFORM_WIN) + #include "../vai/video/video.direct3d.h" + #include "../vai/video/video.directdraw.h" + #include "../vai/video/video.gdi.h" + #include "../vai/audio/audio.directsound.h" + #include "../vai/input/input.directinput.h" +#elif defined(PLATFORM_X) + #include "../vai/video/video.xv.h" + #include "../vai/video/video.gtk.h" + #include "../vai/audio/audio.ao.h" + #include "../vai/input/input.x.h" +#endif + +void ui_init() { + window_main.setup(); + window_about.setup(); + + window_bsxloader.setup(); + window_stloader.setup(); + + window_raster_settings.setup(); + window_input_config.setup(); + window_cheat_editor.setup(); + window_advanced.setup(); + window_settings.setup(); + + event::update_video_settings(); //call first time to resize main window and update menubar + window_main.show(); + while(miu().pending()) miu().run(); + +#if defined(PLATFORM_WIN) + if(config::system.video == "none") { + uiVideo = new Video(); + } else if(config::system.video == "gdi") { + uiVideo = new VideoGDI(); + } else if(config::system.video == "directdraw") { + uiVideo = new VideoDD(); + } else { + uiVideo = new VideoD3D(); + } + + if(config::system.audio == "none") { + uiAudio = new Audio(); + } else { + uiAudio = new AudioDS(); + } + + if(config::system.input == "none") { + uiInput = new Input(); + } else { + uiInput = new InputDI(); + } +#elif defined(PLATFORM_X) + if(config::system.video == "none") { + uiVideo = new Video(); + } else if(config::system.video == "gtk") { + uiVideo = new VideoGTK(); + } else { + uiVideo = new VideoXv(); + } + + if(config::system.audio == "none") { + uiAudio = new Audio(); + } else { + uiAudio = new AudioAO(); + } + + if(config::system.input == "none") { + uiInput = new Input(); + } else { + uiInput = new InputX(); + } +#endif + +//needed only by VideoGDI (default is RGB565) + if(config::system.video == "gdi") snes.set_video_pixel_format(SNES::PIXELFORMAT_RGB555); + + uiVideo->set(Video::Handle, window_main.view.handle()); + uiVideo->set(Video::Synchronize, false); + uiAudio->set(Audio::Handle, window_main.handle()); + uiAudio->set(Audio::Synchronize, config::system.regulate_speed); + uiAudio->set(Audio::Frequency, 32000); + uiInput->set(Input::Handle, window_main.handle()); + + uiVideo->init(); + uiAudio->init(); + uiInput->init(); + + event::update_video_settings(); //call second time to update uiVideo->settings +} + +void ui_term() { + window_main.hide(); + + uiVideo->term(); + uiAudio->term(); + uiInput->term(); + + safe_delete(uiVideo); + safe_delete(uiAudio); + safe_delete(uiInput); +} diff --git a/src/ui/lui/ui.h b/src/ui/miu/ui.h similarity index 85% rename from src/ui/lui/ui.h rename to src/ui/miu/ui.h index eb1470e8..983ad5ea 100644 --- a/src/ui/lui/ui.h +++ b/src/ui/miu/ui.h @@ -5,7 +5,6 @@ #include "loader/ui_stloader.h" #include "settings/ui_settings.h" -#include "settings/ui_videosettings.h" #include "settings/ui_rastersettings.h" #include "settings/ui_inputconfig.h" #include "settings/ui_cheateditor.h" diff --git a/src/ui/lui/ui_about.cpp b/src/ui/miu/ui_about.cpp similarity index 53% rename from src/ui/lui/ui_about.cpp rename to src/ui/miu/ui_about.cpp index 5be7bdad..51742a19 100644 --- a/src/ui/lui/ui_about.cpp +++ b/src/ui/miu/ui_about.cpp @@ -7,17 +7,15 @@ const char AboutWindow::about_text[4096] = "" " anomie, blargg, DMV27, GIGO, kode54, Nach,\n" " Overload, Richard Bannister, TRAC, zones"; +uintptr_t AboutWindow::close(Event) { + hide(); + return false; +} + void AboutWindow::setup() { - create(ui::Window::Center, 400, 200, "About bsnes ..."); + create(Window::AutoCenter, 400, 200, "About bsnes ..."); + about.create(0, 390, 190, about_text); + attach(about, 5, 5); - about.create(*this, 0, 5, 5, 390, 190, about_text); -} - -bool AboutWindow::message(uint id, uintptr_t param) { - if(id == ui::Message::Close) { - hide(); - return false; - } - - return true; + on_close = bind(&AboutWindow::close, this); } diff --git a/src/ui/miu/ui_about.h b/src/ui/miu/ui_about.h new file mode 100644 index 00000000..04707d76 --- /dev/null +++ b/src/ui/miu/ui_about.h @@ -0,0 +1,8 @@ +class AboutWindow : public Window { +public: + Label about; + static const char about_text[4096]; + + void setup(); + uintptr_t close(Event); +} window_about; diff --git a/src/ui/miu/ui_main.cpp b/src/ui/miu/ui_main.cpp new file mode 100644 index 00000000..9015ecb8 --- /dev/null +++ b/src/ui/miu/ui_main.cpp @@ -0,0 +1,343 @@ +bool MainWindow::input_ready() { + return focused() == true; //only allow SNES to recognize input when main window is focused +} + +uintptr_t MainWindow::event(Event e) { + if(e.type == Event::Close) { + _term_ = true; + hide(); + return false; + } + + if(e.type == Event::Tick) { + if(e.widget == &menu_file_load) { + event::load_rom(); + } + + if(e.widget == &menu_file_load_bsx) { + window_bsxloader.mode = BSXLoaderWindow::ModeBSX; + window_bsxloader.set_text("Load BS-X Cartridge"); + window_bsxloader.tbase.set_text(config::path.bsx); + window_bsxloader.focus(); + } + + if(e.widget == &menu_file_load_bsc) { + window_bsxloader.mode = BSXLoaderWindow::ModeBSC; + window_bsxloader.set_text("Load BS-X Slotted Cartridge"); + window_bsxloader.tbase.set_text(""); + window_bsxloader.focus(); + } + + if(e.widget == &menu_file_load_st) { + window_stloader.tbase.set_text(config::path.st); + window_stloader.focus(); + } + + if(e.widget == &menu_file_unload) { + event::unload_rom(); + } + + if(e.widget == &menu_file_reset) { + event::reset(); + } + + if(e.widget == &menu_file_power) { + event::power(); + } + + if(e.widget == &menu_file_exit) { + event(Event(Event::Close)); + } + + if(locked == false) { + //set locked to true to update below menu item check statuses without triggering events + if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); } + if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); } + if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); } + if(e.widget == &menu_settings_videomode_4x) { event::update_multiplier(4); } + if(e.widget == &menu_settings_videomode_5x) { event::update_multiplier(5); } + + if(e.widget == &menu_settings_videomode_aspect_correction) { + event::update_aspect_correction(menu_settings_videomode_aspect_correction.checked()); + } + + if(e.widget == &menu_settings_videomode_ntsc) { event::update_region(0); } + if(e.widget == &menu_settings_videomode_pal) { event::update_region(1); } + + if(e.widget == &menu_settings_videofilter_hwpoint) { event::update_hardware_filter(0); } + if(e.widget == &menu_settings_videofilter_hwlinear) { event::update_hardware_filter(1); } + + if(e.widget == &menu_settings_videofilter_swnone) { event::update_software_filter(0); } + if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(1); } + if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(2); } + if(e.widget == &menu_settings_videofilter_swscale2x) { event::update_software_filter(3); } + + if(e.widget == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; } + if(e.widget == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; } + if(e.widget == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; } + if(e.widget == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; } + if(e.widget == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; } + if(e.widget == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; } + if(e.widget == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; } + if(e.widget == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; } + if(e.widget == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; } + if(e.widget == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; } + + if(e.widget == &menu_settings_mute) { + config::snes.mute = menu_settings_mute.checked(); + } + + if(e.widget == &menu_settings_speedreg_enable) { + config::system.regulate_speed = menu_settings_speedreg_enable.checked(); + if(uiAudio) uiAudio->set(Audio::Synchronize, config::system.regulate_speed); + } + + if(e.widget == &menu_settings_speedreg_slowest) { event::update_speed_regulation(1); } + if(e.widget == &menu_settings_speedreg_slow) { event::update_speed_regulation(2); } + if(e.widget == &menu_settings_speedreg_normal) { event::update_speed_regulation(3); } + if(e.widget == &menu_settings_speedreg_fast) { event::update_speed_regulation(4); } + if(e.widget == &menu_settings_speedreg_fastest) { event::update_speed_regulation(5); } + } + + if(e.widget == &menu_settings_config) { window_settings.show(); } + + if(e.widget == &menu_misc_logaudio) { + (menu_misc_logaudio.checked() == true) ? snes.log_audio_enable() : snes.log_audio_disable(); + } + + if(e.widget == &menu_misc_showfps) { + config::misc.show_frame_counter = menu_misc_showfps.checked(); + if(config::misc.show_frame_counter == false) { + set_text(BSNES_TITLE); + } + } + + if(e.widget == &menu_misc_about) { + window_about.focus(); + } + } + + return true; +} + +uintptr_t MainWindow::block(Event) { + if(uiAudio) uiAudio->clear_audio(); + return true; +} + +uintptr_t MainWindow::keydown(Event e) { + if(e.param == keymap::esc) { event::toggle_menu(); } + if(e.param == keymap::f11) { event::toggle_fullscreen(); } +} + +void MainWindow::setup() { + snesinterface.input_ready = bind(&MainWindow::input_ready, this); + locked = true; + + create(Window::AutoCenter, 256, 224, BSNES_TITLE); + set_background_color(0, 0, 0); + +MenuRadioItemGroup group; + attach(menu_file.create("File")); + menu_file.attach(menu_file_load.create("Load Cartridge ...")); + menu_file.attach(menu_file_load_special.create("Load Special")); + menu_file_load_special.attach(menu_file_load_bsx.create("Load BS-X Cartridge ...")); + menu_file_load_special.attach(menu_file_load_bsc.create("Load BS-X Slotted Cartridge ...")); + menu_file_load_special.attach(menu_file_load_st.create("Load ST Cartridge ...")); + menu_file.attach(menu_file_unload.create("Unload Cartridge")); + menu_file.attach(menu_file_sep1.create()); + menu_file.attach(menu_file_reset.create("Reset System")); + menu_file.attach(menu_file_power.create("Power Cycle System")); + menu_file.attach(menu_file_sep2.create()); + menu_file.attach(menu_file_exit.create("Exit")); + + attach(menu_settings.create("Settings")); + menu_settings.attach(menu_settings_videomode.create("Video Mode")); + group.add(&menu_settings_videomode_1x); + group.add(&menu_settings_videomode_2x); + group.add(&menu_settings_videomode_3x); + group.add(&menu_settings_videomode_4x); + group.add(&menu_settings_videomode_5x); + menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, "Scale 1x")); + menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, "Scale 2x")); + menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, "Scale 3x")); + menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, "Scale 4x")); + menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, "Scale 5x")); + group.reset(); + menu_settings_videomode.attach(menu_settings_videomode_sep1.create()); + menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create("Correct Aspect Ratio")); + menu_settings_videomode.attach(menu_settings_videomode_sep2.create()); + group.add(&menu_settings_videomode_ntsc); + group.add(&menu_settings_videomode_pal); + menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, "NTSC")); + menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, "PAL")); + group.reset(); + + menu_settings.attach(menu_settings_videofilter.create("Video Filter")); + group.add(&menu_settings_videofilter_hwpoint); + group.add(&menu_settings_videofilter_hwlinear); + menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, "Point")); + menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, "Linear")); + group.reset(); + menu_settings_videofilter.attach(menu_settings_videofilter_sep1.create()); + group.add(&menu_settings_videofilter_swnone); + group.add(&menu_settings_videofilter_swntsc); + group.add(&menu_settings_videofilter_swhq2x); + group.add(&menu_settings_videofilter_swscale2x); + menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, "None")); + menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, "NTSC")); + menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, "HQ2x")); + menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, "Scale2x")); + group.reset(); + + menu_settings.attach(menu_settings_videoframeskip.create("Video Frameskip")); + group.add(&menu_settings_videoframeskip_0); + group.add(&menu_settings_videoframeskip_1); + group.add(&menu_settings_videoframeskip_2); + group.add(&menu_settings_videoframeskip_3); + group.add(&menu_settings_videoframeskip_4); + group.add(&menu_settings_videoframeskip_5); + group.add(&menu_settings_videoframeskip_6); + group.add(&menu_settings_videoframeskip_7); + group.add(&menu_settings_videoframeskip_8); + group.add(&menu_settings_videoframeskip_9); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, "0")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_sep1.create()); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, "1")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, "2")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, "3")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, "4")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, "5")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, "6")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, "7")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, "8")); + menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, "9")); + group.reset(); + + menu_settings.attach(menu_settings_sep1.create()); + menu_settings.attach(menu_settings_mute.create("Mute Sound Output")); + menu_settings.attach(menu_settings_sep2.create()); + + menu_settings.attach(menu_settings_speedreg.create("Speed Regulation")); + menu_settings_speedreg.attach(menu_settings_speedreg_enable.create("Enable")); + menu_settings_speedreg.attach(menu_settings_speedreg_sep1.create()); + group.add(&menu_settings_speedreg_slowest); + group.add(&menu_settings_speedreg_slow); + group.add(&menu_settings_speedreg_normal); + group.add(&menu_settings_speedreg_fast); + group.add(&menu_settings_speedreg_fastest); + menu_settings_speedreg.attach(menu_settings_speedreg_slowest.create(group, "Slowest")); + menu_settings_speedreg.attach(menu_settings_speedreg_slow.create(group, "Slow")); + menu_settings_speedreg.attach(menu_settings_speedreg_normal.create(group, "Normal")); + menu_settings_speedreg.attach(menu_settings_speedreg_fast.create(group, "Fast")); + menu_settings_speedreg.attach(menu_settings_speedreg_fastest.create(group, "Fastest")); + group.reset(); + + menu_settings.attach(menu_settings_sep3.create()); + menu_settings.attach(menu_settings_config.create("Configuration ...")); + + attach(menu_misc.create("Misc")); + menu_misc.attach(menu_misc_logaudio.create("Log Audio Data")); + menu_misc.attach(menu_misc_showfps.create("Show FPS")); + menu_misc.attach(menu_misc_sep1.create()); + menu_misc.attach(menu_misc_about.create("About ...")); + + view.create(0, 256, 224); + attach(view, 0, 0); + + on_close = bind(&MainWindow::event, this); + on_block = bind(&MainWindow::block, this); + on_keydown = bind(&MainWindow::keydown, this); + + menu_file_load.on_tick = + menu_file_load_bsx.on_tick = + menu_file_load_bsc.on_tick = + menu_file_load_st.on_tick = + menu_file_unload.on_tick = + menu_file_reset.on_tick = + menu_file_power.on_tick = + menu_file_exit.on_tick = + + menu_settings_videomode_1x.on_tick = + menu_settings_videomode_2x.on_tick = + menu_settings_videomode_3x.on_tick = + menu_settings_videomode_4x.on_tick = + menu_settings_videomode_5x.on_tick = + menu_settings_videomode_aspect_correction.on_tick = + menu_settings_videomode_ntsc.on_tick = + menu_settings_videomode_pal.on_tick = + + menu_settings_videofilter_hwpoint.on_tick = + menu_settings_videofilter_hwlinear.on_tick = + menu_settings_videofilter_swnone.on_tick = + menu_settings_videofilter_swntsc.on_tick = + menu_settings_videofilter_swhq2x.on_tick = + menu_settings_videofilter_swscale2x.on_tick = + + menu_settings_videoframeskip_0.on_tick = + menu_settings_videoframeskip_1.on_tick = + menu_settings_videoframeskip_2.on_tick = + menu_settings_videoframeskip_3.on_tick = + menu_settings_videoframeskip_4.on_tick = + menu_settings_videoframeskip_5.on_tick = + menu_settings_videoframeskip_6.on_tick = + menu_settings_videoframeskip_7.on_tick = + menu_settings_videoframeskip_8.on_tick = + menu_settings_videoframeskip_9.on_tick = + + menu_settings_mute.on_tick = + menu_settings_speedreg_enable.on_tick = + menu_settings_speedreg_slowest.on_tick = + menu_settings_speedreg_slow.on_tick = + menu_settings_speedreg_normal.on_tick = + menu_settings_speedreg_fast.on_tick = + menu_settings_speedreg_fastest.on_tick = + menu_settings_config.on_tick = + + menu_misc_logaudio.on_tick = + menu_misc_showfps.on_tick = + menu_misc_about.on_tick = + + bind(&MainWindow::event, this); +} + +void MainWindow::update_menu_settings() { + locked = true; + event::load_video_settings(); + + switch(event::video_settings.multiplier) { default: + case 1: menu_settings_videomode_1x.check(); break; + case 2: menu_settings_videomode_2x.check(); break; + case 3: menu_settings_videomode_3x.check(); break; + case 4: menu_settings_videomode_4x.check(); break; + case 5: menu_settings_videomode_5x.check(); break; + } + + menu_settings_videomode_aspect_correction.check(event::video_settings.aspect_correction); + + switch(event::video_settings.region) { default: + case 0: menu_settings_videomode_ntsc.check(); break; + case 1: menu_settings_videomode_pal.check(); break; + } + + switch(event::video_settings.hardware_filter) { default: + case 0: menu_settings_videofilter_hwpoint.check(); break; + case 1: menu_settings_videofilter_hwlinear.check(); break; + } + + switch(event::video_settings.software_filter) { default: + case 0: menu_settings_videofilter_swnone.check(); break; + case 1: menu_settings_videofilter_swntsc.check(); break; + case 2: menu_settings_videofilter_swhq2x.check(); break; + case 3: menu_settings_videofilter_swscale2x.check(); break; + } + + menu_settings_mute.check(config::snes.mute); + + menu_settings_speedreg_enable.check(config::system.regulate_speed); + menu_settings_speedreg_normal.check(); + + menu_misc_showfps.check(config::misc.show_frame_counter); + + locked = false; +} diff --git a/src/ui/miu/ui_main.h b/src/ui/miu/ui_main.h new file mode 100644 index 00000000..c47f1e83 --- /dev/null +++ b/src/ui/miu/ui_main.h @@ -0,0 +1,78 @@ +class MainWindow : public Window { +public: + MenuGroup menu_file; + MenuItem menu_file_load; + MenuGroup menu_file_load_special; + MenuItem menu_file_load_bsx; + MenuItem menu_file_load_bsc; + MenuItem menu_file_load_st; + MenuItem menu_file_unload; + MenuSeparator menu_file_sep1; + MenuItem menu_file_reset; + MenuItem menu_file_power; + MenuSeparator menu_file_sep2; + MenuItem menu_file_exit; + + MenuGroup menu_settings; + MenuGroup menu_settings_videomode; + MenuRadioItem menu_settings_videomode_1x; + MenuRadioItem menu_settings_videomode_2x; + MenuRadioItem menu_settings_videomode_3x; + MenuRadioItem menu_settings_videomode_4x; + MenuRadioItem menu_settings_videomode_5x; + MenuSeparator menu_settings_videomode_sep1; + MenuCheckItem menu_settings_videomode_aspect_correction; + MenuSeparator menu_settings_videomode_sep2; + MenuRadioItem menu_settings_videomode_ntsc; + MenuRadioItem menu_settings_videomode_pal; + MenuGroup menu_settings_videofilter; + MenuRadioItem menu_settings_videofilter_hwpoint; + MenuRadioItem menu_settings_videofilter_hwlinear; + MenuSeparator menu_settings_videofilter_sep1; + MenuRadioItem menu_settings_videofilter_swnone; + MenuRadioItem menu_settings_videofilter_swntsc; + MenuRadioItem menu_settings_videofilter_swhq2x; + MenuRadioItem menu_settings_videofilter_swscale2x; + MenuGroup menu_settings_videoframeskip; + MenuRadioItem menu_settings_videoframeskip_0; + MenuSeparator menu_settings_videoframeskip_sep1; + MenuRadioItem menu_settings_videoframeskip_1; + MenuRadioItem menu_settings_videoframeskip_2; + MenuRadioItem menu_settings_videoframeskip_3; + MenuRadioItem menu_settings_videoframeskip_4; + MenuRadioItem menu_settings_videoframeskip_5; + MenuRadioItem menu_settings_videoframeskip_6; + MenuRadioItem menu_settings_videoframeskip_7; + MenuRadioItem menu_settings_videoframeskip_8; + MenuRadioItem menu_settings_videoframeskip_9; + MenuSeparator menu_settings_sep1; + MenuCheckItem menu_settings_mute; + MenuSeparator menu_settings_sep2; + MenuGroup menu_settings_speedreg; + MenuCheckItem menu_settings_speedreg_enable; + MenuSeparator menu_settings_speedreg_sep1; + MenuRadioItem menu_settings_speedreg_slowest; + MenuRadioItem menu_settings_speedreg_slow; + MenuRadioItem menu_settings_speedreg_normal; + MenuRadioItem menu_settings_speedreg_fast; + MenuRadioItem menu_settings_speedreg_fastest; + MenuSeparator menu_settings_sep3; + MenuItem menu_settings_config; + + MenuGroup menu_misc; + MenuCheckItem menu_misc_logaudio; + MenuCheckItem menu_misc_showfps; + MenuSeparator menu_misc_sep1; + MenuItem menu_misc_about; + + Canvas view; + + bool locked; + + bool input_ready(); + void setup(); + void update_menu_settings(); + uintptr_t event(Event); + uintptr_t block(Event); + uintptr_t keydown(Event); +} window_main; diff --git a/src/ui/sdl/bsnes.cpp b/src/ui/sdl/bsnes.cpp deleted file mode 100644 index ea4d5f87..00000000 --- a/src/ui/sdl/bsnes.cpp +++ /dev/null @@ -1,66 +0,0 @@ -void bSNES::set_status(uint32 new_status) { run_status = new_status; } -uint32 bSNES::get_status() { return run_status; } - -void bSNES::run() { - switch(run_status) { - case RUN: - SNES::runtoframe(); - return; - case STOP: - break; - } -} - -void bSNES::video_run() { - if(r_ppu->status.frames_updated) { - char s[512], t[512]; - r_ppu->status.frames_updated = false; - sprintf(s, "%s : %d fps", BSNES_TITLE, r_ppu->status.frames_executed); - SDL_WM_SetCaption(s, 0); - } - - render(); -} - -void bSNES::sound_run(uint32 data) { - uiAudio->run(data); -} - -uint16 *bSNES::video_lock(uint &pitch) { - if(SDL_MUSTLOCK(screen)) { - SDL_LockSurface(screen); - } - if(SDL_MUSTLOCK(backbuffer)) { - SDL_LockSurface(backbuffer); - } - - pitch = backbuffer->pitch; - return (uint16*)backbuffer->pixels; -} - -void bSNES::video_unlock() { - if(SDL_MUSTLOCK(backbuffer)) { - SDL_UnlockSurface(backbuffer); - } - if(SDL_MUSTLOCK(screen)) { - SDL_UnlockSurface(screen); - } -} - -/*********************** - *** Input functions *** - ***********************/ - -void bSNES::poll_input(uint8 type) { - uiInput->poll(); -} - -bool bSNES::get_input_status(uint8 device, uint8 button) { - return uiInput->get_status(device, button); -} - -void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {} - -bSNES::bSNES() { - run_status = RUN; -} diff --git a/src/ui/sdl/bsnes.h b/src/ui/sdl/bsnes.h deleted file mode 100644 index 75abfa7c..00000000 --- a/src/ui/sdl/bsnes.h +++ /dev/null @@ -1,23 +0,0 @@ -class bSNES : public SNES { -private: -uint32 run_status; - -public: -enum { STOP = 0, RUN }; - void run(); - void video_run(); - void sound_run(uint32 data); - - uint16 *video_lock(uint &data); - void video_unlock(); - - void set_status(uint32 new_status); - uint32 get_status(); - -//input functions - void poll_input(uint8 type); - bool get_input_status(uint8 device, uint8 button); - - void notify(uint32 message, uint32 param1 = 0, uint32 param2 = 0); - bSNES(); -} bsnes; diff --git a/src/ui/sdl/main.cpp b/src/ui/sdl/main.cpp deleted file mode 100644 index af7ea1d4..00000000 --- a/src/ui/sdl/main.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "main.h" - -#include "bsnes.h" -#include "render.cpp" -#include "bsnes.cpp" - -#include "../video/sdl.h" -#include "../video/sdl.cpp" - -#if defined(PLATFORM_WIN) - #include "../audio/dsound.h" - #include "../audio/dsound.cpp" -#elif defined(PLATFORM_X) - #include "../audio/ao.h" - #include "../audio/ao.cpp" -#endif - -#include "../input/sdl.h" -#include "../input/sdl.cpp" - -void alert(char *s, ...) { -char str[4096]; -va_list args; - va_start(args, s); - vsprintf(str, s, args); - va_end(args); -#ifdef PLATFORM_WIN - MessageBox(0, str, "bsnes", MB_OK); -#else - fprintf(stdout, "%s\r\n", str); -#endif -} - -void dprintf(char *s, ...) { -char str[4096]; -va_list args; - va_start(args, s); - vsprintf(str, s, args); - va_end(args); - fprintf(stdout, "%s\r\n", str); -} - -void dprintf(uint source, char *s, ...) { -char str[4096]; -va_list args; - va_start(args, s); - vsprintf(str, s, args); - va_end(args); - fprintf(stdout, "[%d]: %s\r\n", source, str); -} - -void center_window() { -#ifdef PLATFORM_WIN -HWND hwnd; -RECT rc; -int x, y; - hwnd = FindWindow(0, BSNES_TITLE); - GetWindowRect(hwnd, &rc); - x = (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) >> 1; - y = (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) >> 1; - SetWindowPos(hwnd, HWND_TOPMOST, x, y, 0, 0, SWP_NOSIZE); -#endif -} - -#ifdef PLATFORM_WIN -int __stdcall WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { -int argc = __argc; -char **argv = __argv; - SDL_SetModuleHandle(GetModuleHandle(0)); -#else -int main(int argc, char *argv[]) { -#endif - -SDL_Event event; - - if(argc < 2) { - alert("Usage: bsnes_sdl "); - return 0; - } - - config_file.load("bsnes_sdl.cfg"); - - init_snes(); - - uiVideo = new VideoSDL(); -#if defined(PLATFORM_WIN) - uiAudio = new AudioDS(); -#elif defined(PLATFORM_X) - uiAudio = new AudioAO(); - ((AudioAO*)uiAudio)->set_driver("oss"); -#endif - uiInput = new InputSDL(); - - uiVideo->init(); - uiAudio->init(); - uiInput->init(); - - cartridge.load_begin(Cartridge::CART_NORMAL); - cartridge.load(argv[1]); - cartridge.load_end(); - - SDL_Init(SDL_INIT_VIDEO); - atexit(SDL_Quit); - - screen_rect.x = 0; - screen_rect.y = 0; - screen_rect.w = 256; - screen_rect.h = 224; - - screen = SDL_SetVideoMode(screen_rect.w, screen_rect.h, 16, - SDL_HWSURFACE | (0 ? SDL_FULLSCREEN : 0)); - if(!screen) { alert("Failed to initialize SDL"); goto _end; } - - backbuffer = SDL_CreateRGBSurface(SDL_HWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000); - if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; } - - SDL_WM_SetCaption(BSNES_TITLE, 0); - center_window(); - - snes.power(); - bsnes.set_status(bSNES::RUN); - -int cursor_status; - while(1) { - bsnes.run(); - while(SDL_PollEvent(&event)) { - switch(event.type) { - case SDL_KEYUP: - switch(event.key.keysym.sym) { - case SDLK_ESCAPE: - goto _end; - case SDLK_BACKSPACE: - //snes->capture_screenshot(); - break; - case SDLK_F10: //toggle cursor display - cursor_status = (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) ? SDL_DISABLE : SDL_ENABLE; - SDL_ShowCursor(cursor_status); - break; - case SDLK_F11: //only supported on X11 - SDL_WM_ToggleFullScreen(screen); - break; - } - break; - case SDL_QUIT: - goto _end; - } - } - } - -_end: - config_file.save("bsnes_sdl.cfg"); - cartridge.unload(); - uiVideo->term(); - uiAudio->term(); - uiInput->term(); - safe_delete(uiVideo); - safe_delete(uiAudio); - safe_delete(uiInput); - term_snes(); - - return 0; -} diff --git a/src/ui/sdl/main.h b/src/ui/sdl/main.h deleted file mode 100644 index ff22ab8a..00000000 --- a/src/ui/sdl/main.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifdef PLATFORM_WIN - #include -#endif - -#include "SDL.h" - -SDL_Surface *screen, *backbuffer; -SDL_Rect screen_rect; diff --git a/src/ui/sdl/render.cpp b/src/ui/sdl/render.cpp deleted file mode 100644 index 3c28d180..00000000 --- a/src/ui/sdl/render.cpp +++ /dev/null @@ -1,18 +0,0 @@ -void render() { -SNES::video_info vi; - snes.get_video_info(&vi); - -SDL_Rect rect; - rect.x = 0; - rect.y = (vi.height == 224) ? 1 : 2; - rect.w = vi.width; - rect.h = (vi.height == 224) ? 223 : 446; - -//documentation says not to use this, but it's rather ridiculous that a graphics -//library wouldn't support simple image scaling... so let's use it anyway and see -//what happens... - SDL_SoftStretch(backbuffer, &rect, screen, &screen_rect); -//SDL_BlitSurface(backbuffer, &rect, screen, &screen_rect); - - SDL_UpdateRect(screen, screen_rect.x, screen_rect.y, screen_rect.w, screen_rect.h); -} diff --git a/src/ui/vai/audio.h b/src/ui/vai/audio.h new file mode 100644 index 00000000..8d42a948 --- /dev/null +++ b/src/ui/vai/audio.h @@ -0,0 +1,27 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include "../../lib/bbase.h" + +class Audio { +public: + enum Setting { + Handle, + Synchronize, + Frequency, + }; + + virtual bool cap(Setting) { return false; } + virtual uintptr_t get(Setting) { return false; } + virtual bool set(Setting, uintptr_t) { return false; } + + virtual void sample(uint16 left, uint16 right) {} + virtual void clear_audio() {} + virtual void init() {} + virtual void term() {} + + Audio() {} + virtual ~Audio() {} +}; + +#endif //ifndef AUDIO_H diff --git a/src/ui/vai/audio/audio.ao.cpp b/src/ui/vai/audio/audio.ao.cpp new file mode 100644 index 00000000..caca1c22 --- /dev/null +++ b/src/ui/vai/audio/audio.ao.cpp @@ -0,0 +1,85 @@ +#include "audio.ao.h" + +#include + +class pAudioAO { +public: + AudioAO &self; + int driver_id; + ao_sample_format driver_format; + ao_device *audio_device; + + struct { + uint frequency; + } settings; + + bool cap(Audio::Setting setting) { + if(setting == Audio::Frequency) return true; + return false; + } + + uintptr_t get(Audio::Setting setting) { + if(setting == Audio::Frequency) return settings.frequency; + return false; + } + + bool set(Audio::Setting setting, uintptr_t param) { + if(setting == Audio::Frequency) { + settings.frequency = param; + if(audio_device) { + term(); + init(); + } + return true; + } + return false; + } + + void sample(uint16 l_sample, uint16 r_sample) { + uint32 samp = (l_sample << 0) + (r_sample << 16); + ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian + } + + void init() { + driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver) + if(driver_id < 0) driver_id = ao_default_driver_id(); //fallback on default if driver doesn't exist + driver_format.bits = 16; + driver_format.channels = 2; + driver_format.rate = settings.frequency; + driver_format.byte_format = AO_FMT_LITTLE; + + audio_device = ao_open_live(driver_id, &driver_format, 0); + if(audio_device) { + ao_info *di = ao_driver_info(driver_id); + } else { + printf("libao: failed to open audio device.\n"); + } + } + + void term() { + if(audio_device) { + ao_close(audio_device); + audio_device = 0; + } + } + + pAudioAO(AudioAO &self_) : self(self_) { + settings.frequency = 22050; + audio_device = 0; + ao_initialize(); + } + + ~pAudioAO() { + term(); + //ao_shutdown(); //FIXME: this is causing a segfault for some reason when called ... + } +}; + +bool AudioAO::cap(Setting setting) { return p.cap(setting); } +uintptr_t AudioAO::get(Setting setting) { return p.get(setting); } +bool AudioAO::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +void AudioAO::sample(uint16 l_sample, uint16 r_sample) { p.sample(l_sample, r_sample); } +void AudioAO::init() { p.init(); } +void AudioAO::term() { p.term(); } +AudioAO::AudioAO() : p(*new pAudioAO(*this)) {} +AudioAO::~AudioAO() { delete &p; } diff --git a/src/ui/vai/audio/audio.ao.h b/src/ui/vai/audio/audio.ao.h new file mode 100644 index 00000000..2037ea4f --- /dev/null +++ b/src/ui/vai/audio/audio.ao.h @@ -0,0 +1,25 @@ +#ifndef AUDIO_AO_H +#define AUDIO_AO_H + +#include "../audio.h" + +class pAudioAO; + +class AudioAO : public Audio { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + void sample(uint16 left, uint16 right); + void init(); + void term(); + + AudioAO(); + ~AudioAO(); + +private: + pAudioAO &p; +}; + +#endif //ifndef AUDIO_AO_H diff --git a/src/ui/vai/audio/audio.directsound.cpp b/src/ui/vai/audio/audio.directsound.cpp new file mode 100644 index 00000000..a27eed9b --- /dev/null +++ b/src/ui/vai/audio/audio.directsound.cpp @@ -0,0 +1,177 @@ +#include "audio.directsound.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +class pAudioDS { +public: + AudioDS &self; + LPDIRECTSOUND ds; + LPDIRECTSOUNDBUFFER dsb_p, dsb_b; + DSBUFFERDESC dsbd; + WAVEFORMATEX wfx; + + struct { + uint32 *buffer; + uint buffer_pos, ring_pos; + uint buffer_size, ring_size; + } data; + + struct { + HWND handle; + bool synchronize; + uint frequency; + uint latency; + } settings; + + bool cap(Audio::Setting setting) { + if(setting == Audio::Handle) return true; + if(setting == Audio::Synchronize) return true; + if(setting == Audio::Frequency) return true; + return false; + } + + uintptr_t get(Audio::Setting setting) { + if(setting == Audio::Handle) return (uintptr_t)settings.handle; + if(setting == Audio::Synchronize) return settings.synchronize; + if(setting == Audio::Frequency) return settings.frequency; + return false; + } + + bool set(Audio::Setting setting, uintptr_t param) { + if(setting == Audio::Handle) { + settings.handle = (HWND)param; + return true; + } + if(setting == Audio::Synchronize) { + settings.synchronize = param; + return true; + } + if(setting == Audio::Frequency) { + settings.frequency = param; + settings.latency = param / 40; + if(ds) init(); //reinitialize only if previously initialized + return true; + } + return false; + } + + void sample(uint16 l_sample, uint16 r_sample) { + data.buffer[data.buffer_pos++] = (l_sample << 0) + (r_sample << 16); + if(data.buffer_pos < settings.latency) return; + + DWORD ring_pos, pos, size; + for(;;) { + dsb_b->GetCurrentPosition(&pos, 0); + ring_pos = pos / data.ring_size; + if(settings.synchronize == false || ring_pos != data.ring_pos) break; + Sleep(1); + } + + data.ring_pos = ring_pos; + void *output; + if(dsb_b->Lock(((data.ring_pos + 2) % 3) * data.ring_size, data.ring_size, + &output, &size, 0, 0, 0) == DS_OK) { + memcpy(output, data.buffer, data.ring_size); + dsb_b->Unlock(output, size, 0, 0); + } + + data.buffer_pos = 0; + } + + void clear_audio() { + data.buffer_pos = 0; + data.ring_pos = 0; + if(data.buffer) memset(data.buffer, 0, data.buffer_size); + if(!dsb_b) return; + + dsb_b->Stop(); + dsb_b->SetCurrentPosition(0); + + DWORD size; + void *output; + dsb_b->Lock(0, data.ring_size * 3, &output, &size, 0, 0, 0); + memset(output, 0, size); + dsb_b->Unlock(output, size, 0, 0); + + dsb_b->Play(0, 0, DSBPLAY_LOOPING); + } + + void init() { + clear_audio(); + term(); + + data.ring_size = settings.latency * sizeof(uint32); + data.buffer_size = data.ring_size * 16; + data.buffer = (uint32*)malloc(data.buffer_size); + data.buffer_pos = 0; + + DirectSoundCreate(0, &ds, 0); + ds->SetCooperativeLevel(settings.handle, DSSCL_PRIORITY); + + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = 0; + ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); + + memset(&wfx, 0, sizeof(wfx)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = settings.frequency; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + dsb_p->SetFormat(&wfx); + + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | + DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE; + dsbd.dwBufferBytes = data.ring_size * 3; + dsbd.guid3DAlgorithm = GUID_NULL; + dsbd.lpwfxFormat = &wfx; + ds->CreateSoundBuffer(&dsbd, &dsb_b, 0); + dsb_b->SetFrequency(settings.frequency); + dsb_b->SetCurrentPosition(0); + + clear_audio(); + } + + void term() { + safe_free(data.buffer); + + if(dsb_b) { dsb_b->Stop(); dsb_b->Release(); dsb_b = 0; } + if(dsb_p) { dsb_p->Stop(); dsb_p->Release(); dsb_p = 0; } + if(ds) { ds->Release(); ds = 0; } + } + + pAudioDS(AudioDS &self_) : self(self_) { + ds = 0; + dsb_p = 0; + dsb_b = 0; + + data.buffer = 0; + data.buffer_pos = 0; + data.ring_pos = 0; + data.buffer_size = 0; + data.ring_size = 0; + + settings.handle = GetDesktopWindow(); + settings.synchronize = false; + settings.frequency = 22050; + settings.latency = settings.frequency / 40; + } +}; + +bool AudioDS::cap(Setting setting) { return p.cap(setting); } +uintptr_t AudioDS::get(Setting setting) { return p.get(setting); } +bool AudioDS::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +void AudioDS::sample(uint16 l_sample, uint16 r_sample) { p.sample(l_sample, r_sample); } +void AudioDS::clear_audio() { p.clear_audio(); } +void AudioDS::init() { p.init(); } +void AudioDS::term() { p.term(); } +AudioDS::AudioDS() : p(*new pAudioDS(*this)) {} +AudioDS::~AudioDS() { delete &p; } diff --git a/src/ui/vai/audio/audio.directsound.h b/src/ui/vai/audio/audio.directsound.h new file mode 100644 index 00000000..0d2e4f41 --- /dev/null +++ b/src/ui/vai/audio/audio.directsound.h @@ -0,0 +1,26 @@ +#ifndef AUDIO_DIRECTSOUND_H +#define AUDIO_DIRECTSOUND_H + +#include "../audio.h" + +class pAudioDS; + +class AudioDS : public Audio { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + void sample(uint16 left, uint16 right); + void clear_audio(); + void init(); + void term(); + + AudioDS(); + ~AudioDS(); + +private: + pAudioDS &p; +}; + +#endif //ifndef AUDIO_DIRECTSOUND_H diff --git a/src/ui/vai/input.h b/src/ui/vai/input.h new file mode 100644 index 00000000..fd9d4199 --- /dev/null +++ b/src/ui/vai/input.h @@ -0,0 +1,29 @@ +#ifndef INPUT_H +#define INPUT_H + +#include "../../lib/bbase.h" +#include "../../lib/bkeymap.h" + +class Input { +public: + enum Setting { + Handle, + }; + + virtual bool cap(Setting) { return false; } + virtual uintptr_t get(Setting) { return false; } + virtual bool set(Setting, uintptr_t) { return false; } + + virtual bool key_down(uint16 key) { return false; } + virtual bool key_up (uint16 key) { return !key_down(key); } + + virtual void clear_input() {} + virtual void poll() {} + virtual void init() {} + virtual void term() {} + + Input() {} + virtual ~Input() {} +}; + +#endif //ifndef INPUT_H diff --git a/src/ui/vai/input/input.directinput.cpp b/src/ui/vai/input/input.directinput.cpp new file mode 100644 index 00000000..ff1b5899 --- /dev/null +++ b/src/ui/vai/input/input.directinput.cpp @@ -0,0 +1,293 @@ +#include "input.directinput.h" + +#define WIN32_LEAN_AND_MEAN +#include + +#define DIRECTINPUT_VERSION 0x0800 +#define DIRECTINPUT_JOYMAX 16 +#include + +BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p); + +class pInputDI { +public: + InputDI &self; + uint8 keystate[65536]; + LPDIRECTINPUT8 di; + LPDIRECTINPUTDEVICE8 di_key, di_joy[DIRECTINPUT_JOYMAX]; + uint32 di_joy_count; + + struct { + HWND handle; + } settings; + + bool cap(Input::Setting setting) { + if(setting == Input::Handle) return true; + return false; + } + + uintptr_t get(Input::Setting setting) { + if(setting == Input::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(Input::Setting setting, uintptr_t param) { + if(setting == Input::Handle) { + settings.handle = (HWND)param; + return true; + } + return false; + } + + void clear_input() { + memset(keystate, 0, sizeof keystate); + } + + void poll() { + clear_input(); + + HRESULT hr; + DIJOYSTATE2 js; + if(di_key) { + hr = di_key->GetDeviceState(256, keystate); + if(FAILED(hr)) { + di_key->Acquire(); + hr = di_key->GetDeviceState(256, keystate); + } + } + + for(int i = 0; i < di_joy_count; i++) { + if(!di_joy[i])continue; + + memset(js.rgbButtons, 0, 128); + + hr = di_joy[i]->Poll(); + if(FAILED(hr)) { + di_joy[i]->Acquire(); + di_joy[i]->Poll(); + } + di_joy[i]->GetDeviceState(sizeof(DIJOYSTATE2), &js); + + uint index = keymap::joypad_flag | (i << 8); //joypad index + memcpy(keystate + index, js.rgbButtons, 128); + + //map d-pad axes + int resistance = 75; //config::input.axis_resistance; + if(resistance < 1)resistance = 1; + if(resistance > 99)resistance = 99; + resistance = int32(double(resistance) * 32768.0 / 100.0); + int resistance_lo = 0x7fff - resistance; + int resistance_hi = 0x8000 + resistance; + keystate[index + keymap::joypad_up] = (js.lY <= resistance_lo) ? 0x80 : 0x00; + keystate[index + keymap::joypad_down] = (js.lY >= resistance_hi) ? 0x80 : 0x00; + keystate[index + keymap::joypad_left] = (js.lX <= resistance_lo) ? 0x80 : 0x00; + keystate[index + keymap::joypad_right] = (js.lX >= resistance_hi) ? 0x80 : 0x00; + + //map analog POV (analog directional pad) as well + uint pov = js.rgdwPOV[0]; + keystate[index + keymap::joypad_up] |= (pov == 0 || pov == 31500 || pov == 4500) ? 0x80 : 0x00; + keystate[index + keymap::joypad_down] |= (pov == 18000 || pov == 13500 || pov == 22500) ? 0x80 : 0x00; + keystate[index + keymap::joypad_left] |= (pov == 27000 || pov == 22500 || pov == 31500) ? 0x80 : 0x00; + keystate[index + keymap::joypad_right] |= (pov == 9000 || pov == 4500 || pov == 13500) ? 0x80 : 0x00; + } + } + + bool enum_joypads(const DIDEVICEINSTANCE *instance) { + HRESULT hr = di->CreateDevice(instance->guidInstance, &di_joy[di_joy_count], 0); + if(FAILED(hr)) { + return DIENUM_CONTINUE; + } + + di_joy[di_joy_count]->SetDataFormat(&c_dfDIJoystick2); + di_joy[di_joy_count]->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + + if(++di_joy_count >= DIRECTINPUT_JOYMAX) { + //too many joypads? + return DIENUM_STOP; + } + + return DIENUM_CONTINUE; + } + + void init() { + di_key = 0; + for(int i = 0; i < DIRECTINPUT_JOYMAX; i++)di_joy[i] = 0; + di = 0; + di_joy_count = 0; + + DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION, + IID_IDirectInput8, (void**)&di, 0); + di->CreateDevice(GUID_SysKeyboard, &di_key, 0); + + di_key->SetDataFormat(&c_dfDIKeyboard); + di_key->SetCooperativeLevel(settings.handle, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND); + di_key->Acquire(); + + di->EnumDevices(DI8DEVCLASS_GAMECTRL, DI_EnumJoypadsCallback, (void*)this, DIEDFL_ATTACHEDONLY); + } + + void term() { + if(di_key) { di_key->Unacquire(); di_key->Release(); di_key = 0; } + for(int i = 0; i < DIRECTINPUT_JOYMAX; i++) { + if(di_joy[i]) { di_joy[i]->Unacquire(); di_joy[i]->Release(); di_joy[i] = 0; } + } + if(di) { di->Release(); di = 0; } + di_joy_count = 0; + } + + bool key_down(uint16 key) { + return keystate[translate(key)] & 0x80; + } + + //translate keymap code to DirectInput code, to lookup key status in DI status table + uint16 translate(uint16 key) { + //DI joypad codes share 1:1 mapping with keymap codes + if(key & keymap::joypad_flag) { return key; } + + switch(key) { + case keymap::esc: return 0x01; + + case keymap::f1: return 0x3b; + case keymap::f2: return 0x3c; + case keymap::f3: return 0x3d; + case keymap::f4: return 0x3e; + case keymap::f5: return 0x3f; + case keymap::f6: return 0x40; + case keymap::f7: return 0x41; + case keymap::f8: return 0x42; + case keymap::f9: return 0x43; + case keymap::f10: return 0x44; + case keymap::f11: return 0x57; + case keymap::f12: return 0x58; + + case keymap::print_screen: return 0xb7; + case keymap::scroll_lock: return 0x46; + case keymap::pause: return 0xc5; + + case keymap::grave: return 0x29; + + case keymap::num_1: return 0x02; + case keymap::num_2: return 0x03; + case keymap::num_3: return 0x04; + case keymap::num_4: return 0x05; + case keymap::num_5: return 0x06; + case keymap::num_6: return 0x07; + case keymap::num_7: return 0x08; + case keymap::num_8: return 0x09; + case keymap::num_9: return 0x0a; + case keymap::num_0: return 0x0b; + + case keymap::minus: return 0x0c; + case keymap::equal: return 0x0d; + case keymap::backspace: return 0x0e; + + case keymap::ins: return 0xd2; + case keymap::del: return 0xd3; + case keymap::home: return 0xc7; + case keymap::end: return 0xcf; + case keymap::page_up: return 0xc9; + case keymap::page_down: return 0xd1; + + case keymap::a: return 0x1e; + case keymap::b: return 0x30; + case keymap::c: return 0x2e; + case keymap::d: return 0x20; + case keymap::e: return 0x12; + case keymap::f: return 0x21; + case keymap::g: return 0x22; + case keymap::h: return 0x23; + case keymap::i: return 0x17; + case keymap::j: return 0x24; + case keymap::k: return 0x25; + case keymap::l: return 0x26; + case keymap::m: return 0x32; + case keymap::n: return 0x31; + case keymap::o: return 0x18; + case keymap::p: return 0x19; + case keymap::q: return 0x10; + case keymap::r: return 0x13; + case keymap::s: return 0x1f; + case keymap::t: return 0x14; + case keymap::u: return 0x16; + case keymap::v: return 0x2f; + case keymap::w: return 0x11; + case keymap::x: return 0x2d; + case keymap::y: return 0x15; + case keymap::z: return 0x2c; + + case keymap::lbracket: return 0x1a; + case keymap::rbracket: return 0x1b; + case keymap::backslash: return 0x2b; + case keymap::semicolon: return 0x27; + case keymap::apostrophe: return 0x28; + case keymap::comma: return 0x33; + case keymap::period: return 0x34; + case keymap::slash: return 0x35; + + case keymap::kp_1: return 0x4f; + case keymap::kp_2: return 0x50; + case keymap::kp_3: return 0x51; + case keymap::kp_4: return 0x4b; + case keymap::kp_5: return 0x4c; + case keymap::kp_6: return 0x4d; + case keymap::kp_7: return 0x47; + case keymap::kp_8: return 0x48; + case keymap::kp_9: return 0x49; + case keymap::kp_0: return 0x52; + case keymap::kp_decimal: return 0x53; + + case keymap::kp_plus: return 0x4e; + case keymap::kp_minus: return 0x4a; + case keymap::kp_mul: return 0x37; + case keymap::kp_div: return 0xb5; + case keymap::kp_enter: return 0x9c; + + case keymap::num_lock : return 0x45; + case keymap::caps_lock: return 0x3a; + + case keymap::up: return 0xc8; + case keymap::down: return 0xd0; + case keymap::left: return 0xcb; + case keymap::right: return 0xcd; + + case keymap::tab: return 0x0f; + case keymap::enter: return 0x1c; + case keymap::space: return 0x39; + + case keymap::lctrl : return 0x1d; + case keymap::rctrl : return 0x9d; + case keymap::lalt : return 0x38; + case keymap::ralt : return 0xb8; + case keymap::lshift: return 0x2a; + case keymap::rshift: return 0x36; + case keymap::lsuper: return 0xdb; + case keymap::rsuper: return 0xdc; + case keymap::menu: return 0xdd; + } + + return 0x00; + } + + pInputDI(InputDI &self_) : self(self_) { + di = 0; + di_key = 0; + for(int i = 0; i < DIRECTINPUT_JOYMAX; i++) di_joy[i] = 0; + } + + ~pInputDI() { term(); } +}; + +BOOL CALLBACK DI_EnumJoypadsCallback(const DIDEVICEINSTANCE *instance, void *p) { + return ((pInputDI*)p)->enum_joypads(instance); +} + +bool InputDI::cap(Setting setting) { return p.cap(setting); } +uintptr_t InputDI::get(Setting setting) { return p.get(setting); } +bool InputDI::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool InputDI::key_down(uint16 key) { return p.key_down(key); } +void InputDI::clear_input() { p.clear_input(); } +void InputDI::poll() { p.poll(); } +void InputDI::init() { p.init(); } +void InputDI::term() { p.term(); } +InputDI::InputDI() : p(*new pInputDI(*this)) {} +InputDI::~InputDI() { delete &p; } diff --git a/src/ui/vai/input/input.directinput.h b/src/ui/vai/input/input.directinput.h new file mode 100644 index 00000000..e7efd819 --- /dev/null +++ b/src/ui/vai/input/input.directinput.h @@ -0,0 +1,28 @@ +#ifndef INPUT_DIRECTINPUT_H +#define INPUT_DIRECTINPUT_H + +#include "../input.h" + +class pInputDI; + +class InputDI : public Input { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + bool key_down(uint16 key); + + void clear_input(); + void poll(); + void init(); + void term(); + + InputDI(); + ~InputDI(); + +private: + pInputDI &p; +}; + +#endif //ifndef INPUT_DIRECTINPUT_H diff --git a/src/ui/vai/input/input.x.cpp b/src/ui/vai/input/input.x.cpp new file mode 100644 index 00000000..2cf9ddde --- /dev/null +++ b/src/ui/vai/input/input.x.cpp @@ -0,0 +1,168 @@ +#include "input.x.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +class pInputX { +public: + InputX &self; + Display *display; + char keymap[32]; + + bool key_down(uint16 key) { + #define map(i) (keymap[i >> 3] & (1 << (i & 7))) + + switch(key) { + case keymap::esc: return map(0x09); + + case keymap::f1: return map(0x43); + case keymap::f2: return map(0x44); + case keymap::f3: return map(0x45); + case keymap::f4: return map(0x46); + case keymap::f5: return map(0x47); + case keymap::f6: return map(0x48); + case keymap::f7: return map(0x49); + case keymap::f8: return map(0x4a); + case keymap::f9: return map(0x4b); + case keymap::f10: return map(0x4c); + case keymap::f11: return map(0x5f); + case keymap::f12: return map(0x60); + + case keymap::print_screen: return map(0x6f); + case keymap::scroll_lock: return map(0x4e); + case keymap::pause: return map(0x6e); + + case keymap::grave: return map(0x31); + + case keymap::num_1: return map(0x0a); + case keymap::num_2: return map(0x0b); + case keymap::num_3: return map(0x0c); + case keymap::num_4: return map(0x0d); + case keymap::num_5: return map(0x0e); + case keymap::num_6: return map(0x0f); + case keymap::num_7: return map(0x10); + case keymap::num_8: return map(0x11); + case keymap::num_9: return map(0x12); + case keymap::num_0: return map(0x13); + + case keymap::minus: return map(0x14); + case keymap::equal: return map(0x15); + case keymap::backspace: return map(0x16); + + case keymap::ins: return map(0x6a); + case keymap::del: return map(0x6b); + case keymap::home: return map(0x61); + case keymap::end: return map(0x67); + case keymap::page_up: return map(0x63); + case keymap::page_down: return map(0x69); + + case keymap::a: return map(0x26); + case keymap::b: return map(0x38); + case keymap::c: return map(0x36); + case keymap::d: return map(0x28); + case keymap::e: return map(0x1a); + case keymap::f: return map(0x29); + case keymap::g: return map(0x2a); + case keymap::h: return map(0x2b); + case keymap::i: return map(0x1f); + case keymap::j: return map(0x2c); + case keymap::k: return map(0x2d); + case keymap::l: return map(0x2e); + case keymap::m: return map(0x3a); + case keymap::n: return map(0x39); + case keymap::o: return map(0x20); + case keymap::p: return map(0x21); + case keymap::q: return map(0x18); + case keymap::r: return map(0x1b); + case keymap::s: return map(0x27); + case keymap::t: return map(0x1c); + case keymap::u: return map(0x1e); + case keymap::v: return map(0x37); + case keymap::w: return map(0x19); + case keymap::x: return map(0x35); + case keymap::y: return map(0x1d); + case keymap::z: return map(0x34); + + case keymap::lbracket: return map(0x22); + case keymap::rbracket: return map(0x23); + case keymap::backslash: return map(0x33); + case keymap::semicolon: return map(0x2f); + case keymap::apostrophe: return map(0x30); + case keymap::comma: return map(0x3b); + case keymap::period: return map(0x3c); + case keymap::slash: return map(0x3d); + + case keymap::kp_1: return map(0x57); + case keymap::kp_2: return map(0x58); + case keymap::kp_3: return map(0x59); + case keymap::kp_4: return map(0x53); + case keymap::kp_5: return map(0x54); + case keymap::kp_6: return map(0x55); + case keymap::kp_7: return map(0x4f); + case keymap::kp_8: return map(0x50); + case keymap::kp_9: return map(0x51); + + case keymap::kp_plus: return map(0x56); + case keymap::kp_minus: return map(0x52); + case keymap::kp_mul: return map(0x3f); + case keymap::kp_div: return map(0x70); + case keymap::kp_enter: return map(0x6c); + + case keymap::num_lock: return map(0x4d); + case keymap::caps_lock: return map(0x42); + + case keymap::up: return map(0x62); + case keymap::down: return map(0x68); + case keymap::left: return map(0x64); + case keymap::right: return map(0x66); + + case keymap::tab: return map(0x17); + case keymap::enter: return map(0x24); + case keymap::space: return map(0x41); + + case keymap::lctrl: return map(0x25); + case keymap::rctrl: return map(0x6d); + case keymap::lalt: return map(0x40); + case keymap::ralt: return map(0x71); + case keymap::lshift: return map(0x32); + case keymap::rshift: return map(0x3e); + case keymap::lsuper: return map(0x73); + case keymap::rsuper: return map(0x74); + case keymap::menu: return map(0x75); + } + + #undef map + return false; + } + + void clear_input() { + memset(keymap, 0, sizeof keymap); + } + + void poll() { + XQueryKeymap(display, keymap); + } + + void init() { + display = XOpenDisplay(0); + } + + void term() { + } + + pInputX(InputX &self_) : self(self_) {} +}; + +bool InputX::key_down(uint16 key) { return p.key_down(key); } +void InputX::clear_input() { p.clear_input(); } +void InputX::poll() { p.poll(); } +void InputX::init() { p.init(); } +void InputX::term() { p.term(); } +InputX::InputX() : p(*new pInputX(*this)) {} +InputX::~InputX() { delete &p; } diff --git a/src/ui/vai/input/input.x.h b/src/ui/vai/input/input.x.h new file mode 100644 index 00000000..3ff94b29 --- /dev/null +++ b/src/ui/vai/input/input.x.h @@ -0,0 +1,24 @@ +#ifndef INPUT_X_H +#define INPUT_X_H + +#include "../input.h" + +class pInputX; + +class InputX : public Input { +public: + bool key_down(uint16 key); + + void clear_input(); + void poll(); + void init(); + void term(); + + InputX(); + ~InputX(); + +private: + pInputX &p; +}; + +#endif //ifndef INPUT_X_H diff --git a/src/ui/vai/video.h b/src/ui/vai/video.h new file mode 100644 index 00000000..d01fa216 --- /dev/null +++ b/src/ui/vai/video.h @@ -0,0 +1,35 @@ +#ifndef VIDEO_H +#define VIDEO_H + +#include "../../lib/bbase.h" + +class Video { +public: + enum Setting { + Handle, + Synchronize, + Filter, + }; + + enum Filter { + FilterPoint, + FilterLinear, + }; + + virtual bool cap(Setting) { return false; } + virtual uintptr_t get(Setting) { return false; } + virtual bool set(Setting, uintptr_t) { return false; } + + virtual bool lock(uint16 *&data, uint &pitch) { return false; } + virtual void unlock() {} + + virtual void clear_video() {} + virtual void refresh(uint width, uint height) {} + virtual void init() {} + virtual void term() {} + + Video() {} + virtual ~Video() {} +}; + +#endif //ifndef VIDEO_H diff --git a/src/ui/vai/video/video.direct3d.cpp b/src/ui/vai/video/video.direct3d.cpp new file mode 100644 index 00000000..951bcb8f --- /dev/null +++ b/src/ui/vai/video/video.direct3d.cpp @@ -0,0 +1,352 @@ +#include "video.direct3d.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) + +class pVideoD3D { +public: + VideoD3D &self; + + LPDIRECT3D9 lpd3d; + LPDIRECT3DDEVICE9 device; + LPDIRECT3DVERTEXBUFFER9 vertex_buffer, *vertex_ptr; + D3DPRESENT_PARAMETERS presentation; + D3DSURFACE_DESC d3dsd; + D3DLOCKED_RECT d3dlr; + D3DRASTER_STATUS d3drs; + D3DCAPS9 d3dcaps; + LPDIRECT3DTEXTURE9 texture; + LPDIRECT3DSURFACE9 surface; + + struct d3dvertex { + float x, y, z, rhw; //screen coords + uint32 color; //diffuse color + float u, v; //texture coords + }; + + struct { + uint32 t_usage, v_usage; + uint32 t_pool, v_pool; + uint32 lock; + uint32 filter; + } flags; + + struct { + bool dynamic; //device supports dynamic textures + bool addresswrap; //device supports texture address (u,v) wrapping + bool stretchrect; //device supports StretchRect + } caps; + + struct { + HWND handle; + bool synchronize; + uint filter; + } settings; + + bool cap(Video::Setting setting) { + if(setting == Video::Handle) return true; + if(setting == Video::Synchronize) return true; + if(setting == Video::Filter) return true; + return false; + } + + uintptr_t get(Video::Setting setting) { + if(setting == Video::Handle) return (uintptr_t)settings.handle; + if(setting == Video::Synchronize) return settings.synchronize; + if(setting == Video::Filter) return settings.filter; + return false; + } + + bool set(Video::Setting setting, uintptr_t param) { + if(setting == Video::Handle) { + settings.handle = (HWND)param; + return true; + } + if(setting == Video::Synchronize) { + settings.synchronize = param; + return true; + } + if(setting == Video::Filter) { + settings.filter = param; + update_filter(); + return true; + } + return false; + } + + bool update_video_mode() { + HRESULT hr; + term(); + + lpd3d = Direct3DCreate9(D3D_SDK_VERSION); + if(!lpd3d) { + printf("VideoD3D: failed to create Direct3D9 interface"); + return false; + } + + memset(&presentation, 0, sizeof(presentation)); + presentation.Flags = D3DPRESENTFLAG_VIDEO; + presentation.SwapEffect = D3DSWAPEFFECT_FLIP; + presentation.hDeviceWindow = settings.handle; + presentation.BackBufferCount = 1; + presentation.MultiSampleType = D3DMULTISAMPLE_NONE; + presentation.MultiSampleQuality = 0; + presentation.EnableAutoDepthStencil = false; + presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + presentation.Windowed = true; + presentation.BackBufferFormat = D3DFMT_UNKNOWN; + presentation.BackBufferWidth = 0; + presentation.BackBufferHeight = 0; + + if(lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, settings.handle, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) { + printf("VideoD3D: failed to create Direct3D9 device"); + return false; + } + + //detect device capabilities + device->GetDeviceCaps(&d3dcaps); + if(d3dcaps.MaxTextureWidth < 1024 || d3dcaps.MaxTextureWidth < 1024) { + printf("VideoD3D: renderer requires that the video card supports textures up to 1024x1024.\n" + "However, this display adapter only supports %dx%d-sized textures.\n" + "", d3dcaps.MaxTextureWidth, d3dcaps.MaxTextureHeight); + return false; + } + caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); + caps.addresswrap = bool(d3dcaps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP); + caps.stretchrect = (d3dcaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) && + (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT) && + (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) && + (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) && + (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR); + + if(caps.dynamic == true) { + flags.t_usage = D3DUSAGE_DYNAMIC; + flags.v_usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; + flags.t_pool = D3DPOOL_DEFAULT; + flags.v_pool = D3DPOOL_DEFAULT; + flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; + } else { + flags.t_usage = 0; + flags.v_usage = D3DUSAGE_WRITEONLY; + flags.t_pool = D3DPOOL_MANAGED; + flags.v_pool = D3DPOOL_MANAGED; + flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; + } + + device->SetDialogBoxMode(false); + + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + if(caps.addresswrap == true) { + device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + } + + device->SetRenderState(D3DRS_LIGHTING, false); + device->SetRenderState(D3DRS_ZENABLE, false); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); + + device->SetVertexShader(NULL); + device->SetFVF(D3DVERTEX); + + update_filter(); + + if(caps.stretchrect == true) { + device->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_R5G6B5, + D3DPOOL_DEFAULT, &surface, NULL); + } else { + device->CreateTexture(1024, 1024, 1, flags.t_usage, D3DFMT_R5G6B5, + static_cast(flags.t_pool), &texture, NULL); + } + + device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, + static_cast(flags.v_pool), &vertex_buffer, NULL); + + clear_video(); + return true; + } + + void update_filter() { + if(!device) return; + + switch(settings.filter) { default: + case Video::FilterPoint: flags.filter = D3DTEXF_POINT; break; + case Video::FilterLinear: flags.filter = D3DTEXF_LINEAR; break; + } + + device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter); + } + + /* Vertex format: + + 0----------1 + | /| + | / | + | / | + | / | + | / | + 2----------3 + + (x,y) screen coords, in pixels (-0.5 for texel / pixel correction) + (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right) + */ + void set_vertex(uint32 px, uint32 py, uint32 pw, uint32 ph, + uint32 tw, uint32 th, uint32 x, uint32 y, uint32 w, uint32 h) { + d3dvertex vertex[4]; + vertex[0].x = vertex[2].x = (float)(x ) - 0.5; + vertex[1].x = vertex[3].x = (float)(x + w) - 0.5; + vertex[0].y = vertex[1].y = (float)(y ) - 0.5; + vertex[2].y = vertex[3].y = (float)(y + h) - 0.5; + + //unused + vertex[0].z = vertex[1].z = 1.0; + vertex[2].z = vertex[3].z = 1.0; + vertex[0].rhw = vertex[1].rhw = 1.0; + vertex[2].rhw = vertex[3].rhw = 1.0; + + //setup a gradient fade for when pause is enabled + vertex[0].color = 0x80000000; + vertex[1].color = 0xa8000000; + vertex[2].color = 0xa8000000; + vertex[3].color = 0xd0000000; + + float rw = (float)w / (float)pw * (float)tw; + float rh = (float)h / (float)ph * (float)th; + vertex[0].u = vertex[2].u = (float)(px ) / rw; + vertex[1].u = vertex[3].u = (float)(px + w) / rw; + vertex[0].v = vertex[1].v = (float)(py ) / rh; + vertex[2].v = vertex[3].v = (float)(py + h) / rh; + + vertex_buffer->Lock(0, sizeof(d3dvertex) * 4, (void**)&vertex_ptr, 0); + memcpy(vertex_ptr, vertex, sizeof(d3dvertex) * 4); + vertex_buffer->Unlock(); + + device->SetStreamSource(0, vertex_buffer, 0, sizeof(d3dvertex)); + } + + void clear_video() { + if(!device) return; + if(caps.stretchrect == false && !texture) return; + + if(caps.stretchrect == false) { + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); + } + + if(surface) { + device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00)); + if(caps.stretchrect == false) { + surface->Release(); + } + } + + //clear primary display and all backbuffers + for(int i = 0; i < 3; i++) { + device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0); + device->Present(0, 0, 0, 0); + } + } + + bool lock(uint16 *&data, uint &pitch) { + if(caps.stretchrect == false) { + texture->GetLevelDesc(0, &d3dsd); + texture->GetSurfaceLevel(0, &surface); + } + surface->LockRect(&d3dlr, 0, flags.lock); + pitch = d3dlr.Pitch; + data = (uint16*)d3dlr.pBits; + return data; + } + + void unlock() { + surface->UnlockRect(); + if(caps.stretchrect == false)surface->Release(); + } + + void refresh(uint r_width, uint r_height) { + if(!device) return; + + device->BeginScene(); + + if(caps.stretchrect == true) { + RECT rs; + SetRect(&rs, 0, 0, r_width, r_height); + LPDIRECT3DSURFACE9 temp; + device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &temp); + device->StretchRect(surface, &rs, temp, 0, static_cast(flags.filter)); + temp->Release(); + } else { + RECT rd; + GetClientRect(settings.handle, &rd); + set_vertex(0, 0, r_width, r_height, 1024, 1024, 0, 0, rd.right, rd.bottom); + device->SetTexture(0, texture); + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + } + + device->EndScene(); + + if(settings.synchronize) { + D3DRASTER_STATUS status; + for(;;) { + device->GetRasterStatus(0, &status); + if(bool(status.InVBlank) == true) break; + //Sleep(1); + } + } + + device->Present(0, 0, 0, 0); + } + + void init() { + term(); + update_video_mode(); + } + + void term() { + safe_release(vertex_buffer); + safe_release(surface); + safe_release(texture); + safe_release(device); + safe_release(lpd3d); + } + + pVideoD3D(VideoD3D &self_) : self(self_) { + vertex_buffer = 0; + surface = 0; + texture = 0; + device = 0; + lpd3d = 0; + + settings.handle = 0; + settings.synchronize = false; + settings.filter = Video::FilterLinear; + } +}; + +bool VideoD3D::cap(Setting setting) { return p.cap(setting); } +uintptr_t VideoD3D::get(Setting setting) { return p.get(setting); } +bool VideoD3D::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool VideoD3D::lock(uint16 *&data, uint &pitch) { return p.lock(data, pitch); } +void VideoD3D::unlock() { p.unlock(); } +void VideoD3D::clear_video() { p.clear_video(); } +void VideoD3D::refresh(uint width, uint height) { p.refresh(width, height); } +void VideoD3D::init() { p.init(); } +void VideoD3D::term() { p.term(); } +VideoD3D::VideoD3D() : p(*new pVideoD3D(*this)) {} +VideoD3D::~VideoD3D() { delete &p; } diff --git a/src/ui/vai/video/video.direct3d.h b/src/ui/vai/video/video.direct3d.h new file mode 100644 index 00000000..e2cdc7ce --- /dev/null +++ b/src/ui/vai/video/video.direct3d.h @@ -0,0 +1,29 @@ +#ifndef VIDEO_DIRECT3D_H +#define VIDEO_DIRECT3D_H + +#include "../video.h" + +class pVideoD3D; + +class VideoD3D : public Video { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + bool lock(uint16 *&data, uint &pitch); + void unlock(); + + void clear_video(); + void refresh(uint width, uint height); + void init(); + void term(); + + VideoD3D(); + ~VideoD3D(); + +private: + pVideoD3D &p; +}; + +#endif //ifndef VIDEO_DIRECT3D_H diff --git a/src/ui/vai/video/video.directdraw.cpp b/src/ui/vai/video/video.directdraw.cpp new file mode 100644 index 00000000..c26a1bed --- /dev/null +++ b/src/ui/vai/video/video.directdraw.cpp @@ -0,0 +1,177 @@ +#include "video.directdraw.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +class pVideoDD { +public: + VideoDD &self; + + LPDIRECTDRAW lpdd; + LPDIRECTDRAW7 lpdd7; + LPDIRECTDRAWSURFACE7 screen, raster; + LPDIRECTDRAWCLIPPER clipper; + DDSURFACEDESC2 ddsd; + DDSCAPS2 ddscaps; + + struct { + HWND handle; + bool synchronize; + } settings; + + bool cap(Video::Setting setting) { + if(setting == Video::Handle) return true; + if(setting == Video::Synchronize) return true; + return false; + } + + uintptr_t get(Video::Setting setting) { + if(setting == Video::Handle) return (uintptr_t)settings.handle; + if(setting == Video::Synchronize) return settings.synchronize; + return false; + } + + bool set(Video::Setting setting, uintptr_t param) { + if(setting == Video::Handle) { + settings.handle = (HWND)param; + return true; + } + if(setting == Video::Synchronize) { + settings.synchronize = param; + return true; + } + return false; + } + + void clear_video() { + DDBLTFX fx; + fx.dwSize = sizeof(DDBLTFX); + fx.dwFillColor = 0x00000000; + screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); + raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); + } + + bool lock(uint16 *&data, uint &pitch) { + if(raster->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK) return false; + pitch = ddsd.lPitch; + data = (uint16*)ddsd.lpSurface; + return data; + } + + void unlock() { + raster->Unlock(0); + } + + void refresh(uint r_width, uint r_height) { + if(settings.synchronize) { + for(;;) { + BOOL in_vblank; + lpdd7->GetVerticalBlankStatus(&in_vblank); + if(bool(in_vblank) == true) break; + //Sleep(1); + } + } + + HRESULT hr; + RECT rd, rs; + SetRect(&rs, 0, 0, r_width, r_height); + + POINT p = { 0, 0 }; + ClientToScreen(settings.handle, &p); + GetClientRect(settings.handle, &rd); + OffsetRect(&rd, p.x, p.y); + + if(screen->Blt(&rd, raster, &rs, DDBLT_WAIT, 0) == DDERR_SURFACELOST) { + screen->Restore(); + raster->Restore(); + } + } + + void init() { + term(); + + DirectDrawCreate(0, &lpdd, 0); + lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7); + safe_release(lpdd); + + lpdd7->SetCooperativeLevel(settings.handle, DDSCL_NORMAL); + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + lpdd7->CreateSurface(&ddsd, &screen, 0); + + lpdd7->CreateClipper(0, &clipper, 0); + clipper->SetHWnd(0, settings.handle); + screen->SetClipper(clipper); + + create_raster(); + clear_video(); + } + + void create_raster() { + int depth; + screen->GetSurfaceDesc(&ddsd); + depth = ddsd.ddpfPixelFormat.dwRGBBitCount; + if(depth == 15 || depth == 16) goto try_native_surface; + + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY + ddsd.dwWidth = 1024; + ddsd.dwHeight = 1024; + + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; + ddsd.ddpfPixelFormat.dwRGBBitCount = 16; + ddsd.ddpfPixelFormat.dwRBitMask = 0xf800; + ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0; + ddsd.ddpfPixelFormat.dwBBitMask = 0x001f; + + if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return; + + try_native_surface: + memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); + ddsd.dwSize = sizeof(DDSURFACEDESC2); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; //DDSCAPS_SYSTEMMEMORY + ddsd.dwWidth = 1024; + ddsd.dwHeight = 1024; + + lpdd7->CreateSurface(&ddsd, &raster, 0); + } + + void term() { + safe_release(clipper); + safe_release(raster); + safe_release(screen); + safe_release(lpdd7); + safe_release(lpdd); + } + + pVideoDD(VideoDD &self_) : self(self_) { + lpdd = 0; + lpdd7 = 0; + screen = 0; + raster = 0; + clipper = 0; + + settings.handle = 0; + } +}; + +bool VideoDD::cap(Setting setting) { return p.cap(setting); } +uintptr_t VideoDD::get(Setting setting) { return p.get(setting); } +bool VideoDD::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool VideoDD::lock(uint16 *&data, uint &pitch) { return p.lock(data, pitch); } +void VideoDD::unlock() { p.unlock(); } +void VideoDD::clear_video() { p.clear_video(); } +void VideoDD::refresh(uint width, uint height) { p.refresh(width, height); } +void VideoDD::init() { p.init(); } +void VideoDD::term() { p.term(); } +VideoDD::VideoDD() : p(*new pVideoDD(*this)) {} +VideoDD::~VideoDD() { delete &p; } diff --git a/src/ui/vai/video/video.directdraw.h b/src/ui/vai/video/video.directdraw.h new file mode 100644 index 00000000..304f123b --- /dev/null +++ b/src/ui/vai/video/video.directdraw.h @@ -0,0 +1,29 @@ +#ifndef VIDEO_DIRECTDRAW_H +#define VIDEO_DIRECTDRAW_H + +#include "../video.h" + +class pVideoDD; + +class VideoDD : public Video { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + bool lock(uint16 *&data, uint &pitch); + void unlock(); + + void clear_video(); + void refresh(uint width, uint height); + void init(); + void term(); + + VideoDD(); + ~VideoDD(); + +private: + pVideoDD &p; +}; + +#endif //ifndef VIDEO_DIRECTDRAW_H diff --git a/src/ui/vai/video/video.gdi.cpp b/src/ui/vai/video/video.gdi.cpp new file mode 100644 index 00000000..0863d1b8 --- /dev/null +++ b/src/ui/vai/video/video.gdi.cpp @@ -0,0 +1,98 @@ +#include "video.gdi.h" + +#define WIN32_LEAN_AND_MEAN +#include + +class pVideoGDI { +public: + VideoGDI &self; + + uint16 *buffer; + HBITMAP bitmap; + HDC bitmapdc; + BITMAPINFO bmi; + + struct { + HWND handle; + } settings; + + bool cap(Video::Setting setting) { + if(setting == Video::Handle) return true; + return false; + } + + uintptr_t get(Video::Setting setting) { + if(setting == Video::Handle) return (uintptr_t)settings.handle; + return false; + } + + bool set(Video::Setting setting, uintptr_t param) { + if(setting == Video::Handle) { + settings.handle = (HWND)param; + return true; + } + return false; + } + + bool lock(uint16 *&data, uint &pitch) { + pitch = 2048; + data = buffer; + return data; + } + + void unlock() {} + + void refresh(uint r_width, uint r_height) { + RECT rc; + GetClientRect(settings.handle, &rc); + + SetDIBits(bitmapdc, bitmap, 0, r_height, (void*)buffer, &bmi, DIB_RGB_COLORS); + HDC hdc = GetDC(settings.handle); + StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, bitmapdc, 0, 1024 - r_height, r_width, r_height, SRCCOPY); + ReleaseDC(settings.handle, hdc); + } + + void init() { + HDC hdc = GetDC(settings.handle); + bitmapdc = CreateCompatibleDC(hdc); + assert(bitmapdc); + bitmap = CreateCompatibleBitmap(hdc, 1024, 1024); + assert(bitmap); + SelectObject(bitmapdc, bitmap); + ReleaseDC(settings.handle, hdc); + + memset(&bmi, 0, sizeof(BITMAPINFO)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = 1024; + bmi.bmiHeader.biHeight = -1024; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 16; //biBitCount of 15 is invalid, biBitCount of 16 is really RGB555 + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint16); + } + + void term() { + DeleteObject(bitmap); + DeleteDC(bitmapdc); + } + + pVideoGDI(VideoGDI &self_) : self(self_) { + buffer = (uint16*)malloc(1024 * 1024 * sizeof(uint16)); + settings.handle = 0; + } + + ~pVideoGDI() { + if(buffer) free(buffer); + } +}; + +bool VideoGDI::cap(Setting setting) { return p.cap(setting); } +uintptr_t VideoGDI::get(Setting setting) { return p.get(setting); } +bool VideoGDI::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool VideoGDI::lock(uint16 *&data, uint &pitch) { return p.lock(data, pitch); } +void VideoGDI::unlock() { p.unlock(); } +void VideoGDI::refresh(uint width, uint height) { p.refresh(width, height); } +void VideoGDI::init() { p.init(); } +void VideoGDI::term() { p.term(); } +VideoGDI::VideoGDI() : p(*new pVideoGDI(*this)) {} +VideoGDI::~VideoGDI() { delete &p; } diff --git a/src/ui/video/gdi.h b/src/ui/vai/video/video.gdi.h similarity index 53% rename from src/ui/video/gdi.h rename to src/ui/vai/video/video.gdi.h index e8fbb616..4399c257 100644 --- a/src/ui/video/gdi.h +++ b/src/ui/vai/video/video.gdi.h @@ -1,15 +1,16 @@ #ifndef VIDEO_GDI_H #define VIDEO_GDI_H -class VideoGDI : public Video { -private: -HWND hwnd; -uint16 *buffer; -HBITMAP bitmap; -HDC bitmapdc; -BITMAPINFO bmi; +#include "../video.h" +class pVideoGDI; + +class VideoGDI : public Video { public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + bool lock(uint16 *&data, uint &pitch); void unlock(); @@ -17,8 +18,11 @@ public: void init(); void term(); - VideoGDI(HWND handle); + VideoGDI(); ~VideoGDI(); + +private: + pVideoGDI &p; }; -#endif +#endif //ifndef VIDEO_GDI_H diff --git a/src/ui/vai/video/video.gtk.cpp b/src/ui/vai/video/video.gtk.cpp new file mode 100644 index 00000000..7e862e61 --- /dev/null +++ b/src/ui/vai/video/video.gtk.cpp @@ -0,0 +1,120 @@ +#include "video.gtk.h" + +#include +#include +#include +#include + +class pVideoGTK { +public: + VideoGTK &self; + GtkWidget *widget; + uint16 *buffer; + uint8 *gdkbuffer; + + struct { + Window handle; + } settings; + + bool cap(Video::Setting setting) { + if(setting == Video::Handle) return false; + return false; + } + + uintptr_t get(Video::Setting setting) { + if(setting == Video::Handle) return settings.handle; + return false; + } + + bool set(Video::Setting setting, uintptr_t param) { + if(setting == Video::Handle) { + settings.handle = param; + return false; + } + return false; + } + + bool lock(uint16 *&data, uint &pitch) { + pitch = 1024 * 2; + return data = buffer; + } + + void unlock() { + } + + void refresh(uint r_width, uint r_height) { + for(uint y = 0; y < r_height; y++) { + uint8 *dest = gdkbuffer + y * 1024 * 3; + uint16 *src = buffer + y * 1024; + for(uint x = 0; x < r_width; x++) { + uint32 p = *src++; + uint32 pix = ((p & 0xf800) << 8) | ((p & 0x07e0) << 5) | ((p & 0x001f) << 3); + *dest++ = pix >> 16; + *dest++ = pix >> 8; + *dest++ = pix; + } + } + + gdk_draw_rgb_image(GDK_DRAWABLE(widget->window), + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + 0, 0, r_width, r_height, + GDK_RGB_DITHER_NONE, gdkbuffer, 1024 * 3); + } + + void init_no_handle() { + GdkColor color; + color.pixel = color.red = color.green = color.blue = 0; + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "video.gtk"); + gtk_window_set_resizable(GTK_WINDOW(window), false); + gtk_widget_set_size_request(window, 512, 480); + GtkWidget *container = gtk_fixed_new(); + gtk_widget_set_size_request(container, 512, 480); + gtk_container_add(GTK_CONTAINER(window), container); + widget = gtk_drawing_area_new(); + gtk_fixed_put(GTK_FIXED(container), widget, 0, 0); + gtk_widget_set_size_request(widget, 512, 480); + gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color); + gtk_widget_modify_bg(container, GTK_STATE_NORMAL, &color); + gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); + gtk_widget_show(widget); + gtk_widget_show(container); + gtk_widget_show(window); + + if(settings.handle) { + /* below does not work, sadly ... + XReparentWindow( + GDK_WINDOW_XDISPLAY(window->window), + GDK_WINDOW_XWINDOW(window->window), + settings.handle, 0, 0); + */ + } + } + + void init() { + buffer = (uint16*)malloc(1024 * 1024 * 2); + gdkbuffer = (uint8*) malloc(1024 * 1024 * 3); + + init_no_handle(); + } + + void term() { + safe_free(buffer); + safe_free(gdkbuffer); + } + + pVideoGTK(VideoGTK &self_) : self(self_) { + settings.handle = 0; + } +}; + +bool VideoGTK::cap(Setting setting) { return p.cap(setting); } +uintptr_t VideoGTK::get(Setting setting) { return p.get(setting); } +bool VideoGTK::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool VideoGTK::lock(uint16 *&data, uint &pitch) { return p.lock(data, pitch); } +void VideoGTK::unlock() { p.unlock(); } +void VideoGTK::refresh(uint width, uint height) { p.refresh(width, height); } +void VideoGTK::init() { p.init(); } +void VideoGTK::term() { p.term(); } +VideoGTK::VideoGTK() : p(*new pVideoGTK(*this)) {} +VideoGTK::~VideoGTK() { delete &p; } diff --git a/src/ui/vai/video/video.gtk.h b/src/ui/vai/video/video.gtk.h new file mode 100644 index 00000000..3014e7b5 --- /dev/null +++ b/src/ui/vai/video/video.gtk.h @@ -0,0 +1,28 @@ +#ifndef VIDEO_GTK_H +#define VIDEO_GTK_H + +#include "../video.h" + +class pVideoGTK; + +class VideoGTK : public Video { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + bool lock(uint16 *&data, uint &pitch); + void unlock(); + + void refresh(uint width, uint height); + void init(); + void term(); + + VideoGTK(); + ~VideoGTK(); + +private: + pVideoGTK &p; +}; + +#endif //ifndef VIDEO_GTK_H diff --git a/src/ui/vai/video/video.xv.cpp b/src/ui/vai/video/video.xv.cpp new file mode 100644 index 00000000..24937908 --- /dev/null +++ b/src/ui/vai/video/video.xv.cpp @@ -0,0 +1,195 @@ +#include "video.xv.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" XvImage* XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*); + +class pVideoXv { +public: + VideoXv &self; + uint16 *buffer; + XvImage *xvimage; + GC gc; + Display *display; + int screen, xv_port; + XShmSegmentInfo shminfo; + uint8 *ytable, *utable, *vtable; + + struct { + Window handle; + } settings; + + bool cap(Video::Setting setting) { + if(setting == Video::Handle) return true; + return false; + } + + uintptr_t get(Video::Setting setting) { + if(setting == Video::Handle) return settings.handle; + return false; + } + + bool set(Video::Setting setting, uintptr_t param) { + if(setting == Video::Handle) { + settings.handle = param; + return true; + } + return false; + } + + bool lock(uint16 *&data, uint &pitch) { + pitch = 1024 * 2; + data = buffer; + return data; + } + + void unlock() { + } + + void clear_video() { + memset(buffer, 0, 1024 * 1024 * sizeof(uint16)); + //clear twice in case video is double buffered ... + refresh(1024, 1024); + refresh(1024, 1024); + } + + void refresh(uint r_width, uint r_height) { + Window dw; + int d0, d1; + uint d2, d3; + uint width, height; + XGetGeometry(display, settings.handle, &dw, &d0, &d1, &width, &height, &d2, &d3); + + uint16 *input = (uint16*)buffer; + uint16 *output = (uint16*)xvimage->data; + for(int y = 0; y < r_height; y++) { + for(int x = 0; x < r_width >> 1; x++) { + uint16 p0 = *input++; + uint16 p1 = *input++; + + uint8 u = (utable[p0] + utable[p1]) >> 1; + uint8 v = (vtable[p0] + vtable[p1]) >> 1; + + *output++ = (u << 8) | ytable[p0]; + *output++ = (v << 8) | ytable[p1]; + } + input += 1024 - r_width; + output += 1024 - r_width; + } + + XvShmPutImage(display, xv_port, settings.handle, gc, xvimage, + 0, 0, r_width, r_height, + 0, 0, width, height, + true); + } + + void init() { + buffer = (uint16*)malloc(1024 * 1024 * sizeof(uint16)); + display = XOpenDisplay(0); + screen = DefaultScreen(display); + gc = XCreateGC(display, settings.handle, 0, 0); + + XVisualInfo visual_info; + if(XMatchVisualInfo(display, screen, 24, TrueColor, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 16, TrueColor, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 15, TrueColor, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 8, PseudoColor, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 8, GrayScale, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 8, StaticGray, &visual_info)) { + } else if(XMatchVisualInfo(display, screen, 1, StaticGray, &visual_info)) { + } else { + printf("VideoXv: unable to find suitable video display.\n"); + } + + if(!XShmQueryExtension(display)) printf("VideoXv: XShm extension not found.\n"); + + xv_port = -1; + XvAdaptorInfo *adaptor_info; + uint adaptor_count; + XvQueryAdaptors(display, DefaultRootWindow(display), &adaptor_count, &adaptor_info); + for(uint i = 0; i < adaptor_count; i++) { + //find adaptor that supports both input (memory->drawable) and image (drawable->screen) masks + if(adaptor_info[i].type & XvInputMask && adaptor_info[i].type & XvImageMask) { + xv_port = adaptor_info[i].base_id; + break; + } + } + XvFreeAdaptorInfo(adaptor_info); + if(xv_port == -1) printf("VideoXv: failed to find valid XvPort.\n"); + + //set colorkey to auto paint, so that Xv video output is always visible + const Atom atom = XInternAtom(display, "XV_AUTOPAINT_COLORKEY", true); + if(atom != None) XvSetPortAttribute(display, xv_port, atom, 1); + + //0x00000003 = 32-bit X8R8G8B8 [xRGB] (few drivers support this mode) + //0x32595559 = 16-bit Y8U8,Y8V8 [YUY2] (most drivers support this mode) + xvimage = XvShmCreateImage(display, xv_port, 0x32595559, 0, 1024, 1024, &shminfo); + if(!xvimage) printf("VideoXv: XShmCreateImage failed.\n"); + shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size, IPC_CREAT | 0777); + shminfo.shmaddr = xvimage->data = (char*)shmat(shminfo.shmid, 0, 0); + shminfo.readOnly = false; + if(!XShmAttach(display, &shminfo)) printf("VideoXv: XShmAttach failed.\n"); + + init_yuv_tables(); + clear_video(); + } + + void term() { + XShmDetach(display, &shminfo); + free(ytable); + free(utable); + free(vtable); + } + + void init_yuv_tables() { + ytable = (uint8*)malloc(65536); + utable = (uint8*)malloc(65536); + vtable = (uint8*)malloc(65536); + + for(int i = 0; i < 65536; i++) { + //extract RGB565 color data from i + uint8 r = (i >> 11) & 31, g = (i >> 5) & 63, b = (i) & 31; + r = (r << 3) | (r >> 2); //R5->R8 + g = (g << 2) | (g >> 4); //G6->G8 + b = (b << 3) | (b >> 2); //B5->B8 + + //RGB->YUV conversion + int y = int( +(double(r) * 0.257) + (double(g) * 0.504) + (double(b) * 0.098) + 16.0 ); + int u = int( -(double(r) * 0.148) - (double(g) * 0.291) + (double(b) * 0.439) + 128.0 ); + int v = int( +(double(r) * 0.439) - (double(g) * 0.368) - (double(b) * 0.071) + 128.0 ); + + //RGB->YCbCr conversion + //double lr = 0.2126, lb = 0.0722, lg = (1.0 - lr - lb); + //int y = int( double(r) * lr + double(g) * lg + double(b) * lb ); + //int u = int( (double(b) - y) / (2.0 - 2.0 * lb) + 128.0 ); + //int v = int( (double(r) - y) / (2.0 - 2.0 * lr) + 128.0 ); + + ytable[i] = y < 0 ? 0 : y > 255 ? 255 : y; + utable[i] = u < 0 ? 0 : u > 255 ? 255 : u; + vtable[i] = v < 0 ? 0 : v > 255 ? 255 : v; + } + } + + pVideoXv(VideoXv &self_) : self(self_) { + settings.handle = 0; + } +}; + +bool VideoXv::cap(Setting setting) { return p.cap(setting); } +uintptr_t VideoXv::get(Setting setting) { return p.get(setting); } +bool VideoXv::set(Setting setting, uintptr_t param) { return p.set(setting, param); } +bool VideoXv::lock(uint16 *&data, uint &pitch) { return p.lock(data, pitch); } +void VideoXv::unlock() { p.unlock(); } +void VideoXv::clear_video() { p.clear_video(); } +void VideoXv::refresh(uint width, uint height) { p.refresh(width, height); } +void VideoXv::init() { p.init(); } +void VideoXv::term() { p.term(); } +VideoXv::VideoXv() : p(*new pVideoXv(*this)) {} +VideoXv::~VideoXv() { delete &p; } diff --git a/src/ui/vai/video/video.xv.h b/src/ui/vai/video/video.xv.h new file mode 100644 index 00000000..816a587e --- /dev/null +++ b/src/ui/vai/video/video.xv.h @@ -0,0 +1,29 @@ +#ifndef VIDEO_XV_H +#define VIDEO_XV_H + +#include "../video.h" + +class pVideoXv; + +class VideoXv : public Video { +public: + bool cap(Setting); + uintptr_t get(Setting); + bool set(Setting, uintptr_t); + + bool lock(uint16 *&data, uint &pitch); + void unlock(); + + void clear_video(); + void refresh(uint width, uint height); + void init(); + void term(); + + VideoXv(); + ~VideoXv(); + +private: + pVideoXv &p; +}; + +#endif //ifndef VIDEO_XV_H diff --git a/src/ui/video/d3d.cpp b/src/ui/video/d3d.cpp deleted file mode 100644 index 1c8e509d..00000000 --- a/src/ui/video/d3d.cpp +++ /dev/null @@ -1,271 +0,0 @@ -#define D3DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) - -bool VideoD3D::update_video_mode() { -HRESULT hr; - term(); - - lpd3d = Direct3DCreate9(D3D_SDK_VERSION); - if(!lpd3d) { - alert("Failed to create Direct3D9 interface"); - return false; - } - - memset(&presentation, 0, sizeof(presentation)); - presentation.Flags = D3DPRESENTFLAG_VIDEO; - presentation.SwapEffect = D3DSWAPEFFECT_FLIP; - presentation.hDeviceWindow = hwnd; - presentation.BackBufferCount = 1; - presentation.MultiSampleType = D3DMULTISAMPLE_NONE; - presentation.MultiSampleQuality = 0; - presentation.EnableAutoDepthStencil = false; - presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; - presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - presentation.Windowed = true; - presentation.BackBufferFormat = D3DFMT_UNKNOWN; - presentation.BackBufferWidth = 0; - presentation.BackBufferHeight = 0; - - if(lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentation, &device) != D3D_OK) { - alert("Failed to create Direct3D9 device"); - return false; - } - -//detect device capabilities - device->GetDeviceCaps(&d3dcaps); - if(d3dcaps.MaxTextureWidth < 1024 || d3dcaps.MaxTextureWidth < 1024) { - alert("Error: Direct3D renderer requires that the video card supports textures up to 1024x1024.\n" - "However, this display adapter only supports %dx%d-sized textures.\n" - "", d3dcaps.MaxTextureWidth, d3dcaps.MaxTextureHeight); - return false; - } - caps.dynamic = bool(d3dcaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES); - caps.addresswrap = bool(d3dcaps.TextureAddressCaps & D3DPTADDRESSCAPS_WRAP); - caps.stretchrect = (d3dcaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) && - (d3dcaps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR); - - if(config::video.use_vram == true && caps.dynamic == true) { - flags.t_usage = D3DUSAGE_DYNAMIC; - flags.v_usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; - flags.t_pool = D3DPOOL_DEFAULT; - flags.v_pool = D3DPOOL_DEFAULT; - flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; - } else { - flags.t_usage = 0; - flags.v_usage = D3DUSAGE_WRITEONLY; - flags.t_pool = D3DPOOL_MANAGED; - flags.v_pool = D3DPOOL_MANAGED; - flags.lock = D3DLOCK_NOSYSLOCK | D3DLOCK_DISCARD; - } - - device->SetDialogBoxMode(false); - - device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - - device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); - device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - - if(caps.addresswrap == true) { - device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - } - - device->SetRenderState(D3DRS_LIGHTING, false); - device->SetRenderState(D3DRS_ZENABLE, false); - device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - - device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); - - device->SetVertexShader(NULL); - device->SetFVF(D3DVERTEX); - - update_settings(); - - if(caps.stretchrect == true) { - device->CreateOffscreenPlainSurface(1024, 1024, D3DFMT_R5G6B5, - D3DPOOL_DEFAULT, &surface, NULL); - } else { - device->CreateTexture(1024, 1024, 1, flags.t_usage, D3DFMT_R5G6B5, - static_cast(flags.t_pool), &texture, NULL); - } - - device->CreateVertexBuffer(sizeof(d3dvertex) * 4, flags.v_usage, D3DVERTEX, - static_cast(flags.v_pool), &vertex_buffer, NULL); - - clear_video(); - return true; -} - -void VideoD3D::update_settings() { - if(!device)return; - - switch(settings.filter) { - case Video::FilterPoint: - flags.filter = D3DTEXF_POINT; - break; - case Video::FilterLinear: - default: - flags.filter = D3DTEXF_LINEAR; - break; - } - - device->SetSamplerState(0, D3DSAMP_MINFILTER, flags.filter); - device->SetSamplerState(0, D3DSAMP_MAGFILTER, flags.filter); -} - -/* Vertex format: - - 0----------1 - | /| - | / | - | / | - | / | - | / | - 2----------3 - - (x,y) screen coords, in pixels (-0.5 for texel / pixel correction) - (u,v) texture coords, betweeen 0.0 (top, left) to 1.0 (bottom, right) -*/ - -void VideoD3D::set_vertex(uint32 px, uint32 py, uint32 pw, uint32 ph, -uint32 tw, uint32 th, uint32 x, uint32 y, uint32 w, uint32 h) { -d3dvertex vertex[4]; - vertex[0].x = vertex[2].x = (float)(x ) - 0.5; - vertex[1].x = vertex[3].x = (float)(x + w) - 0.5; - vertex[0].y = vertex[1].y = (float)(y ) - 0.5; - vertex[2].y = vertex[3].y = (float)(y + h) - 0.5; - -//unused - vertex[0].z = vertex[1].z = 1.0; - vertex[2].z = vertex[3].z = 1.0; - vertex[0].rhw = vertex[1].rhw = 1.0; - vertex[2].rhw = vertex[3].rhw = 1.0; - -//setup a gradient fade for when pause is enabled - vertex[0].color = 0x80000000; - vertex[1].color = 0xa8000000; - vertex[2].color = 0xa8000000; - vertex[3].color = 0xd0000000; - -float rw = (float)w / (float)pw * (float)tw; -float rh = (float)h / (float)ph * (float)th; - vertex[0].u = vertex[2].u = (float)(px ) / rw; - vertex[1].u = vertex[3].u = (float)(px + w) / rw; - vertex[0].v = vertex[1].v = (float)(py ) / rh; - vertex[2].v = vertex[3].v = (float)(py + h) / rh; - - vertex_buffer->Lock(0, sizeof(d3dvertex) * 4, (void**)&vertex_ptr, 0); - memcpy(vertex_ptr, vertex, sizeof(d3dvertex) * 4); - vertex_buffer->Unlock(); - - device->SetStreamSource(0, vertex_buffer, 0, sizeof(d3dvertex)); -} - -void VideoD3D::clear_video() { - if(!device)return; - if(caps.stretchrect == false && !texture)return; - - if(caps.stretchrect == false) { - texture->GetLevelDesc(0, &d3dsd); - texture->GetSurfaceLevel(0, &surface); - } - - if(surface) { - device->ColorFill(surface, 0, D3DCOLOR_XRGB(0x00, 0x00, 0x00)); - if(caps.stretchrect == false) { - surface->Release(); - } - } - -//clear primary display and all backbuffers - for(int i = 0; i < 3; i++) { - device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00, 0x00, 0x00), 1.0f, 0); - device->Present(0, 0, 0, 0); - } -} - -bool VideoD3D::lock(uint16 *&data, uint &pitch) { - if(caps.stretchrect == false) { - texture->GetLevelDesc(0, &d3dsd); - texture->GetSurfaceLevel(0, &surface); - } - surface->LockRect(&d3dlr, 0, flags.lock); - pitch = d3dlr.Pitch; - data = (uint16*)d3dlr.pBits; - return data; -} - -void VideoD3D::unlock() { - surface->UnlockRect(); - if(caps.stretchrect == false)surface->Release(); -} - -void VideoD3D::refresh(uint r_width, uint r_height) { - if(!device)return; - - device->BeginScene(); - - if(caps.stretchrect == true) { - RECT rs; - SetRect(&rs, 0, 0, r_width, r_height); - LPDIRECT3DSURFACE9 temp; - device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &temp); - device->StretchRect(surface, &rs, temp, 0, static_cast(flags.filter)); - temp->Release(); - } else { - RECT rd; - GetClientRect(hwnd, &rd); - set_vertex(0, 0, r_width, r_height, 1024, 1024, 0, 0, rd.right, rd.bottom); - device->SetTexture(0, texture); - device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); - } - - device->EndScene(); - - if(settings.synchronize == true) { - D3DRASTER_STATUS status; - for(;;) { - device->GetRasterStatus(0, &status); - if(bool(status.InVBlank) == true)break; - //Sleep(1); - } - } - - device->Present(0, 0, 0, 0); -} - -void VideoD3D::init() { - term(); - update_video_mode(); -} - -void VideoD3D::term() { - safe_release(vertex_buffer); - safe_release(surface); - safe_release(texture); - safe_release(device); - safe_release(lpd3d); -} - -VideoD3D::VideoD3D(HWND handle) { - hwnd = handle; - - vertex_buffer = 0; - surface = 0; - texture = 0; - device = 0; - lpd3d = 0; -} - -VideoD3D::~VideoD3D() { -} - -#undef D3DVERTEX diff --git a/src/ui/video/d3d.h b/src/ui/video/d3d.h deleted file mode 100644 index c10d0a68..00000000 --- a/src/ui/video/d3d.h +++ /dev/null @@ -1,58 +0,0 @@ -#include - -class VideoD3D : public Video { -public: -HWND hwnd; -LPDIRECT3D9 lpd3d; -LPDIRECT3DDEVICE9 device; -LPDIRECT3DVERTEXBUFFER9 vertex_buffer, *vertex_ptr; -D3DPRESENT_PARAMETERS presentation; -D3DSURFACE_DESC d3dsd; -D3DLOCKED_RECT d3dlr; -D3DRASTER_STATUS d3drs; -D3DCAPS9 d3dcaps; -LPDIRECT3DTEXTURE9 texture; -LPDIRECT3DSURFACE9 surface; - -struct d3dvertex { - float x, y, z, rhw; //screen coords - uint32 color; //diffuse color - float u, v; //texture coords -}; - -struct { - uint32 t_usage, v_usage; - uint32 t_pool, v_pool; - uint32 lock; - uint32 filter; -} flags; - -struct { - bool dynamic; //device supports dynamic textures - bool addresswrap; //device supports texture address (u,v) wrapping - bool stretchrect; //device supports StretchRect -} caps; - - void set_vertex(uint32 px, uint32 py, uint32 pw, uint32 ph, - uint32 tw, uint32 th, uint32 x, uint32 y, uint32 w, uint32 h); - - bool lock(uint16 *&data, uint &pitch); - void unlock(); - - uint screen_width() { return GetSystemMetrics(SM_CXSCREEN); } - uint screen_height() { return GetSystemMetrics(SM_CYSCREEN); } - - bool update_video_mode(); - void update_settings(); - - bool capture_screenshot(); - - void init(); - void term(); - - void clear_video(); - void refresh(uint width, uint height); - - VideoD3D(HWND handle); - ~VideoD3D(); -}; diff --git a/src/ui/video/ddraw.cpp b/src/ui/video/ddraw.cpp deleted file mode 100644 index 3bc7ea71..00000000 --- a/src/ui/video/ddraw.cpp +++ /dev/null @@ -1,124 +0,0 @@ -void VideoDD::clear_video() { -DDBLTFX fx; - fx.dwSize = sizeof(DDBLTFX); - fx.dwFillColor = 0x00000000; - screen->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); - raster->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &fx); -} - -bool VideoDD::lock(uint16 *&data, uint &pitch) { - if(raster->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK) return false; - pitch = ddsd.lPitch; - data = (uint16*)ddsd.lpSurface; - return data; -} - -void VideoDD::unlock() { - raster->Unlock(0); -} - -void VideoDD::refresh(uint r_width, uint r_height) { - if(settings.synchronize) { - for(;;) { - BOOL in_vblank; - lpdd7->GetVerticalBlankStatus(&in_vblank); - if(bool(in_vblank) == true) break; - //Sleep(1); - } - } - -HRESULT hr; -RECT rd, rs; - SetRect(&rs, 0, 0, r_width, r_height); - -POINT p = { 0, 0 }; - ClientToScreen(hwnd, &p); - GetClientRect(hwnd, &rd); - OffsetRect(&rd, p.x, p.y); - - if(screen->Blt(&rd, raster, &rs, DDBLT_WAIT, 0) == DDERR_SURFACELOST) { - screen->Restore(); - raster->Restore(); - } -} - -void VideoDD::init() { - term(); - -// - DirectDrawCreate(0, &lpdd, 0); - lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7); - safe_release(lpdd); - - lpdd7->SetCooperativeLevel(hwnd, DDSCL_NORMAL); - - memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); - ddsd.dwSize = sizeof(DDSURFACEDESC2); - - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - lpdd7->CreateSurface(&ddsd, &screen, 0); - - lpdd7->CreateClipper(0, &clipper, 0); - clipper->SetHWnd(0, hwnd); - screen->SetClipper(clipper); -// - - create_raster(); - clear_video(); -} - -void VideoDD::create_raster() { -int depth; - screen->GetSurfaceDesc(&ddsd); - depth = ddsd.ddpfPixelFormat.dwRGBBitCount; - if(depth == 15 || depth == 16 || config::video.use_vram == false) { - goto try_native_surface; - } - - memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); - ddsd.dwSize = sizeof(DDSURFACEDESC2); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | - (config::video.use_vram == true ? DDSCAPS_VIDEOMEMORY : DDSCAPS_SYSTEMMEMORY); - ddsd.dwWidth = 1024; - ddsd.dwHeight = 1024; - - ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); - ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; - ddsd.ddpfPixelFormat.dwRGBBitCount = 16; - ddsd.ddpfPixelFormat.dwRBitMask = 0xf800; - ddsd.ddpfPixelFormat.dwGBitMask = 0x07e0; - ddsd.ddpfPixelFormat.dwBBitMask = 0x001f; - - if(lpdd7->CreateSurface(&ddsd, &raster, 0) == DD_OK) return; - -try_native_surface: - memset(&ddsd, 0, sizeof(DDSURFACEDESC2)); - ddsd.dwSize = sizeof(DDSURFACEDESC2); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | - (config::video.use_vram == true ? DDSCAPS_VIDEOMEMORY : DDSCAPS_SYSTEMMEMORY); - ddsd.dwWidth = 1024; - ddsd.dwHeight = 1024; - - lpdd7->CreateSurface(&ddsd, &raster, 0); -} - -void VideoDD::term() { - safe_release(clipper); - safe_release(raster); - safe_release(screen); - safe_release(lpdd7); - safe_release(lpdd); -} - -VideoDD::VideoDD(HWND handle) { - hwnd = handle; - - lpdd = 0; - lpdd7 = 0; - screen = 0; - raster = 0; - clipper = 0; -} diff --git a/src/ui/video/ddraw.h b/src/ui/video/ddraw.h deleted file mode 100644 index afeaafa3..00000000 --- a/src/ui/video/ddraw.h +++ /dev/null @@ -1,24 +0,0 @@ -#include - -class VideoDD : public Video { -private: -HWND hwnd; -LPDIRECTDRAW lpdd; -LPDIRECTDRAW7 lpdd7; -LPDIRECTDRAWSURFACE7 screen, raster; -LPDIRECTDRAWCLIPPER clipper; -DDSURFACEDESC2 ddsd; -DDSCAPS2 ddscaps; - void create_raster(); - void clear_video(); - -public: - bool lock(uint16 *&data, uint &pitch); - void unlock(); - - void refresh(uint width, uint height); - void init(); - void term(); - - VideoDD(HWND handle); -}; diff --git a/src/ui/video/gdi.cpp b/src/ui/video/gdi.cpp deleted file mode 100644 index b79da962..00000000 --- a/src/ui/video/gdi.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "gdi.h" - -bool VideoGDI::lock(uint16 *&data, uint &pitch) { - pitch = 2048; - data = buffer; - return data; -} - -void VideoGDI::unlock() {} - -void VideoGDI::refresh(uint r_width, uint r_height) { -RECT rc; - GetClientRect(hwnd, &rc); - - SetDIBits(bitmapdc, bitmap, 0, r_height, (void*)buffer, &bmi, DIB_RGB_COLORS); -HDC hdc = GetDC(hwnd); - StretchBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, bitmapdc, 0, 1024 - r_height, r_width, r_height, SRCCOPY); - ReleaseDC(hwnd, hdc); -} - -void VideoGDI::init() { -HDC hdc = GetDC(hwnd); - bitmapdc = CreateCompatibleDC(hdc); - assert(bitmapdc); - bitmap = CreateCompatibleBitmap(hdc, 1024, 1024); - assert(bitmap); - SelectObject(bitmapdc, bitmap); - ReleaseDC(hwnd, hdc); - - memset(&bmi, 0, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = 1024; - bmi.bmiHeader.biHeight = -1024; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 16; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = 1024 * 1024 * sizeof(uint16); - -//note: -//biBitCount of 15 is invalid, biBitCount of 16 is really RGB555 - - snes.set_video_pixel_format(SNES::PIXELFORMAT_RGB555); -} - -void VideoGDI::term() { - DeleteObject(bitmap); - DeleteDC(bitmapdc); -} - -VideoGDI::VideoGDI(HWND handle) { - hwnd = handle; - buffer = (uint16*)malloc(1024 * 1024 * sizeof(uint16)); -} - -VideoGDI::~VideoGDI() { - safe_free(buffer); -} diff --git a/src/ui/video/gtk.cpp b/src/ui/video/gtk.cpp deleted file mode 100644 index 8a5452bd..00000000 --- a/src/ui/video/gtk.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "gtk.h" - -bool VideoGTK::lock(uint16 *&data, uint &pitch) { - pitch = 1024 * 2; - data = buffer; - return data; -} - -void VideoGTK::unlock() {} - -void VideoGTK::refresh(uint r_width, uint r_height) { - for(uint y = 0; y < r_height; y++) { - uint8 *dest = gdkbuffer + y * 1024 * 3; - uint16 *src = buffer + y * 1024; - for(uint x = 0; x < r_width; x++) { - uint32 p = *src++; - uint32 pix = ((p & 0xf800) << 8) | ((p & 0x07e0) << 5) | ((p & 0x001f) << 3); - *dest++ = pix >> 16; - *dest++ = pix >> 8; - *dest++ = pix; - } - } - - gdk_draw_rgb_image(GDK_DRAWABLE(widget->window), - widget->style->fg_gc[GTK_WIDGET_STATE(widget)], - 0, 0, r_width, r_height, - GDK_RGB_DITHER_NONE, gdkbuffer, 1024 * 3); -} - -void VideoGTK::init() { - buffer = (uint16*)malloc(1024 * 1024 * 2); - gdkbuffer = (uint8*) malloc(1024 * 1024 * 3); -} - -void VideoGTK::term() { - safe_free(buffer); - safe_free(gdkbuffer); -} - -VideoGTK::VideoGTK(GtkWidget *output_widget) { - widget = output_widget; -} diff --git a/src/ui/video/gtk.h b/src/ui/video/gtk.h deleted file mode 100644 index ddb79e84..00000000 --- a/src/ui/video/gtk.h +++ /dev/null @@ -1,21 +0,0 @@ -#include - -class VideoGTK : public Video { -private: -GtkWidget *widget; -uint16 *buffer; -uint8 *gdkbuffer; - -public: - bool lock(uint16 *&data, uint &pitch); - void unlock(); - - uint screen_width() { return gdk_screen_width(); } - uint screen_height() { return gdk_screen_height(); } - - void refresh(uint width, uint height); - void init(); - void term(); - - VideoGTK(GtkWidget *output_widget); -}; diff --git a/src/ui/video/video.cpp b/src/ui/video/video.cpp deleted file mode 100644 index 09e03b06..00000000 --- a/src/ui/video/video.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "video.h" diff --git a/src/ui/video/video.h b/src/ui/video/video.h deleted file mode 100644 index 6c88f619..00000000 --- a/src/ui/video/video.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef VIDEO_H -#define VIDEO_H - -class Video { public: - -struct Settings { - bool synchronize; - uint filter; - Settings() : synchronize(false), filter(0) {} -} settings; - -enum Filter { - FilterPoint, - FilterLinear, -}; - - virtual bool lock(uint16 *&data, uint &pitch) { return false; } - virtual void unlock() {} - - virtual void clear_video() {} - virtual void refresh(uint width, uint height) {} - virtual void init() {} - virtual void term() {} - - virtual void update_settings() {} - - Video() {} - virtual ~Video() {} -} *uiVideo; - -#endif diff --git a/src/ui/video/xv.cpp b/src/ui/video/xv.cpp deleted file mode 100644 index 95930ad7..00000000 --- a/src/ui/video/xv.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "xv.h" - -bool VideoXv::lock(uint16 *&data, uint &pitch) { - pitch = 1024 * 2; - data = buffer; - return data; -} - -void VideoXv::unlock() { -} - -void VideoXv::clear_video() { - memset(buffer, 0, 1024 * 1024 * sizeof(uint16)); -//clear twice in case video is double buffered ... - refresh(1024, 1024); - refresh(1024, 1024); -} - -void VideoXv::refresh(uint r_width, uint r_height) { -Window dw; -int d0, d1; -unsigned int d2, d3; -unsigned int width, height; - XGetGeometry(display, window, &dw, &d0, &d1, &width, &height, &d2, &d3); - -uint16 *input = (uint16*)buffer; -uint16 *output = (uint16*)xvimage->data; - for(int y = 0; y < r_height; y++) { - for(int x = 0; x < r_width >> 1; x++) { - uint16 p0 = *input++; - uint16 p1 = *input++; - - uint8 u = (utable[p0] + utable[p1]) >> 1; - uint8 v = (vtable[p0] + vtable[p1]) >> 1; - - *output++ = (u << 8) | ytable[p0]; - *output++ = (v << 8) | ytable[p1]; - } - input += 1024 - r_width; - output += 1024 - r_width; - } - - XvShmPutImage(display, xv_port, window, gc, xvimage, - 0, 0, r_width, r_height, - 0, 0, width, height, - true); -} - -void VideoXv::init() { -} - -void VideoXv::term() { -} - -void VideoXv::init_yuv_tables() { - ytable = (uint8*)malloc(65536); - utable = (uint8*)malloc(65536); - vtable = (uint8*)malloc(65536); - - for(uint i = 0; i < 65536; i++) { - //extract RGB565 color data from i - uint8 r = (i >> 11) & 31, g = (i >> 5) & 63, b = (i) & 31; - r = (r << 3) | (r >> 2); //R5->R8 - g = (g << 2) | (g >> 4); //G6->G8 - b = (b << 3) | (b >> 2); //B5->B8 - - //RGB->YUV conversion - int y = int( +(double(r) * 0.257) + (double(g) * 0.504) + (double(b) * 0.098) + 16.0 ); - int u = int( -(double(r) * 0.148) - (double(g) * 0.291) + (double(b) * 0.439) + 128.0 ); - int v = int( +(double(r) * 0.439) - (double(g) * 0.368) - (double(b) * 0.071) + 128.0 ); - - //RGB->YCbCr conversion - //double lr = 0.2126, lb = 0.0722, lg = (1.0 - lr - lb); - //int y = int( double(r) * lr + double(g) * lg + double(b) * lb ); - //int u = int( (double(b) - y) / (2.0 - 2.0 * lb) + 128.0 ); - //int v = int( (double(r) - y) / (2.0 - 2.0 * lr) + 128.0 ); - - ytable[i] = y < 0 ? 0 : y > 255 ? 255 : y; - utable[i] = u < 0 ? 0 : u > 255 ? 255 : u; - vtable[i] = v < 0 ? 0 : v > 255 ? 255 : v; - } -} - -VideoXv::VideoXv(unsigned long handle) { - buffer = (uint16*)malloc(1024 * 1024 * sizeof(uint16)); - window = handle; - display = XOpenDisplay(0); - screen = DefaultScreen(display); - gc = XCreateGC(display, window, 0, 0); - -XVisualInfo visual_info; - if(XMatchVisualInfo(display, screen, 24, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 16, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 15, TrueColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, PseudoColor, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, GrayScale, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 8, StaticGray, &visual_info)) { - } else if(XMatchVisualInfo(display, screen, 1, StaticGray, &visual_info)) { - } else { - printf("VideoXv: unable to find suitable video display.\n"); - } - - if(!XShmQueryExtension(display)) { printf("VideoXv: XShm extension not found.\n"); } - - xv_port = -1; -XvAdaptorInfo *adaptor_info; -unsigned int adaptor_count; - XvQueryAdaptors(display, DefaultRootWindow(display), &adaptor_count, &adaptor_info); - for(uint i = 0; i < adaptor_count; i++) { - //find adaptor that supports both input (memory->drawable) and image (drawable->screen) masks - if(adaptor_info[i].type & XvInputMask && adaptor_info[i].type & XvImageMask) { - xv_port = adaptor_info[i].base_id; - break; - } - } - XvFreeAdaptorInfo(adaptor_info); - if(xv_port == -1) { printf("VideoXv: failed to find valid XvPort.\n"); } - -//set colorkey to auto paint, so that Xv video output is always visible -const Atom atom = XInternAtom(display, "XV_AUTOPAINT_COLORKEY", true); - if(atom != None) { XvSetPortAttribute(display, xv_port, atom, 1); } - -//0x00000003 = 32-bit X8R8G8B8 [xRGB] (few drivers support this mode) -//0x32595559 = 16-bit Y8U8,Y8V8 [YUY2] (most drivers support this mode) - xvimage = XvShmCreateImage(display, xv_port, 0x32595559, 0, 1024, 1024, &shminfo); - if(!xvimage) { printf("VideoXv: XShmCreateImage failed.\n"); } - shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size, IPC_CREAT | 0777); - shminfo.shmaddr = xvimage->data = (char*)shmat(shminfo.shmid, 0, 0); - shminfo.readOnly = false; - if(!XShmAttach(display, &shminfo)) { printf("VideoXv: XShmAttach failed.\n"); } - - init_yuv_tables(); - clear_video(); -} - -VideoXv::~VideoXv() { - XShmDetach(display, &shminfo); - safe_free(ytable); - safe_free(utable); - safe_free(vtable); -} diff --git a/src/ui/video/xv.h b/src/ui/video/xv.h deleted file mode 100644 index 168dffbc..00000000 --- a/src/ui/video/xv.h +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -extern "C" XvImage* XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*); - -class VideoXv : public Video { -private: -unsigned long window; -uint16 *buffer; -XvImage *xvimage; -GC gc; -Display *display; -int screen, xv_port; -XShmSegmentInfo shminfo; - -uint8 *ytable, *utable, *vtable; - -public: - bool lock(uint16 *&data, uint &pitch); - void unlock(); - - uint screen_width() { return gdk_screen_width(); } - uint screen_height() { return gdk_screen_height(); } - - void clear_video(); - void refresh(uint width, uint height); - void init(); - void term(); - - VideoXv(unsigned long handle); - ~VideoXv(); - -protected: - void init_yuv_tables(); -};