Update to bsnes v027 release.

This version replaces libui with miu -- a new GUI wrapper library, and cleans up large portions of the source code.
Unfortunately, the GUI rewrite took far, far longer than I ever imagined. As a result, no work has gone into the core emulation for this version. But with the GUI rewrite out of the way, that should change in the near future. And thanks to the new UI library, I can now begin work on adding a cross-platform debugger to bsnes, at long last.
Changelog:
    - Major source code cleanup (lib/, ui/miu/, ui/vai/)
    - Cheat code editor was broken in v0.026, this is now fixed
    - Cheat code file format simplified for human readability
    - Makefile install target improvements [belegdol]
    - libui replaced with miu GUI library
    - Custom video / audio / input drivers replaced with vai HW library
    - ppc and ppc64 libco targets added [Vas Crabb]
    - x86 and x86-64 libco targets now work on OS X [Lucas Newman]
This commit is contained in:
byuu 2007-12-22 18:26:54 +00:00
parent 9da42c18c3
commit 4c43e85141
242 changed files with 10332 additions and 8557 deletions
license.txtreadme.txt
src
Makefilebase.h
cart
cc.batcc.sh
cheat
clean.batclean.sh
config
configureinterface.h
lib

View File

@ -1,4 +1,4 @@
bsnes (TM) Open Source Reference License
bsnes (TM) Reference License
Copyright (C) 2004 - 2007 byuu
All rights reserved

View File

@ -1,5 +1,5 @@
bsnes
Version 0.026
Version 0.027
Author: byuu
--------

View File

@ -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 ""

View File

@ -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"

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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, "");
}

View File

@ -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

View File

@ -1,2 +1 @@
#!/bin/sh
make PLATFORM=x-gcc-lui clean
make PLATFORM=x-gcc-x86 clean

View File

@ -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;

5
src/configure vendored
View File

@ -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

View File

@ -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

87
src/lib/barray.h Normal file
View File

@ -0,0 +1,87 @@
/*
barray : version 0.10 ~byuu (2007-11-29)
license: public domain
*/
#ifndef BARRAY_H
#define BARRAY_H
template<typename T> 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

View File

@ -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 <assert.h>
#include <limits.h>
@ -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<typename T>
struct base_from_member {
T value;
base_from_member(T value_) : value(value_) {}
};
/*****
* template functions
*****/
template<typename T> inline void safe_free(T &handle) {
@ -324,4 +344,4 @@ uint32 crc32 = ~0;
return ~crc32;
}
#endif
#endif //ifndef BBASE_H

View File

@ -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<Setting*> list;
uint list_count;
class Config {
public:
array<Setting*> 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<typename T> bool operator<=(T x) { return (T(data) <= x); }
template<typename T> 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

View File

@ -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<typename T> class function;
#define PL
#define CL
#include "libfunction.h"
#include "bfunction.h"
//parameters = 1
@ -28,7 +28,7 @@ template<typename T> class function;
#define PL P1 p1
#define CL p1
#include "libfunction.h"
#include "bfunction.h"
//parameters = 2
@ -37,7 +37,7 @@ template<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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

View File

@ -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

95
src/lib/bstring.cpp Normal file
View File

@ -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);
}

99
src/lib/bstring.h Normal file
View File

@ -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<string> 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<typename T> class linear_vector {
protected:
@ -204,4 +205,4 @@ public:
}
};
#endif
#endif //ifndef BVECTOR_H

View File

@ -1,86 +0,0 @@
/*
libarray : version 0.09 ~byuu (2007-03-06)
*/
#ifndef LIBARRAY_H
#define LIBARRAY_H
template<typename T> 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

37
src/lib/libco.h Normal file
View File

@ -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

478
src/lib/libco/libco.ppc.s Normal file
View File

@ -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

513
src/lib/libco/libco.ppc64.s Normal file
View File

@ -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

View File

@ -0,0 +1,80 @@
/*
libco.ucontext (2007-09-08)
author: byuu
license: public domain
*/
#include <stdlib.h>
#include <ucontext.h>
#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;
}

View File

@ -0,0 +1,66 @@
/*
libco.win (2007-09-08)
author: byuu
license: public domain
*/
#define WINVER 0x0400
#define _WIN32_WINNT 0x0400
#include <windows.h>
#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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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<string> 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

View File

@ -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)); }

View File

@ -1,5 +0,0 @@
string strfmt(const char *fmt, int num) {
string temp;
sprintf(temp, fmt, num);
return temp;
}

View File

@ -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; }

View File

@ -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);
}
*/

View File

@ -1,283 +0,0 @@
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
#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;
}
};

View File

@ -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 <gtk/gtk.h>
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

View File

@ -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));
}
};

View File

@ -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<Control*> 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<GtkTreeViewColumn*> 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;
};

View File

@ -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);
}
};

View File

@ -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;
}
};

View File

@ -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 <windows.h>
#include <commctrl.h>
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*> control;
uint control_index;
array<MenuRadioItem*> 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

View File

@ -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);
}
};

View File

@ -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<Control*> 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;
};

View File

@ -1,290 +0,0 @@
namespace libui {
long __stdcall libui_wndproc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam) {
Window *window = reinterpret_cast<Window*>(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;
}
};

253
src/lib/miu.cpp Normal file
View File

@ -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<pWindow&>(*new pWindow(*this)),
Widget(base_from_member<pWindow&>::value),
p(base_from_member<pWindow&>::value) { type = WindowType; }
Window::Window(pWindow &p_) :
base_from_member<pWindow&>(p_),
Widget(base_from_member<pWindow&>::value),
p(base_from_member<pWindow&>::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<pMenuControl&>(*new pMenuControl(*this)),
Widget(base_from_member<pMenuControl&>::value),
p(base_from_member<pMenuControl&>::value) { type = MenuControlType; }
MenuControl::MenuControl(pMenuControl &p_) :
base_from_member<pMenuControl&>(p_),
Widget(base_from_member<pMenuControl&>::value),
p(base_from_member<pMenuControl&>::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<pMenuGroup&>(*new pMenuGroup(*this)),
MenuControl(base_from_member<pMenuGroup&>::value),
p(base_from_member<pMenuGroup&>::value) { type = MenuGroupType; }
/* Widget -> MenuControl -> MenuItem */
MenuItem& MenuItem::create(const char *text) { p.create(text); return *this; }
MenuItem::MenuItem() :
base_from_member<pMenuItem&>(*new pMenuItem(*this)),
MenuControl(base_from_member<pMenuItem&>::value),
p(base_from_member<pMenuItem&>::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<pMenuCheckItem&>(*new pMenuCheckItem(*this)),
MenuControl(base_from_member<pMenuCheckItem&>::value),
p(base_from_member<pMenuCheckItem&>::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<pMenuRadioItem&>(*new pMenuRadioItem(*this)),
MenuControl(base_from_member<pMenuRadioItem&>::value),
p(base_from_member<pMenuRadioItem&>::value) { type = MenuRadioItemType; }
/* Widget -> MenuControl -> MenuSeparator */
MenuSeparator& MenuSeparator::create() { p.create(); return *this; }
MenuSeparator::MenuSeparator() :
base_from_member<pMenuSeparator&>(*new pMenuSeparator(*this)),
MenuControl(base_from_member<pMenuSeparator&>::value),
p(base_from_member<pMenuSeparator&>::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<pFormControl&>(*new pFormControl(*this)),
Widget(base_from_member<pFormControl&>::value),
p(base_from_member<pFormControl&>::value) { type = FormControlType; }
FormControl::FormControl(pFormControl &p_) :
base_from_member<pFormControl&>(p_),
Widget(base_from_member<pFormControl&>::value),
p(base_from_member<pFormControl&>::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<pFrame&>(*new pFrame(*this)),
FormControl(base_from_member<pFrame&>::value),
p(base_from_member<pFrame&>::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<pCanvas&>(*new pCanvas(*this)),
FormControl(base_from_member<pCanvas&>::value),
p(base_from_member<pCanvas&>::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<pLabel&>(*new pLabel(*this)),
FormControl(base_from_member<pLabel&>::value),
p(base_from_member<pLabel&>::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<pButton&>(*new pButton(*this)),
FormControl(base_from_member<pButton&>::value),
p(base_from_member<pButton&>::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<pCheckbox&>(*new pCheckbox(*this)),
FormControl(base_from_member<pCheckbox&>::value),
p(base_from_member<pCheckbox&>::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<pRadiobox&>(*new pRadiobox(*this)),
FormControl(base_from_member<pRadiobox&>::value),
p(base_from_member<pRadiobox&>::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<pEditbox&>(*new pEditbox(*this)),
FormControl(base_from_member<pEditbox&>::value),
p(base_from_member<pEditbox&>::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<pListbox&>(*new pListbox(*this)),
FormControl(base_from_member<pListbox&>::value),
p(base_from_member<pListbox&>::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<pCombobox&>(*new pCombobox(*this)),
FormControl(base_from_member<pCombobox&>::value),
p(base_from_member<pCombobox&>::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<pProgressbar&>(*new pProgressbar(*this)),
FormControl(base_from_member<pProgressbar&>::value),
p(base_from_member<pProgressbar&>::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<pSlider&>(*new pSlider(*this)),
FormControl(base_from_member<pSlider&>::value),
p(base_from_member<pSlider&>::value) { type = SliderType; }
} //namespace ns_miu

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

118
src/lib/miu.gtk/miu.gtk.cpp Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

58
src/lib/miu.gtk/miu.gtk.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MIU_GTK_H
#define MIU_GTK_H
#include "../miu.h"
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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<GtkTreeViewColumn*> column_list;
GtkTreeIter iter;
int listbox_selection;
GtkWidget* gtk_handle();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -0,0 +1,11 @@
class pMenuItem : public pMenuControl {
public:
void create(const char *text = "");
MenuItem &self;
pMenuItem(MenuItem&);
/* internal */
GtkWidget *item;
GtkWidget* gtk_handle();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -0,0 +1,11 @@
class pMenuSeparator : public pMenuControl {
public:
MenuSeparator &self;
void create();
pMenuSeparator(MenuSeparator&);
/* internal */
GtkWidget *item;
GtkWidget* gtk_handle();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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();
};

506
src/lib/miu.h Normal file
View File

@ -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<MenuRadioItem*> MenuRadioItemGroup;
typedef array<Radiobox*> 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<pWindow&>, 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<uintptr_t (Event)> on_close;
function<uintptr_t (Event)> on_block;
function<uintptr_t (Event)> on_keydown;
function<uintptr_t (Event)> on_keyup;
Window();
protected:
Window(pWindow&);
private:
pFriends;
pWindow &p;
};
class MenuControl : public base_from_member<pMenuControl&>, 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<pMenuGroup&>, public MenuControl {
public:
MenuGroup& create(const char *text);
void attach(MenuControl &menucontrol);
MenuGroup();
private:
pFriends;
pMenuGroup &p;
};
class MenuItem : public base_from_member<pMenuItem&>, public MenuControl {
public:
MenuItem& create(const char *text);
MenuItem();
function<uintptr_t (Event)> on_tick;
private:
pFriends;
pMenuItem &p;
};
class MenuCheckItem : public base_from_member<pMenuCheckItem&>, public MenuControl {
public:
MenuCheckItem& create(const char *text);
void check(bool = true);
void uncheck();
bool checked();
MenuCheckItem();
function<uintptr_t (Event)> on_tick;
private:
pFriends;
pMenuCheckItem &p;
};
class MenuRadioItem : public base_from_member<pMenuRadioItem&>, public MenuControl {
public:
MenuRadioItem& create(MenuRadioItemGroup &group, const char *text);
void check();
bool checked();
MenuRadioItem();
function<uintptr_t (Event)> on_tick;
private:
pFriends;
pMenuRadioItem &p;
};
class MenuSeparator : public base_from_member<pMenuSeparator&>, public MenuControl {
public:
MenuSeparator& create();
MenuSeparator();
private:
pFriends;
pMenuSeparator &p;
};
class FormControl : private base_from_member<pFormControl&>, 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<pFrame&>, 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<pCanvas&>, 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<pLabel&>, 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<pButton&>, public FormControl {
public:
void create(uint style, uint width, uint height, const char *text = "");
void set_text(const char *text = "");
function<uintptr_t (Event)> on_tick;
Button();
private:
pFriends;
pButton &p;
};
class Checkbox : private base_from_member<pCheckbox&>, 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<uintptr_t (Event)> on_tick;
Checkbox();
private:
pFriends;
pCheckbox &p;
};
class Radiobox : private base_from_member<pRadiobox&>, 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<uintptr_t (Event)> on_tick;
Radiobox();
private:
pFriends;
pRadiobox &p;
};
class Editbox : private base_from_member<pEditbox&>, 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<pListbox&>, 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<uintptr_t (Event)> on_change;
function<uintptr_t (Event)> on_activate;
Listbox();
private:
pFriends;
pListbox &p;
};
class Combobox : private base_from_member<pCombobox&>, 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<uintptr_t (Event)> on_change;
Combobox();
private:
pFriends;
pCombobox &p;
};
class Progressbar : private base_from_member<pProgressbar&>, 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<pSlider&>, 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<uintptr_t (Event)> on_change;
Slider();
private:
pFriends;
pSlider &p;
};
#undef pFriends
} //namespace ns_miu
#endif //ifndef MIU_H

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