Version 1.9: See Changelog for details

List is too long...

Signed-off-by: Michel Pollet <buserror@gmail.com>
This commit is contained in:
Michel Pollet 2024-05-13 16:31:58 +01:00
parent d60bc9bee9
commit 11cdb8b209
111 changed files with 8441 additions and 2610 deletions

View File

@ -3,10 +3,40 @@
</p> </p>
# MII Version Changelog # MII Version Changelog
## 1.9
#### Video
* Video driver now only draw when the apple II video *really* changes. It keeps track of touched lines across the screen, and only updates when needed. This saves a considerable amount of CPU time.
* Redid the monochrome video rendering, low-res, double low-res and dhires
now have luminance based on the color, and not just a fixed value. This
makes the monochrome rendering a lot more accurate (and attractive).
* Added 2 other RGB color palettes, an alternate NTSC and the Mega2 (apple IIgs) one.
| NTSC Palette | Mega2 Palette |
|--------------------------------------|--------------------------------------|
| ![NTSC](docs/screen/v19ntsc.png) | ![Mega2](docs/screen/v19mega2.png) |
|--------------------------------------|--------------------------------------|
* Added AVX/SSE/generic vectorial versions of some code paths, for speed.
* Added some more 'artifacts' color frindges to the HIRES rendering as well.
<p align="center">
<img src="docs/screen/v19artifacts.png" alt="Artifacts">
</p>
#### Other bits
* Fixed a bug in the floppy stepper motor code that was preventing some floppies (demos, but also some prodos disks) from booting.
* Reworked the SmartPort code a bit, should be more compatible with some prodos programs. Also fixed a crash in block reading code.
* Joystick can now be plugged after starting the emulator, it will be detected.
* Changed the way the 65c02 core emulator is interfaced to the rest of the emulation. It was made to be 'pretty' but was also quite suboptimal, so I made it a bit less pretty, but it is now easily twice as fast as before.
* While before the emulator was using perhaps 25% of a core on my current machine, now it uses about 9% CPU for the same task.
* The 'floppy' and 'hard drive' file selector dialog now has a small popup menu with the last few directory used, so you can quickly switch between them.
* Added support for 'pasting' text in the emulator. Paste your pet BASIC programs, it works now. (Control-SHIFT-V -- not in a menu yet).
* There is a non-functional Mockingboard driver in the code, it's not hooked up to the UI, it still needs work (mostly make the audio output work).
* UI library got a massive overhaul, since it was released separately it had to get a serious cleanup. Some files are duplicated unfortunately, but that is needed to be able to use it as a standalone library.
## 1.8 ## 1.8
* Changed the floppy disk view. *It now rotates*, and the heat map is now a * Changed the floppy disk view. *It now rotates*, and the heat map is now a
'trail' of the head, showing where it's been. It's a bit more useful, and 'trail' of the head, showing where it's been. It looks awesome!
looks cooler.
<div align="center"> <div align="center">
<img src="docs/screen/v18new_display.gif" alt="New Floppy display"> <img src="docs/screen/v18new_display.gif" alt="New Floppy display">

View File

@ -1,5 +1,11 @@
# Makefile
#
# Copyright (C) 2024 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
# GCC is default -- simply because it's faster! # GCC is default -- simply because it's faster to compile!
# From cursory tests, clang doesn't really add anything in terms of perfs.
CC = gcc CC = gcc
SHELL = /bin/bash SHELL = /bin/bash
# This is where (g)make looks for the source files for implicit rules # This is where (g)make looks for the source files for implicit rules
@ -9,16 +15,22 @@ VPATH += ui_gl
CPPFLAGS += -Isrc -Isrc/format -Isrc/roms -Isrc/drivers CPPFLAGS += -Isrc -Isrc/format -Isrc/roms -Isrc/drivers
CPPFLAGS += -Icontrib CPPFLAGS += -Icontrib
CPPFLAGS += -Ilibmish/src CPPFLAGS += -Ilibmish/src
CPPFLAGS += -Ilibmui/mui CPPFLAGS += -Ilibmui/src
OPTIMIZE ?= -O2 -march=native OPTIMIZE ?= -O2 -march=native -ffast-math
CFLAGS += --std=gnu99 -Wall -Wextra -g CFLAGS += --std=gnu99 -Wall -Wextra -g
CFLAGS += -fno-omit-frame-pointer #CFLAGS += -fno-omit-frame-pointer
CFLAGS += $(OPTIMIZE) CFLAGS += $(OPTIMIZE)
CFLAGS += -Wno-unused-parameter -Wno-unused-function CFLAGS += -Wno-unused-parameter -Wno-unused-function
LDLIBS += -lX11 -lGL -lGLU LDLIBS += -lX11 -lGL -lGLU
LDLIBS += -lpthread -lutil -lm LDLIBS += -lpthread -lutil -lm
# better/faster linker
HAS_MOLD := $(shell which mold && echo 1)
ifeq ($(HAS_MOLD),1)
LDFLAGS += -B/usr/libexec/mold
endif
VERSION := ${shell \ VERSION := ${shell \
echo $$(git describe --tags --abbrev=0 2>/dev/null || \ echo $$(git describe --tags --abbrev=0 2>/dev/null || \
echo "(dev)") \ echo "(dev)") \
@ -50,6 +62,13 @@ ALL_OBJ := ${patsubst %, ${OBJ}/%, ${notdir ${SRC:.c=.o}}}
CPPFLAGS += ${shell pkg-config --cflags pixman-1} CPPFLAGS += ${shell pkg-config --cflags pixman-1}
LDLIBS += ${shell pkg-config --libs pixman-1} LDLIBS += ${shell pkg-config --libs pixman-1}
# this requires 64 bits ints, as it's used by xorg
# This uses tinycc, which is handy to run that sort of tools
ui_gl/mii_icon64.h : contrib/mii-icon-64.png
tcc -run libmui/utils/png2raw.c -t "unsigned long" -n mii_icon64 -o $@ $<
ui_gl/mii_mui_apple_logo.h : docs/Apple_logo_rainbow_version2_28x28.png
tcc -run libmui/utils/png2raw.c -n mii_mui_apple_logo -o $@ $<
$(BIN)/mii_emu_gl : $(ALL_OBJ) | mui mish $(BIN)/mii_emu_gl : $(ALL_OBJ) | mui mish
$(BIN)/mii_emu_gl : $(LIB)/libmish.a $(BIN)/mii_emu_gl : $(LIB)/libmish.a
$(BIN)/mii_emu_gl : $(LIB)/libmui.a $(BIN)/mii_emu_gl : $(LIB)/libmui.a
@ -63,7 +82,7 @@ $(LIB)/libmish.a : ${wildcard libmish/src/*} | $(LIB) $(OBJ) $(BIN)
LDLIBS += $(LIB)/libmui.a LDLIBS += $(LIB)/libmui.a
mui : $(LIB)/libmui.a mui : $(LIB)/libmui.a
$(LIB)/libmui.a : ${wildcard libmui/mui/*} | $(LIB) $(OBJ) $(BIN) $(LIB)/libmui.a : ${wildcard libmui/src/*} | $(LIB) $(OBJ) $(BIN)
mkdir -p $(OBJ)/libmui && \ mkdir -p $(OBJ)/libmui && \
make -j -C libmui BUILD_DIR="../" CC="$(CC)" \ make -j -C libmui BUILD_DIR="../" CC="$(CC)" \
V="$(V)" OPTIMIZE="$(OPTIMIZE)" static V="$(V)" OPTIMIZE="$(OPTIMIZE)" static
@ -81,23 +100,33 @@ clean :
# everytime a file is modified. # everytime a file is modified.
watch : watch :
while true; do \ while true; do \
clear; $(MAKE) -j all tests; \ clear; $(MAKE) -j all ; \
inotifywait -qre close_write src src/format ui_gl test \ inotifywait -qre close_write src src/format ui_gl test \
libmui libmui/mui; \ libmui libmui/src; \
done done
tests : $(BIN)/mii_test $(BIN)/mii_cpu_test $(BIN)/mii_asm tests : $(BIN)/mii_test $(BIN)/mii_cpu_test $(BIN)/mii_asm
# Just the library for mii, not any of the UI stuff # Just the library for mii, not any of the UI stuff
TEST_OBJ := ${patsubst %, ${OBJ}/%, ${notdir ${MII_SRC:.c=.o}}} TEST_OBJ := ${patsubst %, ${OBJ}/%, ${notdir ${MII_SRC:.c=.o}}}
VPATH += test
# Base test without the UI, for performance testing
$(BIN)/mii_test : $(TEST_OBJ)
$(BIN)/mii_test : $(OBJ)/mii_test.o $(OBJ)/mii_mish.o
$(OBJ)/mii_test.o : CFLAGS := -O0 -Og ${filter-out -O%, $(CFLAGS)}
$(OBJ)/mii_cpu_test.o : CFLAGS := -O0 -Og ${filter-out -O%, $(CFLAGS)} # Base test without the UI -- this re-include all C source in one big
# executable, ignoring the existing .o files, just so we can have custom flags
# for the test
$(BIN)/mii_test : test/mii_test.c ${MII_SRC}
$(BIN)/mii_test : CFLAGS = --std=gnu99 -Wall -Wextra -g -O0 -Og \
-Wno-unused-parameter -Wno-unused-function
$(BIN)/mii_test : CPPFLAGS = -DMII_TEST \
-Isrc -Isrc/format -Isrc/roms -Isrc/drivers -Icontrib \
-Ilibmish/src
$(BIN)/mii_test :
@echo " TEST" ${filter -O%, $(CPPFLAGS) $(CFLAGS)} $@
$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $^ $(LIB)/libmish.a
VPATH += test
$(BIN)/mii_cpu_test : $(OBJ)/mii_cpu_test.o $(TEST_OBJ) $(BIN)/mii_cpu_test : $(OBJ)/mii_cpu_test.o $(TEST_OBJ)
$(OBJ)/mii_cpu_test.o : CFLAGS := -O0 -Og ${filter-out -O%, $(CFLAGS)}
$(OBJ)/mii_cpu_test.o : CPPFLAGS += -DMII_TEST -DMII_65C02_DIRECT_ACCESS=0
# Assembler for the 6502 # Assembler for the 6502
$(BIN)/mii_asm : $(OBJ)/mii_asm.o $(TEST_OBJ) $(BIN)/mii_asm : $(OBJ)/mii_asm.o $(TEST_OBJ)
@ -126,7 +155,7 @@ compile_commands.json: lsp
lsp: lsp:
{ $$(which gmake) CC=gcc V=1 --always-make --dry-run all tests; \ { $$(which gmake) CC=gcc V=1 --always-make --dry-run all tests; \
$$(which gmake) CC=gcc V=1 --always-make --dry-run -C libmish ; \ $$(which gmake) CC=gcc V=1 --always-make --dry-run -C libmish ; \
$$(which gmake) CC=gcc V=1 --always-make --dry-run -C libmui ; } | \ $$(which gmake) CC=gcc V=1 --always-make --dry-run -C libmui all tests ; } | \
sh utils/clangd_gen.sh >compile_commands.json sh utils/clangd_gen.sh >compile_commands.json
-include $(O)/*.d -include $(O)/*.d
@ -142,3 +171,5 @@ avail:
mkdir -p $(DESTDIR)/bin mkdir -p $(DESTDIR)/bin
rm -f $(DESTDIR)/bin/mii_emu_gl && \ rm -f $(DESTDIR)/bin/mii_emu_gl && \
ln -sf $(realpath $(BIN)/mii_emu_gl) $(DESTDIR)/bin/mii_emu_gl ln -sf $(realpath $(BIN)/mii_emu_gl) $(DESTDIR)/bin/mii_emu_gl
-include Makefile-extras*.local

View File

@ -4,7 +4,10 @@
# MII Apple //e Emulator # MII Apple //e Emulator
Note: Changelog has moves to [CHANGELOG.md](CHANGELOG.md) *Note:* New versions and Changelog are at [CHANGELOG.md](CHANGELOG.md)
*Note2:* UI Library has moved to [libmui](https://github.com/buserror/libmui)
I know there are many out there, but none of them were ticking my fancy, so I decide to write my own. To start with it was "How hard can it be really?" then it snowballed as more and more things were fixed & added. It's been shelved for a while because well, it lacked documentation, headers, licence and stuff, so I spent some time cleaning it up for release. I know there are many out there, but none of them were ticking my fancy, so I decide to write my own. To start with it was "How hard can it be really?" then it snowballed as more and more things were fixed & added. It's been shelved for a while because well, it lacked documentation, headers, licence and stuff, so I spent some time cleaning it up for release.
@ -30,15 +33,16 @@ I wanted something:
</center> </center>
## What can it do? ## What can it do?
* 65c02 //e with 128K of ram. * 65c02 //e with 128K of ram (RAM exensible to 2MB).
* Support all known graphic modes: * Support all known graphic modes:
* Double-hires in mono and color, with automatic switch * Double-hires in mono and color, with automatic switch
* All the other modes in color/mono * All the other modes in color/mono
* Color, Green, Amber rendering * Color (NTSC/RGB), Green, Amber rendering
* Simulated 'scanlines' to make it look vintage * Simulated 'scanlines' & artifacts to make it look vintage
* Speaker audio. ALSA For playback. * Speaker audio. ALSA For playback.
* Adds a small 'attack' filter when playing back to soften the often annoying 'click' of typical audio effects from the apple II. * Adds a small 'attack' filter when playing back to soften the often annoying 'click' of typical audio effects from the apple II.
* Mouse Card -- mouse isn't captured like in some other emulators. * Mouse Card -- mouse isn't captured like in some other emulators.
* Super Serial Card -- can open a /dev/tty device, or a 'loopback' device.
* No Slot Clock * No Slot Clock
* Joystick Support * Joystick Support
* Smartport DMA 'hard drive' card * Smartport DMA 'hard drive' card
@ -66,6 +70,7 @@ I wanted something:
* For more details on development, see [Compiling](docs/Compiling.md) * For more details on development, see [Compiling](docs/Compiling.md)
* Then just type `make` and it should compile. * Then just type `make` and it should compile.
* To run it, just type `build-x86_64-linux-gnu/bin/mii_emu_gl` and it should start. * To run it, just type `build-x86_64-linux-gnu/bin/mii_emu_gl` and it should start.
* If you want to install it, I suggest 'make avail' this will install a symlink into /usr/local/bin pointing back to the source tree, so you can run it from anywhere.
## Command line options ## Command line options
If you run it with no options, and there are no config file, it will present If you run it with no options, and there are no config file, it will present
@ -158,9 +163,10 @@ There are just a few keys that are mapped for anything useful. List is not exaus
## What it could do with ## What it could do with
* The main window is 1280x720 on purpose, so it could do Full Screen. * The main window is 1280x720 on purpose, so it could do Full Screen.
* Port it to Raspbery Pi. I don't expect compiling issues, just video issues with GLes * ~~Port it to Raspbery Pi~~. This was reported to work on a raspi 5.
* Make a tool to 'flatten' overlay files back into the primary image. * Make a tool to 'flatten' overlay files back into the primary image.
* Make a UI for the debugger, instead of telnet. * Make a UI for the debugger, instead of telnet.
* A mockinbird sound card emulation [In Progress].
<div align="center"> <div align="center">
<img src="docs/screen/screen_total.png" alt="Total Replay"> <img src="docs/screen/screen_total.png" alt="Total Replay">

View File

@ -1,584 +0,0 @@
/* this file is auto-generated by icon-convert-tcc.c */
#define MII_ICON64_SIZE 4098
extern const unsigned long mii_icon64[MII_ICON64_SIZE];
#ifdef MII_ICON64_DEFINE
const unsigned long mii_icon64[MII_ICON64_SIZE] = {
64,64,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000000,
0x01000000, 0x039e9ea1, 0x04bebfc1, 0x04c9cacd, 0x04c9cacd, 0x05ccced0, 0x05ccced0, 0x05cfcfd1,
0x05d0d1d3, 0x06d2d3d6, 0x06d3d4d6, 0x06d2d3d6, 0x06d4d5d7, 0x0778a88e, 0x07499b67, 0x07499b67,
0x07499b67, 0x07499b67, 0x07499b67, 0x074a9b67, 0x06499b65, 0x064a9c65, 0x064a9c64, 0x064a9c63,
0x064a9b61, 0x064a9c5f, 0x064b9d5e, 0x054b9c5d, 0x054b9c5c, 0x054c9c55, 0x044d9a48, 0x01000000,
0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x2ff1f3f7, 0x7bf4f6fa, 0xaff4f7fb, 0xd0f4f7fb, 0xf2f5f7fb,
0xfdf5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xffc2ddc8, 0xff5fba4f, 0xff60ba4e,
0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e,
0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4e, 0xff60ba4f, 0xfe5fba52,
0xf65fba53, 0xd35fba52, 0xb15eb955, 0x7c5db85c, 0x315ab663, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x51f3f5f9, 0xcef5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff1f5f7, 0xff70be68, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff60bb4b, 0xcd5eb954, 0x515bb75f, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x13edeff3,
0xb4f4f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f8fc, 0xffbad9be, 0xff61bb47,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff60bb49, 0xb25db959,
0x1358b361, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20eef1f4, 0xdff5f7fb,
0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc,
0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc,
0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xfff5f8fc, 0xfff5f7fb, 0xfff5f8fc, 0xffecf3f2, 0xff61ba52,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xdd5eb953, 0x1f59b465, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14eaecf0, 0xdff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f8fb, 0xffa2cfa3,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xdd5eb954, 0x1256b062, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000000, 0xb4f4f6fa, 0xfff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb,
0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xfff5f7fb, 0xffd6e6dc,
0xff60bb48, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xb05db858, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x4feff1f5, 0xfff5f7fa, 0xfff5f7fb, 0xfff4f7fa,
0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fb, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fb, 0xfff5f7fa, 0xfff5f7fb,
0xfff4f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fb, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fb, 0xfff5f7fa,
0xfff5f7fb, 0xfff4f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fb, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa,
0xff75bf6e, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff60bb4a, 0x4959b460, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x01000000, 0xccf3f5f9, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa,
0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f6fa, 0xfff5f7fa, 0xfff5f7fa,
0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f6fa, 0xfff5f7fa,
0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa, 0xfff5f7fa,
0xffb3d6b5, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46, 0xff61bb46,
0xff61bb46, 0xff61bb46, 0xff61bb46, 0xc85db854, 0x01000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x2ce8e9ed, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff4f6fa,
0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa,
0xfff4f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa,
0xfff5f6fa, 0xfff4f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa, 0xfff5f6fa,
0xffdbe9e1, 0xff60ba49, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47,
0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47,
0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff61bb47,
0xff61bb47, 0xff61bb47, 0xff61bb47, 0xff60ba4c, 0x2854ae62, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x76f0f1f4, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xffc8b863, 0xffcbb440, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540,
0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540,
0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540, 0xffccb540,
0xffccb540, 0xffccb540, 0xffccb540, 0xffccb541, 0x70cdaf48, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x01000000, 0xa7f1f2f5, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9, 0xfff5f6f9,
0xfff5f6f9, 0xfffad0a0, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xa2f9b325, 0x01000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x02000000, 0xcef2f3f6, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f8,
0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9,
0xfff4f5f8, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9,
0xfff4f5f9, 0xfff4f5f8, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9, 0xfff4f5f9,
0xfff4f5f9, 0xfff8e3d0, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xcafbb425, 0x02000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x04000000, 0xdef2f3f6, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff6f2f0, 0xfffcb625, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xd7fab425, 0x03000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x05000000, 0xeff2f3f6, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff5f5f8, 0xfffbc376, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xe6fbb526, 0x05000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x07000000, 0xf8f3f4f7, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8, 0xfff4f5f8,
0xfff4f5f8, 0xfff4f5f8, 0xfff9d4ad, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xf3fcb525, 0x06000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x07000000, 0xfdf3f5f7, 0xfff3f4f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f4f7,
0xfff4f5f8, 0xfff3f5f8, 0xfff3f4f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f4f7, 0xfff3f5f8, 0xfff3f5f8,
0xfff3f4f7, 0xfff4f5f8, 0xfff3f5f8, 0xfff3f4f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f4f7, 0xfff3f5f8,
0xfff3f5f8, 0xfff3f4f7, 0xfff4f5f8, 0xfff3f5f8, 0xfff3f4f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f4f7,
0xfff3f5f8, 0xfff3f5f8, 0xfff7e2cf, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb726, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xf9fcb526, 0x06000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f7,
0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8,
0xfff3f5f7, 0xfff3f5f7, 0xffe7e8eb, 0xff88898a, 0xff939496, 0xffeeeff2, 0xfff3f5f8, 0xfff3f5f8,
0xfff3f5f8, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8, 0xfff3f5f8,
0xfff3f5f8, 0xfff3f5f8, 0xfff5efea, 0xfffcb726, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xffc58919, 0xff82540b, 0xffd7981d, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfcfdb626, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff3f5f8, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7,
0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7,
0xfff3f5f7, 0xfff3f5f7, 0xffc9cbcd, 0xff616162, 0xff616162, 0xffd9dbdd, 0xfff3f5f7, 0xfff3f5f7,
0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7, 0xfff3f5f7,
0xfff3f5f7, 0xfff3f5f7, 0xfff4f6f8, 0xfffbbb53, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb726, 0xff784a0b, 0xff653b08, 0xff9d6912, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827,
0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb827, 0xfffdb626, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7,
0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7,
0xfff3f4f7, 0xfff3f4f7, 0xffc9cbcd, 0xff616162, 0xff616162, 0xffd7d9db, 0xfff3f4f7, 0xfff3f4f7,
0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7,
0xfff3f4f7, 0xfff3f4f7, 0xfff3f4f7, 0xfff9c88d, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626,
0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb425, 0xfe76460f, 0xfe65370d, 0xfe9a6414, 0xfffdb525,
0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626,
0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb626, 0xfffdb424, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff3f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff3f4f7, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff3f4f7, 0xffc9cacc, 0xff606162, 0xff606162, 0xffd7d9db, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xfff3f4f7, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2bcb3, 0xfff86c3f, 0xfffd6e41, 0xfffe6e42, 0xfffe6e42,
0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfe723618, 0xfe653113, 0xfe974425, 0xfffe6e42,
0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42,
0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e42, 0xfffe6e43, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xffc9cacc, 0xff606162, 0xff606162, 0xffd7d8da, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6,
0xfff2f4f6, 0xfff2f4f6, 0xfff2f4f6, 0xfff2cdcb, 0xfff56240, 0xfffd6542, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6744, 0xff72311c, 0xff652c17, 0xff973f27, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6,
0xfff2f4f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f4f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6,
0xfff2f3f6, 0xfff2f4f6, 0xffd1d2d4, 0xff606162, 0xff606162, 0xffe1e3e5, 0xfff2f3f6, 0xfff2f3f6,
0xfff2f3f6, 0xfff2f3f6, 0xfff2f4f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff2f4f6, 0xfff2f3f6, 0xfff2f3f6,
0xfff2f3f6, 0xfff2f3f6, 0xfff2f3f6, 0xfff3e0e0, 0xfff36140, 0xfffc6542, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xff8d3c27, 0xff65291a, 0xffac4931, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5,
0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5,
0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xffd2d3d5, 0xffd8d9db, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5,
0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5,
0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff4eff0, 0xfff0603f, 0xfffb6442, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfff16646, 0xffd35d42, 0xfff86847, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5,
0xfff2f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5,
0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5,
0xfff2f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff2f3f5, 0xfff1f3f5,
0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff3f5f6, 0xffef6b51, 0xfffa6441, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5,
0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5,
0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5,
0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5,
0xfff1f3f5, 0xfff2f3f5, 0xfff1f3f5, 0xfff2f3f5, 0xfff08f82, 0xfff96441, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5,
0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5,
0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f4, 0xfff2f3f5, 0xffef9f95, 0xfff86341, 0xfffd6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5,
0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff1f2f5, 0xfff0b1ab, 0xfff66340, 0xfffd6542, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xffefbab5, 0xfff56240, 0xfffd6542, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643,
0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6643, 0xfffe6745, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f2f4, 0xfff1f1f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f1f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f1f4, 0xfff1f2f4, 0xfff1f2f4,
0xfff1f1f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f1f4, 0xfff1f2f4,
0xfff1f2f4, 0xfff1f1f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f2f4, 0xfff1f1f4,
0xfff1f2f4, 0xfff1f2f4, 0xfff1f1f4, 0xfff1f2f4, 0xfeedc8c6, 0xfdeb5a41, 0xfdf35e43, 0xfdf55f44,
0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44,
0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44,
0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfdf55f44, 0xfef56046, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4,
0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f3,
0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4,
0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f4, 0xfff1f1f3,
0xfff1f1f4, 0xfff1f1f3, 0xfff1f1f4, 0xfff1f1f4, 0xffe0c5c8, 0xffc6313f, 0xffce3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03644, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xffe5cfd1, 0xffc5313e, 0xffcd3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03644, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff0f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff0f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff0f1f3,
0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff0f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff0f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xfff0f1f3, 0xfff1f1f3, 0xfff1f1f3,
0xfff1f1f3, 0xfff0f1f3, 0xfff1f1f3, 0xfff1f1f3, 0xffe5d0d2, 0xffc4313e, 0xffcd3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03644, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff1f2f3, 0xffd09da0, 0xffc4313e, 0xffcd3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xfed03644, 0x08000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff1f2f3, 0xffc9a8aa, 0xffbb898c, 0xffb98587, 0xffb88386,
0xffb88386, 0xffb88285, 0xffb87e81, 0xffb6696e, 0xffb62d39, 0xffc5313e, 0xffcd3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xfcd03644, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2,
0xfff0f1f2, 0xfff0f1f2, 0xfff0f1f2, 0xfff2f1f2, 0xffa42934, 0xffa72935, 0xffa82a35, 0xffa82a35,
0xffa82a35, 0xffa82a35, 0xffaa2a36, 0xffb12c38, 0xffbc2f3b, 0xffc8313f, 0xffce3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xfbd03644, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfff0f0f1, 0xffeff0f1, 0xffeff0f1, 0xfff0f0f1, 0xffeff0f1,
0xfff0f0f1, 0xffeff0f1, 0xfff0f0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xfff0f0f1,
0xffeff0f1, 0xfff0f0f1, 0xffeff0f1, 0xfff0f0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xfff0f0f1, 0xffeff0f1, 0xfff0f0f1, 0xfff2f2f3, 0xffae2b37, 0xffb52d39, 0xffb82e3a, 0xffb82e3a,
0xffb82e3a, 0xffb82e3a, 0xffba2e3b, 0xffbe2f3c, 0xffc5313e, 0xffcb3240, 0xffcf3341, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xfad03644, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffe4e5e6,
0xffedeeef, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xfff2f3f4, 0xffb92f3b, 0xffc3303d, 0xffc6313f, 0xffc7313f,
0xffc7313f, 0xffc7313f, 0xffc8313f, 0xffca323f, 0xffcc3340, 0xffce3341, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffcf3442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442,
0xffd03442, 0xffd03442, 0xffd03442, 0xffd03442, 0xf8d03643, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffdadbdc, 0xff626363,
0xff919292, 0xffebeced, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xfff2f2f4, 0xffbe3241, 0xffc83245, 0xffcc3347, 0xffcc3347,
0xffcc3347, 0xffcc3347, 0xffcd3348, 0xffcd3448, 0xffcd3448, 0xffce3448, 0xffce3448, 0xffce3448,
0xffce3448, 0xffce3448, 0xffce3448, 0xffce3448, 0xffce3448, 0xffce3448, 0xffce3448, 0xffce3446,
0xfe892439, 0xfe461832, 0xffb83145, 0xffce3549, 0xffce3549, 0xffce3549, 0xffce3549, 0xffce3549,
0xffce3549, 0xffce3549, 0xffce3549, 0xffce3549, 0xf7cd384c, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffefeff1,
0xffeff0f1, 0xffeff0f1, 0xffeff0f1, 0xffefeff1, 0xffeff0f1, 0xffeff0f1, 0xffe3e3e5, 0xff6a6b6b,
0xff5f5f60, 0xff949495, 0xffeaebec, 0xffeff0f1, 0xffefeff1, 0xffeff0f1, 0xffeff0f1, 0xffeff0f1,
0xffeff0f1, 0xffefeff1, 0xffeff0f1, 0xfff2f2f3, 0xff933e9a, 0xff953d98, 0xff953d98, 0xff953d98,
0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98,
0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff953d98, 0xff943d99, 0xfe672d75,
0xfe36193d, 0xfe391c41, 0xff823f8f, 0xff953f99, 0xff953f99, 0xff953f99, 0xff953f99, 0xff953f99,
0xff953f99, 0xff953f99, 0xff953f99, 0xff953f99, 0xfd92449d, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xffefeff1, 0xffeeeff0, 0xffefeff1, 0xffefeff1, 0xffefeff1,
0xffefeff1, 0xffefeff1, 0xffefeff1, 0xffefeff1, 0xffefeff1, 0xffeeeff0, 0xffefeff1, 0xffd6d6d7,
0xff686969, 0xff5f5f60, 0xff878788, 0xffe2e2e4, 0xffefeff1, 0xffefeff1, 0xffeeeff0, 0xffefeff1,
0xffefeff1, 0xffefeff1, 0xffefeff1, 0xfff2f2f3, 0xff953d98, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff933c96, 0xff632b70, 0xfe2e1b49,
0xfe321e4c, 0xff783a85, 0xff963e98, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xfe944099, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0,
0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0,
0xffd6d7d8, 0xff6d6e6e, 0xff5f5f60, 0xff6c6c6d, 0xffc4c4c5, 0xffeeeef0, 0xffeeeff0, 0xffeeeff0,
0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xfff0eff1, 0xff953d98, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff86388e, 0xff4d2564, 0xff281c4f, 0xff332055,
0xff7a3b89, 0xff963e98, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xfe944099, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x08000000, 0xfdeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0,
0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeeeff0,
0xffeeeff0, 0xffe0e1e2, 0xff868787, 0xff5f5f60, 0xff5f5f60, 0xff888889, 0xffcdcdce, 0xffedeeef,
0xffeeeff0, 0xffeeeff0, 0xffeeeff0, 0xffeae8ed, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff8a3991, 0xff632c74, 0xff2e1d54, 0xff261c51, 0xff442863, 0xff843e90,
0xff963e97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xfd953f99, 0x07000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x07000000, 0xf9edeeef, 0xffeeeeef, 0xffeeeef0, 0xffeeeef0, 0xffeeeeef,
0xffeeeef0, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeef0, 0xffeeeef0,
0xffeeeeef, 0xffeeeef0, 0xffebeced, 0xffb7b7b8, 0xff666667, 0xff5f5f5f, 0xff5f5f5f, 0xff7a7a7a,
0xffb4b5b6, 0xffd6d6d8, 0xffededef, 0xffe2dde5, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff953d98, 0xff8e3b93,
0xff7a3485, 0xff58296d, 0xff2e1d55, 0xff261c52, 0xff302057, 0xff67357c, 0xff904097, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xfb93429a, 0x06000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x07000000, 0xf0ececed, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef,
0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef,
0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffe2e2e3, 0xffababab, 0xff676767, 0xff5f5f5f,
0xff5e5e5f, 0xff5a5a5e, 0xff5b5a64, 0xff7f7888, 0xff71377d, 0xff7a3584, 0xff7f3688, 0xff82368a,
0xff85378b, 0xff83378a, 0xff803688, 0xff7a3485, 0xff70307d, 0xff612b73, 0xff492464, 0xff2f1e56,
0xff261c52, 0xff261c52, 0xff332159, 0xff623378, 0xff893f93, 0xff963e98, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xe7934199, 0x06000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x06000000, 0xdfebebec, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef,
0xffeeeeef, 0xffeeeeef, 0xffedeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffeeeeef,
0xffeeeeef, 0xffeeeeef, 0xffeeeeef, 0xffedeeef, 0xffeeeeef, 0xffeeeeef, 0xffe7e7e7, 0xffc0c0c1,
0xff939394, 0xff5b5b5f, 0xff514f5b, 0xff444057, 0xff362f54, 0xff2c2352, 0xff281e51, 0xff271c52,
0xff281c53, 0xff271c53, 0xff271c52, 0xff261c52, 0xff261c52, 0xff261c52, 0xff281d53, 0xff35225a,
0xff552e6f, 0xff753985, 0xff8e4096, 0xff963e98, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xdb924098, 0x05000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x04000000, 0xd0eaeaeb, 0xffeeeeee, 0xffededee, 0xffeeeeee, 0xffededee,
0xffeeeeee, 0xffededee, 0xffeeeeee, 0xffededee, 0xffededee, 0xffeeeeee, 0xffededee, 0xffeeeeee,
0xffededee, 0xffeeeeee, 0xffededee, 0xffeeeeee, 0xffededee, 0xffededee, 0xffeeeeee, 0xffededee,
0xffeeeeee, 0xffe8e8e9, 0xffd1d1d3, 0xffa196ad, 0xff6f3d80, 0xff623577, 0xff583071, 0xff532f70,
0xff4f2b6b, 0xff532e6f, 0xff572f71, 0xff5e3175, 0xff6a357e, 0xff773986, 0xff853d8f, 0xff914098,
0xff953e98, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97,
0xff963d97, 0xff963d97, 0xff963d97, 0xff963d97, 0xcf914199, 0x04000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x03000000, 0xace7e7e8, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee,
0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee,
0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee,
0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffbfa8c6, 0xff953f98, 0xff953f98, 0xff954098, 0xff954099,
0xff954099, 0xff954099, 0xff954098, 0xff954098, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98,
0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98,
0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98,
0xff953f98, 0xff953f98, 0xff953f98, 0xff953f98, 0xa78e4398, 0x02000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x01000000, 0x7ee2e2e3, 0xffeeeeee, 0xffededee, 0xffeeeeee, 0xffededed,
0xffeeeeee, 0xffeeeeee, 0xffededed, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffededee, 0xffeeeeee,
0xffededed, 0xffeeeeee, 0xffeeeeee, 0xffededed, 0xffeeeeee, 0xffeeeeee, 0xffeeeeee, 0xffededee,
0xffeeeeee, 0xffededed, 0xffeeeeee, 0xff8aacd9, 0xff4f8bcd, 0xff518acc, 0xff5289cc, 0xff5289cc,
0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc,
0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc,
0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc,
0xff5289cc, 0xff5289cc, 0xff5289cc, 0xff5289cc, 0x7a5b7abd, 0x01000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x38cbcbcb, 0xffedeeee, 0xffedeeee, 0xffeeeeee, 0xffedeeee,
0xffeeeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffeeeeee,
0xffedeeee, 0xffeeeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee, 0xffedeeee,
0xffeeeeee, 0xffedeeee, 0xfff0f0f0, 0xff3da2dc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff129bdb, 0x343579b4, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x0b000000, 0xd3e9e9e9, 0xffededee, 0xffededee, 0xffededee,
0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee,
0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee, 0xffededee,
0xffededee, 0xffededee, 0xffe1e7ed, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xcf2295d4, 0x0a000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x03000000, 0x62d5d5d5, 0xffededed, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffc7d8ea, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff099cdb, 0x5c2884c0, 0x02000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0e000000, 0xc0e5e5e6, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed, 0xffededed,
0xffededed, 0xffededed, 0xffa5c6e5, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff019ddc, 0xbd2093d2, 0x0d000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x2ca4a4a4, 0xe5eaeaea, 0xffececec,
0xffededed, 0xffededed, 0xffececec, 0xffeceded, 0xffececed, 0xffececec, 0xffececed, 0xffeceded,
0xffececec, 0xffededed, 0xffededed, 0xffececec, 0xffeceded, 0xffececed, 0xffececec, 0xffececed,
0xffeceded, 0xffeeeeee, 0xff66acdf, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xe41798d8, 0x29216392, 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000000, 0x3cb1b1b1, 0xe6eaeaea,
0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffececec, 0xffe3e8ed, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xe51598d8, 0x391d6ea2, 0x05000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000000, 0x339f9f9f,
0xc4e4e4e4, 0xffededed, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffececec, 0xffececec, 0xffededed, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffececec, 0xffbbd1e7, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff039ddc, 0xc31994d3,
0x301e6290, 0x06000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000000,
0x19020202, 0x73d0d0d0, 0xdce8e8e8, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec, 0xffececec,
0xffededed, 0xff84b7e1, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc,
0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff009ddc, 0xff069cdc, 0xdc1697d6, 0x712084be, 0x18000101,
0x04000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x02000000, 0x0b000000, 0x1d000000, 0x55bdbdbd, 0x97dbdbdb, 0xc4e3e3e3, 0xdee7e7e7, 0xfaececec,
0xffececec, 0xffededed, 0xffededed, 0xffececec, 0xffececec, 0xffededed, 0xffececec, 0xffededed,
0xffe4e7ec, 0xff069cdb, 0xff009ddc, 0xff019ddc, 0xff089cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb,
0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb,
0xff0b9cdb, 0xff0b9cdb, 0xff0b9cdb, 0xff0c9cdb, 0xff0d9cdb, 0xff0e9cdb, 0xff0e9bdb, 0xff119bdb,
0xfc159ada, 0xe31598d7, 0xc61794d3, 0x971b8dc9, 0x572378af, 0x1c000000, 0x0b000000, 0x01000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x02000000, 0x07000000, 0x10000000, 0x18000000, 0x1e000000, 0x22000000,
0x261c1c1c, 0x29424242, 0x2a4f4f4f, 0x2b555555, 0x2b565656, 0x2b575757, 0x2b575757, 0x2b575757,
0x2b484c51, 0x2b06304a, 0x2b05324c, 0x2b07324c, 0x2b0a314c, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b,
0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0b304b,
0x2b0b304b, 0x2b0b304b, 0x2b0b304b, 0x2b0c304b, 0x2b0c304b, 0x2b0c2f4a, 0x2a0c2e48, 0x27082134,
0x22000000, 0x1e000000, 0x17000000, 0x0f000000, 0x07000000, 0x02000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000000, 0x01000000, 0x02000000,
0x03000000, 0x03000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000,
0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000,
0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000,
0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x03000000, 0x03000000,
0x02000000, 0x01000000, 0x01000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
docs/screen/v19mega2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

BIN
docs/screen/v19ntsc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

8
libmui/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.bash_history
build-*
.vscode
compile_commands.json
cachegrind.out.*
callgrind.out.*
.cache
*_scrot.png

15
libmui/CHANGELOG.md Normal file
View File

@ -0,0 +1,15 @@
# MUI Version Changelog
## 1.2
* More tweaks to the menus. Popup menus can be justified left/right/center. Removed quite a few fudge factors.
* Added a notion of a control (per window) having the 'focus'. Currently listboxes and text edit boxes can have the focus.
## 1.1 -- since the release of the original verison
* Added support for horizontal scrollbars.
* Added a faster (vectorized) version of an obvious 'cg' function.
* Fixed a problem with mui_timers. Also typed it now.
* Added a bunch of extra comments to mui.h
* Added a *fully justified* text style for text boxes.
## 1.0 -- original version
* Initial release. Doh.

21
libmui/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Michel Pollet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,91 +1,62 @@
# Makefile
#
# Copyright (C) 2020 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
CC = gcc CC = gcc
CPPFLAGS += -Imui
# for bsd_queue.h
CPPFLAGS += -I../libmish/src
CPPFLAGS += -DUI_HAS_XCB=1 -DUI_HAS_XKB=1
OPTIMIZE ?= -O0 -g
CFLAGS += --std=gnu99 -Wall -Wextra
CFLAGS += $(OPTIMIZE)
CFLAGS += -Wno-unused-parameter -Wno-unused-function
# PIC is necessary for the shared library/plugin to work
CFLAGS += -fPIC
CPPFLAGS += ${shell pkg-config --cflags pixman-1} LIBMUI =
LDLIBS += ${shell pkg-config --libs pixman-1} MUI_SRC := $(wildcard $(LIBMUI)src/*.c)
LDLIBS += $(shell pkg-config --libs \
xcb xcb-shm xcb-randr \
xkbcommon-x11)
LDLIBS += -lm -ldl
O := $(BUILD_DIR)build-$(shell $(CC) -dumpmachine) vpath %.c $(LIBMUI)src $(LIBMUI)mui_shell
BIN := $(O)/bin
OBJ := $(O)/obj/libmui
LIB := $(O)/lib
MUI_SRC := $(wildcard mui/*.c) # this is just so we compile the tests if not a submodule
SRC := $(MUI_SRC) IS_SUBMODULE := ${wildcard ../ui_gl/mii_mui.h}
MUI_OBJ := ${patsubst %, $(OBJ)/%, ${notdir ${SRC:.c=.o}}}
SRC_VPATH := mui tests all : static mui_shell
SRC_VPATH += ../ui_gl
vpath %.c $(SRC_VPATH)
CPPFLAGS += -I../contrib include $(LIBMUI)Makefile.common
VERSION := ${shell git log -1 --date=short --pretty="%h %cd"} ifeq ($(IS_SUBMODULE),)
CPPFLAGS += -DUI_VERSION="\"$(VERSION)\"" all : tests
endif
MUI_OBJ := ${patsubst %, $(OBJ)/%, ${notdir ${MUI_SRC:.c=.o}}}
TARGET_LIB := $(LIB)/libmui.a TARGET_LIB := $(LIB)/libmui.a
all : $(BIN)/mui_playground $(LIB)/ui_tests.so .PHONY : mui_shell static tests
mui_shell : $(BIN)/mui_shell
.PHONY : static
static : $(TARGET_LIB) static : $(TARGET_LIB)
tests : | $(TARGET_LIB)
ifeq ($(V),1) $(MAKE) -j -C tests
Q := @echo " ** To launch the demo, run "
else @echo " $(BIN)/mui_shell -f $(LIB)/mui_widgets_demo.so"
Q := @
endif
$(TARGET_LIB) : $(MUI_OBJ) | $(LIB) $(TARGET_LIB) : $(MUI_OBJ) | $(LIB)
@echo " AR $@" @echo " AR $@"
$(Q)$(AR) rcs $@ $^ $(Q)$(AR) rcs $@ $^
$(OBJ)/ui_tests.o : CPPFLAGS += -Itests -I../ui_gl #
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_slots.o # The shell program is used to test the UI library using plugins
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_loadbin.o # It is made using XCB and XKB libraries to have a minimal dependency
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_1mb.o # on X11. Also, allows partial updates to be tested properly
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_2dsk.o #
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_about.o $(OBJ)/mui_shell.o : CPPFLAGS += -DUI_HAS_XCB=1 -DUI_HAS_XKB=1
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_ssc.o ifeq ($(shell uname),NetBSD)
$(LIB)/ui_tests.so : $(OBJ)/mii_mui_prefs.o # NetBSD requirements
$(OBJ)/mui_shell.o : CPPFLAGS += $(shell pkg-config --cflags xorg-server xkbcommon)
$(BIN)/mui_shell : LDLIBS += $(shell pkg-config --libs xorg-server)
endif
$(OBJ)/mii_mui_about.o : CPPFLAGS+=-DMII_ICON64_DEFINE $(BIN)/mui_shell : LDLIBS += $(shell pkg-config --libs \
xcb xcb-shm xcb-image \
# use a .temp file, otherwise the playground tries to reload before the file xkbcommon xkbcommon-x11)
# is fully written, and it fails. $(BIN)/mui_shell : LDLIBS += -lm
# the ${filter} are there to make the sure object files are linked before the .a ifeq ($(shell uname),Linux)
$(LIB)/ui_tests.so : $(OBJ)/ui_tests.o $(LIB)/libmui.a | $(O) $(BIN)/mui_shell : LDLIBS += -ldl
@echo " LDSO $@" endif
$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -shared -fPIC -o $@.temp \ $(BIN)/mui_shell : $(OBJ)/mui_shell.o $(LIB)/libmui.a
${filter %.o, $^} ${filter %.a, $^} $(LDLIBS) && \
mv $@.temp $@
$(BIN)/mui_playground : $(OBJ)/mui_playground.o $(LIB)/libmui.a
$(OBJ)/%.o : %.c | $(OBJ)
@echo " CC" ${filter -O%, $(CPPFLAGS) $(CFLAGS)} "$<"
$(Q)$(CC) -MMD $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
$(BIN)/% : | $(BIN)
@echo " LD $@"
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(O) $(OBJ) $(BIN) $(LIB):
@mkdir -p $@
clean : clean :
rm -rf $(O) rm -rf $(O)
@ -94,13 +65,13 @@ clean :
# everytime a file is modified. # everytime a file is modified.
watch : watch :
while true; do \ while true; do \
clear; $(MAKE) -j all; \ clear; $(MAKE) -j all tests; \
inotifywait -qre close_write mui tests ../ui_gl; \ inotifywait -qre close_write src mui_shell tests/* ../ui_gl; \
done done
compile_commands.json: lsp compile_commands.json: lsp
lsp: lsp:
{ $$(which gmake) CC=gcc V=1 --always-make --dry-run all ; } | \ { $$(which gmake) CC=gcc V=1 --always-make --dry-run all tests ; } | \
sh ../utils/clangd_gen.sh >compile_commands.json sh ../utils/clangd_gen.sh >compile_commands.json
-include $(OBJ)/*.d -include $(OBJ)/*.d

73
libmui/Makefile.common Normal file
View File

@ -0,0 +1,73 @@
# Makefile
#
# Copyright (C) 2024 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
LIBMUI ?= ../
# for bsd_queue.h and incbin.h
#MII ?= $(LIBMUI)..
#CPPFLAGS += -I$(MII)/libmish/src -I$(MII)/contrib
CPPFLAGS += -I$(LIBMUI)contrib
BUILD_DIR ?= $(LIBMUI)
O := $(BUILD_DIR)build-$(shell $(CC) -dumpmachine)
BIN := $(O)/bin
OBJ := $(O)/obj/libmui
LIB := $(O)/lib
CPPFLAGS += -I$(LIBMUI)src
CPPFLAGS += -I$(LIBMUI)mui_shell
CPPFLAGS += ${shell pkg-config --cflags pixman-1}
LDLIBS += ${shell pkg-config --libs pixman-1}
MUI_VERSION := ${shell \
echo $$(git describe --tags --abbrev=0 2>/dev/null || \
echo "(dev)") \
$$(git log -1 --date=short --pretty="%h %cd")}
CPPFLAGS += -DMUI_VERSION="\"$(MUI_VERSION)\""
OPTIMIZE ?= -O0 -g
CFLAGS += --std=gnu99 -Wall -Wextra
CFLAGS += $(OPTIMIZE)
CFLAGS += -Wno-unused-parameter -Wno-unused-function
# PIC is necessary for the shared library/plugin to work
CFLAGS += -fPIC
#CFLAGS += -fsanitize=address
#LDFLAGS += -fsanitize=address
#LDLIBS +=
ifeq ($(V),1)
Q :=
else
Q := @
endif
# use a .temp file, otherwise the mui_shell tries to reload before the file
# is fully written, and it fails.
# the ${filter} are there to make the sure object files are linked before the .a
$(LIB)/%.so : $(OBJ)/%.o $(LIB)/libmui.a | $(O)
ifeq ($(V),)
@echo " LDSO $@"
endif
$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) -shared -fPIC -o $@.temp \
${filter %.o, $^} ${filter %.a, $^} $(LDLIBS) && \
mv $@.temp $@
$(OBJ)/%.o : %.c | $(OBJ)
ifeq ($(V),)
@echo " CC" ${filter -O%, $(CPPFLAGS) $(CFLAGS)} "$<"
endif
$(Q)$(CC) -MMD $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
$(BIN)/% : | $(BIN)
ifeq ($(V),)
@echo " LD $@"
endif
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(O) $(OBJ) $(BIN) $(LIB):
@mkdir -p $@

View File

@ -1,21 +1,33 @@
# What is this? # What the hell is this?
This is a contender for the World Record for Feature Creep Side Project. It is pretty high in the contender list as it's a bolt on to *another* contender for the World Record for Feature Creep Side Project (the MII Apple //e emulator). This is a contender for the World Record for Feature Creep Side Project. It is pretty high in the contender list as it's a bolt on to *another* contender for the World Record for Feature Creep Side Project (the [MII Apple //e emulator](http://github.com/buserror/mii_emu)).
It is a library that duplicate a lot of a Macintosh Classic "Toolbox" APIs. It is not a complete implementation, but it is enough to make a few simple applications, also, all the bits I needed for the MII emulator. It is a library that duplicate a lot of a Macintosh Classic "Toolbox" APIs. It is not a complete implementation, but it is enough to make a few simple applications, also, all the bits I needed for the MII emulator.
<center>
<img src="doc/widgets.gif" alt="10 seconds demo">
<i>10 seconds demo</i>
</center>
# Why? # Why?
Well I wanted a UI library for MII -- something without tons of dependencies, and I didn't want the typical 'game like' style with "Arrow Keys + Return + Escape" sort of menus. Well I wanted a UI library for MII -- something without tons of dependencies, and I didn't want the typical 'game like' style with "Arrow Keys + Return + Escape" sort of menus.
I started with Nuklear immediate mode UI, but it both look super ugly, AND is very limited as soon as you want to do something 'custom', and I didn't see myself hacking into that codebase. One thing I particularly dislike is the 'layout' engine that decide to put stuff where it wants, and it's *never* in the 'right' place, like a hard case of 'computer say so' -- typicaly result into I started with Nuklear immediate mode UI, but it both look super ugly, AND is very limited as soon as you want to do something 'custom', and I didn't see myself hacking into that codebase. One thing I particularly dislike is the 'layout' engine that decide to put stuff where it wants, and it's *never* in the 'right' place, like a hard case of 'computer say so' -- typicaly result into
something like Programmer's Art. That's why Linux On The Deskop is famous for it's Pixel Perfection polished UIs. *Cough*. something like Programmer's Art, just worse. That's why Linux On The Deskop is famous for it's Pixel Perfection polished UIs. *Cough*.
The other things I don't like with the trendy IM UIs is that they promise you that you don't have to keep a separate state around blah blah, however they forget to mention that there IS a state kept for you, based on hash values, and if you are unlucky enough to have a hash clash, you are screwed. I've seen that happen in real life, and it's not pretty to debug. The other things I don't like with the trendy IM UIs is that they promise you that you don't have to keep a separate state around blah blah, however they forget to mention that there IS a state kept for you, based on hash values, and if you are unlucky enough to have a hash clash, you are screwed. I've seen that happen in real life, and it's not pretty to debug.
I miss the days were UIs were /crafted/ not just decided for you bad a bad 'layouting' engine with huge rectangular flat buttons and no sense whatsoever of 'design' or usability.
Also, I realized I had quite a few bits that I could use to make my own library anyway, so I started to do that. Also, I realized I had quite a few bits that I could use to make my own library anyway, so I started to do that.
Also, I like making my own toys. There, happy now? Also, I like making my own toys. There, happy now?
<center>
<img src="doc/control_demo.png" alt="Basic Controls">
<i>Control Demo</i>
</center>
# What can it do? # What can it do?
Well, it has a few of the classic 'managers' that the Macintosh Toolbox had. Or the later GS/OS. However it behaves more like a modern system, it's not 'synchronous' like the old toolbox. Stuff gets redrawn even if you are clicking/dragging etc without having to 'do it yourself'. Well, it has a few of the classic 'managers' that the Macintosh Toolbox had. Or the later GS/OS. However it behaves more like a modern system, it's not 'synchronous' like the old toolbox. Stuff gets redrawn even if you are clicking/dragging etc without having to 'do it yourself'.
@ -29,6 +41,12 @@ luckily, you only have to draw/convert the 'dirty' regions, so it's not too bad.
It could be possible to 'vectorize' the rendering to vertice buffers and stuff, but really, it's not needed, it's fast enough as it is and it would fall back the 'lets redraw everything' behaviour of the IMmediate UI libraries. It could be possible to 'vectorize' the rendering to vertice buffers and stuff, but really, it's not needed, it's fast enough as it is and it would fall back the 'lets redraw everything' behaviour of the IMmediate UI libraries.
<center>
<img src="doc/static_text.png" alt="Basic text boxes">
<i>Some basic text boxes</i>
</center>
# How does it differ from the original? # How does it differ from the original?
Well, in terms of looks, it's kinda like I started with MacOS8/9, but removed all the grayscale bits. Well, in terms of looks, it's kinda like I started with MacOS8/9, but removed all the grayscale bits.
Bizarelly, I think System 7 'flat' looks has aged better than the 'grayscale' look of 8/9, so I went with that. Most of the 'visible' difference are really related to the dialog's popup menus, which are a lot more 'OS8' than 'OS7'. The Scrollbar is definitely more GS/OS though, never understood why it took so long for MacOS to adopt that. Bizarelly, I think System 7 'flat' looks has aged better than the 'grayscale' look of 8/9, so I went with that. Most of the 'visible' difference are really related to the dialog's popup menus, which are a lot more 'OS8' than 'OS7'. The Scrollbar is definitely more GS/OS though, never understood why it took so long for MacOS to adopt that.
@ -52,7 +70,7 @@ It can create windows, and it can draw into them. Has up to 15 'layers', and can
I deliberately limited the number of coordinate systems to 2 -- like the old one; so you get the 'screen coordinates' and the 'window content coordinates'. I was half tempted to create a fully hierarchical system, but realized it was really not neeeded, and would just make things more complicated. I deliberately limited the number of coordinate systems to 2 -- like the old one; so you get the 'screen coordinates' and the 'window content coordinates'. I was half tempted to create a fully hierarchical system, but realized it was really not neeeded, and would just make things more complicated.
It's a 'smart' window manager, it keeps track of an 'invalid' list of rectangles, and clips to that when redrawing, so it doesn't redraw the whole window every time, yeah, like the original. None of that 'lets redraw absolutely everything every frame' stuff. It's a 'smart' window manager, it keeps track of an 'invalid' list of rectangles, and clips to that when redrawing, so it doesn't redraw the whole window every time, yeah, like the original. None of that 'lets redraw absolutely everything every frame' stuff like Immediate Mode UIs.
- It's missing bits like 'zooming' (TODO), and 'resizing' (TODO). - It's missing bits like 'zooming' (TODO), and 'resizing' (TODO).
- It doesn't do transparent windows. It is by design, it draws windows 'top down' to optimize clipping -- adding transparency wouldn't be hard, but I'd have to draw the windows 'bottom up' to handle blending, and we'd revert back to drawing a lot of stuff for very little return. - It doesn't do transparent windows. It is by design, it draws windows 'top down' to optimize clipping -- adding transparency wouldn't be hard, but I'd have to draw the windows 'bottom up' to handle blending, and we'd revert back to drawing a lot of stuff for very little return.
- Also, you can always alpha blend the whole *ui* 'screen' to wherever you want, so it's not like you can't have transparency. - Also, you can always alpha blend the whole *ui* 'screen' to wherever you want, so it's not like you can't have transparency.
@ -66,7 +84,7 @@ Menubar, menus, checkmarks, keyboard shortcuts, all that stuff. Made to looks li
## Control Manager ## Control Manager
Buttons, checkboxes, radio buttons, scrollbars (vertical), wrapping textboxes, all that stuff. Buttons, checkboxes, radio buttons, scrollbars (vertical), wrapping textboxes, all that stuff.
- It's missing bits like Edit Field (TODO), and a Slider. - It's missing bits like Edit Field (Work in Progress), and a Slider.
- There IS a prototype version of a text edit control, but it's not quite right yet -- works fine for a one liner etc, but not for a multi line text box. Not far off tho. - There IS a prototype version of a text edit control, but it's not quite right yet -- works fine for a one liner etc, but not for a multi line text box. Not far off tho.
## List Manager ## List Manager
More or less hard coded to display filenames so far, but plain lists are actually easier than this so. Handle arrow keys/page up/down, scroll wheel, etc. More or less hard coded to display filenames so far, but plain lists are actually easier than this so. Handle arrow keys/page up/down, scroll wheel, etc.
@ -75,11 +93,21 @@ More or less hard coded to display filenames so far, but plain lists are actuall
## Alerts ## Alerts
It has the typical 'Cancel'+'OK' alert. It has the typical 'Cancel'+'OK' alert.
- Could do with more types of alerts (TODO). - Could do with more types of alerts (TODO).
<center>
<img src="doc/alert.png" alt="Basic Alert">
<i>Basic Alert Dialog</i>
</center>
## Standard File ## Standard File
It has the classic 'Open' a file dialog. Haven't needed the other one. yet. It has the classic 'Open' a file dialog. Haven't needed the other one. yet. This one one of the primary goal of the UI library to start with, so I spent quite a bit of time getting it 'right', quite happy about how it turned out.
- Could do with a 'Save' dialog (TODO). - Could do with a 'Save' dialog (TODO).
- Maybe a 'period correct' way to handle previously visited folders... Currently it can same the last folder you visited *per file type*. + It has an extra popup with the last few used directories.
- You can use arrow keys, page/up down, and you can even typehead to the file you want, like in the old days. - You can use arrow keys, page/up down, and you can even typehead to the file you want, like in the old MacOS!
<center>
<img src="doc/standard_get_file.png" alt="Standard Get File">
<i>Standard Get File</i>
</center>
## Resource Manager ## Resource Manager
Nope! Not there; I'd need some sort of ResEdit and stuff -- and now that is *ONE* Feature Creep Too Far thank you very much. Nope! Not there; I'd need some sort of ResEdit and stuff -- and now that is *ONE* Feature Creep Too Far thank you very much.
@ -99,17 +127,17 @@ That's it, all the other bits I already had 'in stock' -- the 2D geometry bits I
# How do I build it? # How do I build it?
It's a simple Makefile, so you just need to do a 'make' in the root directory. It will build the library, and the tests/demos/samples. It's a simple Makefile, so you just need to do a 'make' in the root directory. It will build the library, and the tests/demos/samples.
To build the tests/demos/samples, you'll need: To build the tests/demos/samples, you'll need:
* xcb xcb-shm xcb-randr xkbcommon-x11 -- this is just to run the 'playground' demo, which is a simple window with a few buttons and stuff. * xcb xcb-shm xcb-randr xkbcommon-x11 -- this is just to run the 'mui_shell' demo, which is a simple window with a few buttons and stuff.
## Nvidia Driver gotcha ## Nvidia Driver gotcha
* *Note* that if you use the nvidia binary driver (I do), you will need to add a flag to your config, otherwise the playground won't work. * *Note* that if you use the nvidia binary driver (I do), you will need to add a flag to your config, otherwise the mui_shell won't work.
- Add: 'Option \"AllowSHMPixmaps\" \"1\"' to the "Device" In your /etc/X11/xorg.conf file. - Add: 'Option \"AllowSHMPixmaps\" \"1\"' to the "Device" In your /etc/X11/xorg.conf file.
# How do I use it? # How do I use it?
Well the best way is to hack around *mui_playground.c* and *ui_tests.c*. It's a simple window with a few buttons and stuff, and it's a good place to start. Well the best way is to hack around *mui_shell.c* and *mui_widgets_demo.c*. It's a simple window with a few buttons and stuff, and it's a good place to start.
The cool thing about ui_playground is that it loads ui_test.so as a *plugin* and auto-reload it if it detects a change. So you can hack around ui_test.c, and it will reload it and run it again! You can code a new dialog insanely fast with that, pretty must as fast as you would with a resource editor. The cool thing about ui_mui_shell is that it loads mui_widgets_demo.so as a *plugin* and auto-reload it if it detects a change. So you can hack around mui_widgets_demo.c, and it will reload it and run it again! You can code a new dialog insanely fast with that, pretty must as fast as you would with a resource editor.
A good trick is to use 'make watch' on the *libmui* directory in a terminal tab, and it will rebuild the library and the playground automatically when you change something, that with the 'auto save' of your editor, and you will have a constantly building/running playground as you hack around. A good trick is to use 'make watch' on the *libmui* directory in a terminal tab, and it will rebuild the library and the mui_shell automatically when you change something, that with the 'auto save' of your editor, and you will have a constantly building/running mui_shell as you hack around.
Have fun! Have fun!
@ -134,3 +162,4 @@ Have fun!
- nope - nope
* And Wayland then? Wayland is The Future after all! * And Wayland then? Wayland is The Future after all!
- nope - nope
<center><h1>Now, GET OFF MY LAWN!</h1></center>

860
libmui/contrib/bsd_queue.h Normal file
View File

@ -0,0 +1,860 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
//#include <sys/cdefs.h>
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may be traversed in either direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
* Below is a summary of implemented functions where:
* + means the macro is available
* - means the macro is not available
* s means the macro is available but is slow (runs in O(n) time)
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _CLASS_HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _CLASS_ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - + - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_FROM_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_FROM - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _FOREACH_REVERSE_FROM_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT s s + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE s + s +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
#define QUEUE_MACRO_DEBUG_TRACE
#define QUEUE_MACRO_DEBUG_TRASH
#endif
#ifdef QUEUE_MACRO_DEBUG_TRACE
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
unsigned long lastline;
unsigned long prevline;
const char *lastfile;
const char *prevfile;
};
#define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else /* !QUEUE_MACRO_DEBUG_TRACE */
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRACEBUF_INITIALIZER
#endif /* QUEUE_MACRO_DEBUG_TRACE */
#ifdef QUEUE_MACRO_DEBUG_TRASH
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1)
#else /* !QUEUE_MACRO_DEBUG_TRASH */
#define TRASHIT(x)
#define QMD_IS_TRASHED(x) 0
#endif /* QUEUE_MACRO_DEBUG_TRASH */
#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#else /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */
#define QMD_SAVELINK(name, link)
#endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */
#ifdef __cplusplus
/*
* In C++ there can be structure lists and class lists:
*/
#define QUEUE_TYPEOF(type) type
#else
#define QUEUE_TYPEOF(type) struct type
#endif
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_CLASS_HEAD(name, type) \
struct name { \
class type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
#define SLIST_CLASS_ENTRY(type) \
struct { \
class type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
if (*(prevp) != (elm)) \
panic("Bad prevptr *(%p) == %p != %p", \
(prevp), *(prevp), (elm)); \
} while (0)
#else
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
#endif
#define SLIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
if (curelm == NULL) { \
if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
SLIST_INIT(head2); \
} else if (SLIST_FIRST(head2) != NULL) { \
while (SLIST_NEXT(curelm, field) != NULL) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \
SLIST_INIT(head2); \
} \
} while (0)
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \
QMD_SLIST_CHECK_PREVPTR(prevp, elm); \
*(prevp) = SLIST_NEXT(elm, field); \
TRASHIT((elm)->field.sle_next); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \
QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *stqh_first; /* first element */ \
class type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
#define STAILQ_CLASS_ENTRY(type) \
struct { \
class type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, \
QUEUE_TYPEOF(type), field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_CLASS_HEAD(name, type) \
struct name { \
class type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
#define LIST_CLASS_ENTRY(type) \
struct { \
class type *le_next; /* next element */ \
class type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
*
* If the list is non-empty, validates that the first element of the list
* points back at 'head.'
*/
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
/*
* QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME)
*
* If an element follows 'elm' in the list, validates that the next element
* points back at 'elm.'
*/
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
* QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME)
*
* Validates that the previous element (or head of the list) points to 'elm.'
*/
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
if (curelm == NULL) { \
if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \
LIST_FIRST(head2)->field.le_prev = \
&LIST_FIRST((head1)); \
LIST_INIT(head2); \
} \
} else if (LIST_FIRST(head2) != NULL) { \
while (LIST_NEXT(curelm, field) != NULL) \
curelm = LIST_NEXT(curelm, field); \
LIST_NEXT(curelm, field) = LIST_FIRST(head2); \
LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
LIST_INIT(head2); \
} \
} while (0)
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, \
QUEUE_TYPEOF(type), field.le_next))
#define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *tqh_first; /* first element */ \
class type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
#define TAILQ_CLASS_ENTRY(type) \
struct { \
class type *tqe_next; /* next element */ \
class type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* If the tailq is non-empty, validates that the first element of the tailq
* points back at 'head.'
*/
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
/*
* QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* Validates that the tail of the tailq is a pointer to pointer to NULL.
*/
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
/*
* QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME)
*
* If an element follows 'elm' in the tailq, validates that the next element
* points back at 'elm.'
*/
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
* QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME)
*
* Validates that the previous element (or head of the tailq) points to 'elm.'
*/
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

379
libmui/contrib/incbin.h Normal file
View File

@ -0,0 +1,379 @@
/**
* @file incbin.h
* @author Dale Weiler
* @brief Utility for including binary files
*
* Facilities for including binary files into the current translation unit and
* making use from them externally in other translation units.
*/
#ifndef INCBIN_HDR
#define INCBIN_HDR
#include <limits.h>
// Michel addition:
// Allow the included file to have an extra zero, to include text files
// as plain zero terminated strings
#ifdef INCBIN_TRAILING_ZERO
#define INCBIN_TRAIL INCBIN_BYTE "0\n"
#else
#define INCBIN_TRAIL
#endif
#if defined(__AVX512BW__) || \
defined(__AVX512CD__) || \
defined(__AVX512DQ__) || \
defined(__AVX512ER__) || \
defined(__AVX512PF__) || \
defined(__AVX512VL__) || \
defined(__AVX512F__)
# define INCBIN_ALIGNMENT_INDEX 6
#elif defined(__AVX__) || \
defined(__AVX2__)
# define INCBIN_ALIGNMENT_INDEX 5
#elif defined(__SSE__) || \
defined(__SSE2__) || \
defined(__SSE3__) || \
defined(__SSSE3__) || \
defined(__SSE4_1__) || \
defined(__SSE4_2__) || \
defined(__neon__)
# define INCBIN_ALIGNMENT_INDEX 4
#elif ULONG_MAX != 0xffffffffu
# define INCBIN_ALIGNMENT_INDEX 3
# else
# define INCBIN_ALIGNMENT_INDEX 2
#endif
/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */
#define INCBIN_ALIGN_SHIFT_0 1
#define INCBIN_ALIGN_SHIFT_1 2
#define INCBIN_ALIGN_SHIFT_2 4
#define INCBIN_ALIGN_SHIFT_3 8
#define INCBIN_ALIGN_SHIFT_4 16
#define INCBIN_ALIGN_SHIFT_5 32
#define INCBIN_ALIGN_SHIFT_6 64
/* Actual alignment value */
#define INCBIN_ALIGNMENT \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \
INCBIN_ALIGNMENT_INDEX)
/* Stringize */
#define INCBIN_STR(X) \
#X
#define INCBIN_STRINGIZE(X) \
INCBIN_STR(X)
/* Concatenate */
#define INCBIN_CAT(X, Y) \
X ## Y
#define INCBIN_CONCATENATE(X, Y) \
INCBIN_CAT(X, Y)
/* Deferred macro expansion */
#define INCBIN_EVAL(X) \
X
#define INCBIN_INVOKE(N, ...) \
INCBIN_EVAL(N(__VA_ARGS__))
/* Green Hills uses a different directive for including binary data */
#if defined(__ghs__)
# if (__ghs_asm == 2)
# define INCBIN_MACRO ".file"
/* Or consider the ".myrawdata" entry in the ld file */
# else
# define INCBIN_MACRO "\tINCBIN"
# endif
#else
# define INCBIN_MACRO ".incbin"
#endif
#ifndef _MSC_VER
# define INCBIN_ALIGN \
__attribute__((aligned(INCBIN_ALIGNMENT)))
#else
# define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))
#endif
#if defined(__arm__) || /* GNU C and RealView */ \
defined(__arm) || /* Diab */ \
defined(_ARM) /* ImageCraft */
# define INCBIN_ARM
#endif
#ifdef __GNUC__
/* Utilize .balign where supported */
# define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
# define INCBIN_ALIGN_BYTE ".balign 1\n"
#elif defined(INCBIN_ARM)
/*
* On arm assemblers, the alignment value is calculated as (1 << n) where `n' is
* the shift count. This is the value passed to `.align'
*/
# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n"
# define INCBIN_ALIGN_BYTE ".align 0\n"
#else
/* We assume other inline assembler's treat `.align' as `.balign' */
# define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
# define INCBIN_ALIGN_BYTE ".align 1\n"
#endif
/* INCBIN_CONST is used by incbin.c generated files */
#if defined(__cplusplus)
# define INCBIN_EXTERNAL extern "C"
# define INCBIN_CONST extern const
#else
# define INCBIN_EXTERNAL extern
# define INCBIN_CONST const
#endif
/**
* @brief Optionally override the linker section into which data is emitted.
*
* @warning If you use this facility, you'll have to deal with platform-specific linker output
* section naming on your own
*
* Overriding the default linker output section, e.g for esp8266/Arduino:
* @code
* #define INCBIN_OUTPUT_SECTION ".irom.text"
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
* // Data is emitted into program memory that never gets copied to RAM
* @endcode
*/
#if !defined(INCBIN_OUTPUT_SECTION)
# if defined(__APPLE__)
# define INCBIN_OUTPUT_SECTION ".const_data"
# else
# define INCBIN_OUTPUT_SECTION ".rodata"
# endif
#endif
#if defined(__APPLE__)
/* The directives are different for Apple branded compilers */
# define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n"
# define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
# define INCBIN_INT ".long "
# define INCBIN_MANGLE "_"
# define INCBIN_BYTE ".byte "
# define INCBIN_TYPE(...)
#else
# define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n"
# define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
# if defined(__ghs__)
# define INCBIN_INT ".word "
# else
# define INCBIN_INT ".int "
# endif
# if defined(__USER_LABEL_PREFIX__)
# define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)
# else
# define INCBIN_MANGLE ""
# endif
# if defined(INCBIN_ARM)
/* On arm assemblers, `@' is used as a line comment token */
# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
# elif defined(__MINGW32__) || defined(__MINGW64__)
/* Mingw doesn't support this directive either */
# define INCBIN_TYPE(NAME)
# else
/* It's safe to use `@' on other architectures */
# define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
# endif
# define INCBIN_BYTE ".byte "
#endif
/* List of style types used for symbol names */
#define INCBIN_STYLE_CAMEL 0
#define INCBIN_STYLE_SNAKE 1
/**
* @brief Specify the prefix to use for symbol names.
*
* By default this is `g', producing symbols of the form:
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
*
* // Now you have the following symbols:
* // const unsigned char gFooData[];
* // const unsigned char *const gFooEnd;
* // const unsigned int gFooSize;
* @endcode
*
* If however you specify a prefix before including: e.g:
* @code
* #define INCBIN_PREFIX incbin
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
*
* // Now you have the following symbols instead:
* // const unsigned char incbinFooData[];
* // const unsigned char *const incbinFooEnd;
* // const unsigned int incbinFooSize;
* @endcode
*/
#if !defined(INCBIN_PREFIX)
# define INCBIN_PREFIX g
#endif
/**
* @brief Specify the style used for symbol names.
*
* Possible options are
* - INCBIN_STYLE_CAMEL "CamelCase"
* - INCBIN_STYLE_SNAKE "snake_case"
*
* Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
* @code
* #include "incbin.h"
* INCBIN(Foo, "foo.txt");
*
* // Now you have the following symbols:
* // const unsigned char <prefix>FooData[];
* // const unsigned char *const <prefix>FooEnd;
* // const unsigned int <prefix>FooSize;
* @endcode
*
* If however you specify a style before including: e.g:
* @code
* #define INCBIN_STYLE INCBIN_STYLE_SNAKE
* #include "incbin.h"
* INCBIN(foo, "foo.txt");
*
* // Now you have the following symbols:
* // const unsigned char <prefix>foo_data[];
* // const unsigned char *const <prefix>foo_end;
* // const unsigned int <prefix>foo_size;
* @endcode
*/
#if !defined(INCBIN_STYLE)
# define INCBIN_STYLE INCBIN_STYLE_CAMEL
#endif
/* Style lookup tables */
#define INCBIN_STYLE_0_DATA Data
#define INCBIN_STYLE_0_END End
#define INCBIN_STYLE_0_SIZE Size
#define INCBIN_STYLE_1_DATA _data
#define INCBIN_STYLE_1_END _end
#define INCBIN_STYLE_1_SIZE _size
/* Style lookup: returning identifier */
#define INCBIN_STYLE_IDENT(TYPE) \
INCBIN_CONCATENATE( \
INCBIN_STYLE_, \
INCBIN_CONCATENATE( \
INCBIN_EVAL(INCBIN_STYLE), \
INCBIN_CONCATENATE(_, TYPE)))
/* Style lookup: returning string literal */
#define INCBIN_STYLE_STRING(TYPE) \
INCBIN_STRINGIZE( \
INCBIN_STYLE_IDENT(TYPE)) \
/* Generate the global labels by indirectly invoking the macro with our style
* type and concatenating the name against them. */
#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
INCBIN_INVOKE( \
INCBIN_GLOBAL, \
INCBIN_CONCATENATE( \
NAME, \
INCBIN_INVOKE( \
INCBIN_STYLE_IDENT, \
TYPE))) \
INCBIN_INVOKE( \
INCBIN_TYPE, \
INCBIN_CONCATENATE( \
NAME, \
INCBIN_INVOKE( \
INCBIN_STYLE_IDENT, \
TYPE)))
/**
* @brief Externally reference binary data included in another translation unit.
*
* Produces three external symbols that reference the binary data included in
* another translation unit.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name given for the binary data
*
* @code
* INCBIN_EXTERN(Foo);
*
* // Now you have the following symbols:
* // extern const unsigned char <prefix>FooData[];
* // extern const unsigned char *const <prefix>FooEnd;
* // extern const unsigned int <prefix>FooSize;
* @endcode
*/
#define INCBIN_EXTERN(NAME) \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(DATA))[]; \
INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(END)); \
INCBIN_EXTERNAL const unsigned int \
INCBIN_CONCATENATE( \
INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
INCBIN_STYLE_IDENT(SIZE))
/**
* @brief Include a binary file into the current translation unit.
*
* Includes a binary file into the current translation unit, producing three symbols
* for objects that encode the data and size respectively.
*
* The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
* "Data", as well as "End" and "Size" after. An example is provided below.
*
* @param NAME The name to associate with this binary data (as an identifier.)
* @param FILENAME The file to include (as a string literal.)
*
* @code
* INCBIN(Icon, "icon.png");
*
* // Now you have the following symbols:
* // const unsigned char <prefix>IconData[];
* // const unsigned char *const <prefix>IconEnd;
* // const unsigned int <prefix>IconSize;
* @endcode
*
* @warning This must be used in global scope
* @warning The identifiers may be different if INCBIN_STYLE is not default
*
* To externally reference the data included by this in another translation unit
* please @see INCBIN_EXTERN.
*/
#ifdef _MSC_VER
#define INCBIN(NAME, FILENAME) \
INCBIN_EXTERN(NAME)
#else
#define INCBIN(NAME, FILENAME) \
__asm__(INCBIN_SECTION \
INCBIN_GLOBAL_LABELS(NAME, DATA) \
INCBIN_ALIGN_HOST \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
INCBIN_MACRO " \"" FILENAME "\"\n" \
INCBIN_TRAIL \
INCBIN_GLOBAL_LABELS(NAME, END) \
INCBIN_ALIGN_BYTE \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
INCBIN_BYTE "1\n" \
INCBIN_GLOBAL_LABELS(NAME, SIZE) \
INCBIN_ALIGN_HOST \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \
INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \
INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \
INCBIN_ALIGN_HOST \
".text\n" \
); \
INCBIN_EXTERN(NAME)
#endif
#endif

BIN
libmui/doc/alert.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
libmui/doc/control_demo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
libmui/doc/static_text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
libmui/doc/widgets.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

View File

@ -22,7 +22,7 @@ OS2Version: 0
OS2_WeightWidthSlopeOnly: 0 OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0 OS2_UseTypoMetrics: 0
CreationTime: 830956166 CreationTime: 830956166
ModificationTime: 1700234837 ModificationTime: 1711450964
PfmFamily: 81 PfmFamily: 81
TTFWeight: 400 TTFWeight: 400
TTFWidth: 5 TTFWidth: 5
@ -800,10 +800,10 @@ NameList: AGL For New Fonts
DisplaySize: -96 DisplaySize: -96
AntiAlias: 1 AntiAlias: 1
FitToEm: 1 FitToEm: 1
WinInfo: 323 19 9 WinInfo: 230 23 12
BeginPrivate: 0 BeginPrivate: 0
EndPrivate EndPrivate
BeginChars: 488 470 BeginChars: 489 471
StartChar: .notdef StartChar: .notdef
Encoding: 409 -1 0 Encoding: 409 -1 0
@ -857,7 +857,7 @@ EndChar
StartChar: .null StartChar: .null
Encoding: 5 8 1 Encoding: 5 8 1
AltUni2: 00001d.ffffffff.0 002400.ffffffff.0 00001d.ffffffff.0 002400.ffffffff.0 AltUni2: 002400.ffffffff.0 00001d.ffffffff.0 002400.ffffffff.0 00001d.ffffffff.0
Width: 0 Width: 0
GlyphClass: 1 GlyphClass: 1
Flags: W Flags: W
@ -2429,7 +2429,7 @@ EndChar
StartChar: hyphen StartChar: hyphen
Encoding: 36 45 16 Encoding: 36 45 16
AltUni2: 0000ad.ffffffff.0 002010.ffffffff.0 0000ad.ffffffff.0 002010.ffffffff.0 AltUni2: 002010.ffffffff.0 0000ad.ffffffff.0 002010.ffffffff.0 0000ad.ffffffff.0
Width: 1190 Width: 1190
GlyphClass: 1 GlyphClass: 1
Flags: W Flags: W
@ -30762,24 +30762,24 @@ Refer: 15 44 N 1 0 0 1 350 -451 2
Validated: 1 Validated: 1
EndChar EndChar
StartChar: uniE0B0 StartChar: uni25B6
Encoding: 474 57520 456 Encoding: 474 9654 456
Width: 1051 Width: 1051
VWidth: 1000 VWidth: 1000
Flags: W Flags: W
LayerCount: 2 LayerCount: 2
Fore Fore
SplineSet SplineSet
354.5 59 m 0,0,1 354.5 59 m 4,0,1
294.5 -1 294.5 -1 206.900390625 -2.2001953125 c 0,2,3 294.5 -1 294.5 -1 206.900390625 -2.2001953125 c 4,2,3
122.900390625 -2.2001953125 122.900390625 -2.2001953125 61.7001953125 59 c 128,-1,4 122.900390625 -2.2001953125 122.900390625 -2.2001953125 61.7001953125 59 c 132,-1,4
0.5 120.200195312 0.5 120.200195312 0.5 207.799804688 c 2,5,-1 0.5 120.200195312 0.5 120.200195312 0.5 207.799804688 c 6,5,-1
0.5 1242.20019531 l 2,6,7 0.5 1242.20019531 l 6,6,7
0.5 1328.59960938 0.5 1328.59960938 61.7001953125 1390.40039062 c 128,-1,8 0.5 1328.59960938 0.5 1328.59960938 61.7001953125 1390.40039062 c 132,-1,8
122.900390625 1452.20019531 122.900390625 1452.20019531 206.900390625 1452.20019531 c 0,9,10 122.900390625 1452.20019531 122.900390625 1452.20019531 206.900390625 1452.20019531 c 4,9,10
294.5 1452.20019531 294.5 1452.20019531 354.5 1391 c 2,11,-1 294.5 1452.20019531 294.5 1452.20019531 354.5 1391 c 6,11,-1
1038.5 725 l 1,12,13 1038.5 725 l 5,12,13
628.099609375 325.400390625 628.099609375 325.400390625 354.5 59 c 0,0,1 628.099609375 325.400390625 628.099609375 325.400390625 354.5 59 c 4,0,1
EndSplineSet EndSplineSet
Validated: 1 Validated: 1
EndChar EndChar
@ -31663,39 +31663,62 @@ StartChar: uniE0B1
Encoding: 487 57521 469 Encoding: 487 57521 469
Width: 2331 Width: 2331
VWidth: 1000 VWidth: 1000
Flags: W
LayerCount: 2
Fore
SplineSet
2408.40039062 129 m 5,0,-1
2408.40039062 -105 l 5,1,-1
1948.79980469 -105 l 6,2,3
1765.20019531 -105 1765.20019531 -105 1632 6 c 132,-1,4
1498.79980469 117 1498.79980469 117 1498.79980469 298.200195312 c 4,5,6
1498.79980469 454.200195312 1498.79980469 454.200195312 1633.79980469 574.799804688 c 132,-1,7
1768.79980469 695.400390625 1768.79980469 695.400390625 1950 695.400390625 c 6,8,-1
2408.40039062 695.400390625 l 5,9,-1
2408.40039062 461.400390625 l 5,10,-1
2227.20019531 196.200195312 l 5,11,-1
1918.79980469 196.200195312 l 5,12,-1
2110.79980469 461.400390625 l 5,13,-1
1970.40039062 461.400390625 l 6,14,15
1892.40039062 461.400390625 1892.40039062 461.400390625 1844.40039062 416.400390625 c 132,-1,16
1796.40039062 371.400390625 1796.40039062 371.400390625 1796.40039062 301.799804688 c 4,17,18
1796.40039062 227.400390625 1796.40039062 227.400390625 1847.40039062 178.200195312 c 132,-1,19
1898.40039062 129 1898.40039062 129 1970.40039062 129 c 6,20,-1
2408.40039062 129 l 5,0,-1
1244.40039062 1611 m 5,21,-1
1777.20019531 1611 l 5,22,-1
1185.60058594 -111 l 5,23,24
1184.40039062 -111 1184.40039062 -111 654 -111 c 5,25,-1
1244.40039062 1611 l 5,21,-1
505.200195312 1611 m 5,26,-1
1039.20019531 1611 l 5,27,-1
447.600585938 -111 l 5,28,-1
-84 -111 l 5,29,-1
505.200195312 1611 l 5,26,-1
EndSplineSet
Validated: 524289
EndChar
StartChar: triagdn
Encoding: 488 9660 470
Width: 1467
VWidth: 1000
Flags: WO Flags: WO
LayerCount: 2 LayerCount: 2
Fore Fore
SplineSet SplineSet
2408.40039062 72 m 1,0,-1 65.5 890 m 0,0,1
2408.40039062 -162 l 1,1,-1 5.5 950 5.5 950 4.2998046875 1037.59960938 c 0,2,3
1948.79980469 -162 l 2,2,3 4.2998046875 1121.59960938 4.2998046875 1121.59960938 65.5 1182.79980469 c 128,-1,4
1765.20019531 -162 1765.20019531 -162 1632 -51 c 128,-1,4 126.700195312 1244 126.700195312 1244 214.299804688 1244 c 2,5,-1
1498.79980469 60 1498.79980469 60 1498.79980469 241.200195312 c 0,5,6 1248.70019531 1244 l 2,6,7
1498.79980469 397.200195312 1498.79980469 397.200195312 1633.79980469 517.799804688 c 128,-1,7 1335.09960938 1244 1335.09960938 1244 1396.90039062 1182.79980469 c 128,-1,8
1768.79980469 638.400390625 1768.79980469 638.400390625 1950 638.400390625 c 2,8,-1 1458.70019531 1121.59960938 1458.70019531 1121.59960938 1458.70019531 1037.59960938 c 0,9,10
2408.40039062 638.400390625 l 1,9,-1 1458.70019531 950 1458.70019531 950 1397.5 890 c 2,11,-1
2408.40039062 404.400390625 l 1,10,-1 731.5 206 l 1,12,13
2227.20019531 139.200195312 l 1,11,-1 331.900390625 616.400390625 331.900390625 616.400390625 65.5 890 c 0,0,1
1918.79980469 139.200195312 l 1,12,-1
2110.79980469 404.400390625 l 1,13,-1
1970.40039062 404.400390625 l 2,14,15
1892.40039062 404.400390625 1892.40039062 404.400390625 1844.40039062 359.400390625 c 128,-1,16
1796.40039062 314.400390625 1796.40039062 314.400390625 1796.40039062 244.799804688 c 0,17,18
1796.40039062 170.400390625 1796.40039062 170.400390625 1847.40039062 121.200195312 c 128,-1,19
1898.40039062 72 1898.40039062 72 1970.40039062 72 c 2,20,-1
2408.40039062 72 l 1,0,-1
1244.40039062 1554 m 1,21,-1
1777.20019531 1554 l 1,22,-1
1185.60058594 -168 l 1,23,24
1184.40039062 -168 1184.40039062 -168 654 -168 c 1,25,-1
1244.40039062 1554 l 1,21,-1
505.200195312 1554 m 1,26,-1
1039.20019531 1554 l 1,27,-1
447.600585938 -168 l 1,28,-1
-84 -168 l 1,29,-1
505.200195312 1554 l 1,26,-1
EndSplineSet EndSplineSet
Validated: 524289
EndChar EndChar
EndChars EndChars
EndSplineFont EndSplineFont

Binary file not shown.

Binary file not shown.

View File

@ -22,7 +22,7 @@ OS2Version: 4
OS2_WeightWidthSlopeOnly: 0 OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 1 OS2_UseTypoMetrics: 1
CreationTime: 1406487198 CreationTime: 1406487198
ModificationTime: 1710318804 ModificationTime: 1712598375
PfmFamily: 17 PfmFamily: 17
TTFWeight: 400 TTFWeight: 400
TTFWidth: 5 TTFWidth: 5
@ -2630,8 +2630,8 @@ NameList: AGL For New Fonts
DisplaySize: -96 DisplaySize: -96
AntiAlias: 1 AntiAlias: 1
FitToEm: 0 FitToEm: 0
WinInfo: 224 14 9 WinInfo: 144 18 12
BeginChars: 349 339 BeginChars: 351 341
StartChar: .notdef StartChar: .notdef
Encoding: 336 -1 0 Encoding: 336 -1 0
@ -7504,16 +7504,16 @@ EndTTInstrs
LayerCount: 2 LayerCount: 2
Fore Fore
SplineSet SplineSet
500 467 m 2,0,1 500 467 m 6,0,1
517 467 517 467 529.5 454 c 128,-1,2 517 467 517 467 529.5 454 c 132,-1,2
542 441 542 441 542 425 c 128,-1,3 542 441 542 441 542 425 c 132,-1,3
542 409 542 409 529 396 c 2,4,-1 542 409 542 409 529 396 c 6,4,-1
271 133 l 1,5,-1 271 133 l 5,5,-1
12 396 l 2,6,7 12 396 l 6,6,7
0 408 0 408 0 425 c 128,-1,8 0 408 0 408 0 425 c 132,-1,8
0 442 0 442 12.5 454.5 c 128,-1,9 0 442 0 442 12.5 454.5 c 132,-1,9
25 467 25 467 42 467 c 2,10,-1 25 467 25 467 42 467 c 6,10,-1
500 467 l 2,0,1 500 467 l 6,0,1
EndSplineSet EndSplineSet
Validated: 1 Validated: 1
EndChar EndChar
@ -54120,13 +54120,13 @@ SplineSet
667 210 l 5,55,-1 667 210 l 5,55,-1
667 85 l 5,52,-1 667 85 l 5,52,-1
EndSplineSet EndSplineSet
Validated: 524329 Validated: 41
EndChar EndChar
StartChar: uniE151 StartChar: uniE151
Encoding: 338 57681 338 Encoding: 338 57681 338
Width: 750 Width: 750
Flags: WO Flags: W
LayerCount: 2 LayerCount: 2
Fore Fore
SplineSet SplineSet
@ -54174,5 +54174,46 @@ SplineSet
EndSplineSet EndSplineSet
Validated: 37 Validated: 37
EndChar EndChar
StartChar: uniE152
Encoding: 339 57682 339
Width: 449
Flags: WO
LayerCount: 2
Fore
SplineSet
104 529 m 2,0,1
104 546 104 546 117 558.5 c 128,-1,2
130 571 130 571 146 571 c 128,-1,3
162 571 162 571 175 558 c 2,4,-1
438 300 l 1,5,-1
175 41 l 2,6,7
163 29 163 29 146 29 c 128,-1,8
129 29 129 29 116.5 41.5 c 128,-1,9
104 54 104 54 104 71 c 2,10,-1
104 529 l 2,0,1
EndSplineSet
EndChar
StartChar: uniE153
Encoding: 340 57683 340
Width: 542
Flags: W
LayerCount: 2
Fore
SplineSet
438 71 m 6,0,1
438 54 438 54 425 41.5 c 132,-1,2
412 29 412 29 396 29 c 132,-1,3
380 29 380 29 367 42 c 6,4,-1
104 300 l 5,5,-1
367 559 l 6,6,7
379 571 379 571 396 571 c 132,-1,8
413 571 413 571 425.5 558.5 c 132,-1,9
438 546 438 546 438 529 c 6,10,-1
438 71 l 6,0,1
EndSplineSet
Validated: 1
EndChar
EndChars EndChars
EndSplineFont EndSplineFont

View File

@ -1,366 +0,0 @@
/*
* mui_cdef_scrollbar.c
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdlib.h>
#include "mui.h"
#include "cg.h"
enum {
MUI_CONTROL_SCROLLBAR = FCC('s','b','a','r'),
};
extern const mui_control_color_t mui_control_color[MUI_CONTROL_STATE_COUNT];
enum mui_sb_part_e {
MUI_SB_PART_FRAME = 0,
MUI_SB_PART_UP,
MUI_SB_PART_DOWN,
MUI_SB_PART_PAGEUP,
MUI_SB_PART_PAGEDOWN,
MUI_SB_PART_THUMB,
MUI_SB_PART_COUNT,
};
typedef struct mui_scrollbar_control_t {
mui_control_t control;
uint32_t visible;
uint32_t max;
c2_pt_t drag_offset;
uint32_t saved_value; // to handle 'snapback'
} mui_scrollbar_control_t;
static void
mui_scrollbar_make_rects(
mui_control_t * c,
c2_rect_t * parts)
{
c2_rect_t f = c->frame;
c2_rect_offset(&f, c->win->content.l, c->win->content.t);
parts[MUI_SB_PART_FRAME] = f;
c2_rect_t part = f;
part.b = part.t + c2_rect_width(&part);
parts[MUI_SB_PART_UP] = part;
part = f;
part.t = part.b - c2_rect_width(&part);
parts[MUI_SB_PART_DOWN] = part;
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
if (sb->max <= sb->visible) {
c2_rect_t z = {};
parts[MUI_SB_PART_THUMB] = z;
parts[MUI_SB_PART_PAGEUP] = z;
parts[MUI_SB_PART_PAGEDOWN] = z;
return;
}
part = f;
part.t = parts[MUI_SB_PART_UP].b + 1;
part.b = parts[MUI_SB_PART_DOWN].t - 1;
float visible = sb->visible / (float)sb->max;
float thumb_size = visible * sb->visible;
if (thumb_size < 20)
thumb_size = 20;
float thumb_pos = c->value / ((float)sb->max- sb->visible);
float thumb_offset = 0.5 + thumb_pos * (c2_rect_height(&part) - thumb_size);
// printf("%s visible:%.2f ts: %.2f thumb_pos:%.2f thumb_offset:%.2f\n",
// __func__, visible, thumb_size, thumb_pos, thumb_offset);
part.b = part.t + thumb_size;
c2_rect_offset(&part, 0, thumb_offset);
if (part.b > parts[MUI_SB_PART_DOWN].t) {
c2_rect_offset(&part, 0, parts[MUI_SB_PART_DOWN].t - part.b);
}
parts[MUI_SB_PART_THUMB] = part;
part = f;
part.t = parts[MUI_SB_PART_UP].b + 1;
part.b = parts[MUI_SB_PART_THUMB].t - 1;
parts[MUI_SB_PART_PAGEUP] = part;
part = f;
part.t = parts[MUI_SB_PART_THUMB].b + 1;
part.b = parts[MUI_SB_PART_DOWN].t - 1;
parts[MUI_SB_PART_PAGEDOWN] = part;
}
static void
mui_scrollbar_draw(
mui_window_t * win,
mui_control_t * c,
mui_drawable_t *dr )
{
c2_rect_t f = c->frame;
c2_rect_offset(&f, win->content.l, win->content.t);
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
cg_set_line_width(cg, 1);
cg_rectangle(cg, f.l, f.t,
c2_rect_width(&f), c2_rect_height(&f));
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
mui_font_t * icons = mui_font_find(win->ui, "icon_small");
c2_rect_t parts[MUI_SB_PART_COUNT];
mui_scrollbar_make_rects(c, parts);
mui_color_t contentFill = MUI_COLOR(0xa0a0a0ff);
mui_color_t decoColor = MUI_COLOR(0x666666ff);
c2_rect_t pf;
pf = parts[MUI_SB_PART_UP];
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_UP ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
stb_ttc_measure m = {};
mui_font_text_measure(icons, "", &m);
pf.l = pf.l + (c2_rect_width(&pf) - m.x1 - m.x0) / 2;
mui_font_text_draw(icons, dr, pf.tl, "", 0,
mui_control_color[c->state].text);
pf = parts[MUI_SB_PART_DOWN];
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_DOWN ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
mui_font_text_measure(icons, "", &m);
pf.l = pf.l + (c2_rect_width(&pf) - m.x1 - m.x0) / 2;
mui_font_text_draw(icons, dr, pf.tl, "", 0,
mui_control_color[c->state].text);
pf = parts[MUI_SB_PART_PAGEUP];
if (c2_rect_height(&pf) > 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_PAGEUP ?
&CG_COLOR(decoColor) :
&CG_COLOR(contentFill));
cg_fill(cg);
}
pf = parts[MUI_SB_PART_PAGEDOWN];
if (c2_rect_height(&pf) > 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_PAGEDOWN ?
&CG_COLOR(decoColor) :
&CG_COLOR(contentFill));
cg_fill(cg);
}
pf = parts[MUI_SB_PART_THUMB];
if (c2_rect_height(&pf) > 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_THUMB ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg,
&CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
}
}
static void
_mui_scrollbar_scroll(
mui_control_t * c,
int32_t delta )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
int32_t v = (int32_t)c->value + delta;
if (v < 0)
v = 0;
if (v > ((int32_t)sb->max - (int32_t)sb->visible))
v = sb->max - sb->visible;
c->value = v;
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
}
static bool
mui_scrollbar_mouse(
struct mui_control_t * c,
mui_event_t * ev)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
c2_rect_t parts[MUI_SB_PART_COUNT];
mui_scrollbar_make_rects(c, parts);
switch (ev->type) {
case MUI_EVENT_BUTTONDOWN: {
for (int i = 1; i < MUI_SB_PART_COUNT; ++i) {
if (c2_rect_contains_pt(&parts[i], &ev->mouse.where)) {
c->flags.hit_part = i;
sb->drag_offset.x =
ev->mouse.where.x - parts[i].l;
sb->drag_offset.y =
ev->mouse.where.y - parts[i].t;
sb->saved_value = c->value;
break;
}
}
int part = c->flags.hit_part % MUI_SB_PART_COUNT;
switch (part) {
case MUI_SB_PART_DOWN:
case MUI_SB_PART_UP: {
_mui_scrollbar_scroll(c,
part == MUI_SB_PART_UP ? -30 : 30);
} break;
case MUI_SB_PART_PAGEUP:
case MUI_SB_PART_PAGEDOWN: {
int32_t offset = sb->visible;
_mui_scrollbar_scroll(c,
part == MUI_SB_PART_PAGEUP ?
-offset : offset);
} break;
case MUI_SB_PART_THUMB:
mui_control_inval(c);
break;
}
// printf("%s hit part %d\n", __func__, c->flags.hit_part);
} break;
case MUI_EVENT_DRAG: {
if (!c->flags.hit_part)
break;
int part = c->flags.hit_part % MUI_SB_PART_COUNT;
c2_rect_t test_rect = parts[part];
if (part == MUI_SB_PART_THUMB)
c2_rect_inset(&test_rect, -60, -60);
if (c2_rect_contains_pt(&test_rect, &ev->mouse.where)) {
c->flags.hit_part = part;
switch (part) {
case MUI_SB_PART_THUMB: {
c2_rect_t nt = parts[part];
c2_rect_offset(&nt, 0,
-(nt.t + parts[MUI_SB_PART_UP].b) +
ev->mouse.where.y - sb->drag_offset.y);
// printf("%s thumb %s\n", __func__, c2_rect_as_str(&nt));
if (nt.t < 0)
c2_rect_offset(&nt, 0, -nt.t);
if (nt.b > parts[MUI_SB_PART_DOWN].t)
c2_rect_offset(&nt, 0, parts[MUI_SB_PART_DOWN].t - nt.b);
int max_pixels = parts[MUI_SB_PART_DOWN].t -
parts[MUI_SB_PART_UP].b -
c2_rect_height(&nt);
uint32_t nv = nt.t * (sb->max - sb->visible) / max_pixels;
if (nv > (sb->max - sb->visible))
nv = sb->max - sb->visible;
c->value = nv;
// printf("v is %d vs %d max %d = %d new val %d\n",
// nt.t, max_pixels, sb->max, nv,
// mui_control_get_value(c));
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
} break;
}
} else {
c->flags.hit_part = part + MUI_SB_PART_COUNT;
if (part == MUI_SB_PART_THUMB) {
c->value = sb->saved_value;
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
}
}
} break;
case MUI_EVENT_BUTTONUP: {
if (!c->flags.hit_part)
break;
mui_control_inval(c);
c->flags.hit_part = 0;
} break;
}
return true;
}
static bool
mui_cdef_scrollbar(
struct mui_control_t * c,
uint8_t what,
void * param)
{
switch (what) {
case MUI_CDEF_INIT:
break;
case MUI_CDEF_DISPOSE:
break;
case MUI_CDEF_DRAW: {
mui_drawable_t * dr = param;
mui_scrollbar_draw(c->win, c, dr);
} break;
case MUI_CDEF_EVENT: {
// printf("%s event\n", __func__);
mui_event_t *ev = param;
switch (ev->type) {
case MUI_EVENT_BUTTONUP:
case MUI_EVENT_DRAG:
case MUI_EVENT_BUTTONDOWN: {
return mui_scrollbar_mouse(c, ev);
} break;
}
} break;
}
return false;
}
uint32_t
mui_scrollbar_get_max(
mui_control_t * c)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
return sb->max;
}
void
mui_scrollbar_set_max(
mui_control_t * c,
uint32_t max)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
sb->max = max;
mui_control_inval(c);
}
void
mui_scrollbar_set_page(
mui_control_t * c,
uint32_t page)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
sb->visible = page;
mui_control_inval(c);
}
mui_control_t *
mui_scrollbar_new(
mui_window_t * win,
c2_rect_t frame,
uint32_t uid )
{
return mui_control_new(
win, MUI_CONTROL_SCROLLBAR, mui_cdef_scrollbar,
frame, NULL, uid,
sizeof(mui_scrollbar_control_t));
}

View File

@ -1,5 +1,5 @@
/* /*
* mui_playground.c * mui_shell.c
* *
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com> * Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
* *
@ -9,18 +9,22 @@
#define MUI_HAS_XKB 1 #define MUI_HAS_XKB 1
#if MUI_HAS_XCB #if MUI_HAS_XCB
#include <sys/stat.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <libgen.h> #include <libgen.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <sys/ipc.h> #include <sys/ipc.h>
#include <sys/shm.h> #include <sys/shm.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/shm.h> #include <xcb/shm.h>
#include <xcb/xcb_image.h> #include <xcb/xcb_image.h>
#include <xcb/randr.h> //#include <xcb/randr.h>
#if MUI_HAS_XKB #if MUI_HAS_XKB
#include <xcb/xkb.h> #include <xcb/xkb.h>
@ -32,7 +36,7 @@ struct xkb_state;
#endif #endif
#include "mui.h" #include "mui.h"
#include "mui_plugin.h" #include "mui_shell_plugin.h"
@ -44,10 +48,11 @@ typedef struct mui_xcb_t {
float ui_scale_x, ui_scale_y; float ui_scale_x, ui_scale_y;
c2_pt_t size; c2_pt_t size;
xcb_connection_t * xcb; xcb_connection_t * xcb;
xcb_image_t * xcb_image; // if no shared memory
xcb_shm_segment_info_t shm; xcb_shm_segment_info_t shm;
xcb_window_t window; xcb_window_t window;
xcb_pixmap_t xcb_pix; xcb_pixmap_t xcb_pix;
xcb_gcontext_t xcb_context; xcb_gcontext_t xcb_win_gc;
struct xkb_state * xkb_state; struct xkb_state * xkb_state;
int redraw; int redraw;
@ -133,72 +138,6 @@ _mui_xcb_convert_keycode(
return true; return true;
} }
int
mui_xcb_list_physical_screens(
struct xcb_connection_t * xcb,
struct c2_rect_array_t *out)
{
if (!xcb || !out)
return -1;
c2_rect_array_clear(out);
xcb_screen_t *screen = xcb_setup_roots_iterator(
xcb_get_setup(xcb)).data;
xcb_randr_get_screen_resources_current_reply_t *reply =
xcb_randr_get_screen_resources_current_reply(
xcb,
xcb_randr_get_screen_resources_current(
xcb, screen->root),
NULL);
xcb_timestamp_t timestamp = reply->config_timestamp;
int len = xcb_randr_get_screen_resources_current_outputs_length(reply);
xcb_randr_output_t *randr_outputs =
xcb_randr_get_screen_resources_current_outputs(reply);
for (int i = 0; i < len; i++) {
xcb_randr_get_output_info_reply_t *output =
xcb_randr_get_output_info_reply(
xcb,
xcb_randr_get_output_info(
xcb, randr_outputs[i], timestamp),
NULL);
if (!output || output->crtc == XCB_NONE ||
output->connection == XCB_RANDR_CONNECTION_DISCONNECTED)
continue;
xcb_randr_get_crtc_info_reply_t *crtc =
xcb_randr_get_crtc_info_reply(xcb,
xcb_randr_get_crtc_info(
xcb, output->crtc, timestamp),
NULL);
c2_rect_t r = C2_RECT(crtc->x, crtc->y,
crtc->x +crtc->width, crtc->y + crtc->height);
c2_rect_array_add(out, r);
free(crtc);
free(output);
}
free(reply);
return 0;
}
static bool
_mui_match_physical_screen(
xcb_connection_t *xcb,
c2_pt_t want_size,
c2_pt_p found_pos )
{
bool res = false;
c2_rect_array_t sc = {};
mui_xcb_list_physical_screens(xcb, &sc);
for (uint i = 0; i < sc.count; i++) {
if (c2_rect_width(&sc.e[i]) == want_size.x &&
c2_rect_height(&sc.e[i]) == want_size.y) {
*found_pos = sc.e[i].tl;
res = true;
}
}
return res;
}
struct mui_t * struct mui_t *
mui_xcb_init( mui_xcb_init(
struct mui_t *mui, struct mui_t *mui,
@ -222,12 +161,6 @@ mui_xcb_init(
ui->xcb = xcb_connect(NULL, NULL); ui->xcb = xcb_connect(NULL, NULL);
bool windowed = 1;
bool opaque = 1;
c2_pt_t found_position = {};
bool has_position = !windowed && _mui_match_physical_screen(
ui->xcb, ui->size, &found_position);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator( xcb_screen_iterator_t iter = xcb_setup_roots_iterator(
xcb_get_setup(ui->xcb)); xcb_get_setup(ui->xcb));
printf("%s %d screens\n", __func__, iter.rem); printf("%s %d screens\n", __func__, iter.rem);
@ -241,46 +174,19 @@ mui_xcb_init(
} }
printf("XCB Screen depth %d\n", screen->root_depth); printf("XCB Screen depth %d\n", screen->root_depth);
/*
* This walks thru the 'visual', looking for a true colour *32 bits* one
* which means it handles ARGB colors, which we can draw into. Also find
* one which color bit masks matches libcui & libpixman.
*/
xcb_visualtype_t *argb_visual = NULL;
xcb_depth_iterator_t depth_iter =
xcb_screen_allowed_depths_iterator(screen);
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
xcb_visualtype_iterator_t visual_iter =
xcb_depth_visuals_iterator(depth_iter.data);
// printf("XCB Depth %d\n", depth_iter.data->depth);
if (depth_iter.data->depth != 32)
continue;
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR
&& visual_iter.data->red_mask == 0xff0000
&& visual_iter.data->green_mask == 0x00ff00
&& visual_iter.data->blue_mask == 0x0000ff) {
argb_visual = visual_iter.data;
break;
}
}
}
printf("XCB ARGB Transparency %s\n",
argb_visual ? "Supported" : "Not available");
if (windowed || opaque)
argb_visual = NULL;
xcb_shm_query_version_reply_t *xcb_shm_present; xcb_shm_query_version_reply_t *xcb_shm_present;
xcb_shm_present = xcb_shm_query_version_reply( xcb_shm_present = xcb_shm_query_version_reply(
ui->xcb, xcb_shm_query_version(ui->xcb), NULL); ui->xcb, xcb_shm_query_version(ui->xcb), NULL);
bool slow_path = false;
if (!xcb_shm_present || !xcb_shm_present->shared_pixmaps) { if (!xcb_shm_present || !xcb_shm_present->shared_pixmaps) {
printf("xcb_shm error... %p\n", xcb_shm_present); printf("xcb_shm error... %p\n", xcb_shm_present);
printf("If using nvidia driver, you need\n" printf("If using nvidia driver, you need\n"
" Option \"AllowSHMPixmaps\" \"1\"\n" " Option \"AllowSHMPixmaps\" \"1\"\n"
" In your /etc/X11/xorg.conf file\n"); " In your /etc/X11/xorg.conf file\n");
exit(0); slow_path = true;
} // exit(0);
printf("XCB Shared memory present\n"); } else
printf("XCB Shared memory present\n");
_mui_xcb_init_keyboard(ui); _mui_xcb_init_keyboard(ui);
@ -290,19 +196,14 @@ mui_xcb_init(
XCB_CW_EVENT_MASK; XCB_CW_EVENT_MASK;
xcb_colormap_t cmap = xcb_generate_id(ui->xcb); xcb_colormap_t cmap = xcb_generate_id(ui->xcb);
/* required for having transparent windows */
if (argb_visual) {
xcb_create_colormap(ui->xcb, XCB_COLORMAP_ALLOC_NONE, cmap,
screen->root, argb_visual->visual_id);
value_mask |= XCB_CW_COLORMAP;
}
uint32_t w_mask[] = { uint32_t w_mask[] = {
screen->black_pixel, screen->black_pixel,
// Border Pixel; not really needed for anything, but needed // Border Pixel; not really needed for anything, but needed
// for ARGB window otherwise it doesn't get created properly // for ARGB window otherwise it doesn't get created properly
0x88888888, 0x88888888,
// if we found a screen of the exact size, remove the border // if we found a screen of the exact size, remove the border
has_position ? 1 : 0, 0,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
@ -312,12 +213,12 @@ mui_xcb_init(
ui->window = xcb_generate_id(ui->xcb); ui->window = xcb_generate_id(ui->xcb);
xcb_create_window( xcb_create_window(
ui->xcb, ui->xcb,
argb_visual ? 32 : XCB_COPY_FROM_PARENT, XCB_COPY_FROM_PARENT,
ui->window, screen->root, ui->window, screen->root,
found_position.x, found_position.y, 0,0,
pix->size.x, pix->size.y, 0, pix->size.x, pix->size.y, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_INPUT_OUTPUT,
argb_visual ? argb_visual->visual_id : screen->root_visual, screen->root_visual,
value_mask, w_mask); value_mask, w_mask);
xcb_free_colormap(ui->xcb, cmap); xcb_free_colormap(ui->xcb, cmap);
@ -329,29 +230,62 @@ mui_xcb_init(
value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
value_list[0] = screen->white_pixel; value_list[0] = screen->white_pixel;
value_list[1] = 0; value_list[1] = 0;
ui->xcb_context = xcb_generate_id(ui->xcb); ui->xcb_win_gc = xcb_generate_id(ui->xcb);
xcb_create_gc( xcb_create_gc(
ui->xcb, ui->xcb_context, ui->window, value_mask, value_list); ui->xcb, ui->xcb_win_gc, ui->window, value_mask, value_list);
// map the window onto the screen // map the window onto the screen
xcb_map_window(ui->xcb, ui->window); xcb_map_window(ui->xcb, ui->window);
// wont show unless I do this // wont show unless I do this
xcb_flush(ui->xcb); xcb_flush(ui->xcb);
ui->shm.shmid = shmget(IPC_PRIVATE,
pix->size.x * pix->size.y * 4, IPC_CREAT | 0777);
ui->shm.shmaddr = shmat(ui->shm.shmid, 0, 0);
ui->shm.shmseg = xcb_generate_id(ui->xcb);
xcb_shm_attach(ui->xcb, ui->shm.shmseg, ui->shm.shmid, 0);
shmctl(ui->shm.shmid, IPC_RMID, 0);
ui->xcb_pix = xcb_generate_id(ui->xcb); if (!slow_path) {
xcb_shm_create_pixmap( xcb_generic_error_t *error;
ui->xcb, ui->xcb_pix, ui->window, xcb_void_cookie_t cook;
pix->size.x, pix->size.y, ui->shm.shmid = shmget(IPC_PRIVATE,
argb_visual ? 32 : screen->root_depth, pix->size.x * pix->size.y * 4, IPC_CREAT | 0666);
ui->shm.shmseg, 0); ui->shm.shmaddr = shmat(ui->shm.shmid, 0, 0);
ui->shm.shmseg = xcb_generate_id(ui->xcb);
cook = xcb_shm_attach_checked(ui->xcb, ui->shm.shmseg, ui->shm.shmid, 0);
error = xcb_request_check(ui->xcb, cook);
if (error) {
fprintf(stderr, "XCB: Error xcb_shm_attach_checked: %d\n",
error->error_code);
free(error);
// xcb_disconnect(ui->xcb);
// return 1;
}
shmctl(ui->shm.shmid, IPC_RMID, 0);
pix->pixels = ui->shm.shmaddr; ui->xcb_pix = xcb_generate_id(ui->xcb);
pix->row_bytes = pix->size.x * 4; cook = xcb_shm_create_pixmap_checked(
ui->xcb, ui->xcb_pix, ui->window,
pix->size.x, pix->size.y,
screen->root_depth,
ui->shm.shmseg, 0);
error = xcb_request_check(ui->xcb, cook);
if (error) {
fprintf(stderr, "XCB: Error xcb_shm_create_pixmap: %d\n",
error->error_code);
free(error);
} else
pix->pixels = ui->shm.shmaddr;
pix->row_bytes = pix->size.x * 4;
}
if (!pix->pixels) {
printf("XCB: Not using SHM, slow path\n");
pix->pixels = malloc(pix->size.x * pix->size.y * 4);
ui->xcb_pix = xcb_generate_id(ui->xcb);
xcb_create_pixmap(
ui->xcb, screen->root_depth, ui->xcb_pix, ui->window,
pix->size.x, pix->size.y);
ui->xcb_image = xcb_image_create_native(
ui->xcb, pix->size.x, pix->size.y, XCB_IMAGE_FORMAT_Z_PIXMAP,
screen->root_depth, pix->pixels,
pix->size.x * pix->size.y * 4, pix->pixels);
pix->row_bytes = pix->size.x * 4;
}
xcb_flush(ui->xcb);
// printf("%s pix is %p\n", __func__, pix->pixels); // printf("%s pix is %p\n", __func__, pix->pixels);
ui->redraw = 1; ui->redraw = 1;
return &ui->ui; return &ui->ui;
@ -380,6 +314,7 @@ mui_read_clipboard(
int int
mui_xcb_poll( mui_xcb_poll(
struct mui_t * mui, struct mui_t * mui,
mui_drawable_t * dr,
bool redrawn) bool redrawn)
{ {
mui_xcb_t * ui = (mui_xcb_t *)mui; mui_xcb_t * ui = (mui_xcb_t *)mui;
@ -421,7 +356,7 @@ mui_xcb_poll(
ui->xkb_state, key->detail); ui->xkb_state, key->detail);
key_ev.type = MUI_EVENT_KEYDOWN; key_ev.type = MUI_EVENT_KEYDOWN;
key_ev.key.up = 0; key_ev.key.up = 0;
printf("%s %08x\n", __func__, keysym); // printf("%s %08x\n", __func__, keysym);
if (_mui_xcb_convert_keycode(ui, keysym, &key_ev)) { if (_mui_xcb_convert_keycode(ui, keysym, &key_ev)) {
if (key_ev.key.key >= MUI_KEY_MODIFIERS && if (key_ev.key.key >= MUI_KEY_MODIFIERS &&
key_ev.key.key <= MUI_KEY_MODIFIERS_LAST) { key_ev.key.key <= MUI_KEY_MODIFIERS_LAST) {
@ -504,7 +439,12 @@ mui_xcb_poll(
break; break;
case XCB_EXPOSE: { case XCB_EXPOSE: {
// xcb_expose_event_t *expose_event = (xcb_expose_event_t*) event; // xcb_expose_event_t *expose_event = (xcb_expose_event_t*) event;
ui->redraw++; // ui->redraw++;
xcb_expose_event_t *x = (xcb_expose_event_t*) event;
xcb_copy_area(
ui->xcb, ui->xcb_pix,
ui->window, ui->xcb_win_gc,
x->x, x->y, x->x, x->y, x->width, x->height);
} break; } break;
default: default:
// Handle other events // Handle other events
@ -526,10 +466,24 @@ mui_xcb_poll(
// printf("XCB: %d rects to redraw\n", rc); // printf("XCB: %d rects to redraw\n", rc);
for (int i = 0; i < rc; i++) { for (int i = 0; i < rc; i++) {
c2_rect_t r = ra[i]; c2_rect_t r = ra[i];
// printf("XCB: %d,%d %dx%d\n", r.l, r.t, c2_rect_width(&r), c2_rect_height(&r)); // printf("XCB: %d,%d %dx%d\n", r.l, r.t, c2_rect_width(&r), c2_rect_height(&r));
// cannot update the exact rectangle, just window-wide strips
if (ui->xcb_image) {
mui_pixmap_t * pix = &dr->pix;
xcb_put_image(
ui->xcb, XCB_IMAGE_FORMAT_Z_PIXMAP,
ui->xcb_pix, ui->xcb_win_gc,
pix->size.x, c2_rect_height(&r),
0, r.t, 0, 24,
c2_rect_height(&r) * pix->row_bytes,
(uint8_t*)pix->pixels + (r.t * pix->row_bytes) /*+ r.l * 4*/);
}
xcb_copy_area( xcb_copy_area(
ui->xcb, ui->xcb_pix, ui->window, ui->xcb_context, ui->xcb, ui->xcb_pix,
r.l, r.t, r.l, r.t, c2_rect_width(&r), c2_rect_height(&r)); ui->window, ui->xcb_win_gc,
r.l, r.t, r.l, r.t,
c2_rect_width(&r), c2_rect_height(&r));
} }
} }
pixman_region32_clear(&mui->redraw); pixman_region32_clear(&mui->redraw);
@ -552,15 +506,29 @@ mui_xcb_terminate(
#endif #endif
#include <sys/types.h> int
#include <sys/stat.h> main(
#include <unistd.h> int argc,
#include <fcntl.h> const char * argv[])
#include <stdio.h>
#include <dlfcn.h>
int main()
{ {
const char * filename = NULL;// "build-x86_64-linux-gnu/lib/ui_tests.so";
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'f':
filename = argv[++i];
break;
}
} else {
filename = argv[i];
}
}
if (!filename) {
fprintf(stderr, "Usage: %s -f <filename>\n", basename((char*)argv[0]));
return 1;
}
mui_xcb_t xcb_ui = {}; mui_xcb_t xcb_ui = {};
mui_drawable_t dr = {}; mui_drawable_t dr = {};
@ -570,7 +538,6 @@ int main()
mui_t *mui = mui_xcb_init((struct mui_t *)&xcb_ui, &dr.pix); mui_t *mui = mui_xcb_init((struct mui_t *)&xcb_ui, &dr.pix);
mui_xcb_t * ui = &xcb_ui; mui_xcb_t * ui = &xcb_ui;
void * dynload = NULL; void * dynload = NULL;
char * filename = "build-x86_64-linux-gnu/lib/ui_tests.so";
struct stat st_current = {}, st = {}; struct stat st_current = {}, st = {};
mui_time_t stamp = 0; mui_time_t stamp = 0;
@ -621,7 +588,7 @@ int main()
mui_run(mui); mui_run(mui);
if (ui->plug && ui->plug->draw) if (ui->plug && ui->plug->draw)
draw = ui->plug->draw(mui, ui->plug_data, &dr, false); draw = ui->plug->draw(mui, ui->plug_data, &dr, false);
if (mui_xcb_poll(mui, draw)) if (mui_xcb_poll(mui, &dr, draw))
break; break;
mui_time_t now = mui_get_time(); mui_time_t now = mui_get_time();
while (stamp < now) while (stamp < now)
@ -642,4 +609,4 @@ int main()
mui_drawable_dispose(&dr); mui_drawable_dispose(&dr);
mui_xcb_terminate(mui); mui_xcb_terminate(mui);
return 0; return 0;
} }

View File

@ -0,0 +1,42 @@
/*
* mui_shell_plugin.h
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
/*
* Quck and dirty plugin interface for mui_shell, just allows a quick reload
* of a plugin without having to restart the whole shell.
* In combination with 'make watch' you have have 1s turnaround time for
* your plugin development, helps a ton when tweaking a dialog etc.
*/
struct mui_t;
struct mui_drawable_t;
typedef struct mui_plug_t {
const char * name; // 'Human' name of the plugin
const uint32_t * icon; // optional
// return a 'handle' to some data for this plugin.
void * (*init)(
struct mui_t * ui,
struct mui_plug_t * plug,
struct mui_drawable_t * dr );
void (*dispose)(
void * plug );
int (*draw)(
struct mui_t * ui,
void * plug,
struct mui_drawable_t * dr,
uint16_t all );
int (*event)(
struct mui_t * ui,
void * plug,
struct mui_event_t * event );
} mui_plug_t;

View File

@ -298,7 +298,7 @@ c2_polyline_clear(
int int
c2_polyline_get_segment( c2_polyline_get_segment(
c2_polyline_p pl, c2_polyline_p pl,
long ind, unsigned long ind,
c2_segment_p o ) c2_segment_p o )
{ {
if (ind > pl->pt.count) if (ind > pl->pt.count)
@ -444,7 +444,7 @@ c2_polyline_array_clip(
c2_rect_p clip, c2_rect_p clip,
c2_polyline_array_p outPoly ) c2_polyline_array_p outPoly )
{ {
for (long poly = 0; poly < pa->count; poly++) { for (unsigned long poly = 0; poly < pa->count; poly++) {
c2_polyline_t *p = pa->e[poly]; c2_polyline_t *p = pa->e[poly];
if (!p) if (!p)
break; break;

View File

@ -32,7 +32,7 @@ c2_polyline_clear(
int int
c2_polyline_get_segment( c2_polyline_get_segment(
c2_polyline_p pl, c2_polyline_p pl,
long ind, unsigned long ind,
c2_segment_p o ); c2_segment_p o );
void void

View File

@ -27,6 +27,22 @@
#include "cg.h" #include "cg.h"
// make this optional on darwin, where the is no weak linking
#if defined(__APPLE__) && defined(__MACH__)
#define CG_WEAK_LINKING 0
#else
#define CG_WEAK_LINKING 1
#endif
#if CG_WEAK_LINKING
#define _cg_stringify(_a) #_a
#define _cg_und(_b) _cg_stringify(__ ## _b)
#define cg_weak_alias(_name) \
extern __typeof(__##_name) _name __attribute__((weak, alias(_cg_und(_name))))
#else
#define cg_weak_alias(_name)
#endif
#define cg_array_init(array) \ #define cg_array_init(array) \
do { \ do { \
array.data = NULL; \ array.data = NULL; \
@ -1431,12 +1447,36 @@ static inline uint32_t interpolate_pixel(uint32_t x, uint32_t a, uint32_t y, uin
return x; return x;
} }
#if defined(__AVX2__)
typedef uint32_t u32_v __attribute__((vector_size(32)));
#define VEC_ALIGN 31
#define VEC_ECOUNT 8
#else
typedef uint32_t u32_v __attribute__((vector_size(16)));
#define VEC_ALIGN 15
#define VEC_ECOUNT 4
#endif
static void __cg_memfill32(uint32_t * dst, uint32_t val, int len) static void __cg_memfill32(uint32_t * dst, uint32_t val, int len)
{ {
for(int i = 0; i < len; i++) // use extensions to do the first part, as long as it is aligned properly
dst[i] = val; while (len > 0 && ((uintptr_t)dst & VEC_ALIGN)) {
*dst++ = val;
len--;
}
u32_v v = val - (u32_v){};
while (len >= VEC_ECOUNT) {
*(u32_v *)dst = v;
dst += VEC_ECOUNT; len -= VEC_ECOUNT;
}
// do the last part
while (len > 0) {
*dst++ = val;
len--;
}
} }
extern __typeof(__cg_memfill32) cg_memfill32 __attribute__((weak, alias("__cg_memfill32"))); cg_weak_alias(cg_memfill32);
static inline int gradient_clamp(struct cg_gradient_data_t * gradient, int ipos) static inline int gradient_clamp(struct cg_gradient_data_t * gradient, int ipos)
{ {
@ -1615,7 +1655,7 @@ static void __cg_comp_solid_source(uint32_t * dst, int len, uint32_t color, uint
dst[i] = color + CG_BYTE_MUL(dst[i], ialpha); dst[i] = color + CG_BYTE_MUL(dst[i], ialpha);
} }
} }
extern __typeof(__cg_comp_solid_source) cg_comp_solid_source __attribute__((weak, alias("__cg_comp_solid_source"))); cg_weak_alias(cg_comp_solid_source);
static void __cg_comp_solid_source_over(uint32_t * dst, int len, uint32_t color, uint32_t alpha) static void __cg_comp_solid_source_over(uint32_t * dst, int len, uint32_t color, uint32_t alpha)
{ {
@ -1632,7 +1672,7 @@ static void __cg_comp_solid_source_over(uint32_t * dst, int len, uint32_t color,
dst[i] = color + CG_BYTE_MUL(dst[i], ialpha); dst[i] = color + CG_BYTE_MUL(dst[i], ialpha);
} }
} }
extern __typeof(__cg_comp_solid_source_over) cg_comp_solid_source_over __attribute__((weak, alias("__cg_comp_solid_source_over"))); cg_weak_alias(cg_comp_solid_source_over);
static void __cg_comp_solid_destination_in(uint32_t * dst, int len, uint32_t color, uint32_t alpha) static void __cg_comp_solid_destination_in(uint32_t * dst, int len, uint32_t color, uint32_t alpha)
{ {
@ -1642,7 +1682,7 @@ static void __cg_comp_solid_destination_in(uint32_t * dst, int len, uint32_t col
for(int i = 0; i < len; i++) for(int i = 0; i < len; i++)
dst[i] = CG_BYTE_MUL(dst[i], a); dst[i] = CG_BYTE_MUL(dst[i], a);
} }
extern __typeof(__cg_comp_solid_destination_in) cg_comp_solid_destination_in __attribute__((weak, alias("__cg_comp_solid_destination_in"))); cg_weak_alias(cg_comp_solid_destination_in);
static void __cg_comp_solid_destination_out(uint32_t * dst, int len, uint32_t color, uint32_t alpha) static void __cg_comp_solid_destination_out(uint32_t * dst, int len, uint32_t color, uint32_t alpha)
{ {
@ -1652,7 +1692,7 @@ static void __cg_comp_solid_destination_out(uint32_t * dst, int len, uint32_t co
for(int i = 0; i < len; i++) for(int i = 0; i < len; i++)
dst[i] = CG_BYTE_MUL(dst[i], a); dst[i] = CG_BYTE_MUL(dst[i], a);
} }
extern __typeof(__cg_comp_solid_destination_out) cg_comp_solid_destination_out __attribute__((weak, alias("__cg_comp_solid_destination_out"))); cg_weak_alias(cg_comp_solid_destination_out);
static void __cg_comp_source(uint32_t * dst, int len, uint32_t * src, uint32_t alpha) static void __cg_comp_source(uint32_t * dst, int len, uint32_t * src, uint32_t alpha)
{ {
@ -1667,7 +1707,7 @@ static void __cg_comp_source(uint32_t * dst, int len, uint32_t * src, uint32_t a
dst[i] = interpolate_pixel(src[i], alpha, dst[i], ialpha); dst[i] = interpolate_pixel(src[i], alpha, dst[i], ialpha);
} }
} }
extern __typeof(__cg_comp_source) cg_comp_source __attribute__((weak, alias("__cg_comp_source"))); cg_weak_alias(cg_comp_source);
static void __cg_comp_source_over(uint32_t * dst, int len, uint32_t * src, uint32_t alpha) static void __cg_comp_source_over(uint32_t * dst, int len, uint32_t * src, uint32_t alpha)
{ {
@ -1696,7 +1736,7 @@ static void __cg_comp_source_over(uint32_t * dst, int len, uint32_t * src, uint3
} }
} }
} }
extern __typeof(__cg_comp_source_over) cg_comp_source_over __attribute__((weak, alias("__cg_comp_source_over"))); cg_weak_alias(cg_comp_source_over);
static void __cg_comp_destination_in(uint32_t * dst, int len, uint32_t * src, uint32_t alpha) static void __cg_comp_destination_in(uint32_t * dst, int len, uint32_t * src, uint32_t alpha)
{ {
@ -1716,7 +1756,7 @@ static void __cg_comp_destination_in(uint32_t * dst, int len, uint32_t * src, ui
} }
} }
} }
extern __typeof(__cg_comp_destination_in) cg_comp_destination_in __attribute__((weak, alias("__cg_comp_destination_in"))); cg_weak_alias(cg_comp_destination_in);
static void __cg_comp_destination_out(uint32_t * dst, int len, uint32_t * src, uint32_t alpha) static void __cg_comp_destination_out(uint32_t * dst, int len, uint32_t * src, uint32_t alpha)
{ {
@ -1736,7 +1776,7 @@ static void __cg_comp_destination_out(uint32_t * dst, int len, uint32_t * src, u
} }
} }
} }
extern __typeof(__cg_comp_destination_out) cg_comp_destination_out __attribute__((weak, alias("__cg_comp_destination_out"))); cg_weak_alias(cg_comp_destination_out);
typedef void (*cg_comp_solid_function_t)(uint32_t * dst, int len, uint32_t color, uint32_t alpha); typedef void (*cg_comp_solid_function_t)(uint32_t * dst, int len, uint32_t color, uint32_t alpha);
static const cg_comp_solid_function_t cg_comp_solid_map[] = { static const cg_comp_solid_function_t cg_comp_solid_map[] = {

View File

@ -178,29 +178,34 @@ mui_handle_event(
break; break;
} else { } else {
/* We can't use the REVERSE_SAFE macro here, as the window /* We can't use the REVERSE_SAFE macro here, as the window
* list can change quite a bit, especially when menus are involved*/ * list can change quite a bit, especially when menus are
mui_window_t *w, *prev; * involved */
mui_window_t *w;
w = TAILQ_LAST(&ui->windows, windows); w = TAILQ_LAST(&ui->windows, windows);
while (w) { int done = 0;
while (w && !done) {
mui_window_lock(w); mui_window_lock(w);
int done = 0; // in case 'prev' gets deleted, keep a ref on it.
mui_window_ref_t prev = {};
mui_window_ref(&prev, TAILQ_PREV(w, windows, self),
FCC('H', 'O', 'L', 'D'));
if ((res = mui_window_handle_mouse(w, ev))) { if ((res = mui_window_handle_mouse(w, ev))) {
if (ev->modifiers & MUI_MODIFIER_EVENT_TRACE) if (ev->modifiers & MUI_MODIFIER_EVENT_TRACE)
printf(" window:%s handled it\n", printf(" window:%s handled it\n",
w->title); w->title);
done = 1; done = 1;
} }
prev = TAILQ_PREV(w, windows, self); mui_window_unlock(w); // COULD delete window here
mui_window_unlock(w); w = prev.window; // this might have been NULLed
if (done) mui_window_deref(&prev);
break;
w = prev;
} }
} }
if (ev->modifiers & MUI_MODIFIER_EVENT_TRACE) if (ev->modifiers & MUI_MODIFIER_EVENT_TRACE)
if (!res) if (!res)
printf(" no window handled it\n"); printf(" no window handled it\n");
} break; } break;
default:
break;
} }
return res; return res;
} }
@ -236,7 +241,7 @@ mui_event_match_key(
return true; return true;
} }
uint8_t mui_timer_id_t
mui_timer_register( mui_timer_register(
mui_t *ui, mui_t *ui,
mui_timer_p cb, mui_timer_p cb,
@ -245,21 +250,21 @@ mui_timer_register(
{ {
if (ui->timer.map == (uint64_t)-1L) { if (ui->timer.map == (uint64_t)-1L) {
fprintf(stderr, "%s ran out of timers\n", __func__); fprintf(stderr, "%s ran out of timers\n", __func__);
return -1; return MUI_TIMER_NONE;
} }
//printf("%s: delay %d\n", __func__, delay); mui_timer_id_t ti = __builtin_ffsl(~ui->timer.map) - 1;
int ti = ffsl(~ui->timer.map) - 1; // printf("%s:%d delay %d\n", __func__, ti, delay);
ui->timer.map |= 1 << ti; ui->timer.map |= 1 << ti;
ui->timer.timers[ti].cb = cb; ui->timer.timers[ti].cb = cb;
ui->timer.timers[ti].param = param; ui->timer.timers[ti].param = param;
ui->timer.timers[ti].when = mui_get_time() + delay; ui->timer.timers[ti].when = mui_get_time() + delay;
return 0; return ti;
} }
mui_time_t mui_time_t
mui_timer_reset( mui_timer_reset(
struct mui_t * ui, struct mui_t * ui,
uint8_t id, mui_timer_id_t id,
mui_timer_p cb, mui_timer_p cb,
mui_time_t delay) mui_time_t delay)
{ {
@ -267,7 +272,7 @@ mui_timer_reset(
return 0; return 0;
if (!(ui->timer.map & (1L << id)) || if (!(ui->timer.map & (1L << id)) ||
ui->timer.timers[id].cb != cb) { ui->timer.timers[id].cb != cb) {
// printf("%s: timer %d not active\n", __func__, id); // printf("%s:%d not active\n", __func__, id);
return 0; return 0;
} }
mui_time_t res = 0; mui_time_t res = 0;
@ -277,7 +282,7 @@ mui_timer_reset(
ui->timer.timers[id].when = now + delay; ui->timer.timers[id].when = now + delay;
if (delay == 0) { if (delay == 0) {
ui->timer.map &= ~(1L << id); ui->timer.map &= ~(1L << id);
// printf("%s: timer %d removed\n", __func__, id); // printf("%s: %d removed\n", __func__, id);
} }
return res; return res;
} }
@ -289,7 +294,7 @@ mui_timers_run(
uint64_t now = mui_get_time(); uint64_t now = mui_get_time();
uint64_t map = ui->timer.map; uint64_t map = ui->timer.map;
while (map) { while (map) {
int ti = ffsl(map) - 1; int ti = __builtin_ffsl(map) - 1;
map &= ~(1 << ti); map &= ~(1 << ti);
if (ui->timer.timers[ti].when > now) if (ui->timer.timers[ti].when > now)
continue; continue;

View File

@ -18,7 +18,11 @@
#include <pixman.h> #include <pixman.h>
#include "c2_arrays.h" #include "c2_arrays.h"
#if 0 #ifdef __wasm__
typedef unsigned int uint;
#endif
#if 0 // only use to debug queue macros; do not enable
#define _KERNEL #define _KERNEL
#define INVARIANTS #define INVARIANTS
#define QUEUE_MACRO_DEBUG_TRACE #define QUEUE_MACRO_DEBUG_TRACE
@ -38,71 +42,65 @@
* endianess of them makes it a pain to do a printf() with them, this is why * endianess of them makes it a pain to do a printf() with them, this is why
* the values are reversed here. * the values are reversed here.
*/ */
#ifndef FCC #include <ctype.h>
#define FCC(_a,_b,_c,_d) (((_d)<<24)|((_c)<<16)|((_b)<<8)|(_a)) #define FCC(_a,_b,_c,_d) (((_d)<<24)|((_c)<<16)|((_b)<<8)|(_a))
#endif /* These are made to allow FCC to have a numerical index, this is
* mostly used for radio button, menu items and so on */
#define FCC_MASK FCC(0xff,0xff,0xff,0)
/* number of bits to shift to get the fourth character of _fcc */
#define FCC_SHIFT(_fcc) ((_fcc)>>(ffs(~FCC_MASK)-1) & 0xff)
/* extract the index number of a fcc of type abcX where X is '0' - '9' */
#define FCC_INDEX(_fcc) (isdigit(FCC_SHIFT(_fcc)) ? \
((FCC_SHIFT(_fcc)) - '0') : 0)
#define FCC_INDEXED(_fcc, _idx) \
((_fcc & FCC_MASK) | ('0'+((_idx) & 0xff)) << (ffs(~FCC_MASK)-1))
enum mui_event_e { typedef enum mui_event_e {
MUI_EVENT_KEYUP = 0, MUI_EVENT_KEYUP = 0,
MUI_EVENT_KEYDOWN, MUI_EVENT_KEYDOWN,
MUI_EVENT_TEXT, // UTF8 sequence
MUI_EVENT_BUTTONUP, MUI_EVENT_BUTTONUP,
MUI_EVENT_BUTTONDOWN, MUI_EVENT_BUTTONDOWN,
MUI_EVENT_BUTTONDBL, // double click MUI_EVENT_BUTTONDBL, // double click
MUI_EVENT_WHEEL, MUI_EVENT_WHEEL,
MUI_EVENT_DRAG, MUI_EVENT_DRAG,
// the following ones aren't supported yet // the following ones aren't supported yet
MUI_EVENT_TEXT, // UTF8 sequence [TODO]
MUI_EVENT_MOUSEENTER, MUI_EVENT_MOUSEENTER,
MUI_EVENT_MOUSELEAVE, MUI_EVENT_MOUSELEAVE,
MUI_EVENT_RESIZE, MUI_EVENT_RESIZE,
MUI_EVENT_CLOSE, MUI_EVENT_CLOSE,
MUI_EVENT_COUNT, MUI_EVENT_COUNT,
// left, middle, right buttons for clicks // left, middle, right buttons for clicks
MUI_EVENT_BUTTON_MAX = 3, MUI_EVENT_BUTTON_MAX = 3,
}; } mui_event_e;
enum mui_key_e { typedef enum mui_key_e {
// these are ASCII
MUI_KEY_ESCAPE = 0x1b, MUI_KEY_ESCAPE = 0x1b,
MUI_KEY_SPACE = 0x20, MUI_KEY_SPACE = 0x20,
MUI_KEY_RETURN = 0x0d, MUI_KEY_RETURN = 0x0d,
MUI_KEY_TAB = 0x09, MUI_KEY_TAB = 0x09,
MUI_KEY_BACKSPACE = 0x08, MUI_KEY_BACKSPACE = 0x08,
MUI_KEY_LEFT = 0x80, // these are not ASCII
MUI_KEY_UP, MUI_KEY_LEFT = 0x80, MUI_KEY_UP, MUI_KEY_RIGHT, MUI_KEY_DOWN,
MUI_KEY_RIGHT, MUI_KEY_INSERT, MUI_KEY_DELETE,
MUI_KEY_DOWN, MUI_KEY_HOME, MUI_KEY_END,
MUI_KEY_INSERT, MUI_KEY_PAGEUP, MUI_KEY_PAGEDOWN,
MUI_KEY_DELETE,
MUI_KEY_HOME,
MUI_KEY_END,
MUI_KEY_PAGEUP,
MUI_KEY_PAGEDOWN,
MUI_KEY_MODIFIERS = 0x90, MUI_KEY_MODIFIERS = 0x90,
MUI_KEY_LSHIFT = MUI_KEY_MODIFIERS, MUI_KEY_LSHIFT = MUI_KEY_MODIFIERS,
MUI_KEY_RSHIFT, MUI_KEY_RSHIFT,
MUI_KEY_LCTRL, MUI_KEY_LCTRL, MUI_KEY_RCTRL,
MUI_KEY_RCTRL, MUI_KEY_LALT, MUI_KEY_RALT,
MUI_KEY_LALT, MUI_KEY_LSUPER, MUI_KEY_RSUPER,
MUI_KEY_RALT,
MUI_KEY_LSUPER,
MUI_KEY_RSUPER,
MUI_KEY_CAPSLOCK, MUI_KEY_CAPSLOCK,
MUI_KEY_MODIFIERS_LAST, MUI_KEY_MODIFIERS_LAST,
MUI_KEY_F1 = 0x100, MUI_KEY_F1 = 0x100, MUI_KEY_F2, MUI_KEY_F3, MUI_KEY_F4,
MUI_KEY_F2, MUI_KEY_F5, MUI_KEY_F6, MUI_KEY_F7, MUI_KEY_F8,
MUI_KEY_F3, MUI_KEY_F9, MUI_KEY_F10,MUI_KEY_F11,MUI_KEY_F12,
MUI_KEY_F4, } mui_key_e;
MUI_KEY_F5,
MUI_KEY_F6,
MUI_KEY_F7,
MUI_KEY_F8,
MUI_KEY_F9,
MUI_KEY_F10,
MUI_KEY_F11,
MUI_KEY_F12,
};
enum mui_modifier_e { typedef enum mui_modifier_e {
MUI_MODIFIER_LSHIFT = (1 << (MUI_KEY_LSHIFT - MUI_KEY_MODIFIERS)), MUI_MODIFIER_LSHIFT = (1 << (MUI_KEY_LSHIFT - MUI_KEY_MODIFIERS)),
MUI_MODIFIER_RSHIFT = (1 << (MUI_KEY_RSHIFT - MUI_KEY_MODIFIERS)), MUI_MODIFIER_RSHIFT = (1 << (MUI_KEY_RSHIFT - MUI_KEY_MODIFIERS)),
MUI_MODIFIER_LCTRL = (1 << (MUI_KEY_LCTRL - MUI_KEY_MODIFIERS)), MUI_MODIFIER_LCTRL = (1 << (MUI_KEY_LCTRL - MUI_KEY_MODIFIERS)),
@ -118,7 +116,7 @@ enum mui_modifier_e {
MUI_MODIFIER_CTRL = (MUI_MODIFIER_LCTRL | MUI_MODIFIER_RCTRL), MUI_MODIFIER_CTRL = (MUI_MODIFIER_LCTRL | MUI_MODIFIER_RCTRL),
MUI_MODIFIER_ALT = (MUI_MODIFIER_LALT | MUI_MODIFIER_RALT), MUI_MODIFIER_ALT = (MUI_MODIFIER_LALT | MUI_MODIFIER_RALT),
MUI_MODIFIER_SUPER = (MUI_MODIFIER_LSUPER | MUI_MODIFIER_RSUPER), MUI_MODIFIER_SUPER = (MUI_MODIFIER_LSUPER | MUI_MODIFIER_RSUPER),
}; } mui_modifier_e;
/* /*
* The following constants are in UTF8 format, and relate to glyphs in * The following constants are in UTF8 format, and relate to glyphs in
@ -144,8 +142,9 @@ enum mui_modifier_e {
#define MUI_GLYPH_CONTROL "" #define MUI_GLYPH_CONTROL ""
#define MUI_GLYPH_SHIFT "" #define MUI_GLYPH_SHIFT ""
#define MUI_GLYPH_TICK "" // tickmark for menus #define MUI_GLYPH_TICK "" // tickmark for menus
#define MUI_GLYPH_SUBMENU "" // custom, for the hierarchical menus #define MUI_GLYPH_SUBMENU "" // custom, for the hierarchical menus
#define MUI_GLYPH_IIE "" // custom, IIe glyph #define MUI_GLYPH_IIE "" // custom, IIe glyph
#define MUI_GLYPH_POPMARK "▼" // custom, popup menu marker
/* These are also from Charcoal System font (added to the original) */ /* These are also from Charcoal System font (added to the original) */
#define MUI_GLYPH_F1 "" #define MUI_GLYPH_F1 ""
#define MUI_GLYPH_F2 "" #define MUI_GLYPH_F2 ""
@ -177,12 +176,12 @@ typedef uint64_t mui_time_t;
* course, which allows the menu to detect key combos, first. * course, which allows the menu to detect key combos, first.
*/ */
typedef struct mui_event_t { typedef struct mui_event_t {
uint8_t type; mui_event_e type;
mui_time_t when; mui_time_t when;
uint32_t modifiers; mui_modifier_e modifiers;
union { union {
struct key { struct key {
uint32_t key; uint32_t key; // ASCII or mui_key_e
bool up; bool up;
} key; } key;
struct { struct {
@ -222,8 +221,11 @@ typedef union mui_key_equ_t {
(mui_key_equ_t){ .mod = (_mask), .key = (_key) } (mui_key_equ_t){ .mod = (_mask), .key = (_key) }
struct mui_t; struct mui_t;
struct mui_control_t;
struct mui_window_t;
/*
/*!
* References allows arbitrary code to keep a 'handle' on either * References allows arbitrary code to keep a 'handle' on either
* a window or a control. This is used for example to keep track of * a window or a control. This is used for example to keep track of
* the currently focused control. * the currently focused control.
@ -257,6 +259,11 @@ typedef struct mui_ref_t {
mui_deref_p deref; mui_deref_p deref;
} _mui_ref_t; // this is not a 'user' type. } _mui_ref_t; // this is not a 'user' type.
/*
* Window and Control references
* While these two count technically be a union, I've deciced for separate
* types to enforce the type checking.
*/
typedef struct mui_window_ref_t { typedef struct mui_window_ref_t {
_mui_ref_t ref; _mui_ref_t ref;
struct mui_window_t * window; struct mui_window_t * window;
@ -267,7 +274,13 @@ typedef struct mui_control_ref_t {
struct mui_control_t * control; struct mui_control_t * control;
} mui_control_ref_t; } mui_control_ref_t;
// if 'ref' is NULL a new one is allocated, will be freed on deref() /*!
* Initializes a reference to 'control', with the (optional) kind.
* if 'ref' is NULL a new reference is allocated and returned, will be
* freed on deref().
* 'kind' is an optional arbitrary value that can be used to identify
* the reference, it has no meaning to the library.
*/
mui_control_ref_t * mui_control_ref_t *
mui_control_ref( mui_control_ref(
mui_control_ref_t * ref, mui_control_ref_t * ref,
@ -276,7 +289,13 @@ mui_control_ref(
void void
mui_control_deref( mui_control_deref(
mui_control_ref_t * ref); mui_control_ref_t * ref);
// if 'ref' is NULL a new one is allocated, will be freed on deref() /*!
* Initializes a reference to 'window', with the (optional) kind.
* if 'ref' is NULL a new reference is allocated and returned, will be
* freed on deref().
* 'kind' is an optional arbitrary value that can be used to identify
* the reference, it has no meaning to the library.
*/
mui_window_ref_t * mui_window_ref_t *
mui_window_ref( mui_window_ref(
mui_window_ref_t * ref, mui_window_ref_t * ref,
@ -288,7 +307,9 @@ mui_window_deref(
typedef struct mui_listbox_elem_t { typedef struct mui_listbox_elem_t {
uint32_t disabled : 1; uint32_t disabled : 1;
char icon[8]; // currently this is a UTF8 string using the 'icons' font
char icon[8]; // UTF8 icon
// default 'LDEF' is to draw the 'elem' string
void * elem; // char * or... ? void * elem; // char * or... ?
} mui_listbox_elem_t; } mui_listbox_elem_t;
@ -316,39 +337,43 @@ typedef bool (*mui_wdef_p)(
uint8_t what, uint8_t what,
void * param); void * param);
enum mui_cdef_e { enum mui_cdef_e {
MUI_CDEF_INIT = 0, MUI_CDEF_INIT = 0, // param is NULL
MUI_CDEF_DISPOSE, MUI_CDEF_DISPOSE, // param is NULL
MUI_CDEF_DRAW, MUI_CDEF_DRAW, // param is mui_drawable_t*
MUI_CDEF_EVENT, MUI_CDEF_EVENT, // param is mui_event_t*
MUI_CDEF_SET_STATE, MUI_CDEF_SET_STATE, // param is int*
MUI_CDEF_SET_VALUE, MUI_CDEF_SET_VALUE, // param is int*
MUI_CDEF_SET_TITLE, MUI_CDEF_SET_FRAME, // param is c2_rect_t*
MUI_CDEF_SET_TITLE, // param is char * (utf8)
// Used when hot-key is pressed, change control value // Used when hot-key is pressed, change control value
// to simulate a click // to simulate a click
MUI_CDEF_SELECT, MUI_CDEF_SELECT,
// used when a window is selected, to set the focus to the // used when a window is selected, to set the focus to the
// first control that can accept it // first control that can accept it
MUI_CDEF_ACTIVATE, // param is int* with 0,1 MUI_CDEF_FOCUS, // param is int* with 0,1
MUI_CDEF_CAN_FOCUS,// param is NULL, return true or false
}; };
typedef bool (*mui_cdef_p)( typedef bool (*mui_cdef_p)(
struct mui_control_t * c, struct mui_control_t * c,
uint8_t what, uint8_t what,
void * param); void * param);
/* This is currently unused */
typedef void (*mui_ldef_p)( typedef void (*mui_ldef_p)(
struct mui_control_t * c, struct mui_control_t * c,
uint32_t elem_index, uint32_t elem_index,
struct mui_listbox_elem_t * elem); struct mui_listbox_elem_t * elem);
/* /*!
* Timer callback definition. Behaves in a pretty standard way; the timer * Timer callback definition. Behaves in a pretty standard way; the timer
* returns 0 to be cancelled (for one shot timers for example) or return * returns 0 to be cancelled (for one shot timers for example) or return
* the delay to the next call. * the delay to the next call (that will be added to 'now' to get the next)
*/ */
typedef mui_time_t (*mui_timer_p)( typedef mui_time_t (*mui_timer_p)(
struct mui_t * mui, struct mui_t * mui,
mui_time_t now, mui_time_t now,
void * param); void * param);
/* /*!
* Actions are the provided way to add custom response to events for the * Actions are the provided way to add custom response to events for the
* application; action handlers are called for a variety of things, from clicks * application; action handlers are called for a variety of things, from clicks
* in controls, to menu selections, to window close etc. * in controls, to menu selections, to window close etc.
@ -358,7 +383,7 @@ typedef mui_time_t (*mui_timer_p)(
* the 'what' action (hopefully documented with that action constant) * the 'what' action (hopefully documented with that action constant)
* *
* the 'cb_param' is specific to this action function pointer and is passed as * the 'cb_param' is specific to this action function pointer and is passed as
* is to the callback. * is to the callback, this is the pointer you pass to mui_window_add_action()
*/ */
typedef int (*mui_window_action_p)( typedef int (*mui_window_action_p)(
struct mui_window_t * win, struct mui_window_t * win,
@ -391,8 +416,11 @@ struct cg_surface_t;
struct cg_ctx_t; struct cg_ctx_t;
/* /*
* Describes a pixmap. Currently only used for the screen destination pixels. * Describes a pixmap.
* And really, only bpp:32 for ARGB is supported. * And really, only bpp:32 for ARGB is supported if you want to use 'cg' to draw
* on it,
* 8bpp is also used for alpha masks, in which case only the pixman API is used.
* (Alpha mask is used for text rendering)
*/ */
typedef struct mui_pixmap_t { typedef struct mui_pixmap_t {
uint8_t * pixels; uint8_t * pixels;
@ -406,29 +434,45 @@ typedef pixman_region32_t mui_region_t;
DECLARE_C_ARRAY(mui_region_t, mui_clip_stack, 2); DECLARE_C_ARRAY(mui_region_t, mui_clip_stack, 2);
/* /*
* The Drawable is a drawing context -- currently there's only one for the * The Drawable is a drawing context. The important feature
* whole screen, but technically we could have several. The important feature
* of this is that it keeps a context for the pixman library destination * of this is that it keeps a context for the pixman library destination
* image, AND also the context for the 'cg' vectorial library. * image, AND also the context for the 'cg' vectorial library.
*
* Furthermore it keeps track of a stack of clipping rectangles, and is able * Furthermore it keeps track of a stack of clipping rectangles, and is able
* to 'sync' the current clipping area for either (or both) cg and libpixman. * to 'sync' the current clipping area for either (or both) cg and libpixman.
* *
* Important note: the cg vectorial library coordinate system is placed on the * Important note: the cg vectorial library coordinate system is placed on the
* space *between* pixels, ie, if you moveto(1,1) and draw a line down, you * space *between* pixels, ie, if you moveto(1,1) and draw a line down, you
* will light up pixels in columns zero AND one. This differs significantly from * will light up pixels in columns zero AND one (at half transparency).
* for example, pixman that is uses pixel coordinates on hard pixels. * This differs significantly from for example, pixman that is uses pixel
* coordinates on hard pixels.
*
* It's worth remembering as if you draw for example around the border of a * It's worth remembering as if you draw for example around the border of a
* control, it will very likely be 'clipped' somewhat because half the pixels * control, it will very likely be 'clipped' somewhat because half the pixels
* are technically outside the control bounding/clipping rectangle. * are technically outside the control bounding/clipping rectangle.
* You can easily adjust for this by adding 0.5 to the coordinates, if you * You can easily adjust for this by adding 0.5 to the coordinates, if you
* require it. * require it.
*
* Other imporant note: The clipping stack is only converted to pixman/cg when
* the client code asks for the context. So you must make sure not to 'cache'
* the context too early, otherwise the clipping won't work.
* Bad:
* struct cg_t * cg = mui_drawable_get_cg(dr);
* mui_drawable_clip_push(dr, &r);
* ...
* mui_drawable_clip_pop(dr);
* Good:
* mui_drawable_clip_push(dr, &r);
* struct cg_t * cg = mui_drawable_get_cg(dr);
* ...
* mui_drawable_clip_pop(dr);
*/ */
typedef struct mui_drawable_t { typedef struct mui_drawable_t {
mui_pixmap_t pix; // *has* to be first in struct mui_pixmap_t pix; // *has* to be first in struct
void * _pix_hash; // used to detect if pix has changed void * _pix_hash; // used to detect if pix has changed
struct cg_surface_t * cg_surface; struct cg_surface_t * cg_surface;
struct cg_ctx_t * cg; struct cg_ctx_t * cg; // Do not to use these directly
union pixman_image * pixman; // (try) not to use these directly union pixman_image * pixman; // Do not to use these directly
uint pixman_clip_dirty: 1, uint pixman_clip_dirty: 1,
cg_clip_dirty : 1, cg_clip_dirty : 1,
dispose_pixels : 1, dispose_pixels : 1,
@ -439,7 +483,7 @@ typedef struct mui_drawable_t {
c2_pt_t size; c2_pt_t size;
uint id, kind; uint id, kind;
} texture; } texture;
// (default) position in destination when drawing // (default) position in destination when drawing (optional)
c2_pt_t origin; c2_pt_t origin;
mui_clip_stack_t clip; mui_clip_stack_t clip;
} mui_drawable_t; } mui_drawable_t;
@ -450,9 +494,9 @@ DECLARE_C_ARRAY(mui_drawable_t *, mui_drawable_array, 4);
/* /*
* Drawable related * Drawable related
*/ */
/* create a new mui_draware of size w x h, bpp depth. /* create a new mui_drawable of size w x h, bpp depth.
* Optionally allocate the pixels if pixels is NULL. Allocated pixels * Optionally allocate the pixels if pixels is NULL. Allocated pixels
* are not cleared. */ * are not cleared to white/zero. */
mui_drawable_t * mui_drawable_t *
mui_drawable_new( mui_drawable_new(
c2_pt_t size, c2_pt_t size,
@ -606,11 +650,12 @@ typedef enum mui_text_e {
MUI_TEXT_ALIGN_TOP = 0, MUI_TEXT_ALIGN_TOP = 0,
MUI_TEXT_ALIGN_MIDDLE = (MUI_TEXT_ALIGN_CENTER << 2), MUI_TEXT_ALIGN_MIDDLE = (MUI_TEXT_ALIGN_CENTER << 2),
MUI_TEXT_ALIGN_BOTTOM = (MUI_TEXT_ALIGN_RIGHT << 2), MUI_TEXT_ALIGN_BOTTOM = (MUI_TEXT_ALIGN_RIGHT << 2),
MUI_TEXT_ALIGN_COMPACT = (1 << 5), // compact line spacing MUI_TEXT_ALIGN_FULL = (1 << 5),
MUI_TEXT_ALIGN_COMPACT = (1 << 6), // compact line spacing
MUI_TEXT_DEBUG = (1 << 7), MUI_TEXT_DEBUG = (1 << 7),
MUI_TEXT_STYLE_BOLD = (1 << 8), // Synthetic (ugly) bold MUI_TEXT_STYLE_BOLD = (1 << 8), // Synthetic (ugly) bold
MUI_TEXT_STYLE_ULINE = (1 << 9), // Underline MUI_TEXT_STYLE_ULINE = (1 << 9), // Underline
MUI_TEXT_STYLE_NARROW = (1 << 10),// Syntheric narrow MUI_TEXT_STYLE_NARROW = (1 << 10),// Synthetic narrow
MUI_TEXT_FLAGS_COUNT = 11, MUI_TEXT_FLAGS_COUNT = 11,
} mui_text_e; } mui_text_e;
@ -644,6 +689,7 @@ typedef struct mui_glyph_t {
} mui_glyph_t; } mui_glyph_t;
DECLARE_C_ARRAY(mui_glyph_t, mui_glyph_array, 8, DECLARE_C_ARRAY(mui_glyph_t, mui_glyph_array, 8,
uint line_break : 1;
int x, y, t, b; float w;); int x, y, t, b; float w;);
DECLARE_C_ARRAY(mui_glyph_array_t, mui_glyph_line_array, 8, DECLARE_C_ARRAY(mui_glyph_array_t, mui_glyph_line_array, 8,
uint margin_left, margin_right, // minimum x, and max width uint margin_left, margin_right, // minimum x, and max width
@ -652,7 +698,7 @@ DECLARE_C_ARRAY(mui_glyph_array_t, mui_glyph_line_array, 8,
/* /*
* Measure a text string, return the number of lines, and each glyphs * Measure a text string, return the number of lines, and each glyphs
* position already aligned to the MUI_TEXT_ALIGN_* flags. * position already aligned to the MUI_TEXT_ALIGN_* flags.
* Note that the 'compact' and 'narrow' flags are used here, * Note that the 'compact', 'narrow' flags are used here,
* the 'compact' flag is used to reduce the line spacing, and the * the 'compact' flag is used to reduce the line spacing, and the
* 'narrow' flag is used to reduce the advance between glyphs. * 'narrow' flag is used to reduce the advance between glyphs.
*/ */
@ -668,7 +714,7 @@ mui_font_measure(
* to be used exclusively with mui_font_measure. * to be used exclusively with mui_font_measure.
* Draw the lines and glyphs returned by mui_font_measure, with the * Draw the lines and glyphs returned by mui_font_measure, with the
* given color and flags. * given color and flags.
* The significan flags here are no longer the text aligment, but * The significant flags here are no longer the text aligment, but
* how to render them: * how to render them:
* + MUI_TEXT_STYLE_BOLD will draw each glyphs twice, offset by 1 pixel * + MUI_TEXT_STYLE_BOLD will draw each glyphs twice, offset by 1 pixel
* + MUI_TEXT_STYLE_ULINE will draw a line under the text glyphs, unless * + MUI_TEXT_STYLE_ULINE will draw a line under the text glyphs, unless
@ -689,12 +735,12 @@ mui_font_measure_clear(
enum mui_window_layer_e { enum mui_window_layer_e {
MUI_WINDOW_LAYER_NORMAL = 0, MUI_WINDOW_LAYER_NORMAL = 0,
MUI_WINDOW_LAYER_MODAL = 3, MUI_WINDOW_LAYER_MODAL = 3,
MUI_WINDOW_LAYER_ALERT = 5, MUI_WINDOW_LAYER_ALERT = 5,
MUI_WINDOW_LAYER_TOP = 15, MUI_WINDOW_LAYER_TOP = 15,
// Menubar and Menus (popups) are also windows // Menubar and Menus (popups) are also windows
MUI_WINDOW_MENUBAR_LAYER = MUI_WINDOW_LAYER_TOP - 1, MUI_WINDOW_MENUBAR_LAYER = MUI_WINDOW_LAYER_TOP - 1,
MUI_WINDOW_MENU_LAYER, MUI_WINDOW_MENU_LAYER,
}; };
@ -743,6 +789,7 @@ typedef struct mui_window_t {
uint hidden: 1, uint hidden: 1,
disposed : 1, disposed : 1,
layer : 4, layer : 4,
style: 4, // specific to the WDEF
hit_part : 8; hit_part : 8;
} flags; } flags;
c2_pt_t click_loc; c2_pt_t click_loc;
@ -781,8 +828,7 @@ mui_window_create(
uint32_t instance_size); uint32_t instance_size);
// Dispose of a window and it's content (controls). // Dispose of a window and it's content (controls).
/* /*
* Note: if an action is in progress the window is not freed immediately * Note: if the window is 'locked' the window is not freed immediately.
* but added to the zombie list, and freed when the action is done.
* This is to prevent re-entrance problems. This allows window actions to * This is to prevent re-entrance problems. This allows window actions to
* delete their own window without crashing. * delete their own window without crashing.
*/ */
@ -807,13 +853,13 @@ mui_window_front(
bool bool
mui_window_select( mui_window_select(
mui_window_t * win); mui_window_t * win);
// call the window action callback, if any // call the window action callback(s), if any
void void
mui_window_action( mui_window_action(
mui_window_t * c, mui_window_t * c,
uint32_t what, uint32_t what,
void * param ); void * param );
// add an action callback for this window // Add an action callback for this window
void void
mui_window_set_action( mui_window_set_action(
mui_window_t * c, mui_window_t * c,
@ -845,14 +891,15 @@ typedef struct mui_menu_item_t {
uint32_t index: 9; uint32_t index: 9;
uint32_t uid; uint32_t uid;
char * title; char * title;
// curertnly only supported for menu titles // currently only supported for menu titles
const uint32_t * color_icon; // optional, ARGB colors const uint32_t * color_icon; // optional, ARGB colors
char mark[8]; // UTF8 -- Charcoal char mark[8]; // UTF8 -- Charcoal
char icon[8]; // UTF8 -- Wider, icon font char icon[8]; // UTF8 -- Wider, icon font
char kcombo[16]; // UTF8 -- display only char kcombo[16]; // UTF8 -- display only
mui_key_equ_t key_equ; // keystroke to select this item mui_key_equ_t key_equ; // keystroke to select this item
struct mui_menu_item_t * submenu; struct mui_menu_item_t * submenu;
c2_pt_t location; // calculated by menu creation code c2_coord_t location; // calculated by menu creation code
c2_coord_t height;
} mui_menu_item_t; } mui_menu_item_t;
/* /*
@ -891,9 +938,14 @@ mui_menubar_get(
/* /*
* Add a menu to the menubar. 'items' is an array of mui_menu_item_t * Add a menu to the menubar. 'items' is an array of mui_menu_item_t
* terminated by an element with a NULL title. * terminated by an element with a NULL title.
*
* Note: The array is NOT const, it will be tweaked for storing items * Note: The array is NOT const, it will be tweaked for storing items
* position, it can also be tweaked to set/reset the disabled state, * position, it can also be tweaked to set/reset the disabled state,
* check marks etc * check marks etc
*
* Once created, you can do a mui_popupmenu_get_items() to get the array,
* modify it (still make sure there is a NULL item at the end) then
* call mui_popupmenu_prepare() to update the menu.
*/ */
struct mui_control_t * struct mui_control_t *
mui_menubar_add_simple( mui_menubar_add_simple(
@ -1003,6 +1055,10 @@ void
mui_control_inval( mui_control_inval(
mui_control_t * c ); mui_control_t * c );
void void
mui_control_set_frame(
mui_control_t * c,
c2_rect_t * frame );
void
mui_control_action( mui_control_action(
mui_control_t * c, mui_control_t * c,
uint32_t what, uint32_t what,
@ -1034,6 +1090,22 @@ void
mui_control_set_title( mui_control_set_title(
mui_control_t * c, mui_control_t * c,
const char * text ); const char * text );
/* Sets the focus to control 'c' in that window, return true if that
* control was able to take the focus, or false if it wasn't (for example any
* control that are not focusable will return false)
*/
bool
mui_control_set_focus(
mui_control_t * c );
/* Returns true if the control has the focus */
bool
mui_control_has_focus(
mui_control_t * c );
/* Switch focus to the next/previous control in the window */
mui_control_t *
mui_control_switch_focus(
mui_window_t * win,
int dir );
/* Drawable control is just an offscreen buffer (icon, pixel view) */ /* Drawable control is just an offscreen buffer (icon, pixel view) */
mui_control_t * mui_control_t *
@ -1100,11 +1172,19 @@ mui_textedit_set_selection(
uint start, uint start,
uint end); uint end);
/* Page step and line step are optional, they default to '30' pixels and
* the 'visible' area of the scrollbar, respectively.
* If you want to for example have a scrollbar that scrolls by 5 when you
* click the arrows, and by 20 when you click the bar, you would set the
* line_step to 5, and the page_step to 20.
*/
mui_control_t * mui_control_t *
mui_scrollbar_new( mui_scrollbar_new(
mui_window_t * win, mui_window_t * win,
c2_rect_t frame, c2_rect_t frame,
uint32_t uid ); uint32_t uid,
uint32_t line_step,
uint32_t page_step);
uint32_t uint32_t
mui_scrollbar_get_max( mui_scrollbar_get_max(
mui_control_t * c); mui_control_t * c);
@ -1128,16 +1208,23 @@ mui_listbox_prepare(
mui_listbox_elems_t * mui_listbox_elems_t *
mui_listbox_get_elems( mui_listbox_get_elems(
mui_control_t * c); mui_control_t * c);
mui_control_t * mui_control_t *
mui_separator_new( mui_separator_new(
mui_window_t * win, mui_window_t * win,
c2_rect_t frame); c2_rect_t frame);
/* Popup menu control.
* flags are MUI_TEXT_ALIGN_* -- however this corresponds to the margins
* of the popup control itself when placed into it's 'frame' -- the
* popup will be placed left,right,center of the frame rectangle depending.
*/
mui_control_t * mui_control_t *
mui_popupmenu_new( mui_popupmenu_new(
mui_window_t * win, mui_window_t * win,
c2_rect_t frame, c2_rect_t frame,
const char * title, const char * title,
uint32_t uid); uint32_t uid,
uint32_t flags);
mui_menu_items_t * mui_menu_items_t *
mui_popupmenu_get_items( mui_popupmenu_get_items(
mui_control_t * c); mui_control_t * c);
@ -1229,7 +1316,10 @@ enum mui_time_e {
mui_time_t mui_time_t
mui_get_time(); mui_get_time();
#define MUI_TIMER_COUNT 64 #define MUI_TIMER_COUNT 64
#define MUI_TIMER_NONE 0xff
typedef uint8_t mui_timer_id_t;
typedef struct mui_timer_group_t { typedef struct mui_timer_group_t {
uint64_t map; uint64_t map;
@ -1242,12 +1332,13 @@ typedef struct mui_timer_group_t {
/* /*
* Register 'cb' to be called after 'delay'. Returns a timer id (0 to 63) * Register 'cb' to be called after 'delay'. Returns a timer id (0 to 63)
* or 0xff if no timer is available. The timer function cb can return 0 for a * or MUI_TIMER_NONE if no timer is available.
* one shot timer, or another delay that will be added to the current stamp * The timer function cb can return 0 for a one shot timer, or another
* for a further call of the timer. * delay that will be added to the current stamp for a further call
* of the timer.
* 'param' will be also passed to the timer callback. * 'param' will be also passed to the timer callback.
*/ */
uint8_t mui_timer_id_t
mui_timer_register( mui_timer_register(
struct mui_t * ui, struct mui_t * ui,
mui_timer_p cb, mui_timer_p cb,
@ -1262,7 +1353,7 @@ mui_timer_register(
mui_time_t mui_time_t
mui_timer_reset( mui_timer_reset(
struct mui_t * ui, struct mui_t * ui,
uint8_t id, mui_timer_id_t id,
mui_timer_p cb, mui_timer_p cb,
mui_time_t delay); mui_time_t delay);
@ -1295,7 +1386,7 @@ typedef struct mui_t {
mui_utf8_t clipboard; mui_utf8_t clipboard;
mui_timer_group_t timer; mui_timer_group_t timer;
// only used by the text editor, as we can only have one carret // only used by the text editor, as we can only have one carret
uint8_t carret_timer; mui_timer_id_t carret_timer;
char * pref_directory; /* optional */ char * pref_directory; /* optional */
} mui_t; } mui_t;

View File

@ -40,18 +40,15 @@ mui_button_draw(
cg_stroke(cg); cg_stroke(cg);
c2_rect_inset(&f, BUTTON_INSET, BUTTON_INSET); c2_rect_inset(&f, BUTTON_INSET, BUTTON_INSET);
} }
mui_font_t * main = TAILQ_FIRST(&win->ui->fonts); mui_font_t * main = mui_font_find(win->ui, "main");
stb_ttc_measure m = {}; stb_ttc_measure m = {};
mui_font_text_measure(main, c->title, &m); mui_font_text_measure(main, c->title, &m);
int title_width = m.x1 - m.x0; int title_width = m.x1;// - m.x0;
c2_rect_t title = f; c2_rect_t title = C2_RECT_WH(0, 0, title_width, m.ascent - m.descent);
title.t -= 1; c2_rect_offset(&title,
title.r = title.l + title_width + 1; f.l + ((c2_rect_width(&f) / 2) - (c2_rect_width(&title)) / 2),
title.b = title.t + m.ascent - m.descent; f.t + (c2_rect_height(&f) / 2) - (c2_rect_height(&title) / 2));
c2_rect_offset(&title, -m.x0 +
(int)((c2_rect_width(&f) / 2) - (c2_rect_width(&title)) / 2),
(c2_rect_height(&f) / 2) - (c2_rect_height(&title) / 2));
mui_drawable_clip_push(dr, &f); mui_drawable_clip_push(dr, &f);
cg = mui_drawable_get_cg(dr); cg = mui_drawable_get_cg(dr);
c2_rect_t inner = f; c2_rect_t inner = f;
@ -65,8 +62,9 @@ mui_button_draw(
// c2_rect_width(&title), c2_rect_height(&title)); // c2_rect_width(&title), c2_rect_height(&title));
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame)); cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg); cg_stroke(cg);
// offset for leading space
mui_font_text_draw(main, dr, mui_font_text_draw(main, dr,
C2_PT(title.l, title.t), c->title, strlen(c->title), C2_PT(title.l - m.x0, title.t), c->title, strlen(c->title),
mui_control_color[c->state].text); mui_control_color[c->state].text);
mui_drawable_clip_pop(dr); mui_drawable_clip_pop(dr);
} }
@ -197,6 +195,8 @@ mui_button_mouse(
else else
mui_control_set_state(c, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(c, MUI_CONTROL_STATE_NORMAL);
} break; } break;
default:
break;
} }
return true; return true;
} }
@ -238,6 +238,8 @@ mui_cdef_button(
case MUI_EVENT_BUTTONDOWN: { case MUI_EVENT_BUTTONDOWN: {
return mui_button_mouse(c, ev); return mui_button_mouse(c, ev);
} break; } break;
default:
break;
} }
} break; } break;
case MUI_CDEF_SELECT: { case MUI_CDEF_SELECT: {

View File

@ -47,7 +47,7 @@ mui_listbox_draw(
c2_rect_offset(&f, win->content.l, win->content.t); c2_rect_offset(&f, win->content.l, win->content.t);
struct cg_ctx_t * cg = mui_drawable_get_cg(dr); struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
cg_set_line_width(cg, 1); cg_set_line_width(cg, mui_control_has_focus(c) ? 2 : 1);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame)); cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_rectangle(cg, f.l, f.t, cg_rectangle(cg, f.l, f.t,
c2_rect_width(&f), c2_rect_height(&f)); c2_rect_width(&f), c2_rect_height(&f));
@ -60,8 +60,8 @@ mui_listbox_draw(
cg = mui_drawable_get_cg(dr); cg = mui_drawable_get_cg(dr);
mui_listbox_control_t *lb = (mui_listbox_control_t *)c; mui_listbox_control_t *lb = (mui_listbox_control_t *)c;
uint32_t top_element = lb->scroll / lb->elem_height; uint32_t top_element = lb->scroll / lb->elem_height;
uint32_t bottom_element = top_element + 1 + uint32_t bottom_element = (lb->scroll + c2_rect_height(&f) ) /
(c2_rect_height(&f) / lb->elem_height); lb->elem_height;
// printf("%s draw from %d to %d\n", __func__, top_element, bottom_element); // printf("%s draw from %d to %d\n", __func__, top_element, bottom_element);
mui_font_t * icons = mui_font_find(win->ui, "icon_small"); mui_font_t * icons = mui_font_find(win->ui, "icon_small");
@ -69,7 +69,7 @@ mui_listbox_draw(
mui_color_t highlight = win->ui->color.highlight; mui_color_t highlight = win->ui->color.highlight;
for (uint ii = top_element; for (uint ii = top_element;
ii < lb->elems.count && ii < bottom_element; ii++) { ii < lb->elems.count && ii <= bottom_element; ii++) {
c2_rect_t ef = f; c2_rect_t ef = f;
ef.b = ef.t + lb->elem_height; ef.b = ef.t + lb->elem_height;
c2_rect_offset(&ef, 0, ii * lb->elem_height - lb->scroll); c2_rect_offset(&ef, 0, ii * lb->elem_height - lb->scroll);
@ -79,7 +79,10 @@ mui_listbox_draw(
cg_set_source_color(cg, &CG_COLOR(highlight)); cg_set_source_color(cg, &CG_COLOR(highlight));
cg_rectangle(cg, ef.l, ef.t, cg_rectangle(cg, ef.l, ef.t,
c2_rect_width(&ef), c2_rect_height(&ef)); c2_rect_width(&ef), c2_rect_height(&ef));
cg_fill(cg); if (mui_control_has_focus(c))
cg_fill(cg);
else
cg_stroke(cg);
} }
ef.l += 8; ef.l += 8;
mui_listbox_elem_t *e = &lb->elems.e[ii]; mui_listbox_elem_t *e = &lb->elems.e[ii];
@ -173,6 +176,18 @@ mui_listbox_key(
case MUI_KEY_DOWN: delta = 1; break; case MUI_KEY_DOWN: delta = 1; break;
case MUI_KEY_PAGEUP: delta = -page_size; break; case MUI_KEY_PAGEUP: delta = -page_size; break;
case MUI_KEY_PAGEDOWN: delta = page_size; break; case MUI_KEY_PAGEDOWN: delta = page_size; break;
case '\t':
mui_control_switch_focus(c->win,
ev->modifiers & MUI_MODIFIER_SHIFT ? -1 : 0);
break;
#if 0
case 13: // enter
mui_control_action(c, MUI_CONTROL_ACTION_SELECT,
&lb->elems.e[c->value]);
#endif
break;
default:
break;
} }
if (!delta) if (!delta)
return false; return false;
@ -208,13 +223,15 @@ mui_listbox_key(
} }
static bool static bool
mui_cdef_event( mui_listbox_cdef_event(
struct mui_control_t * c, struct mui_control_t * c,
mui_event_t *ev) mui_event_t *ev)
{ {
mui_listbox_control_t *lb = (mui_listbox_control_t *)c; mui_listbox_control_t *lb = (mui_listbox_control_t *)c;
switch (ev->type) { switch (ev->type) {
case MUI_EVENT_BUTTONDOWN: { case MUI_EVENT_BUTTONDOWN: {
if (!mui_control_has_focus(c))
mui_control_set_focus(c);
c2_rect_t f = c->frame; c2_rect_t f = c->frame;
c2_rect_offset(&f, c->win->content.l, c->win->content.t); c2_rect_offset(&f, c->win->content.l, c->win->content.t);
// uint32_t page_size = (c2_rect_height(&f) / lb->elem_height)-1; // uint32_t page_size = (c2_rect_height(&f) / lb->elem_height)-1;
@ -245,9 +262,9 @@ mui_cdef_event(
} }
return true; return true;
} break; } break;
case MUI_EVENT_KEYUP: { case MUI_EVENT_KEYDOWN: {
if (mui_listbox_key(c, ev)) // printf("%s key %d\n", __func__, ev->key.key);
return true; return mui_listbox_key(c, ev);
} break; } break;
case MUI_EVENT_WHEEL: { case MUI_EVENT_WHEEL: {
// printf("%s wheel delta %d\n", __func__, ev->wheel.delta); // printf("%s wheel delta %d\n", __func__, ev->wheel.delta);
@ -263,6 +280,8 @@ mui_cdef_event(
mui_control_inval(c); mui_control_inval(c);
return true; return true;
} break; } break;
default:
break;
} }
return false; return false;
} }
@ -276,6 +295,9 @@ mui_cdef_listbox(
mui_listbox_control_t *lb = (mui_listbox_control_t *)c; mui_listbox_control_t *lb = (mui_listbox_control_t *)c;
switch (what) { switch (what) {
case MUI_CDEF_INIT: case MUI_CDEF_INIT:
if (mui_window_isfront(c->win) &&
c->win->control_focus.control == NULL)
mui_control_set_focus(c);
break; break;
case MUI_CDEF_DISPOSE: case MUI_CDEF_DISPOSE:
// strings for the elements are not owned by the listbox // strings for the elements are not owned by the listbox
@ -287,7 +309,14 @@ mui_cdef_listbox(
} break; } break;
case MUI_CDEF_EVENT: { case MUI_CDEF_EVENT: {
mui_event_t *ev = param; mui_event_t *ev = param;
return mui_cdef_event(c, ev); return mui_listbox_cdef_event(c, ev);
} break;
case MUI_CDEF_CAN_FOCUS: {
return true;
} break;
case MUI_CDEF_FOCUS: {
// int activate = *(int*)param;
// printf("%s activate %d\n", __func__, activate);
} break; } break;
} }
return false; return false;
@ -331,7 +360,7 @@ mui_listbox_new(
win, MUI_CONTROL_LISTBOX, mui_cdef_listbox, win, MUI_CONTROL_LISTBOX, mui_cdef_listbox,
lbf, NULL, uid, sizeof(mui_listbox_control_t)); lbf, NULL, uid, sizeof(mui_listbox_control_t));
mui_listbox_control_t *lb = (mui_listbox_control_t *)c; mui_listbox_control_t *lb = (mui_listbox_control_t *)c;
lb->scrollbar = mui_scrollbar_new(win, sb, 0); lb->scrollbar = mui_scrollbar_new(win, sb, 0, 30, 0);
mui_control_set_action(lb->scrollbar, mui_listbox_sbar_action, c); mui_control_set_action(lb->scrollbar, mui_listbox_sbar_action, c);
lb->elem_height = main->size + 2; lb->elem_height = main->size + 2;
@ -359,7 +388,7 @@ mui_listbox_prepare(
mui_scrollbar_set_max(lb->scrollbar, mui_scrollbar_set_max(lb->scrollbar,
c2_rect_height(&content)); c2_rect_height(&content));
mui_control_set_value(lb->scrollbar, -lb->scroll); mui_control_set_value(lb->scrollbar, -lb->scroll);
mui_scrollbar_set_page(lb->scrollbar, c2_rect_height(&c->frame)); // mui_scrollbar_set_page(lb->scrollbar, c2_rect_height(&c->frame));
} else { } else {
mui_scrollbar_set_max(lb->scrollbar, 0); mui_scrollbar_set_max(lb->scrollbar, 0);
mui_control_set_value(lb->scrollbar, 0); mui_control_set_value(lb->scrollbar, 0);

View File

@ -0,0 +1,517 @@
/*
* mui_cdef_scrollbar.c
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdlib.h>
#include "mui.h"
#include "cg.h"
enum {
MUI_CONTROL_H_SCROLL = 0,
MUI_CONTROL_V_SCROLL
};
extern const mui_control_color_t mui_control_color[MUI_CONTROL_STATE_COUNT];
enum mui_sb_part_e {
MUI_SB_PART_FRAME = 0,
MUI_SB_PART_UP, // aka MUI_SB_PART_LEFT
MUI_SB_PART_DOWN, // aka MUI_SB_PART_RIGHT
MUI_SB_PART_PAGEUP, // aka MUI_SB_PART_PAGELEFT
MUI_SB_PART_PAGEDOWN, // aka MUI_SB_PART_PAGERIGHT
MUI_SB_PART_THUMB,
MUI_SB_PART_THUMBROW,
MUI_SB_PART_COUNT,
};
typedef struct mui_scrollbar_control_t {
mui_control_t control;
uint32_t visible, page_step, line_step;
uint32_t max;
c2_pt_t drag_offset;
uint32_t saved_value; // to handle 'snapback'
uint8_t click_hold_timer;
c2_rect_t parts[MUI_SB_PART_COUNT];
} mui_scrollbar_control_t;
static void
mui_scrollbar_make_rects(
mui_control_t * c )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
c2_rect_t * parts = sb->parts;
c2_rect_t f = c->frame;
c2_rect_offset(&f, c->win->content.l, c->win->content.t);
parts[MUI_SB_PART_FRAME] = f;
parts[MUI_SB_PART_THUMBROW] = f;
c2_rect_t part = f;
if (c->type == MUI_CONTROL_H_SCROLL) {
part.r = part.l + c2_rect_height(&part);
parts[MUI_SB_PART_UP] = part;
parts[MUI_SB_PART_THUMBROW].l = part.r;
part = f;
part.l = part.r - c2_rect_height(&part);
parts[MUI_SB_PART_DOWN] = part;
parts[MUI_SB_PART_THUMBROW].r = part.l;
} else {
part.b = part.t + c2_rect_width(&part);
parts[MUI_SB_PART_UP] = part;
parts[MUI_SB_PART_THUMBROW].t = part.b;
part = f;
part.t = part.b - c2_rect_width(&part);
parts[MUI_SB_PART_DOWN] = part;
parts[MUI_SB_PART_THUMBROW].b = part.t;
}
if (sb->max <= sb->visible) {
c2_rect_t z = {};
if (c->type == MUI_CONTROL_H_SCROLL)
printf("%s ZEROYING max %d visible %d\n", __func__, sb->max, sb->visible);
parts[MUI_SB_PART_THUMB] = z;
parts[MUI_SB_PART_PAGEUP] = z;
parts[MUI_SB_PART_PAGEDOWN] = z;
parts[MUI_SB_PART_THUMBROW] = z;
return;
}
// thumb rectangle
part = parts[MUI_SB_PART_THUMBROW];
uint32_t part_size;
if (c->type == MUI_CONTROL_H_SCROLL)
part_size = c2_rect_width(&part);
else
part_size = c2_rect_height(&part);
float visible = sb->visible / (float)sb->max;
float thumb_size = visible * part_size;
if (thumb_size < 20)
thumb_size = 20;
float thumb_pos = c->value / ((float)sb->max - sb->visible);
float thumb_offset = 0.5 + thumb_pos * (part_size - thumb_size);
if (c->type == MUI_CONTROL_H_SCROLL) {
// printf("%s visible:%.2f ts: %.2f thumb_pos:%.2f thumb_offset:%.2f\n",
// __func__, visible, thumb_size, thumb_pos, thumb_offset);
part.r = part.l + thumb_size;
c2_rect_offset(&part, thumb_offset, 0);
if (part.r > parts[MUI_SB_PART_DOWN].l)
c2_rect_offset(&part, parts[MUI_SB_PART_DOWN].l - part.r, 0);
parts[MUI_SB_PART_THUMB] = part;
part = f;
part.l = parts[MUI_SB_PART_UP].r + 1;
part.r = parts[MUI_SB_PART_THUMB].l - 1;
parts[MUI_SB_PART_PAGEUP] = part;
part = f;
part.l = parts[MUI_SB_PART_THUMB].r + 1;
part.r = parts[MUI_SB_PART_DOWN].l - 1;
parts[MUI_SB_PART_PAGEDOWN] = part;
} else {
part.b = part.t + thumb_size;
c2_rect_offset(&part, 0, thumb_offset);
if (part.b > parts[MUI_SB_PART_DOWN].t)
c2_rect_offset(&part, 0, parts[MUI_SB_PART_DOWN].t - part.b);
parts[MUI_SB_PART_THUMB] = part;
part = f;
part.t = parts[MUI_SB_PART_UP].b + 1;
part.b = parts[MUI_SB_PART_THUMB].t - 1;
parts[MUI_SB_PART_PAGEUP] = part;
part = f;
part.t = parts[MUI_SB_PART_THUMB].b + 1;
part.b = parts[MUI_SB_PART_DOWN].t - 1;
parts[MUI_SB_PART_PAGEDOWN] = part;
}
}
static void
mui_scrollbar_draw(
mui_window_t * win,
mui_control_t * c,
mui_drawable_t * dr )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
c2_rect_t f = c->frame;
c2_rect_offset(&f, win->content.l, win->content.t);
mui_scrollbar_make_rects(c);
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
cg_set_line_width(cg, 2);
cg_rectangle(cg, f.l, f.t,
c2_rect_width(&f), c2_rect_height(&f));
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
mui_font_t * icons = mui_font_find(win->ui, "icon_small");
// c2_rect_t parts[MUI_SB_PART_COUNT];
// mui_scrollbar_make_rects(c, parts);
c2_rect_t * parts = sb->parts;
mui_color_t contentFill = MUI_COLOR(0xa0a0a0ff);
mui_color_t decoColor = MUI_COLOR(0x666666ff);
c2_rect_t pf;
pf = parts[MUI_SB_PART_UP];
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_UP ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
stb_ttc_measure m = {};
char * icon;
icon = c->type == MUI_CONTROL_H_SCROLL ? "" : "";
mui_font_text_measure(icons, icon, &m);
pf.l = pf.l + (c2_rect_width(&pf) - m.x1 - m.x0) / 2;
mui_font_text_draw(icons, dr, pf.tl, icon, 0,
mui_control_color[c->state].text);
pf = parts[MUI_SB_PART_DOWN];
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_DOWN ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
icon = c->type == MUI_CONTROL_H_SCROLL ? "" : "";
mui_font_text_measure(icons, icon, &m);
pf.l = pf.l + (c2_rect_width(&pf) - m.x1 - m.x0) / 2;
mui_font_text_draw(icons, dr, pf.tl, icon, 0,
mui_control_color[c->state].text);
pf = parts[MUI_SB_PART_PAGEUP];
if (c2_rect_isempty(&pf) == 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_PAGEUP ?
&CG_COLOR(decoColor) :
&CG_COLOR(contentFill));
cg_fill(cg);
}
pf = parts[MUI_SB_PART_PAGEDOWN];
if (c2_rect_isempty(&pf) == 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_PAGEDOWN ?
&CG_COLOR(decoColor) :
&CG_COLOR(contentFill));
cg_fill(cg);
}
pf = parts[MUI_SB_PART_THUMB];
if (c2_rect_isempty(&pf) == 0) {
cg_rectangle(cg, pf.l, pf.t,
c2_rect_width(&pf), c2_rect_height(&pf));
cg_set_source_color(cg,
c->flags.hit_part == MUI_SB_PART_THUMB ?
&CG_COLOR(decoColor) :
&CG_COLOR(mui_control_color[c->state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg,
&CG_COLOR(mui_control_color[c->state].frame));
cg_stroke(cg);
}
}
static void
_mui_scrollbar_scroll(
mui_control_t * c,
int32_t delta )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
int32_t v = (int32_t)c->value + delta;
if (v < 0)
v = 0;
if (v > ((int32_t)sb->max - (int32_t)sb->visible))
v = sb->max - sb->visible;
c->value = v;
mui_scrollbar_make_rects(c);
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
}
static void
_mui_scrollbar_part_click(
mui_control_t * c )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
int part = c->flags.hit_part % MUI_SB_PART_COUNT;
switch (part) {
case MUI_SB_PART_DOWN:
case MUI_SB_PART_UP: {
int32_t offset = sb->line_step ? sb->line_step : 30;
_mui_scrollbar_scroll(c,
part == MUI_SB_PART_UP ? -offset : offset);
} break;
case MUI_SB_PART_PAGEUP:
case MUI_SB_PART_PAGEDOWN: {
int32_t offset = sb->page_step ? sb->page_step : sb->visible;
_mui_scrollbar_scroll(c,
part == MUI_SB_PART_PAGEUP ? -offset : offset);
} break;
case MUI_SB_PART_THUMB:
mui_control_inval(c);
break;
}
}
static mui_time_t
_mui_scrollbar_click_hold_timer_cb(
struct mui_t * mui,
mui_time_t now,
void * param)
{
mui_control_t * c = param;
_mui_scrollbar_part_click(c);
return 100 * MUI_TIME_MS;
}
static void
mui_scrollbar_thumb_drag(
mui_control_t * c,
c2_pt_t * where )
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
c2_rect_t * parts = sb->parts;
int max_pixels;
uint32_t nv;
c2_rect_t nt = parts[MUI_SB_PART_THUMB];
if (c->type == MUI_CONTROL_H_SCROLL) {
c2_rect_offset(&nt,
-(nt.l + parts[MUI_SB_PART_UP].r) +
where->x - sb->drag_offset.x, 0);
if (nt.l < 0)
c2_rect_offset(&nt, -nt.l, 0);
if (nt.r > parts[MUI_SB_PART_DOWN].l)
c2_rect_offset(&nt, parts[MUI_SB_PART_DOWN].l - nt.r, 0);
max_pixels = parts[MUI_SB_PART_DOWN].l -
parts[MUI_SB_PART_UP].r -
c2_rect_width(&nt);
nv = nt.l * (sb->max - sb->visible) / max_pixels;
} else {
c2_rect_offset(&nt, 0,
-(nt.t + parts[MUI_SB_PART_UP].b) +
where->y - sb->drag_offset.y);
if (nt.t < 0)
c2_rect_offset(&nt, 0, -nt.t);
if (nt.b > parts[MUI_SB_PART_DOWN].t)
c2_rect_offset(&nt, 0, parts[MUI_SB_PART_DOWN].t - nt.b);
max_pixels = parts[MUI_SB_PART_DOWN].t -
parts[MUI_SB_PART_UP].b -
c2_rect_height(&nt);
nv = nt.t * (sb->max - sb->visible) / max_pixels;
}
if (nv > (sb->max - sb->visible))
nv = sb->max - sb->visible;
c->value = nv;
//printf("%s nv %3d visible %d max %d\n", __func__, nv, sb->visible, sb->max);
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
}
static bool
mui_scrollbar_mouse(
struct mui_control_t * c,
mui_event_t * ev)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
mui_scrollbar_make_rects(c);
c2_rect_t * parts = sb->parts;
switch (ev->type) {
case MUI_EVENT_BUTTONDOWN: {
for (int i = 1; i < MUI_SB_PART_COUNT; ++i) {
if (c2_rect_contains_pt(&parts[i], &ev->mouse.where)) {
c->flags.hit_part = i;
sb->drag_offset.x = ev->mouse.where.x - parts[i].l;
sb->drag_offset.y = ev->mouse.where.y - parts[i].t;
sb->saved_value = c->value;
break;
}
}
_mui_scrollbar_part_click(c);
if (c->flags.hit_part != MUI_SB_PART_THUMB) {
/*
* If the user clicks and holds, we want to keep scrolling,
* so keep a timer around that gets disabled later anyway
*/
sb->click_hold_timer = mui_timer_register(c->win->ui,
_mui_scrollbar_click_hold_timer_cb, c, 500 * MUI_TIME_MS);
}
// printf("%s hit part %d\n", __func__, c->flags.hit_part);
} break;
case MUI_EVENT_DRAG: {
if (!c->flags.hit_part)
break;
int part = c->flags.hit_part % MUI_SB_PART_COUNT;
c2_rect_t test_rect = parts[part];
if (part == MUI_SB_PART_THUMB)
c2_rect_inset(&test_rect, -60, -60);
if (c2_rect_contains_pt(&test_rect, &ev->mouse.where)) {
c->flags.hit_part = part;
switch (part) {
case MUI_SB_PART_THUMB:
mui_scrollbar_thumb_drag(c, &ev->mouse.where);
break;
default:
if (sb->click_hold_timer == 0xff)
sb->click_hold_timer = mui_timer_register(
c->win->ui,
_mui_scrollbar_click_hold_timer_cb,
c, 500 * MUI_TIME_MS);
break;
}
} else {
if (sb->click_hold_timer != 0xff) {
mui_timer_reset(c->win->ui,
sb->click_hold_timer,
_mui_scrollbar_click_hold_timer_cb, 0);
sb->click_hold_timer = 0xff;
}
c->flags.hit_part = part + MUI_SB_PART_COUNT;
if (part == MUI_SB_PART_THUMB) {
c->value = sb->saved_value;
mui_control_inval(c);
mui_control_action(c, MUI_CONTROL_ACTION_VALUE_CHANGED, NULL);
}
}
} break;
case MUI_EVENT_BUTTONUP: {
if (sb->click_hold_timer != 0xff) {
mui_timer_reset(c->win->ui,
sb->click_hold_timer,
_mui_scrollbar_click_hold_timer_cb, 0);
sb->click_hold_timer = 0xff;
}
if (!c->flags.hit_part)
break;
mui_control_inval(c);
c->flags.hit_part = 0;
} break;
default:
break;
}
return true;
}
static bool
mui_cdef_scrollbar(
struct mui_control_t * c,
uint8_t what,
void * param)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
switch (what) {
case MUI_CDEF_INIT: {
mui_scrollbar_make_rects(c);
sb->visible = c->type == MUI_CONTROL_H_SCROLL ?
c2_rect_width(&sb->parts[MUI_SB_PART_FRAME]) :
c2_rect_height(&sb->parts[MUI_SB_PART_FRAME]);
// printf("%s visible %d\n", __func__, sb->visible);
} break;
case MUI_CDEF_DISPOSE:
if (sb->click_hold_timer != 0xff) {
mui_timer_reset(c->win->ui,
sb->click_hold_timer,
_mui_scrollbar_click_hold_timer_cb, 0);
sb->click_hold_timer = 0xff;
}
break;
case MUI_CDEF_SET_FRAME: // inval is done by the caller
mui_scrollbar_make_rects(c);
break;
case MUI_CDEF_DRAW: {
mui_drawable_t * dr = param;
mui_scrollbar_draw(c->win, c, dr);
} break;
case MUI_CDEF_SET_VALUE:
mui_scrollbar_make_rects(c);
mui_control_inval(c);
break;
case MUI_CDEF_EVENT: {
// printf("%s event\n", __func__);
mui_event_t *ev = param;
switch (ev->type) {
case MUI_EVENT_BUTTONUP:
case MUI_EVENT_DRAG:
case MUI_EVENT_BUTTONDOWN: {
return mui_scrollbar_mouse(c, ev);
} break;
case MUI_EVENT_WHEEL: {
int offset = sb->line_step ? sb->line_step : 30;
_mui_scrollbar_scroll(c, ev->wheel.delta * offset);
return true;
} break;
default:
break;
}
} break;
}
return false;
}
uint32_t
mui_scrollbar_get_max(
mui_control_t * c)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
return sb->max;
}
void
mui_scrollbar_set_max(
mui_control_t * c,
uint32_t max)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
sb->max = max;
// printf("%s max %3d visible %d\n", __func__, max, sb->visible);
mui_scrollbar_make_rects(c);
mui_control_inval(c);
}
void
mui_scrollbar_set_page(
mui_control_t * c,
uint32_t page)
{
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
sb->page_step = page;
mui_control_inval(c);
}
mui_control_t *
mui_scrollbar_new(
mui_window_t * win,
c2_rect_t frame,
uint32_t uid,
uint32_t line_step,
uint32_t page_step)
{
mui_control_t * c = mui_control_new(win,
c2_rect_width(&frame) < c2_rect_height(&frame) ?
MUI_CONTROL_V_SCROLL : MUI_CONTROL_H_SCROLL,
mui_cdef_scrollbar, frame, NULL, uid,
sizeof(mui_scrollbar_control_t));
mui_scrollbar_control_t *sb = (mui_scrollbar_control_t *)c;
sb->line_step = line_step;
sb->page_step = page_step;
return c;
}

View File

@ -49,12 +49,39 @@ enum {
MUI_CONTROL_TEXTEDIT = FCC('T','e','a','c'), MUI_CONTROL_TEXTEDIT = FCC('T','e','a','c'),
}; };
#define D(_w) ; // _w
enum { enum {
MUI_TE_SELECTING_GLYPHS = 0, MUI_TE_SELECTING_GLYPHS = 0,
MUI_TE_SELECTING_WORDS, MUI_TE_SELECTING_WORDS,
// MUI_TE_SELECTING_LINES, // TODO? // MUI_TE_SELECTING_LINES, // TODO?
}; };
/*
* This describes a text edit action, either we insert some text at some position,
* or we delete some text at some position.
* These actions are queued in a TAILQ, so we can undo/redo them.
* The text is UTF8, and the position is a BYTE index in the text (not a glyph).
*
* We preallocate a fixed number of actions, and when we reach the limit, we
* start reusing the oldest ones. This limits the number of undo/redo actions
* to something sensible.
*/
typedef struct mui_te_action_t {
TAILQ_ENTRY(mui_te_action_t) self;
uint insert : 1; // if not insert, its a delete
uint32_t position, length;
mui_utf8_t text;
} mui_te_action_t;
// action queue
typedef TAILQ_HEAD(mui_te_action_queue_t, mui_te_action_t) mui_te_action_queue_t;
/*
* This describes the selection in the text-edit, it can either be a carret,
* or a selection of text. The selection is kept as a start and end glyph index,
* and the drawing code calculates the rectangles for the selection.
*/
typedef struct mui_sel_t { typedef struct mui_sel_t {
uint carret: 1; // carret is visible (if sel.start == end) uint carret: 1; // carret is visible (if sel.start == end)
uint start, end; // glyph index in text uint start, end; // glyph index in text
@ -127,7 +154,8 @@ _mui_textedit_carret_timer(
mui_window_t *win = mui_window_front(mui); mui_window_t *win = mui_window_front(mui);
// printf("carret timer win %p focus %p\n", win, win->control_focus); // printf("carret timer win %p focus %p\n", win, win->control_focus);
if (win && win->control_focus.control) { if (win && win->control_focus.control &&
win->control_focus.control->type == MUI_CONTROL_TEXTEDIT) {
mui_textedit_control_t *te = mui_textedit_control_t *te =
(mui_textedit_control_t *)win->control_focus.control; (mui_textedit_control_t *)win->control_focus.control;
te->sel.carret = !te->sel.carret; te->sel.carret = !te->sel.carret;
@ -152,7 +180,6 @@ _mui_textedit_show_carret(
} }
te->sel.carret = 1; te->sel.carret = 1;
_mui_textedit_refresh_sel(te, NULL); _mui_textedit_refresh_sel(te, NULL);
} }
/* Return the line number, and glyph position in line a glyph index */ /* Return the line number, and glyph position in line a glyph index */
@ -352,9 +379,12 @@ _mui_textedit_refresh_sel(
sel = &te->sel; sel = &te->sel;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
c2_rect_t r = te->sel.e[i]; c2_rect_t r = te->sel.e[i];
if (i == 0 && te->sel.start == te->sel.end) if (i == 0 && te->sel.start == te->sel.end) {
c2_rect_inset(&r, -1, -1); c2_rect_inset(&r, -1, -1);
_mui_textedit_inval(te, r); // printf("refresh_sel: carret %s\n", c2_rect_as_str(&r));
}
if (!c2_rect_isempty(&r))
_mui_textedit_inval(te, r);
} }
} }
@ -370,9 +400,9 @@ _mui_textedit_clamp_text_frame(
c2_rect_t old = te->text_content; c2_rect_t old = te->text_content;
te->text_content.r = te->text_content.l + te->measure.margin_right; te->text_content.r = te->text_content.l + te->measure.margin_right;
te->text_content.b = te->text_content.t + te->measure.height; te->text_content.b = te->text_content.t + te->measure.height;
printf(" %s %s / %3dx%3d\n", __func__, D(printf(" %s %s / %3dx%3d\n", __func__,
c2_rect_as_str(&te->text_content), c2_rect_as_str(&te->text_content),
c2_rect_width(&f), c2_rect_height(&f)); c2_rect_width(&f), c2_rect_height(&f));)
if (te->text_content.b < c2_rect_height(&f)) if (te->text_content.b < c2_rect_height(&f))
c2_rect_offset(&te->text_content, 0, c2_rect_offset(&te->text_content, 0,
c2_rect_height(&f) - te->text_content.b); c2_rect_height(&f) - te->text_content.b);
@ -385,8 +415,8 @@ _mui_textedit_clamp_text_frame(
c2_rect_offset(&te->text_content, f.l - te->text_content.l, 0); c2_rect_offset(&te->text_content, f.l - te->text_content.l, 0);
if (c2_rect_equal(&te->text_content, &old)) if (c2_rect_equal(&te->text_content, &old))
return; return;
printf(" clamped TE from %s to %s\n", c2_rect_as_str(&old), D(printf(" clamped TE from %s to %s\n", c2_rect_as_str(&old),
c2_rect_as_str(&te->text_content)); c2_rect_as_str(&te->text_content));)
mui_control_inval(&te->control); mui_control_inval(&te->control);
} }
@ -405,15 +435,15 @@ _mui_textedit_ensure_carret_visible(
return; return;
c2_rect_t old = te->text_content; c2_rect_t old = te->text_content;
c2_rect_t r = te->sel.first; c2_rect_t r = te->sel.first;
printf("%s carret %s frame %s\n", __func__, D(printf("%s carret %s frame %s\n", __func__,
c2_rect_as_str(&r), c2_rect_as_str(&f)); c2_rect_as_str(&r), c2_rect_as_str(&f));)
c2_rect_offset(&r, -te->text_content.l, -te->text_content.t); c2_rect_offset(&r, -te->text_content.l, -te->text_content.t);
if (r.r < f.l) { if (r.r < f.l) {
printf(" moved TE LEFT %d\n", -(f.l - r.r)); D(printf(" moved TE LEFT %d\n", -(f.l - r.r));)
c2_rect_offset(&te->text_content, -(f.l - r.l), 0); c2_rect_offset(&te->text_content, -(f.l - r.l), 0);
} }
if (r.l > f.r) { if (r.l > f.r) {
printf(" moved TE RIGHT %d\n", -(r.l - f.r)); D(printf(" moved TE RIGHT %d\n", -(r.l - f.r));)
c2_rect_offset(&te->text_content, -(r.l - f.r), 0); c2_rect_offset(&te->text_content, -(r.l - f.r), 0);
} }
if (r.t < f.t) if (r.t < f.t)
@ -422,8 +452,8 @@ _mui_textedit_ensure_carret_visible(
c2_rect_offset(&te->text_content, 0, r.b - f.b); c2_rect_offset(&te->text_content, 0, r.b - f.b);
if (c2_rect_equal(&te->text_content, &old)) if (c2_rect_equal(&te->text_content, &old))
return; return;
printf(" moved TE from %s to %s\n", c2_rect_as_str(&old), D(printf(" moved TE from %s to %s\n", c2_rect_as_str(&old),
c2_rect_as_str(&te->text_content)); c2_rect_as_str(&te->text_content));)
_mui_textedit_clamp_text_frame(te); _mui_textedit_clamp_text_frame(te);
} }
@ -560,7 +590,7 @@ _mui_textedit_select_signed(
glyph_end = t; glyph_end = t;
} }
printf("%s %d:%d\n", __func__, glyph_start, glyph_end); // printf("%s %d:%d\n", __func__, glyph_start, glyph_end);
c2_rect_t f = te->control.frame; c2_rect_t f = te->control.frame;
if (te->flags & MUI_CONTROL_TEXTBOX_FRAME) if (te->flags & MUI_CONTROL_TEXTBOX_FRAME)
c2_rect_inset(&f, te->margin.x, te->margin.y); c2_rect_inset(&f, te->margin.x, te->margin.y);
@ -602,12 +632,13 @@ mui_textedit_draw(
mui_drawable_clip_push(dr, &f); mui_drawable_clip_push(dr, &f);
struct cg_ctx_t * cg = mui_drawable_get_cg(dr); struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
if (te->flags & MUI_CONTROL_TEXTBOX_FRAME) { if (te->flags & MUI_CONTROL_TEXTBOX_FRAME) {
cg_set_line_width(cg, 1); cg_set_line_width(cg, mui_control_has_focus(c) ? 2 : 1);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame)); cg_set_source_color(cg, &CG_COLOR(mui_control_color[c->state].frame));
cg_rectangle(cg, f.l, f.t, cg_rectangle(cg, f.l + 0.5, f.t + 0.5,
c2_rect_width(&f), c2_rect_height(&f)); c2_rect_width(&f)-1, c2_rect_height(&f)-1);
cg_stroke(cg); cg_stroke(cg);
} }
// cg = mui_drawable_get_cg(dr); // this updates the cg clip too
if (te->text.count <= 1) if (te->text.count <= 1)
goto done; goto done;
if (te->flags & MUI_CONTROL_TEXTBOX_FRAME) if (te->flags & MUI_CONTROL_TEXTBOX_FRAME)
@ -727,18 +758,9 @@ mui_textedit_mouse(
case MUI_EVENT_BUTTONDOWN: { case MUI_EVENT_BUTTONDOWN: {
if (!c2_rect_contains_pt(&f, &ev->mouse.where)) if (!c2_rect_contains_pt(&f, &ev->mouse.where))
break; break;
// if we aren't the focus, make us the focus if (!mui_control_has_focus(c))
if (c != c->win->control_focus.control) { mui_control_set_focus(c);
mui_control_t * prev = c->win->control_focus.control;
mui_cdef_textedit(c, MUI_CDEF_ACTIVATE, &(int){0});
mui_control_inval(c);
mui_cdef_textedit(prev, MUI_CDEF_ACTIVATE, &(int){1});
mui_control_inval(prev);
mui_control_deref(&c->win->control_focus);
mui_control_ref(&c->win->control_focus, c,
FCC('T','e','a','c'));
}
if (_mui_point_to_line_index(te, te->font, f, if (_mui_point_to_line_index(te, te->font, f,
ev->mouse.where, &line, &index) == 0) { ev->mouse.where, &line, &index) == 0) {
uint pos = _mui_line_index_to_glyph( uint pos = _mui_line_index_to_glyph(
@ -764,8 +786,8 @@ mui_textedit_mouse(
} }
te->click.start = te->sel.start; te->click.start = te->sel.start;
te->click.end = te->sel.end; te->click.end = te->sel.end;
printf("DOWN line %2d index %3d pos:%3d\n", D(printf("DOWN line %2d index %3d pos:%3d\n",
line, index, pos); line, index, pos);)
res = true; res = true;
}; };
te->sel.carret = 0; te->sel.carret = 0;
@ -774,7 +796,7 @@ mui_textedit_mouse(
res = true; res = true;
if (_mui_point_to_line_index(te, te->font, f, if (_mui_point_to_line_index(te, te->font, f,
ev->mouse.where, &line, &index) == 0) { ev->mouse.where, &line, &index) == 0) {
printf("UP line %d index %d\n", line, index); D(printf("UP line %d index %d\n", line, index);)
} }
te->sel.carret = 1; te->sel.carret = 1;
_mui_textedit_refresh_sel(te, NULL); _mui_textedit_refresh_sel(te, NULL);
@ -785,24 +807,24 @@ mui_textedit_mouse(
if (te->flags & MUI_CONTROL_TEXTEDIT_VERTICAL) { if (te->flags & MUI_CONTROL_TEXTEDIT_VERTICAL) {
if (ev->mouse.where.y > f.b) { if (ev->mouse.where.y > f.b) {
te->text_content.tl.y -= ev->mouse.where.y - f.b; te->text_content.tl.y -= ev->mouse.where.y - f.b;
printf("scroll down %3d\n", te->text_content.tl.y); D(printf("scroll down %3d\n", te->text_content.tl.y);)
_mui_textedit_clamp_text_frame(te); _mui_textedit_clamp_text_frame(te);
mui_control_inval(c); mui_control_inval(c);
} else if (ev->mouse.where.y < f.t) { } else if (ev->mouse.where.y < f.t) {
te->text_content.tl.y += f.t - ev->mouse.where.y; te->text_content.tl.y += f.t - ev->mouse.where.y;
printf("scroll up %3d\n", te->text_content.tl.y); D(printf("scroll up %3d\n", te->text_content.tl.y);)
_mui_textedit_clamp_text_frame(te); _mui_textedit_clamp_text_frame(te);
mui_control_inval(c); mui_control_inval(c);
} }
} else { } else {
if (ev->mouse.where.x > f.r) { if (ev->mouse.where.x > f.r) {
te->text_content.tl.x -= ev->mouse.where.x - f.r; te->text_content.tl.x -= ev->mouse.where.x - f.r;
printf("scroll right %3d\n", te->text_content.tl.x); D(printf("scroll right %3d\n", te->text_content.tl.x);)
_mui_textedit_clamp_text_frame(te); _mui_textedit_clamp_text_frame(te);
mui_control_inval(c); mui_control_inval(c);
} else if (ev->mouse.where.x < f.l) { } else if (ev->mouse.where.x < f.l) {
te->text_content.tl.x += f.l - ev->mouse.where.x; te->text_content.tl.x += f.l - ev->mouse.where.x;
printf("scroll left %3d\n", te->text_content.tl.x); D(printf("scroll left %3d\n", te->text_content.tl.x);)
_mui_textedit_clamp_text_frame(te); _mui_textedit_clamp_text_frame(te);
mui_control_inval(c); mui_control_inval(c);
} }
@ -843,6 +865,8 @@ mui_textedit_mouse(
} }
res = true; res = true;
} break; } break;
default:
break;
} }
return res; return res;
} }
@ -988,27 +1012,13 @@ mui_textedit_key(
} }
} break; } break;
case '\t': { case '\t': {
// look for the next window control that is a text-edit (loop to mui_control_switch_focus(c->win,
// start of necessary, and set it as the focus -- deactivate this one) ev->modifiers & MUI_MODIFIER_SHIFT ? -1 : 0);
mui_control_t * next = c;
do {
next = TAILQ_NEXT(next, self);
if (!next)
next = TAILQ_FIRST(&c->win->controls);
if (next->cdef == mui_cdef_textedit) {
mui_cdef_textedit(c, MUI_CDEF_ACTIVATE, &(int){0});
mui_control_inval(c);
mui_cdef_textedit(next, MUI_CDEF_ACTIVATE, &(int){1});
mui_control_inval(next);
mui_control_deref(&c->win->control_focus);
mui_control_ref(&c->win->control_focus, next,
FCC('T','e','a','c'));
break;
}
} while (next != c);
} break; } break;
default: default:
printf("%s key 0x%x\n", __func__, ev->key.key); printf("%s key 0x%x\n", __func__, ev->key.key);
if (ev->key.key == 13 && !(te->flags & MUI_CONTROL_TEXTEDIT_VERTICAL))
return false;
if (ev->key.key == 13 || if (ev->key.key == 13 ||
(ev->key.key >= 32 && ev->key.key < 127)) { (ev->key.key >= 32 && ev->key.key < 127)) {
if (te->sel.start != te->sel.end) { if (te->sel.start != te->sel.end) {
@ -1038,18 +1048,14 @@ mui_cdef_textedit(
mui_textedit_control_t *te = (mui_textedit_control_t *)c; mui_textedit_control_t *te = (mui_textedit_control_t *)c;
switch (what) { switch (what) {
case MUI_CDEF_INIT: { case MUI_CDEF_INIT: {
if (!c->win->control_focus.control)
mui_control_ref(&c->win->control_focus, c,
FCC('T','e','a','c'));
/* If we are the first text-edit created, register the timer */ /* If we are the first text-edit created, register the timer */
if (c->win->ui->carret_timer == 0xff) if (c->win->ui->carret_timer == MUI_TIMER_NONE)
c->win->ui->carret_timer = mui_timer_register(c->win->ui, c->win->ui->carret_timer = mui_timer_register(c->win->ui,
_mui_textedit_carret_timer, NULL, _mui_textedit_carret_timer, NULL,
500 * MUI_TIME_MS); 500 * MUI_TIME_MS);
if (mui_window_isfront(c->win)) { if (mui_window_isfront(c->win) &&
int activate = 1; c->win->control_focus.control == NULL)
mui_cdef_textedit(c, MUI_CDEF_ACTIVATE, &activate); mui_control_set_focus(c);
}
} break; } break;
case MUI_CDEF_DRAW: { case MUI_CDEF_DRAW: {
mui_drawable_t * dr = param; mui_drawable_t * dr = param;
@ -1081,9 +1087,14 @@ mui_cdef_textedit(
case MUI_EVENT_KEYDOWN: { case MUI_EVENT_KEYDOWN: {
return mui_textedit_key(c, ev); return mui_textedit_key(c, ev);
} break; } break;
default:
break;
} }
} break; } break;
case MUI_CDEF_ACTIVATE: { case MUI_CDEF_CAN_FOCUS: {
return true;
} break;
case MUI_CDEF_FOCUS: {
// int activate = *(int*)param; // int activate = *(int*)param;
// printf("%s activate %d\n", __func__, activate); // printf("%s activate %d\n", __func__, activate);
// mui_textedit_control_t *te = (mui_textedit_control_t *)c; // mui_textedit_control_t *te = (mui_textedit_control_t *)c;

View File

@ -76,6 +76,8 @@ mui_control_new(
TAILQ_INSERT_TAIL(&win->controls, c, self); TAILQ_INSERT_TAIL(&win->controls, c, self);
if (c->cdef) if (c->cdef)
c->cdef(c, MUI_CDEF_INIT, NULL); c->cdef(c, MUI_CDEF_INIT, NULL);
// should we auto-focus the control? not sure..
// mui_control_set_focus(c);
return c; return c;
} }
@ -219,10 +221,28 @@ mui_control_event(
res = true; res = true;
} }
break; break;
default: break;
} }
return res; return res;
} }
void
mui_control_set_frame(
mui_control_t * c,
c2_rect_t * frame )
{
if (!c || !frame)
return;
c2_rect_t old = c->frame;
if (c2_rect_equal(&old, frame))
return;
mui_control_inval(c); // old position
c->frame = *frame;
if (c->cdef && c->cdef(c, MUI_CDEF_SET_FRAME, frame))
return;
mui_control_inval(c); // new position
}
void void
mui_control_inval( mui_control_inval(
mui_control_t * c ) mui_control_t * c )
@ -297,12 +317,12 @@ mui_control_lock(
} }
} }
void mui_control_t *
mui_control_unlock( mui_control_unlock(
mui_control_t *c) mui_control_t *c)
{ {
if (!c) if (!c)
return; return NULL;
if (c->lock.control) { if (c->lock.control) {
if (c->lock.ref.trace) if (c->lock.ref.trace)
printf("%s: control %s was locked\n", printf("%s: control %s was locked\n",
@ -316,13 +336,16 @@ mui_control_unlock(
printf("%s: control %s unlocked delete %d\n", printf("%s: control %s unlocked delete %d\n",
__func__, c->title, delete); __func__, c->title, delete);
mui_control_deref(&c->lock); mui_control_deref(&c->lock);
if (delete) if (delete) {
mui_control_dispose(c); mui_control_dispose(c);
c = NULL;
}
} }
} else { } else {
// if (c->lock.ref.trace) // if (c->lock.ref.trace)
printf("%s: control %s was not locked\n", __func__, c->title); printf("%s: control %s was not locked\n", __func__, c->title);
} }
return c;
} }
static void static void
@ -387,3 +410,61 @@ mui_control_get_by_id(
} }
return NULL; return NULL;
} }
bool
mui_control_set_focus(
mui_control_t * c )
{
mui_window_t * win = c->win;
if (!win || !c)
return false;
if (!c->cdef || !c->cdef(c, MUI_CDEF_CAN_FOCUS, NULL))
return false;
if (win->control_focus.control == c)
return true;
if (win->control_focus.control) {
win->control_focus.control->cdef(
win->control_focus.control, MUI_CDEF_FOCUS, &(int){0});
mui_control_inval(win->control_focus.control);
mui_control_deref(&win->control_focus);
}
mui_control_inval(c);
c->cdef(c, MUI_CDEF_FOCUS, &(int){1});
mui_control_ref(&c->win->control_focus, c, FCC('T','e','a','c'));
return true;
}
bool
mui_control_has_focus(
mui_control_t * c )
{
if (!c)
return false;
return c->win->control_focus.control == c;
}
mui_control_t *
mui_control_switch_focus(
mui_window_t * win,
int dir )
{
if (!win)
return NULL;
mui_control_t *c = win->control_focus.control;
if (!c)
c = TAILQ_FIRST(&win->controls);
if (!c)
return c;
mui_control_t * start = c;
do {
c = dir > 0 ? TAILQ_NEXT(c, self) : TAILQ_PREV(c, controls, self);
if (!c)
c = dir > 0 ? TAILQ_FIRST(&win->controls) :
TAILQ_LAST(&win->controls, controls);
if (c->cdef && c->cdef(c, MUI_CDEF_CAN_FOCUS, NULL))
break;
} while (c != start);
mui_control_set_focus(c);
printf("focus %4.4s %s\n", (char*)&c->type, c->title);
return c;
}

View File

@ -15,6 +15,7 @@
#include "stb_ttc.h" #include "stb_ttc.h"
//#ifndef __wasm__
#define INCBIN_STYLE INCBIN_STYLE_SNAKE #define INCBIN_STYLE INCBIN_STYLE_SNAKE
#define INCBIN_PREFIX mui_ #define INCBIN_PREFIX mui_
#include "incbin.h" #include "incbin.h"
@ -23,9 +24,16 @@ INCBIN(main_font, "fonts/Charcoal_mui.ttf");
INCBIN(icon_font, "fonts/typicon.ttf"); INCBIN(icon_font, "fonts/typicon.ttf");
INCBIN(dingbat_font, "fonts/Dingbat.ttf"); INCBIN(dingbat_font, "fonts/Dingbat.ttf");
INCBIN(geneva_font, "fonts/Geneva.ttf"); INCBIN(geneva_font, "fonts/Geneva.ttf");
//#endif
#include "mui.h" #include "mui.h"
// "Narrow style" reduces the advance by this factor
// Not the 'space' characters are reduced even more (twice that)
#define MUI_NARROW_ADVANCE_FACTOR 0.92
// Interline factor for compact text
#define MUI_COMPACT_FACTOR 0.85
mui_font_t * mui_font_t *
mui_font_find( mui_font_find(
mui_t *ui, mui_t *ui,
@ -73,12 +81,14 @@ mui_font_init(
mui_t *ui) mui_t *ui)
{ {
// printf("%s: Loading fonts\n", __func__); // printf("%s: Loading fonts\n", __func__);
#ifndef __wasm__
mui_font_from_mem(ui, "main", 28, mui_font_from_mem(ui, "main", 28,
mui_main_font_data, mui_main_font_size); mui_main_font_data, mui_main_font_size);
mui_font_from_mem(ui, "icon_large", 96, mui_font_from_mem(ui, "icon_large", 96,
mui_icon_font_data, mui_icon_font_size); mui_icon_font_data, mui_icon_font_size);
mui_font_from_mem(ui, "icon_small", 30, mui_font_from_mem(ui, "icon_small", 30,
mui_icon_font_data, mui_icon_font_size); mui_icon_font_data, mui_icon_font_size);
#endif
} }
void void
@ -172,7 +182,6 @@ mui_font_text_draw(
IMPLEMENT_C_ARRAY(mui_glyph_array); IMPLEMENT_C_ARRAY(mui_glyph_array);
IMPLEMENT_C_ARRAY(mui_glyph_line_array); IMPLEMENT_C_ARRAY(mui_glyph_line_array);
#define MUI_NARROW_ADVANCE_FACTOR 0.92
void void
mui_font_measure( mui_font_measure(
@ -203,10 +212,12 @@ mui_font_measure(
int wrap_chi = 0; int wrap_chi = 0;
int wrap_w = 0; int wrap_w = 0;
int wrap_count = 0; int wrap_count = 0;
float compact = flags & MUI_TEXT_ALIGN_COMPACT ?
float compact = flags & MUI_TEXT_ALIGN_COMPACT ? 0.85 : 1.0; MUI_COMPACT_FACTOR : 1.0;
float narrow = flags & MUI_TEXT_STYLE_NARROW ? float narrow = flags & MUI_TEXT_STYLE_NARROW ?
MUI_NARROW_ADVANCE_FACTOR : 1.0; MUI_NARROW_ADVANCE_FACTOR : 1.0;
float narrow_space = flags & MUI_TEXT_STYLE_NARROW ?
narrow * 0.9 : 1.0;
mui_glyph_array_t * line = NULL; mui_glyph_array_t * line = NULL;
do { do {
const mui_glyph_array_t zero = {}; const mui_glyph_array_t zero = {};
@ -236,6 +247,7 @@ mui_font_measure(
ch, cp, cp < 32 ? '.' : cp, state, ch, cp, cp < 32 ? '.' : cp, state,
lines->count-1, line->count); lines->count-1, line->count);
if (cp == '\n') { if (cp == '\n') {
line->line_break = true;
ch++; ch++;
break; break;
} }
@ -253,8 +265,9 @@ mui_font_measure(
if (gc->p_y == (unsigned short) -1) if (gc->p_y == (unsigned short) -1)
stb_ttc__ScaledGlyphRenderToCache(ttc, gc); stb_ttc__ScaledGlyphRenderToCache(ttc, gc);
float advance = gc->advance * narrow; float advance = gc->advance * narrow;
// we make spaces even narrower (if narrow style is on)
if (cp == ' ') if (cp == ' ')
advance *= 0.9; advance *= narrow_space;
if (((line->w + advance) * scale) > c2_rect_width(&bbox)) { if (((line->w + advance) * scale) > c2_rect_width(&bbox)) {
if (wrap_count) { if (wrap_count) {
ch = wrap_chi + 1; ch = wrap_chi + 1;
@ -276,6 +289,15 @@ mui_font_measure(
// g.x, g.w); // g.x, g.w);
line->w += advance; line->w += advance;
}; };
if (line->line_break) {
// stuff a newline here
mui_glyph_t g = {
.glyph = 0,
.pos = ch,
.x = (line->w) * scale,
};
mui_glyph_array_push(line, g);
}
// zero terminate the line, so there is a marker at the end // zero terminate the line, so there is a marker at the end
mui_glyph_t g = { mui_glyph_t g = {
.glyph = 0, .glyph = 0,
@ -307,10 +329,19 @@ mui_font_measure(
for (uint i = 0; i < lines->count; i++) { for (uint i = 0; i < lines->count; i++) {
mui_glyph_array_t * line = &lines->e[i]; mui_glyph_array_t * line = &lines->e[i];
line->y += ydiff; line->y += ydiff;
if (i == lines->count - 1) // last line is always a break
line->line_break = true;
if (flags & MUI_TEXT_ALIGN_RIGHT) { if (flags & MUI_TEXT_ALIGN_RIGHT) {
line->x = c2_rect_width(&bbox) - line->w; line->x = c2_rect_width(&bbox) - line->w;
} else if (flags & MUI_TEXT_ALIGN_CENTER) { } else if (flags & MUI_TEXT_ALIGN_CENTER) {
line->x = (c2_rect_width(&bbox) - line->w) / 2; line->x = (c2_rect_width(&bbox) - line->w) / 2;
} else if (flags & MUI_TEXT_ALIGN_FULL) {
line->x = 0;
if (line->count > 1 && !line->line_break) {
float space = (c2_rect_width(&bbox) - line->w) / (line->count - 1);
for (uint ci = 1; ci < line->count; ci++)
line->e[ci].x += ci * space;
}
} }
if (line->x < (int)lines->margin_left) if (line->x < (int)lines->margin_left)
lines->margin_left = line->x; lines->margin_left = line->x;

View File

@ -22,6 +22,7 @@ enum {
MUI_CONTROL_MENUITEM = FCC('m','i','t','m'), MUI_CONTROL_MENUITEM = FCC('m','i','t','m'),
MUI_CONTROL_SUBMENUITEM = FCC('s','m','i','t'), MUI_CONTROL_SUBMENUITEM = FCC('s','m','i','t'),
MUI_CONTROL_POPUP = FCC('p','o','p','u'), MUI_CONTROL_POPUP = FCC('p','o','p','u'),
MUI_CONTROL_POPUP_MARK = FCC('p','o','p','m'),
}; };
/* These are *window action* -- parameter 'target' is a mui_menu_t* */ /* These are *window action* -- parameter 'target' is a mui_menu_t* */
@ -320,6 +321,8 @@ mui_menubar_handle_mouse(
return true; return true;
} }
} break; } break;
default:
break;
} }
return false; return false;
} }
@ -417,6 +420,8 @@ mui_wdef_menubar(
if (mui_menubar_handle_keydown(mbar, ev)) if (mui_menubar_handle_keydown(mbar, ev))
return true; return true;
} break; } break;
default:
break;
} }
} break; } break;
} }
@ -512,6 +517,8 @@ mui_menu_handle_mouse(
} }
} }
} break; } break;
default:
break;
} }
return false; return false;
} }
@ -542,6 +549,8 @@ mui_wdef_menu(
if (mui_menu_handle_mouse(menu, ev)) if (mui_menu_handle_mouse(menu, ev))
return true; return true;
} break; } break;
default:
break;
} }
} break; } break;
} }
@ -561,6 +570,7 @@ mui_menubar_new(
ui, mbf, ui, mbf,
mui_wdef_menubar, MUI_WINDOW_MENUBAR_LAYER, mui_wdef_menubar, MUI_WINDOW_MENUBAR_LAYER,
"Menubar", sizeof(*mbar)); "Menubar", sizeof(*mbar));
mbar->win.flags.style = MUI_MENU_STYLE_MBAR;
mui_window_ref(&ui->menubar, &mbar->win, FCC('m','b','a','r')); mui_window_ref(&ui->menubar, &mbar->win, FCC('m','b','a','r'));
return &mbar->win; return &mbar->win;
} }
@ -643,7 +653,7 @@ mui_menubar_add_menu(
} else } else
title_rect.l = 4; title_rect.l = 4;
title_rect.r = title_rect.l + title_width + 6; title_rect.r = title_rect.l + title_width + 6;
title_rect.b = win->content.b + 2;// title_rect.t + m.ascent - m.descent; title_rect.b = win->content.b + 0;// title_rect.t + m.ascent - m.descent;
mui_control_t * c = mui_control_new( mui_control_t * c = mui_control_new(
win, MUI_CONTROL_MENUTITLE, mui_cdef_popup, win, MUI_CONTROL_MENUTITLE, mui_cdef_popup,
@ -662,7 +672,7 @@ mui_menubar_add_menu(
for (int ii = 1; items[ii].title; ii++) for (int ii = 1; items[ii].title; ii++)
sub_count++; sub_count++;
menu->menu.count = count -1 ; menu->menu.count = sub_count ;
menu->menu.e = items + 1; menu->menu.e = items + 1;
menu->menu.read_only = 1; menu->menu.read_only = 1;
@ -703,13 +713,16 @@ mui_menu_get_enclosing_rect(
mui_menu_item_t * items) mui_menu_item_t * items)
{ {
c2_rect_t frame = {}; c2_rect_t frame = {};
if (!items)
return frame;
frame.b = 1; // space for outside frame
mui_font_t * main = mui_font_find(ui, "main"); mui_font_t * main = mui_font_find(ui, "main");
stb_ttc_measure m = {}; stb_ttc_measure m = {};
for (int i = 0; items[i].title; i++) { for (int i = 0; items[i].title; i++) {
items[i].location = frame.br; items[i].location = frame.b;
if (items[i].title && items[i].title[0] != '-') { if (items[i].title && items[i].title[0] != '-') {
mui_font_text_measure(main, items[i].title, &m); mui_font_text_measure(main, items[i].title, &m);
m.x0 = 0;
int title_width = main->size + m.x1 - m.x0 ; int title_width = main->size + m.x1 - m.x0 ;
if (items[i].kcombo[0]) { if (items[i].kcombo[0]) {
@ -720,11 +733,13 @@ mui_menu_get_enclosing_rect(
if (title_width > frame.r) if (title_width > frame.r)
frame.r = title_width; frame.r = title_width;
frame.b += main->size + 2; items[i].height = main->size + 4;
} else { } else {
frame.b += main->size / 4; items[i].height = main->size / 4;
} }
frame.b += items[i].height;
} }
frame.b += 1; // space for outside frame
return frame; return frame;
} }
@ -765,6 +780,7 @@ _mui_menu_create(
ui, on_screen, ui, on_screen,
mui_wdef_menu, MUI_WINDOW_MENU_LAYER, mui_wdef_menu, MUI_WINDOW_MENU_LAYER,
items[0].title, sizeof(*menu)); items[0].title, sizeof(*menu));
menu->win.flags.style = MUI_MENU_STYLE_MENU;
if (mbar) { if (mbar) {
mui_window_ref(&mbar->open[mbar->open_count], &menu->win, mui_window_ref(&mbar->open[mbar->open_count], &menu->win,
FCC('m','e','n','u')); FCC('m','e','n','u'));
@ -777,11 +793,8 @@ _mui_menu_create(
mui_menu_item_t * item = &items[i]; mui_menu_item_t * item = &items[i];
item->index = i; item->index = i;
c2_rect_t title_rect = frame; c2_rect_t title_rect = frame;
title_rect.t = item->location.y - 1; title_rect.t = item->location;
if (items[i+1].title) title_rect.b = title_rect.t + item->height;
title_rect.b = items[i+1].location.y;
else
title_rect.b = frame.b;
mui_control_t * c = NULL; mui_control_t * c = NULL;
if (item->submenu) { if (item->submenu) {
@ -875,13 +888,18 @@ mui_popupmenu_handle_mouse(
mui_control_set_state(c, mui_control_set_state(c,
ev->type != MUI_EVENT_BUTTONUP ? ev->type != MUI_EVENT_BUTTONUP ?
MUI_CONTROL_STATE_CLICKED : 0); MUI_CONTROL_STATE_CLICKED : 0);
if (!pop->menu_window.window) { if (!pop->menu_window.window && pop->menu.e) {
c2_pt_t loc = pop->menu_frame.tl; c2_pt_t loc = pop->menu_frame.tl;
c2_pt_offset(&loc, c->win->content.l, c->win->content.t); c2_pt_offset(&loc, c->win->content.l, c->win->content.t);
c2_pt_offset(&loc, 0, -pop->menu.e[c->value].location.y); if (c->type == MUI_CONTROL_POPUP)
c2_pt_offset(&loc, 0, -pop->menu.e[c->value].location);
else if (c->type == MUI_CONTROL_POPUP_MARK)
c2_pt_offset(&loc, 0, c2_rect_height(&c->frame));
mui_window_t *new = _mui_menu_create( mui_window_t *new = _mui_menu_create(
c->win->ui, NULL, loc, c->win->ui, NULL, loc,
pop->menu.e); pop->menu.e);
// override the default style to make it specific to a popup
new->flags.style = MUI_MENU_STYLE_POPUP;
mui_window_ref(&pop->menu_window, new, mui_window_ref(&pop->menu_window, new,
FCC('m','e','n','u')); FCC('m','e','n','u'));
mui_window_set_action(pop->menu_window.window, mui_window_set_action(pop->menu_window.window,
@ -891,6 +909,8 @@ mui_popupmenu_handle_mouse(
} }
mui_control_inval(c); mui_control_inval(c);
} break; } break;
default:
break;
} }
return true; return true;
} }
@ -907,6 +927,7 @@ mui_cdef_popup(
case MUI_CDEF_DISPOSE: case MUI_CDEF_DISPOSE:
switch (c->type) { switch (c->type) {
case MUI_CONTROL_POPUP: case MUI_CONTROL_POPUP:
case MUI_CONTROL_POPUP_MARK:
case MUI_CONTROL_MENUTITLE: { case MUI_CONTROL_MENUTITLE: {
mui_menu_control_t *pop = (mui_menu_control_t*)c; mui_menu_control_t *pop = (mui_menu_control_t*)c;
if (pop->menu_window.window) { if (pop->menu_window.window) {
@ -933,6 +954,9 @@ mui_cdef_popup(
case MUI_CONTROL_POPUP: case MUI_CONTROL_POPUP:
mui_popuptitle_draw(c->win, c, dr); mui_popuptitle_draw(c->win, c, dr);
break; break;
case MUI_CONTROL_POPUP_MARK:
mui_popupmark_draw(c->win, c, dr);
break;
case MUI_CONTROL_MENUTITLE: case MUI_CONTROL_MENUTITLE:
mui_menutitle_draw(c->win, c, dr); mui_menutitle_draw(c->win, c, dr);
break; break;
@ -950,6 +974,7 @@ mui_cdef_popup(
case MUI_EVENT_DRAG: case MUI_EVENT_DRAG:
case MUI_EVENT_BUTTONDOWN: { case MUI_EVENT_BUTTONDOWN: {
switch (c->type) { switch (c->type) {
case MUI_CONTROL_POPUP_MARK:
case MUI_CONTROL_POPUP: { case MUI_CONTROL_POPUP: {
mui_menu_control_t *pop = (mui_menu_control_t*)c; mui_menu_control_t *pop = (mui_menu_control_t*)c;
return mui_popupmenu_handle_mouse(pop, ev); return mui_popupmenu_handle_mouse(pop, ev);
@ -959,6 +984,8 @@ mui_cdef_popup(
break; break;
} }
} break; } break;
default:
break;
} }
} break; } break;
} }
@ -970,11 +997,17 @@ mui_popupmenu_new(
mui_window_t * win, mui_window_t * win,
c2_rect_t frame, c2_rect_t frame,
const char * title, const char * title,
uint32_t uid ) uint32_t uid,
uint32_t flags )
{ {
return mui_control_new( int kind = MUI_CONTROL_POPUP;
win, MUI_CONTROL_POPUP, mui_cdef_popup, if (!title || !strcmp(title, MUI_GLYPH_POPMARK))
kind = MUI_CONTROL_POPUP_MARK;
mui_control_t *c = mui_control_new(
win, kind, mui_cdef_popup,
frame, title, uid, sizeof(mui_menu_control_t)); frame, title, uid, sizeof(mui_menu_control_t));
c->style = flags;
return c;
} }
mui_menu_items_t * mui_menu_items_t *
@ -983,7 +1016,9 @@ mui_popupmenu_get_items(
{ {
if (!c) if (!c)
return NULL; return NULL;
if (c->type != MUI_CONTROL_POPUP && c->type != MUI_CONTROL_MENUTITLE) { if (c->type != MUI_CONTROL_POPUP &&
c->type != MUI_CONTROL_POPUP_MARK &&
c->type != MUI_CONTROL_MENUTITLE ) {
D(printf("%s: not a popup or menutitle\n", __func__);) D(printf("%s: not a popup or menutitle\n", __func__);)
return NULL; return NULL;
} }
@ -1001,12 +1036,24 @@ mui_popupmenu_prepare(
mui_window_deref(&pop->menu_window); mui_window_deref(&pop->menu_window);
} }
c2_rect_t frame = mui_menu_get_enclosing_rect(c->win->ui, pop->menu.e); c2_rect_t frame = mui_menu_get_enclosing_rect(c->win->ui, pop->menu.e);
pop->menu_frame = frame; // pop->menu_frame = frame;
c2_rect_offset(&frame, c->frame.l, c->frame.t); c2_rect_offset(&frame, c->frame.l, c->frame.t);
frame.r += 32; // add the popup symbol width switch (c->type) {
if (c2_rect_width(&frame) < c2_rect_width(&c->frame)) { case MUI_CONTROL_POPUP:
c2_rect_offset(&frame, (c2_rect_width(&c->frame) / 2) - frame.r += 32; // add the popup symbol width
(c2_rect_width(&frame) / 2), 0); break;
case MUI_CONTROL_POPUP_MARK:
// little tweak so the popup appears over the bottom border of button
c2_rect_offset(&frame, 0, -2);
break;
}
if (c->style & MUI_TEXT_ALIGN_CENTER) {
if (c2_rect_width(&frame) < c2_rect_width(&c->frame)) {
c2_rect_offset(&frame, (c2_rect_width(&c->frame) / 2) -
(c2_rect_width(&frame) / 2), 0);
}
} else if (c->style & MUI_TEXT_ALIGN_RIGHT) {
c2_rect_offset(&frame, c2_rect_width(&c->frame) - c2_rect_width(&frame), 0);
} }
pop->menu_frame = frame; pop->menu_frame = frame;
c->value = 0; c->value = 0;

View File

@ -82,7 +82,7 @@ mui_menuitem_get_part_locations(
} else if (item->mark[0]) { } else if (item->mark[0]) {
mui_font_text_measure(main, item->mark, &m); mui_font_text_measure(main, item->mark, &m);
c2_pt_t loc = title.tl; c2_pt_t loc = title.tl;
loc.x += (main->size / 2) - ((m.x1 - m.x0) / 2); loc.x += m.x0 + (main->size / 2) - ((m.x1 - m.x0) / 2);
out[MUI_MENUITEM_PART_ICON].tl = loc; out[MUI_MENUITEM_PART_ICON].tl = loc;
} }
// this is the 'left margin' for the menu item // this is the 'left margin' for the menu item
@ -121,7 +121,7 @@ mui_menutitle_get_part_locations(
out[MUI_MENUTITLE_PART_TITLE] = out[MUI_MENUTITLE_PART_TITLE] =
C2_RECT_WH(out[MUI_MENUTITLE_PART_ICON].r, C2_RECT_WH(out[MUI_MENUTITLE_PART_ICON].r,
0, m.x1 - m.x0, m.ascent - m.descent); 0, m.x1 - 0, m.ascent - m.descent);
} }
out[MUI_MENUTITLE_PART_ALL] = out[MUI_MENUTITLE_PART_ICON]; out[MUI_MENUTITLE_PART_ALL] = out[MUI_MENUTITLE_PART_ICON];
c2_rect_union( c2_rect_union(
@ -296,8 +296,51 @@ mui_popuptitle_draw(
loc[1].tl, item.title, 0, loc[1].tl, item.title, 0,
mui_control_color[state].text); mui_control_color[state].text);
} }
// up/down arrow
mui_font_text_draw(icons, dr, mui_font_text_draw(icons, dr,
C2_PT(inner.r - 32 + 8, inner.t + 2), "", 0, C2_PT(inner.r - 32 + 8, inner.t + 2), MUI_ICON_POPUP_ARROWS, 0,
mui_control_color[state].text);
mui_drawable_clip_pop(dr);
}
void
mui_popupmark_draw(
mui_window_t * win,
mui_control_t * c,
mui_drawable_t *dr )
{
mui_menu_control_t *pop = (mui_menu_control_t*)c;
c2_rect_t f = c->frame;
if (c2_rect_width(&pop->menu_frame) &&
c2_rect_width(&pop->menu_frame) < c2_rect_width(&f)) {
f = pop->menu_frame;
f.b = c->frame.b;
}
c2_rect_offset(&f, win->content.l, win->content.t);
mui_font_t * main = mui_font_find(win->ui, "main");
uint32_t state = mui_control_get_state(c);
mui_drawable_clip_push(dr, &f);
struct cg_ctx_t * cg = mui_drawable_get_cg(dr);
c2_rect_t inner = f;
c2_rect_inset(&inner, 1, 1);
cg_set_line_width(cg, 2);
cg_round_rectangle(cg, inner.l, inner.t,
c2_rect_width(&inner), c2_rect_height(&inner), 4, 4);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].fill));
cg_fill_preserve(cg);
cg_set_source_color(cg, &CG_COLOR(mui_control_color[state].frame));
cg_stroke(cg);
#if 0
cg_move_to(cg, inner.r - 32, inner.t + 2);
cg_line_to(cg, inner.r - 32, inner.b - 2);
mui_color_t decoColor = MUI_COLOR(0x666666ff);
cg_set_source_color(cg, &CG_COLOR(decoColor));
cg_stroke(cg);
#endif
mui_font_text_draw(main, dr,
C2_PT(inner.r - 32 + 8, inner.t + 2), c->title, 0,
mui_control_color[state].text); mui_control_color[state].text);
mui_drawable_clip_pop(dr); mui_drawable_clip_pop(dr);
} }

View File

@ -31,7 +31,7 @@ mui_window_handle_keyboard(
void void
mui_window_lock( mui_window_lock(
mui_window_t *win); mui_window_t *win);
void mui_window_t *
mui_window_unlock( mui_window_unlock(
mui_window_t *win); mui_window_t *win);
@ -43,7 +43,7 @@ mui_control_draw(
void void
mui_control_lock( mui_control_lock(
mui_control_t *c); mui_control_t *c);
void mui_control_t *
mui_control_unlock( mui_control_unlock(
mui_control_t *c); mui_control_t *c);
@ -73,6 +73,13 @@ typedef struct mui_menu_control_t {
mui_window_ref_t menu_window; // when open mui_window_ref_t menu_window; // when open
} mui_menu_control_t; } mui_menu_control_t;
// used by mui_wdef_menubar for frame and drawing.
enum mui_mbar_style_e {
MUI_MENU_STYLE_MBAR = 0,
MUI_MENU_STYLE_MENU,
MUI_MENU_STYLE_POPUP,
};
void void
mui_wdef_menubar_draw( mui_wdef_menubar_draw(
struct mui_window_t * win, struct mui_window_t * win,
@ -92,6 +99,11 @@ mui_menutitle_draw(
mui_window_t * win, mui_window_t * win,
mui_control_t * c, mui_control_t * c,
mui_drawable_t *dr ); mui_drawable_t *dr );
void
mui_popupmark_draw(
mui_window_t * win,
mui_control_t * c,
mui_drawable_t *dr );
enum { enum {
MUI_MENUTITLE_PART_ALL = 0, MUI_MENUTITLE_PART_ALL = 0,

View File

@ -33,7 +33,7 @@ IMPLEMENT_C_ARRAY(string_array);
typedef struct mui_stdfile_t { typedef struct mui_stdfile_t {
mui_window_t win; mui_window_t win;
mui_control_t * ok, *cancel, *home, *root; mui_control_t * ok, *cancel, *home, *root;
mui_control_t * listbox, *popup; mui_control_t * listbox, *popup, *recent;
char * pref_file; // pathname we put last path used char * pref_file; // pathname we put last path used
char * re_pattern; char * re_pattern;
struct { struct {
@ -43,6 +43,10 @@ typedef struct mui_stdfile_t {
char * current_path; char * current_path;
char * selected_path; char * selected_path;
string_array_t pop_path; string_array_t pop_path;
struct {
mui_control_t *save_name;
mui_control_t *create_folder;
} save;
#ifdef MUI_HAS_REGEXP #ifdef MUI_HAS_REGEXP
regex_t re; regex_t re;
#endif #endif
@ -56,6 +60,9 @@ enum {
MUI_STD_FILE_PART_ROOT, MUI_STD_FILE_PART_ROOT,
MUI_STD_FILE_PART_LISTBOX, MUI_STD_FILE_PART_LISTBOX,
MUI_STD_FILE_PART_POPUP, MUI_STD_FILE_PART_POPUP,
MUI_STD_FILE_PART_RECENT,
MUI_STD_FILE_PART_NEW,
MUI_STD_FILE_PART_SAVE_NAME,
MUI_STD_FILE_PART_COUNT, MUI_STD_FILE_PART_COUNT,
}; };
@ -93,6 +100,27 @@ mui_hash_nocase(
hash += hash << 5; hash += hash << 5;
return hash; return hash;
} }
static int
_mii_stdfile_check_dir(
const char * path)
{
const char *home = getenv("HOME");
if (home && path[0] == '~' && path[1] == '/') {
char * p = NULL;
asprintf(&p, "%s%s", home, path + 1);
path = p;
} else
path = strdup(path);
struct stat st;
int res = -1;
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode))
res = 0;
}
free((void*)path);
return res;
}
static int static int
_mui_stdfile_populate( _mui_stdfile_populate(
mui_stdfile_t * std, mui_stdfile_t * std,
@ -100,7 +128,14 @@ _mui_stdfile_populate(
{ {
if (std->current_path && !strcmp(std->current_path, path)) if (std->current_path && !strcmp(std->current_path, path))
return 0; return 0;
const char *home = getenv("HOME");
int dupped = 0;
if (home && path[0] == '~' && path[1] == '/') {
char * p = NULL;
asprintf(&p, "%s%s", home, path + 1);
path = p;
dupped = 1;
}
printf("%s %s\n", __func__, path); printf("%s %s\n", __func__, path);
errno = 0; errno = 0;
DIR * dir = opendir(path); DIR * dir = opendir(path);
@ -117,7 +152,7 @@ _mui_stdfile_populate(
} }
if (std->current_path) if (std->current_path)
free(std->current_path); free(std->current_path);
std->current_path = strdup(path); std->current_path = dupped ? (char*)path : strdup(path);
path = NULL; // this COULD be in the list we are now deleting! path = NULL; // this COULD be in the list we are now deleting!
for (uint i = 0; i < std->pop_path.count; i++) for (uint i = 0; i < std->pop_path.count; i++)
free(std->pop_path.e[i]); free(std->pop_path.e[i]);
@ -130,7 +165,6 @@ _mui_stdfile_populate(
mui_menu_items_clear(items); mui_menu_items_clear(items);
char * p = strdup(std->current_path); char * p = strdup(std->current_path);
char * d; char * d;
const char *home = getenv("HOME");
int item_id = 1000; int item_id = 1000;
while ((d = basename(p)) != NULL) { while ((d = basename(p)) != NULL) {
mui_menu_item_t i = { mui_menu_item_t i = {
@ -226,6 +260,82 @@ _mui_stdfile_populate(
return 0; return 0;
} }
static int
_mui_stdfile_load_pref(
mui_stdfile_t * std)
{
int res = 1;
FILE * f = fopen(std->pref_file, "r");
char * path = NULL;
size_t len = 0;
if (!f)
return res; // populate
mui_control_t *pop = std->recent;
mui_menu_items_t * items = mui_popupmenu_get_items(pop);
for (uint i = 0; i < items->count; i++)
free(items->e[i].title);
mui_menu_items_clear(items);
int line_count = 0;
const char *home = getenv("HOME");
do {
errno = 0;
if (getline(&path, &len, f) == -1)
break;
char *nl = strrchr(path, '\n');
if (nl)
*nl = 0;
if (line_count == 0) {
if (_mui_stdfile_populate(std, path) == 0) {
printf("%s last path[%s]: %s\n", __func__,
std->re_pattern, path);
res = 0;
}
}
if (home && !strncmp(home, path, strlen(home)) &&
path[strlen(home)] == '/') {
path[0] = '~';
memmove(path + 1, path + strlen(home),
strlen(path) - strlen(home) + 1);
}
int add = 1;
for (uint ii = 0; ii < items->count; ii++) {
if (!strcmp(items->e[ii].title, path)) {
add = 0;
break;
}
}
if (add)
add = !_mii_stdfile_check_dir(path);
if (add && items->count > 10) // limit to 10 recent paths
add = 0;
if (add) {
int item_id = 10000 + line_count;
mui_menu_item_t i = {
.title = strdup(path),
.uid = item_id,
};
char *d = path;
if (!strcmp(d, "/"))
strcpy(i.icon, MUI_ICON_ROOT);
else if (home && !strcmp(d, home))
strcpy(i.icon, MUI_ICON_HOME);
else
strcpy(i.icon, MUI_ICON_FOLDER);
mui_menu_items_push(items, i);
}
line_count++;
} while (!feof(f) && line_count < 6);
mui_menu_item_t z = {};
mui_menu_items_push(items, z);
mui_popupmenu_prepare(pop);
fclose(f);
if (path)
free(path);
return res;
}
static int static int
_mui_stdfile_window_action( _mui_stdfile_window_action(
mui_window_t * win, mui_window_t * win,
@ -290,6 +400,17 @@ _mui_stdfile_control_action(
FILE * f = fopen(std->pref_file, "w"); FILE * f = fopen(std->pref_file, "w");
if (f) { if (f) {
fprintf(f, "%s\n", std->current_path); fprintf(f, "%s\n", std->current_path);
// write recent paths popup back in
const char *home = getenv("HOME");
mui_menu_items_t * items = mui_popupmenu_get_items(std->recent);
for (uint i = 0; i < items->count; i++) {
if (items->e[i].title &&
strcmp(items->e[i].title, std->current_path) &&
strcmp(items->e[i].title, home) &&
strcmp(items->e[i].title, "/")) {
fprintf(f, "%s\n", items->e[i].title);
}
}
fclose(f); fclose(f);
} }
} }
@ -340,19 +461,32 @@ _mui_stdfile_control_action(
_mui_stdfile_populate(std, std->pop_path.e[idx]); _mui_stdfile_populate(std, std->pop_path.e[idx]);
} }
break; break;
case MUI_STD_FILE_PART_RECENT:
// printf("%s POPUP\n", __func__);
if (what == MUI_CONTROL_ACTION_VALUE_CHANGED) {
int idx = mui_control_get_value(c);
mui_menu_item_t * items = mui_popupmenu_get_items(c)->e;
printf("Recent Selected: %s\n", items[idx].title);
_mui_stdfile_populate(std, items[idx].title);
}
break;
} }
return 0; return 0;
} }
mui_window_t * mui_window_t *
mui_stdfile_get( mui_stdfile_make_window(
struct mui_t * ui, struct mui_t * ui,
c2_pt_t where, c2_pt_t where,
const char * prompt, const char * prompt,
const char * pattern, const char * pattern,
const char * start_path, const char * start_path,
const char * save_filename,
uint16_t flags ) uint16_t flags )
{ {
float base_size = mui_font_find(ui, "main")->size;
float margin = base_size * 0.7;
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 700, 400); c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 700, 400);
if (where.x == 0 && where.y == 0) if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos, c2_rect_offset(&wpos,
@ -401,18 +535,20 @@ mui_stdfile_get(
} }
free(dup); free(dup);
} }
bool save_box = false;
mui_control_t * c = NULL; mui_control_t * c = NULL;
c2_rect_t cf; c2_rect_t cf;
cf = C2_RECT_WH(0, 0, 120, 40); cf = C2_RECT_WH(0, 0, 120, 40);
c2_rect_left_of(&cf, c2_rect_width(&w->content), 20); c2_rect_left_of(&cf, c2_rect_width(&w->content), margin);
c2_rect_top_of(&cf, c2_rect_height(&w->content), 20); c2_rect_top_of(&cf, c2_rect_height(&w->content), margin);
std->cancel = c = mui_button_new(w, std->cancel = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL, cf, MUI_BUTTON_STYLE_NORMAL,
"Cancel", MUI_STD_FILE_PART_CANCEL); "Cancel", MUI_STD_FILE_PART_CANCEL);
c2_rect_top_of(&cf, cf.t, 20); c2_rect_top_of(&cf, cf.t, margin);
std->ok = c = mui_button_new(w, std->ok = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_DEFAULT, cf, MUI_BUTTON_STYLE_DEFAULT,
"Select", MUI_STD_FILE_PART_OK); save_box ? "Save" : "Select", MUI_STD_FILE_PART_OK);
std->ok->key_equ = MUI_KEY_EQU(0, 13); // return std->ok->key_equ = MUI_KEY_EQU(0, 13); // return
std->cancel->key_equ = MUI_KEY_EQU(0, 27); // ESC std->cancel->key_equ = MUI_KEY_EQU(0, 27); // ESC
@ -422,57 +558,67 @@ mui_stdfile_get(
c2_rect_top_of(&t, cf.t, 25); c2_rect_top_of(&t, cf.t, 25);
c = mui_separator_new(w, t); c = mui_separator_new(w, t);
int button_spacer = save_box ? margin * 0.7 : margin;
int listbox_height = save_box ? 250 : 300;
c2_rect_top_of(&cf, cf.t, 40); c2_rect_top_of(&cf, cf.t, 40);
std->home = c = mui_button_new(w, std->home = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL, cf, MUI_BUTTON_STYLE_NORMAL,
"Home", MUI_STD_FILE_PART_HOME); "Home", MUI_STD_FILE_PART_HOME);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 'h'); c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 'h');
c2_rect_top_of(&cf, cf.t, 20); c2_rect_top_of(&cf, cf.t, button_spacer);
std->root = c = mui_button_new(w, std->root = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL, cf, MUI_BUTTON_STYLE_NORMAL,
"Root", MUI_STD_FILE_PART_ROOT); "Root", MUI_STD_FILE_PART_ROOT);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, '/'); c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, '/');
cf = C2_RECT_WH(15, 45, 700-185, 300); if (save_box) {
c2_rect_top_of(&cf, cf.t, button_spacer);
std->save.create_folder = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL,
"New…", MUI_STD_FILE_PART_ROOT);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 'n');
c->uid = MUI_STD_FILE_PART_NEW;
}
cf = C2_RECT_WH(margin, 0, c2_rect_width(&wpos)-185, 35);
c2_rect_top_of(&cf, c2_rect_height(&w->content), margin);
if (save_box) {
std->save.save_name = c = mui_textedit_control_new(w,
cf, MUI_CONTROL_TEXTBOX_FRAME);
c->uid = MUI_STD_FILE_PART_SAVE_NAME;
mui_textedit_set_text(c,
"Fulling Mill Online Return Center.pdf");
mui_textedit_set_selection(c, 0, 255);
}
cf = C2_RECT_WH(margin, 45, c2_rect_width(&wpos)-185, listbox_height);
std->listbox = c = mui_listbox_new(w, cf, std->listbox = c = mui_listbox_new(w, cf,
MUI_STD_FILE_PART_LISTBOX); MUI_STD_FILE_PART_LISTBOX);
cf = C2_RECT_WH(15, 0, 700-185, 34); cf = C2_RECT_WH(margin, 0, c2_rect_width(&wpos)-185, 34);
c2_rect_top_of(&cf, std->listbox->frame.t, 6); c2_rect_top_of(&cf, std->listbox->frame.t, 6);
std->popup = c = mui_popupmenu_new(w, cf, std->popup = c = mui_popupmenu_new(w, cf,
"Popup", MUI_STD_FILE_PART_POPUP); "Popup", MUI_STD_FILE_PART_POPUP,
MUI_TEXT_ALIGN_CENTER);
cf.r = c2_rect_width(&w->content) - margin;
cf.l = cf.r - 34;
std->recent = c = mui_popupmenu_new(w, cf,
MUI_GLYPH_POPMARK, MUI_STD_FILE_PART_RECENT,
MUI_TEXT_ALIGN_RIGHT);
// mui_control_set_state(c, MUI_CONTROL_STATE_DISABLED);
// printf("Popup: %p\n", c); // printf("Popup: %p\n", c);
c = NULL; c = NULL;
TAILQ_FOREACH(c, &w->controls, self) { TAILQ_FOREACH(c, &w->controls, self) {
if (mui_control_get_uid(c) == 0) if (mui_control_get_uid(c))
continue; mui_control_set_action(c, _mui_stdfile_control_action, std);
mui_control_set_action(c, _mui_stdfile_control_action, std);
} }
int dopop = 1; // populate to start_path by default int dopop = 1; // populate to start_path by default
if (!(flags & MUI_STDF_FLAG_NOPREF) && ui->pref_directory) { if (!(flags & MUI_STDF_FLAG_NOPREF) && ui->pref_directory) {
uint32_t hash = std->re_pattern ? mui_hash(std->re_pattern) : 0; uint32_t hash = std->re_pattern ? mui_hash(std->re_pattern) : 0;
asprintf(&std->pref_file, "%s/std_path_%04x", ui->pref_directory, hash); asprintf(&std->pref_file, "%s/std_path_%04x", ui->pref_directory, hash);
printf("%s pref file: %s\n", __func__, std->pref_file); printf("%s pref file: %s\n", __func__, std->pref_file);
/* read last used pathname */
FILE * f = fopen(std->pref_file, "r"); dopop = _mui_stdfile_load_pref(std);
if (f) {
char * path = NULL;
size_t len = 0;
getline(&path, &len, f);
fclose(f);
if (path) {
char *nl = strrchr(path, '\n');
if (nl)
*nl = 0;
if (_mui_stdfile_populate(std, path) == 0) {
printf("%s last path[%s]: %s\n", __func__,
std->re_pattern, path);
dopop = 0;
}
free(path);
}
}
} }
if (dopop) if (dopop)
_mui_stdfile_populate(std, start_path); _mui_stdfile_populate(std, start_path);
@ -480,6 +626,20 @@ mui_stdfile_get(
return w; return w;
} }
mui_window_t *
mui_stdfile_get(
struct mui_t * ui,
c2_pt_t where,
const char * prompt,
const char * pattern,
const char * start_path,
uint16_t flags )
{
mui_window_t *w = mui_stdfile_make_window(ui, where,
prompt, pattern, start_path, NULL, flags);
return w;
}
char * char *
mui_stdfile_get_path( mui_stdfile_get_path(
mui_window_t * w ) mui_window_t * w )

View File

@ -13,7 +13,7 @@ mui_time_t
mui_get_time() mui_get_time()
{ {
struct timespec tim; struct timespec tim;
clock_gettime(CLOCK_MONOTONIC_RAW, &tim); clock_gettime(CLOCK_MONOTONIC, &tim);
uint64_t time = ((uint64_t)tim.tv_sec) * (1000000 / MUI_TIME_RES) + uint64_t time = ((uint64_t)tim.tv_sec) * (1000000 / MUI_TIME_RES) +
tim.tv_nsec / (1000 * MUI_TIME_RES); tim.tv_nsec / (1000 * MUI_TIME_RES);
return time; return time;

View File

@ -120,7 +120,7 @@ mui_wdef_titlewindow(
if (win->control_focus.control->cdef) if (win->control_focus.control->cdef)
win->control_focus.control->cdef( win->control_focus.control->cdef(
win->control_focus.control, win->control_focus.control,
MUI_CDEF_ACTIVATE, &activate); MUI_CDEF_FOCUS, &activate);
} }
break; break;
case MUI_WDEF_DESELECT: case MUI_WDEF_DESELECT:
@ -129,7 +129,7 @@ mui_wdef_titlewindow(
if (win->control_focus.control->cdef) if (win->control_focus.control->cdef)
win->control_focus.control->cdef( win->control_focus.control->cdef(
win->control_focus.control, win->control_focus.control,
MUI_CDEF_ACTIVATE, &activate); MUI_CDEF_FOCUS, &activate);
} }
break; break;
case MUI_WDEF_DISPOSE: case MUI_WDEF_DISPOSE:
@ -256,6 +256,10 @@ mui_window_draw(
mui_drawable_clip_pop(dr); mui_drawable_clip_pop(dr);
} }
/*
* Keys are passed first to the control that is in focus (if any), then
* to all the others in sequence until someone handles it (or not).
*/
bool bool
mui_window_handle_keyboard( mui_window_handle_keyboard(
mui_window_t *win, mui_window_t *win,
@ -273,12 +277,20 @@ mui_window_handle_keyboard(
/* /*
* Start with the control in focus, if there's any * Start with the control in focus, if there's any
*/ */
mui_control_t * c = win->control_focus.control, *safe; mui_control_t * first = win->control_focus.control ?
TAILQ_FOREACH_FROM_SAFE(c, &win->controls, self, safe) { win->control_focus.control :
TAILQ_FIRST(&win->controls);
mui_control_t * c = first;
while (c) {
if (mui_control_event(c, event)) { if (mui_control_event(c, event)) {
// printf("%s control %s handled it\n", __func__, c->title); // printf("%s control %s handled it\n", __func__, c->title);
return true; return true;
} }
c = TAILQ_NEXT(c, self);
if (!c)
c = TAILQ_FIRST(&win->controls);
if (c == first)
break;
} }
return false; return false;
} }
@ -381,6 +393,8 @@ mui_window_handle_mouse(
case MUI_EVENT_MOUSEENTER: case MUI_EVENT_MOUSEENTER:
case MUI_EVENT_MOUSELEAVE: case MUI_EVENT_MOUSELEAVE:
break; break;
default:
break;
} }
// printf("MOUSE %s button %d\n", __func__, event->mouse.button); // printf("MOUSE %s button %d\n", __func__, event->mouse.button);
// printf("MOUSE %s %s\n", __func__, c->title); // printf("MOUSE %s %s\n", __func__, c->title);
@ -513,12 +527,12 @@ mui_window_lock(
// __func__, win->title, win->lock.ref.count); // __func__, win->title, win->lock.ref.count);
} }
void mui_window_t*
mui_window_unlock( mui_window_unlock(
mui_window_t *win) mui_window_t *win)
{ {
if (!win) if (!win)
return; return NULL;
if (win->lock.window) { if (win->lock.window) {
if (win->lock.ref.trace) if (win->lock.ref.trace)
printf("%s: window %s was locked\n", printf("%s: window %s was locked\n",
@ -532,13 +546,16 @@ mui_window_unlock(
printf("%s: window %s unlocked delete %d\n", printf("%s: window %s unlocked delete %d\n",
__func__, win->title, delete); __func__, win->title, delete);
mui_window_deref(&win->lock); mui_window_deref(&win->lock);
if (delete) if (delete) {
mui_window_dispose(win); mui_window_dispose(win);
win = NULL;
}
} }
} else { } else {
// if (win->lock.ref.trace) // if (win->lock.ref.trace)
printf("%s: window %s was not locked\n", __func__, win->title); printf("%s: window %s was not locked\n", __func__, win->title);
} }
return win;
} }
void void

19
libmui/tests/Makefile Normal file
View File

@ -0,0 +1,19 @@
# Makefile
#
# Copyright (C) 2024 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
# Check to see if we are a submodule of the MII emulator
MII_PLUG := ${wildcard ../../ui_gl/*.c}
ifneq ($(MII_PLUG),)
PLUGS += mii_ui
endif
PLUGS += mui_widgets_demo
all :
for plug in $(PLUGS); do \
$(MAKE) -C $$plug; \
done

View File

@ -0,0 +1,39 @@
# Makefile
#
# Copyright (C) 2024 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
TARGET := mii_ui_tests
LIBMUI := ../../
MII := ../../../
all : $(TARGET)
include $(LIBMUI)/Makefile.common
vpath %.c $(MII)/ui_gl
CPPFLAGS += -I$(MII)/ui_gl
.PHONY : $(TARGET)
$(TARGET) : $(LIB)/$(TARGET).so
MII_UI_OBJ := $(OBJ)/mii_mui_slots.o \
$(OBJ)/mii_mui_loadbin.o \
$(OBJ)/mii_mui_1mb.o \
$(OBJ)/mii_mui_2dsk.o \
$(OBJ)/mii_mui_about.o \
$(OBJ)/mii_mui_ssc.o \
$(OBJ)/mii_mui_utils.o
$(LIB)/$(TARGET).so : $(OBJ)/$(TARGET).o $(MII_UI_OBJ)
$(LIB)/$(TARGET).so : LDLIBS += $(LIB)/libmui.a
$(OBJ)/mii_mui_about.o : CPPFLAGS+=-DMII_ICON64_DEFINE
clean:
rm -rf $(LIB)/$(TARGET).so $(MII_UI_OBJ)
-include $(OBJ)/*.d

View File

@ -0,0 +1,4 @@
### MII Emulator test plugin
This is compiled only when libmui is part of the MII build.

View File

@ -13,7 +13,7 @@
#include <unistd.h> #include <unistd.h>
#include "mui.h" #include "mui.h"
#include "mui_plugin.h" #include "mui_shell_plugin.h"
#include "c2_geometry.h" #include "c2_geometry.h"
typedef struct cg_ui_t { typedef struct cg_ui_t {
@ -24,9 +24,8 @@ typedef struct cg_ui_t {
#include "mii_mui_menus.h" #include "mii_mui_menus.h"
#include "mii_mui_settings.h" #include "mii_mui_settings.h"
#ifndef MUI_VERSION
#ifndef UI_VERSION #define MUI_VERSION "0.0.0"
#define UI_VERSION "0.0.0"
#endif #endif
static void static void
@ -39,8 +38,8 @@ _test_show_about(
return; return;
} }
w = mui_alert(g->ui, C2_PT(0,0), w = mui_alert(g->ui, C2_PT(0,0),
"About MII", "About MUI",
"Version " UI_VERSION "\n" "Version " MUI_VERSION "\n"
"Build " __DATE__ " " __TIME__, "Build " __DATE__ " " __TIME__,
MUI_ALERT_INFO); MUI_ALERT_INFO);
mui_window_set_id(w, FCC('a','b','o','t')); mui_window_set_id(w, FCC('a','b','o','t'));
@ -49,8 +48,6 @@ _test_show_about(
static mii_machine_config_t g_machine_conf = {}; static mii_machine_config_t g_machine_conf = {};
static mii_loadbin_conf_t g_loadbin_conf = {}; static mii_loadbin_conf_t g_loadbin_conf = {};
/* this is heavily endian dependend, as is the FCC macro */
#define FCC_INDEX(_fcc) (isdigit(_fcc>>24) ? ((_fcc >> 24) - '0') : 0)
int int
_test_menubar_action( _test_menubar_action(
@ -105,7 +102,8 @@ _test_menubar_action(
(char*)&item->uid, item->title); (char*)&item->uid, item->title);
switch (item->uid) { switch (item->uid) {
case FCC('a','b','o','t'): { case FCC('a','b','o','t'): {
_test_show_about(g); // _test_show_about(g);
mii_mui_about(g->ui);
} break; } break;
case FCC('q','u','i','t'): { case FCC('q','u','i','t'): {
printf("%s Quit\n", __func__); printf("%s Quit\n", __func__);
@ -143,58 +141,6 @@ _test_menubar_action(
return 0; return 0;
} }
static void
plain_test_window(
mui_t *mui)
{
mui_window_t *w = mui_window_get_by_id(mui, FCC('t','e','s','t'));
if (w) {
mui_window_select(w);
return;
}
c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 510, 270);
if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos,
(mui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
(mui->screen_size.y * 0.45) - (c2_rect_height(&wpos) / 2));
w = mui_window_create(mui, wpos, NULL, MUI_WINDOW_LAYER_NORMAL,
"Test", 0);
mui_window_set_id(w, FCC('t','e','s','t'));
mui_control_t * c = NULL;
c2_rect_t cf;
cf = C2_RECT_WH(10, 10, 480, 170);
c = mui_textedit_control_new(w, cf,
MUI_CONTROL_TEXTBOX_FRAME | MUI_CONTROL_TEXTEDIT_VERTICAL);
mui_textedit_set_text(c,
"The quick brown fox Jumps over the Lazy dog.\n"
"Lorem Ipsum is simply dummy text of the printing "
"and typesetting industry. Lorem Ipsum has been the "
"industry's standard dummy text ever since the 1500s.\n"
#if 1
"Now let's step back and look at what's happening. "
"Writing to the disk is a load and shift process, a "
"little like HIRES pattern outputs but much slower.\n"
"Also, the MPU takes a very active role in the loading "
"and shifting of disk write data. There are two 8-Htate "
"loops in the WRITE sequence. After initializing the "
"WRITE sequence, data is stored in the data register "
"at a critical point in the A7' loop. As (quickly "
"thereafter as the 6502 can do it, the sequencer is "
"configured to shift left at the critical point "
"instead of loading."
#endif
);
c2_rect_bottom_of(&cf, cf.b, 10);
cf.b = cf.t + 35;
c = mui_textedit_control_new(w, cf, MUI_CONTROL_TEXTBOX_FRAME);
mui_textedit_set_text(c,
"Fulling Mill Online Return Center.pdf");
}
static void * static void *
_init( _init(
struct mui_t * ui, struct mui_t * ui,
@ -221,9 +167,8 @@ _init(
mui_menubar_add_simple(mbar, "CPU", mui_menubar_add_simple(mbar, "CPU",
FCC('c','p','u','m'), FCC('c','p','u','m'),
m_cpu_menu); m_cpu_menu);
plain_test_window(ui);
// mii_mui_configure_slots(g->ui, &g_machine_conf); // mii_mui_configure_slots(g->ui, &g_machine_conf);
// mii_mui_load_binary(g->ui, &g_loadbin_conf); mii_mui_load_binary(g->ui, &g_loadbin_conf);
// mii_mui_load_1mbrom(g->ui, &g_machine_conf.slot[0].conf.rom1mb); // mii_mui_load_1mbrom(g->ui, &g_machine_conf.slot[0].conf.rom1mb);
// mii_mui_load_2dsk(g->ui, &g_machine_conf.slot[0].conf.disk2, MII_2DSK_DISKII); // mii_mui_load_2dsk(g->ui, &g_machine_conf.slot[0].conf.disk2, MII_2DSK_DISKII);
// mii_mui_about(g->ui); // mii_mui_about(g->ui);
@ -264,7 +209,6 @@ _draw(
mui_drawable_t *dr, mui_drawable_t *dr,
uint16_t all) uint16_t all)
{ {
// cg_ui_t *g = param;
mui_draw(ui, dr, all); mui_draw(ui, dr, all);
return 1; return 1;
} }
@ -275,16 +219,14 @@ _event(
void *param, void *param,
mui_event_t *event) mui_event_t *event)
{ {
// cg_ui_t *g = param;
// printf("%s %d\n", __func__, event->type);
mui_handle_event(ui, event); mui_handle_event(ui, event);
return 0; return 0;
} }
mui_plug_t mui_plug = { mui_plug_t mui_plug = {
.init = _init, .name = "MII UI Test",
.dispose = _dispose, .init = _init,
.draw = _draw, .dispose = _dispose,
.event = _event, .draw = _draw,
.event = _event,
}; };

View File

@ -1,33 +0,0 @@
/*
* mui_plugin.h
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
struct mui_t;
struct mui_drawable_t;
typedef struct mui_plug_t {
void * (*init)(
struct mui_t * ui,
struct mui_plug_t * plug,
struct mui_drawable_t * dr );
void (*dispose)(
void * plug );
int (*draw)(
struct mui_t *ui,
void *param,
struct mui_drawable_t * dr,
uint16_t all );
int (*event)(
struct mui_t *ui,
void *param,
struct mui_event_t * event );
} mui_plug_t;

View File

@ -0,0 +1,24 @@
# Makefile
#
# Copyright (C) 2024 Michel Pollet <buserror@gmail.com>
#
# SPDX-License-Identifier: MIT
TARGET := mui_widgets_demo
LIBMUI := ../../
all : $(TARGET)
include $(LIBMUI)/Makefile.common
.PHONY : $(TARGET)
$(TARGET) : $(LIB)/$(TARGET).so
$(LIB)/$(TARGET).so : $(OBJ)/$(TARGET).o
$(LIB)/$(TARGET).so : LDLIBS += $(LIB)/libmui.a
clean:
rm -rf $(LIB)/$(TARGET).so
-include $(OBJ)/*.d

View File

@ -0,0 +1,110 @@
// Autogenerated with:
// libmui/utils/png2raw.c -n mui_color_apple -o ui_gl/mui_color_apple.h docs/Apple_logo_rainbow_version2_28x28.png
// Image with a W:28px, H:28px and 4 channels
// Converted to ARGB8888 and premultiplied alpha
#pragma once
#define MUI_COLOR_APPLE_SIZE 786
extern const uint32_t mui_color_apple[MUI_COLOR_APPLE_SIZE];
#ifdef MUI_COLOR_APPLE_DEFINE
const uint32_t mui_color_apple[MUI_COLOR_APPLE_SIZE] = {
28, 28, // width, height
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x481b3413,0x99396f29,0x270e1c0a,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x13070d05,0xb3438230,0xff60ba45,0xff60ba45,0x240d1a09,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x02000100,0xbe478a33,0xff60ba45,
0xff60ba45,0xe155a43d,0x03010200,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x5d234319,0xff60ba45,0xff60ba45,0xff60ba45,0x6425491b,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xac417d2f,0xff60ba45,0xff60ba45,
0x9d3b722a,0x02010100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x01000000,0x260d1b09,0x3614270e,0x260d1b09,0x02000100,
0x00000000,0xbe478a33,0xbe478a33,0x56203e17,0x03010200,0x270e1c09,0x38162911,0x280e1c09,
0x02000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x57203f17,0xda529f3b,
0xff60ba45,0xff60ba45,0xff60ba45,0xe054a33d,0x8d356626,0x4d1d3815,0x4b1a3612,0x90366927,
0xe556a73e,0xff60ba45,0xff60ba45,0xff60ba45,0xdf54a23c,0x6225471a,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x86326124,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0x99396f29,0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x6c524e16,0xffc3b834,0xffc3b834,0xffc3b834,
0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,
0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0xffc3b834,0x933b6d2d,0x08030502,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x100f0b03,
0xf0edac24,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0x8d8b6515,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x59573f0d,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xe8e5a623,0x0b0a0803,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x89855713,
0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,
0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,0xfff9a323,
0xa09c6616,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0xa79f5214,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,
0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,
0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0x76703b0e,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xa49c5313,
0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,
0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,0xfff4811e,
0x9d964f13,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x7f773b12,0xfff07724,0xfff07724,0xfff07724,0xfff07724,
0xfff07724,0xfff07724,0xfff07724,0xfff07724,0xfff07724,0xfff07724,0xfff07724,0xfff07724,
0xfff07724,0xfff07724,0xfff07724,0xfff07724,0xe3d56a20,0x05040101,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x4e441112,
0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,
0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,
0xffdf393d,0x79691b1d,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x13100404,0xf8d9383c,0xffdf393d,0xffdf393d,0xffdf393d,
0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,
0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xffdf393d,0xfddd393d,0x74651a1c,0x01000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0xb49e3335,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,
0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,0xffe1484b,
0xffe1484b,0xffe1484b,0xffe1484b,0xab983d3f,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x3e240e24,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0x5c351536,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0xb86b2b6c,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xc8752f75,0x04020102,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x26160a16,0xf4a265a2,0xff5ca4d9,
0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,
0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xff5ca4d9,0xf7a466a4,0x2c1a0b1a,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x630b3a52,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0x670c3c56,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x780e4664,
0xfb0099d7,0xff009cdb,0xff009cdb,0xff009cdb,0xd90085ba,0xaa13638e,0xa913638d,0xca007bad,
0xfe009bda,0xff009cdb,0xff009cdb,0xfd009bd9,0x7f0e4a6a,0x01000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x30001c29,0x8a005476,0x8a005476,0x3c072332,
0x00000000,0x00000000,0x00000000,0x00000000,0x30081e29,0x87005274,0x8c005578,0x3500202d,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};
#endif /* MUI_COLOR_APPLE_DEFINE */

View File

@ -0,0 +1,600 @@
/*
* ui_tests.c
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#define _GNU_SOURCE // for asprintf
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "mui.h"
#include "mui_shell_plugin.h"
#include "c2_geometry.h"
typedef struct cg_ui_t {
mui_t *ui;
} cg_ui_t;
static void
_test_show_about(
cg_ui_t *g)
{
mui_window_t *w = mui_window_get_by_id(g->ui, FCC('a','b','o','t'));
if (w) {
mui_window_select(w);
return;
}
w = mui_alert(g->ui, C2_PT(0,0),
"About MUI",
"Version " MUI_VERSION "\n"
"Build " __DATE__ " " __TIME__,
MUI_ALERT_INFO);
mui_window_set_id(w, FCC('a','b','o','t'));
}
static void
_test_textedit_demo(
mui_t *mui)
{
mui_window_t *w = mui_window_get_by_id(mui, FCC('t','e','s','t'));
if (w) {
mui_window_select(w);
return;
}
c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 510, 270);
if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos,
(mui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
(mui->screen_size.y * 0.45) - (c2_rect_height(&wpos) / 2));
w = mui_window_create(mui, wpos, NULL, MUI_WINDOW_LAYER_NORMAL,
"This is VERY Work in Progress", 0);
mui_window_set_id(w, FCC('t','e','s','t'));
mui_control_t * c = NULL;
c2_rect_t cf;
cf = C2_RECT_WH(10, 10, 480, 170);
c = mui_textedit_control_new(w, cf,
MUI_CONTROL_TEXTBOX_FRAME | MUI_CONTROL_TEXTEDIT_VERTICAL);
mui_textedit_set_text(c,
"The quick brown fox Jumps over the Lazy dog.\n"
"Lorem Ipsum is simply dummy text of the printing "
"and typesetting industry. Lorem Ipsum has been the "
"industry's standard dummy text ever since the 1500s.\n"
#if 1
"Now let's step back and look at what's happening. "
"Writing to the disk is a load and shift process, a "
"little like HIRES pattern outputs but much slower.\n"
"Also, the MPU takes a very active role in the loading "
"and shifting of disk write data. There are two 8-state "
"loops in the WRITE sequence. After initializing the "
"WRITE sequence, data is stored in the data register "
"at a critical point in the A7' loop. As (quickly "
"thereafter as the 6502 can do it, the sequencer is "
"configured to shift left at the critical point "
"instead of loading."
#endif
);
c2_rect_bottom_of(&cf, cf.b, 10);
cf.b = cf.t + 35;
c = mui_textedit_control_new(w, cf, MUI_CONTROL_TEXTBOX_FRAME);
mui_textedit_set_text(c,
"Fulling Mill Online Return Center.pdf");
}
static void
_test_static_text_and_boxes(
struct mui_t *ui)
{
mui_window_t *w = mui_window_get_by_id(ui, FCC('s','t','x','t'));
if (w) {
mui_window_select(w);
return;
}
c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 566, 320);
if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos,
(ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
(ui->screen_size.y * 0.45) - (c2_rect_height(&wpos) / 2));
w = mui_window_create(ui, wpos, NULL, MUI_WINDOW_LAYER_NORMAL,
"Static Text and Boxes", 0);
mui_window_set_id(w, FCC('s','t','x','t'));
float base_size = mui_font_find(ui, "main")->size;
float margin = base_size * 0.7;
mui_control_t * c = NULL;
c2_rect_t cf, cb;
cf = C2_RECT_WH(margin, margin/2, 250, 3 + base_size * 4);
c = mui_groupbox_new(w, cf, "Justification: ", 0);
cb = cf;
cb.t += base_size;
cb.b = cb.t + base_size;
cb.l += margin / 3;
cb.r = cf.r - (margin / 3);
uint16_t debug_frames = 0;//MUI_CONTROL_TEXTBOX_FRAME;
c = mui_textbox_new(w, cb, "Left Aligned", NULL,
MUI_TEXT_ALIGN_LEFT | debug_frames);
cb = c2_rect_bottom_of(&cb, cb.b, 0);
c = mui_textbox_new(w, cb, "Centered & Grayed", NULL,
MUI_TEXT_ALIGN_CENTER | debug_frames);
mui_control_set_state(c, MUI_CONTROL_STATE_DISABLED);
cb = c2_rect_bottom_of(&cb, cb.b, 0);
c = mui_textbox_new(w, cb, "Right Aligned", NULL,
MUI_TEXT_ALIGN_RIGHT | debug_frames);
c2_rect_t bottom_box = cf;
bottom_box = c2_rect_bottom_of(&bottom_box, bottom_box.b, margin*1.5);
c2_rect_t sr = cf;
cf = c2_rect_right_of(&cf, cf.r, margin);
// plonk in a separator to demo them
sr.r = cf.r;
sr.t = sr.b - 2;
c2_rect_inset(&sr, 80, 0);
sr = c2_rect_bottom_of(&sr, sr.b, margin);
mui_separator_new(w, sr);
c = mui_groupbox_new(w, cf, "Style: ", MUI_TEXT_ALIGN_RIGHT);
cb = cf;
cb.t += base_size;
cb.b = cb.t + base_size;
cb.l += margin / 3;
cb.r = cf.r - (margin / 3);
c = mui_textbox_new(w, cb, "Synthetic Bold", NULL,
MUI_TEXT_ALIGN_CENTER | MUI_TEXT_STYLE_BOLD);
cb = c2_rect_bottom_of(&cb, cb.b, 0);
c = mui_textbox_new(w, cb, "With Narrow Spacing", NULL,
MUI_TEXT_ALIGN_CENTER | MUI_TEXT_STYLE_NARROW);
cb = c2_rect_bottom_of(&cb, cb.b, 0);
c = mui_textbox_new(w, cb, "El Cheapo Underline", NULL,
MUI_TEXT_ALIGN_CENTER | MUI_TEXT_STYLE_ULINE);
cb = c2_rect_bottom_of(&cb, cb.b, 0);
cf = bottom_box;
c = mui_groupbox_new(w, cf, "Spacing: ", 0);
cb = cf;
cb.t += base_size;
cb.b = cb.t + base_size*3;
cb.l += margin / 3;
cb.r = cb.l + (c2_rect_width(&cf) / 2) - (margin / 3);
c = mui_textbox_new(w, cb, "Normal\nLine\nSpacing", NULL,
MUI_TEXT_ALIGN_CENTER | 0 | debug_frames);
cb = c2_rect_right_of(&cb, cb.r, margin/3);
c = mui_textbox_new(w, cb, "Compact\nLine\nSpacing", NULL,
MUI_TEXT_ALIGN_CENTER | MUI_TEXT_ALIGN_COMPACT | debug_frames);
cf = c2_rect_right_of(&cf, cf.r, margin);
c = mui_groupbox_new(w, cf, "Justification: ", 0);
cb = cf;
cb.t += base_size;
cb.b = cb.t + base_size * 3;
cb.l += margin / 3;
cb.r = cf.r - (margin / 3);
c = mui_textbox_new(w, cb,
"This quick brown fox is both Narrow, "
"and Fully Justified these days.", NULL,
MUI_TEXT_STYLE_NARROW | MUI_TEXT_ALIGN_FULL | debug_frames);
}
/*
* This demos most of the controls, buttons, radios, checkboxes, listbox
* and a few other things.
*/
static void
_test_demo_all_controls(
struct mui_t *ui)
{
mui_window_t *w = mui_window_get_by_id(ui, FCC('d','e','m','o'));
if (w) {
mui_window_select(w);
return;
}
c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 620, 380);
if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos,
(ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
(ui->screen_size.y * 0.45) - (c2_rect_height(&wpos) / 2));
w = mui_window_create(ui, wpos, NULL, MUI_WINDOW_LAYER_NORMAL,
"Control Demo", 0);
mui_window_set_id(w, FCC('d','e','m','o'));
float base_size = mui_font_find(ui, "main")->size;
float margin = base_size * 0.7;
mui_control_t * c = NULL;
c2_rect_t cf;
cf = C2_RECT_WH(0, 0, base_size * 5, base_size * 1.4);
c2_rect_left_of(&cf, c2_rect_width(&w->content), margin);
c2_rect_top_of(&cf, c2_rect_height(&w->content), margin);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_DEFAULT,
"Default", 0);
c->key_equ = MUI_KEY_EQU(0, 13); // return
cf = c2_rect_left_of(&cf, cf.l, margin);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL,
"Normal", 0);
c->key_equ = MUI_KEY_EQU(0, 32); // space
cf = c2_rect_left_of(&cf, cf.l, margin);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL,
"Disabled", 0);
mui_control_set_state(c, MUI_CONTROL_STATE_DISABLED);
/* Radio can have a mask, if so, they each UID that matches the
* mask will switch like radio buttons ought to, without having to
* keep track of which are on or off */
uint32_t radio_uid = FCC('r','a','d','0');
cf = C2_RECT_WH(margin, margin, base_size * 7, base_size * 1.4);
c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
"Radio Button", FCC_INDEXED(radio_uid, 0));
c->uid_mask = FCC_MASK;
mui_control_set_value(c, 1);
cf = c2_rect_bottom_of(&cf, cf.b, 0);
c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
"Other Radio", FCC_INDEXED(radio_uid, 1));
mui_control_set_state(c, MUI_CONTROL_STATE_DISABLED);
c->uid_mask = FCC_MASK;
cf = c2_rect_bottom_of(&cf, cf.b, 0);
c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
"Third Choice", FCC_INDEXED(radio_uid, 2));
c->uid_mask = FCC_MASK;
c2_rect_t first_column = cf;
cf = c2_rect_right_of(&cf, cf.r, margin);
cf.r = cf.l + base_size * 6;
c2_rect_offset(&cf, 0, -cf.t + margin);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_CHECKBOX,
"Checkbox", 0);
cf = c2_rect_bottom_of(&cf, cf.b, margin/2);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_CHECKBOX,
"Another Checkbox", 0);
mui_control_set_value(c, 1);
c2_rect_t second_column = cf;
cf = first_column;
cf = c2_rect_bottom_of(&cf, cf.b, margin);
c2_rect_t lr = cf;
lr.r = lr.l + base_size * 3;
c = mui_textbox_new(w, lr, "Popup:", NULL, MUI_TEXT_ALIGN_LEFT);
cf = c2_rect_right_of(&cf, lr.r, 0);
//c2_rect_offset(&cf, 0, -cf.t + margin);
cf.b = cf.t + 34;
c = mui_popupmenu_new(w, cf, "Popup", 0, MUI_TEXT_ALIGN_LEFT);
mui_menu_items_t *items = mui_popupmenu_get_items(c);
mui_menu_items_add(items, (mui_menu_item_t){.title="1200", .uid=1200 });
mui_menu_items_add(items, (mui_menu_item_t){.title="2400", .uid=2400 });
mui_menu_items_add(items, (mui_menu_item_t){.title="4800", .uid=4800 });
mui_menu_items_add(items, (mui_menu_item_t){.title="9600", .uid=9600 });
mui_menu_items_add(items, (mui_menu_item_t){.title="19200", .uid=19200 });
// popup needs to be NULL terminated, AND prepared()
mui_menu_items_add(items, (mui_menu_item_t){.title=NULL });
mui_popupmenu_prepare(c);
lr = c2_rect_bottom_of(&lr, lr.b, margin/4);
lr.r = lr.l + base_size * 3;
c = mui_textbox_new(w, lr, "Icons:", NULL, MUI_TEXT_ALIGN_LEFT);
cf = c2_rect_bottom_of(&cf, cf.b, margin/4);
//c2_rect_offset(&cf, 0, -cf.t + margin);
cf.b = cf.t + 34;
c = mui_popupmenu_new(w, cf, "Popup", 0, MUI_TEXT_ALIGN_LEFT);
items = mui_popupmenu_get_items(c);
mui_menu_items_add(items,
(mui_menu_item_t){.title="Icon", .uid=1200, .icon=MUI_ICON_HARDDISK });
mui_menu_items_add(items,
(mui_menu_item_t){.title="Others", .uid=2400, .icon=MUI_ICON_FOLDER });
// popup needs to be NULL terminated, AND prepared()
mui_menu_items_add(items, (mui_menu_item_t){.title=NULL });
mui_popupmenu_prepare(c);
lr = c2_rect_bottom_of(&lr, lr.b, margin/4);
lr.r = lr.l + base_size * 4.2;
c = mui_textbox_new(w, lr, "Scrollbar:", NULL, MUI_TEXT_ALIGN_LEFT);
c2_rect_right_of(&cf, lr.r, margin/4);
cf = c2_rect_bottom_of(&cf, cf.b, margin/2);
cf.b = cf.t + base_size;
cf.r = cf.l + 200;
c = mui_scrollbar_new(w, cf, 0, 5, 20);
mui_scrollbar_set_max(c, 255);
// mui_scrollbar_set_page(c, 10);
cf = second_column;
cf.b = cf.t + base_size;
cf = c2_rect_right_of(&cf, cf.r, margin);
c2_rect_offset(&cf, 0, -cf.t + margin);
c = mui_textbox_new(w, cf, "Listbox:", NULL, 0);
c2_rect_bottom_of(&cf, cf.b, 0);
cf.b = cf.t + 6 * base_size;
c = mui_listbox_new(w, cf, 0);
mui_listbox_elems_t * elems = mui_listbox_get_elems(c);
for (int i = 0; i < 25; i++) {
mui_listbox_elem_t e = {
.icon = MUI_ICON_FILE,
};
asprintf((char**)&e.elem, "Item %d", i);
mui_listbox_elems_add(elems, e);
}
mui_listbox_prepare(c);
}
#define MUI_COLOR_APPLE_DEFINE
#include "mui_color_apple.h"
mui_menu_item_t m_color_apple_menu[] = {
{ .color_icon = mui_color_apple, .is_menutitle = 1, },
{ .title = "About MUI…",
.uid = FCC('a','b','o','t') },
// { .title = "-", },
{ },
};
mui_menu_item_t m_file_menu[] = {
{ .title = "Quit",
.uid = FCC('q','u','i','t'),
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_SUPER, 'Q'),
.kcombo = MUI_GLYPH_COMMAND "Q" },
{ },
};
mui_menu_item_t m_sub_menu1[] = {
{ .title = "Hierarchical Menu",
.uid = FCC('s','h','m','b'),
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_RCTRL, MUI_KEY_F1),
.kcombo = MUI_GLYPH_CONTROL MUI_GLYPH_F1 },
{ .title = "Disabled item",
.disabled = 1,
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_RCTRL, MUI_KEY_F11),
.kcombo = MUI_GLYPH_CONTROL MUI_GLYPH_F11 },
{ .title = "-", },
{ .title = "Tick One",
.mark = MUI_GLYPH_TICK,
.uid = FCC('v','d','c','0') },
{ .title = "Tick Two",
.uid = FCC('v','d','c','1') },
{ },
};
mui_menu_item_t m_sub_menu2[] = {
{ .title = "Other Sub Menu",
.uid = FCC('s','h','m','b'),
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_RCTRL, MUI_KEY_F2),
.kcombo = MUI_GLYPH_CONTROL MUI_GLYPH_F2 },
{ .title = "Other Marked Item",
.uid = FCC('s','h','m','b'),
.mark = "!", },
{ },
};
mui_menu_item_t m_menu_demo[] = {
{ .title = MUI_GLYPH_OAPPLE "-Control-Reset",
.uid = FCC('c','r','e','s'),
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_RCTRL|MUI_MODIFIER_RSHIFT, MUI_KEY_F12),
.kcombo = MUI_GLYPH_CONTROL MUI_GLYPH_SHIFT MUI_GLYPH_F12 },
{ .title = "Control-Reset",
.uid = FCC('r','e','s','t'),
.key_equ = MUI_KEY_EQU(MUI_MODIFIER_RCTRL, MUI_KEY_F12),
.kcombo = MUI_GLYPH_CONTROL MUI_GLYPH_F12 },
{ .title = "-", },
{ .title = "Sub Menu",
.kcombo = MUI_GLYPH_SUBMENU,
.submenu = m_sub_menu1 },
{ .title = "Other Sub Menu",
.kcombo = MUI_GLYPH_SUBMENU,
.submenu = m_sub_menu2 },
{ },
};
mui_menu_item_t m_windows_menu[] = {
{ .title = "Basic Alert…",
.uid = FCC('a','l','e','r'), },
{ .title = "Standard 'get' file…",
.uid = FCC('s','t','d','g'), },
{ .title = "Static Text…",
.uid = FCC('s','t','x','t'), },
{ .title = "Text Edit (WIP!)…",
.uid = FCC('t','x','t','e'), },
{ .title = "Demo All Controls…",
.uid = FCC('d','e','m','o'), },
{ },
};
/*
* This is a 'window' action function that is called when the Alert window
* is interacted with. It typically you will get an ACTION_SELECT with
* ok or cancel.
*/
static int
_test_alert_action_cb(
mui_window_t *win,
void * cb_param,
uint32_t what,
void * param)
{
// cg_ui_t *g = cb_param;
printf("%s %4.4s\n", __func__, (char*)&what);
switch (what) {
case MUI_CONTROL_ACTION_SELECT: {
mui_control_t * c = param;
uint32_t uid = mui_control_get_uid(c);
printf("%s Button %4.4s\n", __func__, (char*)&uid);
} break;
}
return 0;
}
static int
_test_stdfile_action_cb(
mui_window_t *win,
void * cb_param,
uint32_t what,
void * param)
{
// cg_ui_t *g = cb_param;
printf("%s %4.4s\n", __func__, (char*)&what);
switch (what) {
case MUI_CONTROL_ACTION_SELECT: {
mui_control_t * c = param;
uint32_t uid = mui_control_get_uid(c);
printf("%s Button %4.4s\n", __func__, (char*)&uid);
} break;
case MUI_STDF_ACTION_CANCEL: {
printf("%s cancel was clicked\n", __func__);
mui_window_dispose(win);
} break;
}
return 0;
}
int
_test_menubar_action(
mui_window_t *win,
void * cb_param,
uint32_t what,
void * param)
{
cg_ui_t *g = cb_param;
// printf("%s %4.4s\n", __func__, (char*)&what);
switch (what) {
case MUI_MENUBAR_ACTION_PREPARE: {
// mui_menu_item_t * items = param;
} break;
case MUI_MENUBAR_ACTION_SELECT: {
mui_menu_item_t * item = param;
printf("%s Selected %4.4s '%s'\n", __func__,
(char*)&item->uid, item->title);
switch (item->uid) {
case FCC('a','b','o','t'): {
_test_show_about(g);
} break;
case FCC('q','u','i','t'): {
printf("%s Quit\n", __func__);
g->ui->quit_request = 1;
} break;
case FCC('a','l','e','r'): {
mui_window_t * w = mui_alert(g->ui, C2_PT(0,0),
"Testing one Two",
"Do you really want the printer to catch fire?\n"
"This operation cannot be cancelled.",
MUI_ALERT_WARN);
mui_window_set_action(w, _test_alert_action_cb, g);
} break;
case FCC('s','t','d','g'): {
mui_window_t *w = mui_stdfile_get(g->ui,
C2_PT(0, 0),
"Select image for SmartPort card",
"hdv,po,2mg",
getenv("HOME"), 0);
mui_window_set_action(w, _test_stdfile_action_cb, g);
} break;
case FCC('t','x','t','e'):
_test_textedit_demo(g->ui);
break;
case FCC('s','t','x','t'):
_test_static_text_and_boxes(g->ui);
break;
case FCC('d','e','m','o'):
_test_demo_all_controls(g->ui);
break;
default:
printf("%s menu item %4.4s %s IGNORED\n",
__func__, (char*)&item->uid, item->title);
break;
}
} break;
default:
printf("%s %4.4s IGNORED?\n", __func__, (char*)&what);
break;
}
return 0;
}
static void *
_init(
struct mui_t * ui,
struct mui_plug_t * plug,
mui_drawable_t * pix)
{
mui_init(ui);
ui->screen_size = pix->pix.size;
asprintf(&ui->pref_directory, "%s/.local/share/mui", getenv("HOME"));
cg_ui_t *g = calloc(1, sizeof(*g));
g->ui = ui;
printf("%s\n", __func__);
mui_window_t * mbar = mui_menubar_new(ui);
mui_window_set_action(mbar, _test_menubar_action, g);
mui_menubar_add_menu(mbar, FCC('a','p','p','l'), m_color_apple_menu, 2);
mui_menubar_add_simple(mbar, "File",
FCC('f','i','l','e'),
m_file_menu);
mui_menubar_add_simple(mbar, "Menus",
FCC('m','e','n','u'),
m_menu_demo);
mui_menubar_add_simple(mbar, "Windows",
FCC('w','i','n','d'),
m_windows_menu);
// _test_textedit_demo(ui);
// _test_static_text_and_boxes(ui);
_test_demo_all_controls(ui);
return g;
}
static void
_dispose(
void *_ui)
{
cg_ui_t *ui = _ui;
printf("%s\n", __func__);
mui_dispose(ui->ui);
free(ui);
}
static int
_draw(
struct mui_t *ui,
void *param,
mui_drawable_t *dr,
uint16_t all)
{
mui_draw(ui, dr, all);
return 1;
}
static int
_event(
struct mui_t *ui,
void *param,
mui_event_t *event)
{
mui_handle_event(ui, event);
return 0;
}
mui_plug_t mui_plug = {
.name = "MUI Widgets Demo",
.init = _init,
.dispose = _dispose,
.draw = _draw,
.event = _event,
};

108
libmui/utils/png2raw.c Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/tcc -run
/*
* This tool is made to load a PNG, and convert it to a C array with
* ARGB8888 format, premultiplied alpha.
* It uses stb_image.h to load the PNG, which isn't included in the
* repository. The tool isn't essential to build, but is useful if you
* want icons in your menus.
* The output is a C array, with the width and height of the image
* followed by the pixels in ARGB8888 format.
* The output is written to stdout, unless -o is used.
*/
#include <ctype.h>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_SIMD
#define STBI_NO_HDR
#include "/opt/projects/stb/stb_image.h"
static void usage(const char *argv0)
{
fprintf(stderr,
"Usage: %s -n <array_name> "
"[-o <output_filename>] "
"[-t <int type>] "
"<PNG filename>\n",
argv0);
}
int main(int argc, char **argv)
{
const char *array_name = NULL;
const char *fname = "docs/Apple_logo_rainbow_version2_28x28.png";
const char *int_type = "uint32_t";
FILE *out = stdout;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-n") && i + 1 < argc) {
array_name = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-o") && i + 1 < argc) {
out = fopen(argv[i + 1], "w");
if (!out) {
fprintf(stderr, "Error opening %s\n", argv[i + 1]);
usage(argv[0]);
return 1;
}
i++;
} else if (!strcmp(argv[i], "-t") && i + 1 < argc) {
int_type = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-h")) {
usage(argv[0]);
return 0;
} else {
fname = argv[i];
}
}
if (!array_name) {
fprintf(stderr, "Missing array name\n");
usage(argv[0]);
return 1;
}
char define_name[256];
strcpy(define_name, array_name);
for (int i = 0; define_name[i]; i++)
define_name[i] = toupper(define_name[i]);
int width, height, channels;
unsigned char *data = stbi_load(fname, &width, &height, &channels, 0);
if (!data) {
fprintf(stderr, "Error loading image\n");
return 1;
}
fprintf(out, "// Autogenerated with:\n//\t");
for (int i = 0; i < argc; i++)
fprintf(out, " %s", argv[i]);
fprintf(out, "\n");
fprintf(out, "// Image with a W:%dpx, H:%dpx and %d channels\n"
"// Converted to ARGB8888 and premultiplied alpha\n"
"#pragma once\n",
width, height, channels);
fprintf(out, "#define %s_SIZE %d\n", define_name, 2 + (width * height));
fprintf(out, "extern const %s %s[%s_SIZE];\n", int_type, array_name, define_name);
fprintf(out, "#ifdef %s_DEFINE\n", define_name);
fprintf(out, "const %s %s[%s_SIZE] = {\n", int_type, array_name, define_name);
fprintf(out, "%d, %d, // width, height\n", width, height);
uint32_t *pixels = (uint32_t *)data;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint32_t pixel = pixels[y * width + x];
// flip R and B channels
pixel = (pixel & 0xff00ff00) |
((pixel & 0xff) << 16) | ((pixel >> 16) & 0xff);
// also premultiply channels with alpha
uint32_t a = pixel >> 24;
pixel = (pixel & ~(0xff << 0)) |
((((((pixel >> 0) & 0xff) * a) >> 8) & 0xff) << 0);
pixel = (pixel & ~(0xff << 8)) |
((((((pixel >> 8) & 0xff) * a) >> 8) & 0xff) << 8);
pixel = (pixel & ~(0xff << 16)) |
((((((pixel >> 16) & 0xff) * a) >> 8) & 0xff) << 16);
fprintf(out, "0x%08x,", pixel);
if (((y * height) + x) % 8 == 7)
fprintf(out, "\n");
}
}
fprintf(out, "};\n");
fprintf(out, "#endif /* %s_DEFINE */\n", define_name);
return 0;
}

View File

@ -211,7 +211,7 @@ _mii_disk2_reset(
struct mii_slot_t *slot ) struct mii_slot_t *slot )
{ {
mii_card_disk2_t *c = slot->drv_priv; mii_card_disk2_t *c = slot->drv_priv;
printf("%s\n", __func__); // printf("%s\n", __func__);
c->selected = 1; c->selected = 1;
_mii_floppy_motor_off_cb(mii, c); _mii_floppy_motor_off_cb(mii, c);
c->selected = 0; c->selected = 0;
@ -247,11 +247,11 @@ _mii_disk2_access(
int read = 0; int read = 0;
switch (psw) { switch (psw) {
case 0x00 ... 0x07: { case 0x00 ... 0x07: {
static const int8_t delta[4][4] = {
{0, 1, 2, -1}, {-1, 0, 1, 2}, {-2, -1, 0, 1}, {1, -2, -1, 0},
};
if (on) { if (on) {
if ((f->stepper + 3) % 4 == p) _mii_disk2_switch_track(mii, c, delta[f->stepper][p] * 2);
_mii_disk2_switch_track(mii, c, -2);
else if ((f->stepper + 1) % 4 == p)
_mii_disk2_switch_track(mii, c, 2);
f->stepper = p; f->stepper = p;
} }
} break; } break;
@ -265,14 +265,15 @@ _mii_disk2_access(
mii_raise_signal(c->sig + SIG_MOTOR, 1); mii_raise_signal(c->sig + SIG_MOTOR, 1);
} else { } else {
int32_t timer = mii_timer_get(mii, c->timer_off); int32_t timer = mii_timer_get(mii, c->timer_off);
mii_timer_set(mii, c->timer_off, timer + 1000000); // one second mii_timer_set(mii, c->timer_off,
timer + (1000000 * mii->speed)); // one second
} }
} break; } break;
case 0x0A: case 0x0A:
case 0x0B: { case 0x0B: {
if (on != c->selected) { if (on != c->selected) {
c->selected = on; c->selected = on;
printf("SELECTED DRIVE: %d\n", c->selected); // printf("SELECTED DRIVE: %d\n", c->selected);
c->floppy[on].motor = f->motor; c->floppy[on].motor = f->motor;
f->motor = 0; f->motor = 0;
mii_raise_signal(c->sig + SIG_MOTOR, 0); mii_raise_signal(c->sig + SIG_MOTOR, 0);
@ -492,7 +493,7 @@ static const uint8_t lss_rom16s[16][16] = {
[READ|LOAD|QA1|RP0]={ 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A }, [READ|LOAD|QA1|RP0]={ 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A },
}; };
static const uint8_t SEQUENCER_ROM_16[256] = { static const uint8_t SEQUENCER_ROM_16[256] __attribute__((unused)) = {
// See Understanding the Apple IIe, Figure 9.11 The DOS 3.3 Logic State Sequencer // See Understanding the Apple IIe, Figure 9.11 The DOS 3.3 Logic State Sequencer
// Note that the column order here is NOT the same as in Figure 9.11 for Q7 H (Write). // Note that the column order here is NOT the same as in Figure 9.11 for Q7 H (Write).
// //
@ -625,8 +626,8 @@ _mii_disk2_lss_tick(
if (f->tracks[track_id].virgin) { if (f->tracks[track_id].virgin) {
f->tracks[track_id].virgin = 0; f->tracks[track_id].virgin = 0;
f->bit_position = 0; f->bit_position = 0;
if (track_id == 0) // if (track_id == 0)
_mii_disk2_vcd_debug(c, 1); // _mii_disk2_vcd_debug(c, 1);
} }
f->seed_dirty++; f->seed_dirty++;
} }
@ -694,13 +695,17 @@ _mii_mish_d2(
mii_floppy_t *f = &c->floppy[sel]; mii_floppy_t *f = &c->floppy[sel];
if (argv[2]) { if (argv[2]) {
int track = atoi(argv[2]); int track = atoi(argv[2]);
if (track < 0 || track >= MII_FLOPPY_TRACK_COUNT) {
printf("Invalid track %d\n", track);
return;
}
int count = 256; int count = 256;
if (argv[3]) { if (argv[3]) {
if (!strcmp(argv[3], "save")) { if (!strcmp(argv[3], "save")) {
// save one binary file in tmp with just that track // save one binary file in tmp with just that track
uint8_t *data = f->track_data[track]; uint8_t *data = f->track_data[track];
char *filename; char *filename;
asprintf(&filename, "/tmp/track_%d.bin", track); asprintf(&filename, "/tmp/track_%02d.bin", track);
int fd = open(filename, O_CREAT | O_WRONLY, 0666); int fd = open(filename, O_CREAT | O_WRONLY, 0666);
write(fd, data, MII_FLOPPY_DEFAULT_TRACK_SIZE); write(fd, data, MII_FLOPPY_DEFAULT_TRACK_SIZE);
close(fd); close(fd);
@ -729,7 +734,7 @@ _mii_mish_d2(
printf("\n"); printf("\n");
} }
} else { } else {
printf("track <track 0-36> [count]\n"); printf("track <track 0-34> [count]\n");
} }
return; return;
} }
@ -783,6 +788,7 @@ _mii_mish_d2(
if (!strcmp(argv[1], "vcd")) { if (!strcmp(argv[1], "vcd")) {
mii_card_disk2_t *c = _mish_d2; mii_card_disk2_t *c = _mish_d2;
_mii_disk2_vcd_debug(c, !c->vcd); _mii_disk2_vcd_debug(c, !c->vcd);
return;
} }
} }
@ -791,6 +797,16 @@ _mii_mish_d2(
MISH_CMD_NAMES(d2, "d2"); MISH_CMD_NAMES(d2, "d2");
MISH_CMD_HELP(d2, MISH_CMD_HELP(d2,
"d2: disk ][ internals", "d2: disk ][ internals",
" <default>: dump status" " <default>: dump status",
" list: list drives",
" sel [0-1]: select drive",
" wp [0-1]: write protect",
" track <track 0-34> [count]: dump track",
" track <track 0-34> save: save in /tmp/trackXX.bin",
" dirty: mark track as dirty",
" resync: resync all tracks",
" map: show track map",
" trace: toggle debug trace",
" vcd: toggle VCD debug"
); );
MII_MISH(d2, _mii_mish_d2); MII_MISH(d2, _mii_mish_d2);

View File

@ -115,7 +115,7 @@ _mii_ee_command(
res = 0; res = 0;
} }
break; break;
case MII_SLOT_DRIVE_LOAD: case MII_SLOT_DRIVE_LOAD: {
const char *filename = param; const char *filename = param;
mii_dd_file_t *file = NULL; mii_dd_file_t *file = NULL;
if (filename && *filename) { if (filename && *filename) {
@ -126,7 +126,7 @@ _mii_ee_command(
mii_dd_drive_load(&c->drive[0], file); mii_dd_drive_load(&c->drive[0], file);
c->file = file ? file->map : (uint8_t*)mii_1mb_rom_data; c->file = file ? file->map : (uint8_t*)mii_1mb_rom_data;
res = 0; res = 0;
break; } break;
} }
return res; return res;
} }

171
src/drivers/mii_mb.c Normal file
View File

@ -0,0 +1,171 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mii.h"
#include "mockingboard.h"
typedef struct mii_mb_t {
mii_t * mii;
uint8_t init; // init sequence bits
bool init_done;
uint8_t timer;
struct mb_t *mb;
} mii_mb_t;
static uint64_t
_mii_mb_timer(
mii_t * mii,
void * param )
{
mii_mb_t * mb = param;
mb_clock_t clock = {
.ref_step = 1,
.ts = mii->cpu.total_cycle,
};
// delta is ALWAYS negative or zero here
int32_t delta = mii_timer_get(mii, mb->timer);
uint64_t ret = -delta + 1;
if (mb_io_sync(mb->mb, &clock)) {
// printf("MB Sync IRQ\n");
mii->cpu_state.irq = 1;
}
return ret;
}
static void
mii_mb_start(
mii_mb_t *mb)
{
// mb_io_reset(mb->mb, &clock);
printf("MB Start\n");
mb->init = 0;
mb->init_done = true;
mb->timer = mii_timer_register(mb->mii, _mii_mb_timer, mb, 1, __func__);
}
/*
* this is a protothread, so remember no locals that will survive a yield()
*/
static bool
_mii_mb_romspace_access(
struct mii_bank_t *bank,
void *param,
uint16_t addr,
uint8_t * byte,
bool write)
{
if (!bank) { // TODO: dispose
printf("%s: no bank\n", __func__);
return false;
}
mii_mb_t * mb = param;
// addr &= 0xff;
// if (mb->init_done)
switch (addr & 0xff) {
case MB_CARD_MOCKINGBOARD_ORB1 ... MB_CARD_MOCKINGBOARD_ORB1+0xf:
case MB_CARD_MOCKINGBOARD_ORB2 ... MB_CARD_MOCKINGBOARD_ORB2+0xf:
if (write) {
/*
* Once code has writen to the first registers to initialize them,
* the mockingboard is considered initialized.
* At that point we take over the 'reading' of these addresees,
* so the CARD rom (the mouse) can't read them anymore.
* It *still* should be OK as these address do not overlap the
* mouse ROM.
*/
if ((addr & 0x7f) == 2 && *byte == 0xff) {
if (!mb->init_done)
mii_mb_start(mb);
}
// printf("%s: %s addr %04x byte %02x write %d\n", __func__, bank->name, addr, *byte, write);
mb_io_write(mb->mb, *byte, addr & 0xff);
} else if (mb->init_done) {
mb_io_read(mb->mb, byte, addr & 0xff);
}
// printf("%s: %s addr %04x byte %02x write %d\n", __func__,
// bank->name, addr, *byte, write);
return mb->init_done;
break;
default:
if (!write)
*byte = mii_video_get_vapor(mb->mii);
break;
}
return false;
}
static int
_mii_mb_probe(
mii_t *mii,
uint32_t flags)
{
printf("%s %s\n", __func__, flags & MII_INIT_MOCKINGBOARD ?
"enabled" : "disabled");
// if (!(flags & MII_INIT_MOCKINGBOARD))
// return 0;
return 1;
}
static int
_mii_mb_init(
mii_t * mii,
struct mii_slot_t *slot )
{
printf("%s\n", __func__);
mii_mb_t * mb = calloc(1, sizeof(*mb));
slot->drv_priv = mb;
mb->mii = mii;
mb->mb = mb_alloc();
mb_clock_t clock = {
.ref_step = 1,
.ts = mii->cpu.total_cycle,
};
mb_io_reset(mb->mb, &clock);
uint16_t addr = 0xc100 + (slot->id * 0x100);
mii_mb_start(mb);
mii_bank_install_access_cb(&mii->bank[MII_BANK_CARD_ROM],
_mii_mb_romspace_access, mb, addr >> 8, 0);
return 0;
}
static void
_mii_mb_reset(
mii_t * mii,
struct mii_slot_t *slot )
{
mii_mb_t *mb = slot->drv_priv;
printf("%s\n", __func__);
mb_clock_t clock = {
.ref_step = 1,
.ts = mii->cpu.total_cycle,
};
mb_io_reset(mb->mb, &clock);
}
static uint8_t
_mii_mb_iospace_access(
mii_t * mii, struct mii_slot_t *slot,
uint16_t addr, uint8_t byte, bool write)
{
// mii_mb_t *mb = slot->drv_priv;
if (!write)
byte = mii_video_get_vapor(mii);
return byte;
}
static mii_slot_drv_t _driver = {
.name = "mockingboard",
.desc = "Mockingboard",
// .enable_flag = MII_INIT_MOCKINGBOARD,
.init = _mii_mb_init,
.reset = _mii_mb_reset,
.access = _mii_mb_iospace_access,
// .probe = _mii_mb_probe,
};
MI_DRIVER_REGISTER(_driver);

View File

@ -7,8 +7,6 @@
* *
*/ */
#include "mii.h"
// https://github.com/ivanizag/izapple2/blob/master/cardMouse.go // https://github.com/ivanizag/izapple2/blob/master/cardMouse.go
// https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator/log/188017-entry-23-here-mousie-mousie-mousie // https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator/log/188017-entry-23-here-mousie-mousie-mousie
// https://github.com/ct6502/apple2ts/blob/main/src/emulator/mouse.ts // https://github.com/ct6502/apple2ts/blob/main/src/emulator/mouse.ts
@ -170,7 +168,7 @@ _mii_mouse_init(
// Set 8 entrypoints to sofstwitches 2 to 1f // Set 8 entrypoints to sofstwitches 2 to 1f
for (int i = 0; i < 14; i++) { for (int i = 0; i < 14; i++) {
uint8_t base = 0x60 + 0x05 * i; uint8_t base = 0x30 + 0x05 * i;
data[0x12+i] = base; data[0x12+i] = base;
data[base+0] = 0x8D; // STA $C0x2 data[base+0] = 0x8D; // STA $C0x2
data[base+1] = 0x82 + i + ((slot->id + 1) << 4); data[base+1] = 0x82 + i + ((slot->id + 1) << 4);
@ -212,12 +210,12 @@ _mii_mouse_access(
if (write) { if (write) {
byte &= 0xf; byte &= 0xf;
mii_bank_poke(main, MOUSE_MODE + c->slot_offset, byte); mii_bank_poke(main, MOUSE_MODE + c->slot_offset, byte);
printf("%s: mouse mode %02x\n", __func__, byte);
mii->mouse.enabled = byte & mouseEnabled; mii->mouse.enabled = byte & mouseEnabled;
printf("Mouse %s\n", mii->mouse.enabled ? "enabled" : "disabled"); printf("%s: mode %02x: %s Move:%d Button:%d VBL:%d\n", __func__,
printf(" Interupt: %s\n", byte & mouseIntMoveEnabled ? "enabled" : "disabled"); byte, mii->mouse.enabled ? "ON " : "OFF",
printf(" Button: %s\n", byte & mouseIntButtonEnabled ? "enabled" : "disabled"); byte & mouseIntMoveEnabled ? 1 : 0,
printf(" VBlank: %s\n", byte & mouseIntVBlankEnabled ? "enabled" : "disabled"); byte & mouseIntButtonEnabled ? 1 : 0,
byte & mouseIntVBlankEnabled ? 1 : 0);
c->mode = byte; c->mode = byte;
} }
} break; } break;
@ -256,9 +254,9 @@ _mii_mouse_access(
mii->mouse.max_y = mii_bank_peek(main, CLAMP_MAX_LO) | mii->mouse.max_y = mii_bank_peek(main, CLAMP_MAX_LO) |
(mii_bank_peek(main, CLAMP_MAX_HI) << 8); (mii_bank_peek(main, CLAMP_MAX_HI) << 8);
} }
printf("Mouse clamp to %d,%d - %d,%d\n", // printf("Mouse clamp to %d,%d - %d,%d\n",
mii->mouse.min_x, mii->mouse.min_y, // mii->mouse.min_x, mii->mouse.min_y,
mii->mouse.max_x, mii->mouse.max_y); // mii->mouse.max_x, mii->mouse.max_y);
break; break;
case 8: // home mouse case 8: // home mouse
mii->mouse.x = mii->mouse.min_x; mii->mouse.x = mii->mouse.min_x;

View File

@ -36,7 +36,6 @@ extern const unsigned char mii_smartport_rom_data[];
#define MII_SM_DRIVE_COUNT 2 #define MII_SM_DRIVE_COUNT 2
typedef struct mii_card_sm_t { typedef struct mii_card_sm_t {
// struct mii_card_sm_t *next;
mii_dd_t drive[MII_SM_DRIVE_COUNT]; mii_dd_t drive[MII_SM_DRIVE_COUNT];
struct mii_slot_t *slot; struct mii_slot_t *slot;
} mii_card_sm_t; } mii_card_sm_t;
@ -79,6 +78,9 @@ _mii_hd_callback(
mii_bank_t * bank = &mii->bank[mii->mem[buffer >> 8].write]; mii_bank_t * bank = &mii->bank[mii->mem[buffer >> 8].write];
mii->cpu.P.C = mii_dd_read( mii->cpu.P.C = mii_dd_read(
&c->drive[unit], bank, buffer, blk, 1) != 0; &c->drive[unit], bank, buffer, blk, 1) != 0;
// if Prodos is reading a block that happens to be video memory,
// make sure the video driver knows about it
mii_video_OOB_write_check(mii, buffer, 512);
} break; } break;
case 2: {// write block case 2: {// write block
if (!c->drive[unit].file) { if (!c->drive[unit].file) {
@ -107,7 +109,7 @@ _mii_sm_callback(
mii_t *mii, mii_t *mii,
uint8_t trap) uint8_t trap)
{ {
printf("%s\n", __func__); // printf("%s\n", __func__);
int sid = ((mii->cpu.PC >> 8) & 0xf) - 1; int sid = ((mii->cpu.PC >> 8) & 0xf) - 1;
mii_card_sm_t *c = mii->slot[sid].drv_priv; mii_card_sm_t *c = mii->slot[sid].drv_priv;
@ -122,8 +124,8 @@ _mii_sm_callback(
uint8_t spUnit = mii_read_one(mii, spParams + 1); uint8_t spUnit = mii_read_one(mii, spParams + 1);
uint16_t spBuffer = mii_read_word(mii, spParams + 2); uint16_t spBuffer = mii_read_word(mii, spParams + 2);
printf("%s cmd %02x params %04x pcount %d unit %02x buffer %04x\n", __func__, // printf("%s cmd %02x params %04x pcount %d unit %02x buffer %04x\n", __func__,
spCommand, spParams, spPCount, spUnit, spBuffer); // spCommand, spParams, spPCount, spUnit, spBuffer);
switch (spCommand) { switch (spCommand) {
case 0: { // get status case 0: { // get status
if (spPCount != 3) { if (spPCount != 3) {
@ -131,77 +133,110 @@ _mii_sm_callback(
break; break;
} }
uint8_t status = mii_read_one(mii, spParams + 4); uint8_t status = mii_read_one(mii, spParams + 4);
printf("%s: unit %d status %02x \n", __func__, spUnit, status); // printf("%s: unit %d status %02x \n", __func__, spUnit, status);
uint8_t st = 0x80 | 0x40 | 0x20; uint8_t st = 0x80 | 0x40 | 0x20;
uint32_t bsize = 0; uint32_t bsize = 0;
if (spUnit) spUnit--;
if (spUnit < MII_SM_DRIVE_COUNT && c->drive[spUnit].file) {
st |= 0x10;
bsize = (c->drive[spUnit].file->size + 511) / 512;
}
if (status == 0) { if (status == 0) {
mii->cpu.P.C = 0; mii->cpu.P.C = 0;
mii->cpu.A = 0;
/* Apple IIc reference says this ought to be a status byte, /* Apple IIc reference says this ought to be a status byte,
* but practice and A2Desktop says it ought to be a drive * but practice and A2Desktop says it ought to be a drive
* count, so here goes... */ * count, so here goes... */
// mii_write_one(mii, spBuffer++, st); // mii_write_one(mii, spBuffer++, st);
mii_write_one(mii, spBuffer++, MII_SM_DRIVE_COUNT); if (spUnit == 0) {
mii_write_one(mii, spBuffer++, bsize); mii_write_one(mii, spBuffer++, MII_SM_DRIVE_COUNT);
mii_write_one(mii, spBuffer++, bsize >> 8); mii_write_one(mii, spBuffer++, 0x00);
mii_write_one(mii, spBuffer++, bsize >> 16); mii_write_one(mii, spBuffer++, 0x01);
} else if (status == 3 && spUnit < MII_SM_DRIVE_COUNT) { mii_write_one(mii, spBuffer++, 0x13);
} else if (spUnit <= MII_SM_DRIVE_COUNT) {
if (c->drive[spUnit-1].file) {
st |= 0x10;
bsize = (c->drive[spUnit-1].file->size + 511) / 512;
}
mii_write_one(mii, spBuffer++, st);
mii_write_one(mii, spBuffer++, bsize);
mii_write_one(mii, spBuffer++, bsize >> 8);
mii_write_one(mii, spBuffer++, bsize >> 16);
} else {
mii->cpu.P.C = 1;
mii->cpu.A = 0x21; // bad status
}
} else if (status == 3) {
mii->cpu.P.C = 0; mii->cpu.P.C = 0;
mii_write_one(mii, spBuffer++, st); mii->cpu.A = 0;
mii_write_one(mii, spBuffer++, bsize); if (spUnit > 0 && spUnit <= MII_SM_DRIVE_COUNT) {
mii_write_one(mii, spBuffer++, bsize >> 8); if (c->drive[spUnit-1].file) {
mii_write_one(mii, spBuffer++, bsize >> 16); st |= 0x10;
char dname[17] = "\x8MII HD 0 "; bsize = (c->drive[spUnit-1].file->size + 511) / 512;
dname[8] = '0' + spUnit; }
for (int i = 0; i < 17; i++) mii_write_one(mii, spBuffer++, st);
mii_write_one(mii, spBuffer++, dname[i]); mii_write_one(mii, spBuffer++, bsize);
mii_write_one(mii, spBuffer++, 0x02); // Profile mii_write_one(mii, spBuffer++, bsize >> 8);
mii_write_one(mii, spBuffer++, 0x00); // Profile mii_write_one(mii, spBuffer++, bsize >> 16);
mii_write_one(mii, spBuffer++, 0x01); // Version char dname[17] = "\x8MII HD 0 ";
mii_write_one(mii, spBuffer++, 0x13); dname[8] = '0' + spUnit-1;
for (int i = 0; i < 17; i++)
mii_write_one(mii, spBuffer++, dname[i]);
mii_write_one(mii, spBuffer++, 0x02); // Profile
mii_write_one(mii, spBuffer++, 0x00); // Profile
mii_write_one(mii, spBuffer++, 0x01); // Version
mii_write_one(mii, spBuffer++, 0x13);
} else {
mii->cpu.P.C = 1;
mii->cpu.A = 0x21; // bad status
}
} else { } else {
printf("%s: unit %d bad status %d\n", printf("%s: unit %d bad status %d\n",
__func__, spUnit, status); __func__, spUnit, status);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x21; // bad status
} }
} break; } break;
case 1: { // read case 1: { // read
mii->cpu.P.C = 0;
mii->cpu.A = 0;
if (spPCount != 3) { if (spPCount != 3) {
printf("%s: unit %d bad pcount %d\n", printf("%s: unit %d bad pcount %d\n",
__func__, spUnit, spPCount); __func__, spUnit, spPCount);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
break; break;
} }
if (spUnit >= MII_SM_DRIVE_COUNT) { if (spUnit == 0 || spUnit >= MII_SM_DRIVE_COUNT) {
printf("%s: unit %d out of range\n", printf("%s: unit %d out of range\n", __func__, spUnit);
__func__, spUnit);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x28;
break; break;
} }
uint32_t blk = mii_read_word(mii, spParams + 3) | spUnit--;
(mii_read_one(mii, spParams + 4) << 16) | uint32_t blk = mii_read_one(mii, spParams + 4) |
(mii_read_one(mii, spParams + 5) << 24); (mii_read_one(mii, spParams + 5) << 8) |
printf("%s read block %x\n", __func__, blk); (mii_read_one(mii, spParams + 6) << 16);
// printf("%s read block 0x%6x\n", __func__, blk);
if (!c->drive[spUnit].file) { if (!c->drive[spUnit].file) {
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x2f;
break; break;
} }
if (blk >= c->drive[spUnit].file->size / 512) { if (blk >= c->drive[spUnit].file->size / 512) {
printf("%s: block %d out of range\n", printf("%s: block %d out of range\n",
__func__, blk); __func__, blk);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x2d;
break; break;
} }
mii_bank_t * bank = &mii->bank[mii->mem[spBuffer >> 8].write]; mii_bank_t * bank = &mii->bank[mii->mem[spBuffer >> 8].write];
mii->cpu.P.C = mii_dd_read( mii->cpu.P.C = mii_dd_read(
&c->drive[spUnit], bank, spBuffer, blk, 1) != 0; &c->drive[spUnit], bank, spBuffer, blk, 1) != 0;
if (mii->cpu.P.C)
mii->cpu.A = 0x2d;
// if Prodos is reading a block that happens to be video memory,
// make sure the video driver knows about it
mii_video_OOB_write_check(mii, spBuffer, 512);
// mii->cpu.P.C = 0; // mii->cpu.P.C = 0;
} break; } break;
case 2: { // write case 2: { // write
mii->cpu.P.C = 0;
mii->cpu.A = 0;
if (spPCount != 3) { if (spPCount != 3) {
printf("%s: unit %d bad pcount %d\n", printf("%s: unit %d bad pcount %d\n",
__func__, spUnit, spPCount); __func__, spUnit, spPCount);
@ -212,25 +247,31 @@ _mii_sm_callback(
printf("%s: unit %d out of range\n", printf("%s: unit %d out of range\n",
__func__, spUnit); __func__, spUnit);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x28;
break; break;
} }
uint32_t blk = mii_read_word(mii, spParams + 3) | spUnit--;
(mii_read_one(mii, spParams + 4) << 16) | uint32_t blk = mii_read_one(mii, spParams + 4) |
(mii_read_one(mii, spParams + 5) << 24); (mii_read_one(mii, spParams + 5) << 8) |
printf("%s write block %x\n", __func__, blk); (mii_read_one(mii, spParams + 6) << 16);
// printf("%s write block %x\n", __func__, blk);
if (!c->drive[spUnit].file) { if (!c->drive[spUnit].file) {
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x2f;
break; break;
} }
if (blk >= c->drive[spUnit].file->size / 512) { if (blk >= c->drive[spUnit].file->size / 512) {
printf("%s: block %d out of range\n", printf("%s: block %d out of range\n",
__func__, blk); __func__, blk);
mii->cpu.P.C = 1; mii->cpu.P.C = 1;
mii->cpu.A = 0x2d;
break; break;
} }
mii_bank_t * bank = &mii->bank[mii->mem[spBuffer >> 8].read]; mii_bank_t * bank = &mii->bank[mii->mem[spBuffer >> 8].read];
mii->cpu.P.C = mii_dd_write( mii->cpu.P.C = mii_dd_write(
&c->drive[spUnit], bank, spBuffer, blk, 1) != 0; &c->drive[spUnit], bank, spBuffer, blk, 1) != 0;
if (mii->cpu.P.C)
mii->cpu.A = 0x2d;
} break; } break;
} }
} }
@ -244,7 +285,7 @@ _mii_sm_init(
c->slot = slot; c->slot = slot;
slot->drv_priv = c; slot->drv_priv = c;
printf("%s loading in slot %d\n", __func__, slot->id + 1); // printf("%s loading in slot %d\n", __func__, slot->id + 1);
uint16_t addr = 0xc100 + (slot->id * 0x100); uint16_t addr = 0xc100 + (slot->id * 0x100);
mii_bank_write( mii_bank_write(
&mii->bank[MII_BANK_CARD_ROM], &mii->bank[MII_BANK_CARD_ROM],
@ -304,7 +345,7 @@ _mii_sm_command(
res = 0; res = 0;
} }
break; break;
case MII_SLOT_DRIVE_LOAD ... MII_SLOT_DRIVE_LOAD + MII_SM_DRIVE_COUNT - 1: case MII_SLOT_DRIVE_LOAD ... MII_SLOT_DRIVE_LOAD + MII_SM_DRIVE_COUNT - 1: {
int drive = cmd - MII_SLOT_DRIVE_LOAD; int drive = cmd - MII_SLOT_DRIVE_LOAD;
const char *filename = param; const char *filename = param;
mii_dd_file_t *file = NULL; mii_dd_file_t *file = NULL;
@ -315,7 +356,7 @@ _mii_sm_command(
} }
mii_dd_drive_load(&c->drive[drive], file); mii_dd_drive_load(&c->drive[drive], file);
res = 0; res = 0;
break; } break;
} }
return res; return res;
} }

1217
src/drivers/mockingboard.c Normal file

File diff suppressed because it is too large Load Diff

141
src/drivers/mockingboard.h Normal file
View File

@ -0,0 +1,141 @@
/*
* mockingboard.h
* This is a straigth derivative of Clemens IIgs emulator mockingboard
* emulation code. The original code is available at:
* https://github.com/samkusin/clemens_iigs
*
* The original code is also licensed under the MIT License.
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include <stdint.h>
typedef uint64_t mb_clocks_time_t;
typedef uint32_t mb_clocks_t;
/* Typically this is passed around as the current time for the machine
and is guaranteed to be shared between machine and any external cards
based on the ref_step.
For example, MMIO clocks use the Mega2 reference step
*/
typedef struct mb_clock_t {
mb_clocks_time_t ts;
mb_clocks_t ref_step;
} mb_clock_t;
struct mb_t;
/** A bit confusing and created to avoid floating point math whenever possible
* (whether this was a good choice given modern architectures... ?)
*
* Used for calculating our system clock. These values are relative to each other.
*
* The clocks per mega2 cycle (PHI0) value will always be the largest.
* Yet since most time calculations in the emulator are done with fixed point-like
* math, the aim is to keep the clocks count per cycle high enough for fixed
* math to work with uint 32-bit numbers.
*
* SO DON'T CHANGE THESE UNLESS ALL DEPENDENT DEFINE/CALCULATIONS THAT THESE
* VALUES TRICKLE DOWN REMAIN VALID. IF YOU DO, TEST *EVERYTHING* (IWM,
* DIAGNOSTICS)
*
* Based on this, care should be taken when attempting to emulate a 8mhz machine
* in the future - though most I/O is performed using PHI0 cycles.
*
* If you divide the MB_CLOCKS_PHI0_CYCLE by the MB_CLOCKS_PHI2_FAST_CYCLE
* the value will be the effective maximum clock speed in Mhz of the CPU.
*
* Ref: https://www.kansasfest.org/wp-content/uploads/2011-krue-fpi.pdf
*/
#define MB_CLOCKS_14MHZ_CYCLE 200U // 14.318 Mhz
#define MB_CLOCKS_PHI0_CYCLE (MB_CLOCKS_14MHZ_CYCLE * 14) // 1.023 Mhz with stretch
// IMPORTANT! This is rounded from 69.8ns - which when scaling up to PHI0 translates
// to 977.7 ns without rounding. Due to the stretch cycle, this
// effectively rounds up to 980ns, which is really what most system
// timings rely on So, rounding up. Bonne chance.
#define MB_14MHZ_CYCLE_NS 70U
#define MB_MEGA2_CYCLES_PER_SECOND 1023000U
/* these are here for references - the actual functions are determined
by which bits in the address register are set on io_read and io_write
*/
#define MB_CARD_MOCKINGBOARD_ORB1 0x00
#define MB_CARD_MOCKINGBOARD_ORA1 0x01
#define MB_CARD_MOCKINGBOARD_DDRB1 0x02
#define MB_CARD_MOCKINGBOARD_DDRA1 0x03
#define MB_CARD_MOCKINGBOARD_ORB2 0x80
#define MB_CARD_MOCKINGBOARD_ORA2 0x81
#define MB_CARD_MOCKINGBOARD_DDRB2 0x82
#define MB_CARD_MOCKINGBOARD_DDRA2 0x83
/** All mmio memory operations can have this option - both onboard and
* card operations
*/
#define MB_OP_IO_NO_OP 0x01
#define MB_IS_IO_NO_OP(_flags_) (((_flags_) & MB_OP_IO_NO_OP) != 0)
//#define MB_OP_IO_CARD 0x40
//#define MB_OP_IO_DEVSEL 0x80
#define MB_CARD_IRQ 0x80000000
//
/** _clock_ is of type mb_clock_t
BEWARE - these macros act on sub second time intervals (per frame deltas.)
Do not use these utilities to calculate values over long time intervals
*/
#define mb_ns_step_from_clocks(_clocks_step_) \
((uint)(MB_14MHZ_CYCLE_NS * (_clocks_step_) / MB_CLOCKS_14MHZ_CYCLE))
#define mb_clocks_step_from_ns(_ns_) \
((mb_clocks_t)((_ns_) * MB_CLOCKS_14MHZ_CYCLE) / MB_14MHZ_CYCLE_NS)
/* intentional - paranthesized expression should be done first to avoid precision
* loss*/
#define mb_secs_from_clocks(_clock_) \
((MB_14MHZ_CYCLE_NS * (uint64_t)((_clock_)->ts / MB_CLOCKS_14MHZ_CYCLE)) * \
1.0e-9)
#ifdef __cplusplus
extern "C" {
#endif
struct mb_t *
mb_alloc();
void
mb_dispose( //
struct mb_t * mb);
void
mb_io_read( //
struct mb_t *board,
uint8_t *data,
uint8_t addr);
void
mb_io_write( //
struct mb_t *board,
uint8_t data,
uint8_t addr);
uint32_t
mb_io_sync( //
struct mb_t *board,
mb_clock_t *clock);
void
mb_io_reset( //
struct mb_t *board,
mb_clock_t *clock);
uint
mb_ay3_render( //
struct mb_t * mb,
float *samples_out,
uint sample_limit,
uint samples_per_frame,
uint samples_per_second);
#ifdef __cplusplus
}
#endif

View File

@ -56,7 +56,10 @@ mii_floppy_init(
for (int i = 0; i < MII_FLOPPY_TRACK_COUNT + 1; i++) { for (int i = 0; i < MII_FLOPPY_TRACK_COUNT + 1; i++) {
f->tracks[i].dirty = 0; f->tracks[i].dirty = 0;
f->tracks[i].virgin = 1; f->tracks[i].virgin = 1;
f->tracks[i].bit_count = 6550 * 8; // this affects the disk 'speed' -- larger number will slow down the
// apparent speed of the disk, according to disk utilities. This value
// gives 299-300 RPM, which is the correct speed for a 5.25" floppy.
f->tracks[i].bit_count = 6400 * 8;
// fill the whole array up to the end.. // fill the whole array up to the end..
uint8_t *track = f->track_data[i]; uint8_t *track = f->track_data[i];
if (i != MII_FLOPPY_NOISE_TRACK) { if (i != MII_FLOPPY_NOISE_TRACK) {
@ -632,10 +635,10 @@ mii_floppy_nibblize_sector(
{ {
unsigned int gap; unsigned int gap;
if (track == 0 ) // if (track == 0 )
printf("NIB: vol %d track %d sector %d pos %5d\n", // printf("NIB: vol %d track %d sector %d pos %5d\n",
vol, track, sector, dst->bit_count); // vol, track, sector, dst->bit_count);
gap = sector == 0 ? 120 : track == 0 ? 30 : 20; gap = sector == 0 ? 100 : track == 0 ? 20 : 20;
for (uint8_t i = 0; i < gap; ++i) for (uint8_t i = 0; i < gap; ++i)
mii_track_write_bits(dst, track_data, 0xFF << 2, 10); mii_track_write_bits(dst, track_data, 0xFF << 2, 10);
// Address Field // Address Field
@ -710,8 +713,9 @@ mii_floppy_load_dsk(
mii_floppy_nibblize_sector(VOLUME_NUMBER, i, phys_sector, mii_floppy_nibblize_sector(VOLUME_NUMBER, i, phys_sector,
src, dst, track_data); src, dst, track_data);
} }
// printf("%s: track %2d has %d bits %d bytes\n", if (i == 0)
// __func__, i, dst->bit_count, dst->bit_count >> 3); printf("%s: track %2d has %d bits %d bytes\n",
__func__, i, dst->bit_count, dst->bit_count >> 3);
} }
// DSK is read only // DSK is read only
f->write_protected |= MII_FLOPPY_WP_RO_FORMAT; f->write_protected |= MII_FLOPPY_WP_RO_FORMAT;

View File

@ -40,10 +40,10 @@ typedef struct mii_floppy_track_t {
typedef struct mii_track_heatmap_t { typedef struct mii_track_heatmap_t {
// 32 bytes of track data corresponds to one byte of heatmap // 32 bytes of track data corresponds to one byte of heatmap
uint32_t seed, tex, cleared;
// this needs to be aligned, otherwise SSE code will die horribly // this needs to be aligned, otherwise SSE code will die horribly
uint8_t map[MII_FLOPPY_TRACK_COUNT][MII_FLOPPY_HM_TRACK_SIZE] uint8_t map[MII_FLOPPY_TRACK_COUNT][MII_FLOPPY_HM_TRACK_SIZE]
__attribute__((aligned(16))); __attribute__((aligned(32)));
uint32_t seed, tex, cleared;
} mii_track_heatmap_t; } mii_track_heatmap_t;
typedef struct mii_floppy_heatmap_t { typedef struct mii_floppy_heatmap_t {

236
src/mii.c
View File

@ -19,6 +19,12 @@
#include "mii_65c02.h" #include "mii_65c02.h"
#include "minipt.h" #include "minipt.h"
#if MII_65C02_DIRECT_ACCESS
static mii_cpu_state_t
_mii_cpu_direct_access_cb(
struct mii_cpu_t *cpu,
mii_cpu_state_t access );
#endif
mii_slot_drv_t * mii_slot_drv_list = NULL; mii_slot_drv_t * mii_slot_drv_list = NULL;
@ -107,7 +113,7 @@ mii_dump_trace_state(
static const char *s_flags = "CZIDBRVN"; static const char *s_flags = "CZIDBRVN";
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
printf("%c", MII_GET_P_BIT(cpu, i) ? s_flags[i] : tolower(s_flags[i])); printf("%c", MII_GET_P_BIT(cpu, i) ? s_flags[i] : tolower(s_flags[i]));
if (s.sync) { // if (s.sync) {
uint8_t op[16]; uint8_t op[16];
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
mii_mem_access(mii, mii->cpu.PC + i, op + i, false, false); mii_mem_access(mii, mii->cpu.PC + i, op + i, false, false);
@ -123,8 +129,8 @@ mii_dump_trace_state(
printf(" ; taken"); printf(" ; taken");
} }
printf("\n"); printf("\n");
} else // } else
printf("\n"); // printf("\n");
} }
void void
@ -180,15 +186,16 @@ mii_page_table_update(
if (likely(!mii->mem_dirty)) if (likely(!mii->mem_dirty))
return; return;
mii->mem_dirty = 0; mii->mem_dirty = 0;
bool altzp = SW_GETSTATE(mii, SWALTPZ); uint32_t sw = mii->sw_state;
bool page2 = SW_GETSTATE(mii, SWPAGE2); bool altzp = SWW_GETSTATE(sw, SWALTPZ);
bool store80 = SW_GETSTATE(mii, SW80STORE); bool page2 = SWW_GETSTATE(sw, SWPAGE2);
bool hires = SW_GETSTATE(mii, SWHIRES); bool store80 = SWW_GETSTATE(sw, SW80STORE);
bool ramrd = SW_GETSTATE(mii, SWRAMRD); bool hires = SWW_GETSTATE(sw, SWHIRES);
bool ramwrt = SW_GETSTATE(mii, SWRAMWRT); bool ramrd = SWW_GETSTATE(sw, SWRAMRD);
bool intcxrom = SW_GETSTATE(mii, SWINTCXROM); bool ramwrt = SWW_GETSTATE(sw, SWRAMWRT);
bool slotc3rom = SW_GETSTATE(mii, SWSLOTC3ROM); bool intcxrom = SWW_GETSTATE(sw, SWINTCXROM);
bool intc8rom = SW_GETSTATE(mii, INTC8ROM); bool slotc3rom = SWW_GETSTATE(sw, SWSLOTC3ROM);
bool intc8rom = SWW_GETSTATE(sw, INTC8ROM);
if (unlikely(mii->trace_cpu)) if (unlikely(mii->trace_cpu))
printf("%04x: MEM update altzp:%d page2:%d store80:%d " printf("%04x: MEM update altzp:%d page2:%d store80:%d "
@ -215,15 +222,15 @@ mii_page_table_update(
} }
// c1-cf are at ROM state when we arrive here // c1-cf are at ROM state when we arrive here
if (!intcxrom) { if (!intcxrom) {
mii_page_set(mii, MII_BANK_CARD_ROM, _SAME, 0xc1, 0xcf); mii_page_set(mii, MII_BANK_CARD_ROM, MII_BANK_CARD_ROM, 0xc1, 0xcf);
if (!slotc3rom) if (!slotc3rom)
mii_page_set(mii, MII_BANK_ROM, _SAME, 0xc3, 0xc3); mii_page_set(mii, MII_BANK_ROM, _SAME, 0xc3, 0xc3);
if (intc8rom) if (intc8rom)
mii_page_set(mii, MII_BANK_ROM, _SAME, 0xc8, 0xcf); mii_page_set(mii, MII_BANK_ROM, _SAME, 0xc8, 0xcf);
} }
bool bsrread = SW_GETSTATE(mii, BSRREAD); bool bsrread = SWW_GETSTATE(sw, BSRREAD);
bool bsrwrite = SW_GETSTATE(mii, BSRWRITE); bool bsrwrite = SWW_GETSTATE(sw, BSRWRITE);
bool bsrpage2 = SW_GETSTATE(mii, BSRPAGE2); bool bsrpage2 = SWW_GETSTATE(sw, BSRPAGE2);
mii_page_set(mii, mii_page_set(mii,
bsrread ? bsrread ?
altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR : altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR :
@ -342,6 +349,7 @@ mii_access_soft_switches(
bool res = false; bool res = false;
uint8_t on = 0; uint8_t on = 0;
mii_bank_t * sw = &mii->bank[MII_BANK_SW]; mii_bank_t * sw = &mii->bank[MII_BANK_SW];
const uint16_t sw_save = mii->sw_state;
/* /*
* This allows driver (titan accelerator etc) to have their own * This allows driver (titan accelerator etc) to have their own
@ -403,22 +411,19 @@ mii_access_soft_switches(
SW_SETSTATE(mii, BSRREAD, !offSwitch); SW_SETSTATE(mii, BSRREAD, !offSwitch);
} }
SW_SETSTATE(mii, BSRPAGE2, !(addr & 0x08)); SW_SETSTATE(mii, BSRPAGE2, !(addr & 0x08));
mii->mem_dirty = 1; mii->mem_dirty = sw_save != mii->sw_state;
} break; } break;
case SWPAGE2OFF: case SWPAGE2OFF:
case SWPAGE2ON: case SWPAGE2ON:
res = true; // ACTUAL switch is already done in mii_access_video()
SW_SETSTATE(mii, SWPAGE2, addr & 1); res = true; // mii_access_video(mii, addr, byte, write);
mii_bank_poke(sw, SWPAGE2, (addr & 1) << 7); mii->mem_dirty = true;
mii->mem_dirty = 1;
break; break;
case SWHIRESOFF: case SWHIRESOFF:
case SWHIRESON: case SWHIRESON:
res = true; // ACTUAL switch is already done in mii_access_video()
SW_SETSTATE(mii, SWHIRES, addr & 1); res = true; // mii_access_video(mii, addr, byte, write);
mii_bank_poke(sw, SWHIRES, (addr & 1) << 7); mii->mem_dirty = true;
mii->mem_dirty = 1;
// printf("HIRES %s\n", (addr & 1) ? "ON" : "OFF");
break; break;
case SWSPEAKER: case SWSPEAKER:
res = true; res = true;
@ -434,8 +439,10 @@ mii_access_soft_switches(
// IIgs register, read by prodos tho // IIgs register, read by prodos tho
break; break;
} }
if (res && !mii->mem_dirty) if (res) {
mii_page_table_update(mii);
return res; return res;
}
if (write) { if (write) {
switch (addr) { switch (addr) {
case SW80STOREOFF: case SW80STOREOFF:
@ -443,56 +450,55 @@ mii_access_soft_switches(
res = true; res = true;
SW_SETSTATE(mii, SW80STORE, addr & 1); SW_SETSTATE(mii, SW80STORE, addr & 1);
mii_bank_poke(sw, SW80STORE, (addr & 1) << 7); mii_bank_poke(sw, SW80STORE, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWRAMRDOFF: case SWRAMRDOFF:
case SWRAMRDON: case SWRAMRDON:
res = true; res = true;
SW_SETSTATE(mii, SWRAMRD, addr & 1); SW_SETSTATE(mii, SWRAMRD, addr & 1);
mii_bank_poke(sw, SWRAMRD, (addr & 1) << 7); mii_bank_poke(sw, SWRAMRD, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWRAMWRTOFF: case SWRAMWRTOFF:
case SWRAMWRTON: case SWRAMWRTON:
res = true; res = true;
SW_SETSTATE(mii, SWRAMWRT, addr & 1); SW_SETSTATE(mii, SWRAMWRT, addr & 1);
mii_bank_poke(sw, SWRAMWRT, (addr & 1) << 7); mii_bank_poke(sw, SWRAMWRT, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWALTPZOFF: case SWALTPZOFF:
case SWALTPZON: case SWALTPZON:
res = true; res = true;
SW_SETSTATE(mii, SWALTPZ, addr & 1); SW_SETSTATE(mii, SWALTPZ, addr & 1);
mii_bank_poke(sw, SWALTPZ, (addr & 1) << 7); mii_bank_poke(sw, SWALTPZ, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWINTCXROMOFF: case SWINTCXROMOFF:
case SWINTCXROMON: case SWINTCXROMON:
res = true; res = true;
SW_SETSTATE(mii, SWINTCXROM, addr & 1); SW_SETSTATE(mii, SWINTCXROM, addr & 1);
mii_bank_poke(sw, SWINTCXROM, (addr & 1) << 7); mii_bank_poke(sw, SWINTCXROM, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWSLOTC3ROMOFF: case SWSLOTC3ROMOFF:
case SWSLOTC3ROMON: case SWSLOTC3ROMON:
res = true; res = true;
SW_SETSTATE(mii, SWSLOTC3ROM, addr & 1); SW_SETSTATE(mii, SWSLOTC3ROM, addr & 1);
mii_bank_poke(sw, SWSLOTC3ROM, (addr & 1) << 7); mii_bank_poke(sw, SWSLOTC3ROM, (addr & 1) << 7);
mii->mem_dirty = 1;
break; break;
case SWRAMWORKS_BANK: case SWRAMWORKS_BANK:
mii_bank_poke(sw, SWRAMWORKS_BANK, *byte); mii_bank_poke(sw, SWRAMWORKS_BANK, *byte);
mii_bank_update_ramworks(mii, *byte); mii_bank_update_ramworks(mii, *byte);
break; break;
} }
mii->mem_dirty += sw_save != mii->sw_state;
} else { } else {
switch (addr) { switch (addr) {
case SWBSRBANK2: case SWBSRBANK2:
*byte = SW_GETSTATE(mii, BSRPAGE2) ? 0x80 : 0; *byte = SW_GETSTATE(mii, BSRPAGE2) << 7;
res = true; res = true;
break; break;
case SWBSRREADRAM: case SWBSRREADRAM:
*byte = SW_GETSTATE(mii, BSRREAD) ? 0x80 : 0; *byte = SW_GETSTATE(mii, BSRREAD) << 7;
res = true;
break;
case SWPAGE2OFF:
case SWPAGE2ON: // already done by the video code
res = true; res = true;
break; break;
case SWRAMRD: case SWRAMRD:
@ -504,29 +510,33 @@ mii_access_soft_switches(
res = true; res = true;
*byte = mii_bank_peek(sw, addr); *byte = mii_bank_peek(sw, addr);
break; break;
case 0xc020: // toggle TAPE output ?!?!
res = true;
break;
case 0xc068: case 0xc068:
res = true; res = true;
// IIgs register, read by prodos tho // IIgs register, read by prodos tho
break; break;
case 0xc020: // toggle TAPE output ?!?!
// res = true;
// break;
default: default:
res = true; res = true;
// if (addr != 0xc00b)
// printf("VAPOR LOCK %04x\n", addr);
// this doesn't work. Well it does the job of returning
// something semi random, but it's not ready to be a TRUE
// vapor lock.
*byte = mii_video_get_vapor(mii);
#if 0
/* /*
* this is moderately important, return some random value * this is moderately important, return some random value
* as it is supposed to represent what's on the bus at the time, * as it is supposed to represent what's on the bus at the time,
* typically video being decoded etc. * typically video being decoded etc.
*/ */
*byte = mii->random[mii->random_index++]; // *byte = mii->random[mii->random_index++];
mii->random_index &= 0xff; // mii->random_index &= 0xff;
#endif
break; break;
} }
} }
if (!res) {
// printf("%s addr %04x write %d %02x\n", __func__, addr, write, *byte);
// mii->state = MII_STOPPED;
}
mii_page_table_update(mii); mii_page_table_update(mii);
return res; return res;
} }
@ -576,6 +586,7 @@ mii_keypress(
mii_bank_poke(sw, SWKBD, key); mii_bank_poke(sw, SWKBD, key);
} }
/* ramworks came populated in chunks, this duplicates these rows of chips */
#define B(x) ((unsigned __int128)1ULL << (x)) #define B(x) ((unsigned __int128)1ULL << (x))
static const unsigned __int128 _mii_ramworks3_config[] = { static const unsigned __int128 _mii_ramworks3_config[] = {
B(0x00)|B(0x01)|B(0x02)|B(0x03), B(0x00)|B(0x01)|B(0x02)|B(0x03),
@ -625,6 +636,10 @@ mii_init(
mii_reset(mii, true); mii_reset(mii, true);
mii->cpu_state = mii_cpu_init(&mii->cpu); mii->cpu_state = mii_cpu_init(&mii->cpu);
#if MII_65C02_DIRECT_ACCESS
mii->cpu.access_param = mii;
mii->cpu.access = _mii_cpu_direct_access_cb;
#endif
for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++)
mii->slot[i].id = i; mii->slot[i].id = i;
// srandom(time(NULL)); // srandom(time(NULL));
@ -732,11 +747,14 @@ mii_mem_access(
if (wr) { if (wr) {
uint8_t m = mii->mem[page].write; uint8_t m = mii->mem[page].write;
mii_bank_t * b = &mii->bank[m]; mii_bank_t * b = &mii->bank[m];
if (b->ro) { if (!b->ro)
// printf("%s write to RO bank %s %04x:%02x\n",
// __func__, b->name, addr, *d);
} else
mii_bank_write(b, addr, d, 1); mii_bank_write(b, addr, d, 1);
else {
// writing to ROM *is* sort of OK in certain circumstances, if
// there is a 'special' handler of the rom page. the NSC and the
// mockinboard are examples of this.
mii_bank_access(b, addr, d, 1, true);
}
} else { } else {
uint8_t m = mii->mem[page].read; uint8_t m = mii->mem[page].read;
mii_bank_t * b = &mii->bank[m]; mii_bank_t * b = &mii->bank[m];
@ -751,7 +769,9 @@ _mii_handle_trap(
// printf("%s TRAP hit PC: %04x\n", __func__, mii->cpu.PC); // printf("%s TRAP hit PC: %04x\n", __func__, mii->cpu.PC);
mii->cpu_state.sync = 1; mii->cpu_state.sync = 1;
mii->cpu_state.trap = 0; mii->cpu_state.trap = 0;
#if MII_65C02_DIRECT_ACCESS == 0
mii->cpu.state = NULL; mii->cpu.state = NULL;
#endif
uint8_t trap = mii_read_one(mii, mii->cpu.PC); uint8_t trap = mii_read_one(mii, mii->cpu.PC);
mii->cpu.PC += 1; mii->cpu.PC += 1;
// printf("%s TRAP %02x return PC %04x\n", __func__, trap, mii->cpu.PC); // printf("%s TRAP %02x return PC %04x\n", __func__, trap, mii->cpu.PC);
@ -847,6 +867,73 @@ mii_timer_run(
} }
} }
#if MII_65C02_DIRECT_ACCESS
static mii_cpu_state_t
_mii_cpu_direct_access_cb(
struct mii_cpu_t *cpu,
mii_cpu_state_t access )
{
mii_t *mii = cpu->access_param;
uint8_t cycle = mii->timer.last_cycle;
mii_timer_run(mii,
mii->cpu.cycle > cycle ? mii->cpu.cycle - cycle :
mii->cpu.cycle);
mii->timer.last_cycle = mii->cpu.cycle;
const uint16_t addr = access.addr;
int wr = access.w;
if (access.sync) {
// log PC for the running disassembler display
mii->trace.log[mii->trace.idx] = mii->cpu.PC;
mii->trace.idx = (mii->trace.idx + 1) & (MII_PC_LOG_SIZE - 1);
}
if (unlikely(mii->debug.bp_map)) {
for (int i = 0; i < (int)sizeof(mii->debug.bp_map) * 8; i++) {
if (!(mii->debug.bp_map & (1 << i)))
continue;
if (addr >= mii->debug.bp[i].addr &&
addr < mii->debug.bp[i].addr + mii->debug.bp[i].size) {
if (((mii->debug.bp[i].kind & MII_BP_R) && !wr) ||
((mii->debug.bp[i].kind & MII_BP_W) && wr)) {
if (1 || !mii->debug.bp[i].silent) {
printf("BREAKPOINT %d at %04x PC:%04x\n",
i, addr, mii->cpu.PC);
mii_dump_run_trace(mii);
mii_dump_trace_state(mii);
mii->cpu.instruction_run = 0;
mii->state = MII_STOPPED;
}
}
if (!(mii->debug.bp[i].kind & MII_BP_STICKY))
mii->debug.bp_map &= ~(1 << i);
mii->debug.bp[i].kind |= MII_BP_HIT;
}
}
}
mii_mem_access(mii, addr, &access.data, wr, true);
return access;
}
void
mii_run(
mii_t *mii)
{
/* this runs all cycles for one instruction */
if (unlikely(mii->state != MII_RUNNING || mii->trace_cpu > 1)) {
printf("tracing\n");
mii->cpu.instruction_run = 0;
} else
mii->cpu.instruction_run = 100000;
mii->cpu_state = mii_cpu_run(&mii->cpu, mii->cpu_state);
if (unlikely(mii->cpu_state.trap))
_mii_handle_trap(mii);
}
#else
void void
mii_run( mii_run(
mii_t *mii) mii_t *mii)
@ -900,11 +987,8 @@ mii_run(
// log PC for the running disassembler display // log PC for the running disassembler display
mii->trace.log[mii->trace.idx] = mii->cpu.PC; mii->trace.log[mii->trace.idx] = mii->cpu.PC;
mii->trace.idx = (mii->trace.idx + 1) & (MII_PC_LOG_SIZE - 1); mii->trace.idx = (mii->trace.idx + 1) & (MII_PC_LOG_SIZE - 1);
for (int i = 0; i < 7; i++) {
if (mii->slot[i].drv && mii->slot[i].drv->run)
mii->slot[i].drv->run(mii, &mii->slot[i]);
}
} }
#endif
//! Read one byte from and addres, using the current memory mapping //! Read one byte from and addres, using the current memory mapping
uint8_t uint8_t
@ -951,3 +1035,51 @@ mii_write_word(
d = w >> 8; d = w >> 8;
mii_mem_access(mii, addr + 1, &d, 1, false); mii_mem_access(mii, addr + 1, &d, 1, false);
} }
void
mii_cpu_step(
mii_t *mii,
uint32_t count )
{
if (mii->state != MII_STOPPED) {
printf("mii: can't step/next, not stopped\n");
return;
}
mii->trace.step_inst = count ? count : 1;
__sync_synchronize();
mii->state = MII_STEP;
}
void
mii_cpu_next(
mii_t *mii)
{
if (mii->state != MII_STOPPED) {
printf("mii: can't step/next, not stopped\n");
return;
}
// read current opcode, find how how many bytes it take,
// then put a temporary breakpoint to the next PC.
// all of that if this is not a relative branch of course, in
// which case we use a normal 'step' behaviour
uint8_t op;
mii_mem_access(mii, mii->cpu.PC, &op, false, false);
printf("NEXT opcode %04x:%02x\n", mii->cpu.PC, op);
if (op == 0x20) { // JSR here?
// set a temp breakpoint on reading 3 bytes from PC
if (mii->debug.bp_map != 0xffff) {
int i = ffsl(~mii->debug.bp_map) - 1;
mii->debug.bp[i].addr = mii->cpu.PC + 3;
mii->debug.bp[i].kind = MII_BP_R;
mii->debug.bp[i].size = 1;
mii->debug.bp[i].silent = 1;
mii->debug.bp_map |= 1 << i;
__sync_synchronize();
mii->state = MII_RUNNING;
return;
}
printf("%s no more breakpoints available\n", __func__);
} else {
mii_cpu_step(mii, 1);
}
}

View File

@ -97,16 +97,23 @@ typedef uint64_t (*mii_timer_p)(
* principal emulator state, for a faceless emulation * principal emulator state, for a faceless emulation
*/ */
typedef struct mii_t { typedef struct mii_t {
mii_cpu_t cpu;
mii_cpu_state_t cpu_state;
/* this is the video frame/VBL rate vs 60hz, default to MII_SPEED_NTSC */
float speed;
unsigned int state; unsigned int state;
/* /*
* These are 'cycle timers' -- they count down from a set value, * These are 'cycle timers' -- they count down from a set value,
* and stop at 0 (or possiblu -1 or -2, depending on the instructions) * and stop at 0 (or possibly -1 or -2, depending on the instructions)
* and call the callback (if present). * and call the callback (if present).
* The callback returns the number of cycles to wait until the next * The callback returns the number of cycles to wait until the next
* call. * call.
*/ */
struct { struct {
uint64_t map; uint64_t map;
#if MII_65C02_DIRECT_ACCESS
uint8_t last_cycle;
#endif
struct { struct {
mii_timer_p cb; mii_timer_p cb;
void * param; void * param;
@ -114,10 +121,6 @@ typedef struct mii_t {
const char * name; // debug const char * name; // debug
} timers[64]; } timers[64];
} timer; } timer;
/* this is the video frame/VBL rate vs 60hz, default to 1.0 */
float speed;
mii_cpu_t cpu;
mii_cpu_state_t cpu_state;
/* /*
* bank index for each memory page number, this is recalculated * bank index for each memory page number, this is recalculated
* everytime a MMU soft switch is triggered * everytime a MMU soft switch is triggered
@ -139,7 +142,7 @@ typedef struct mii_t {
mii_trace_t trace; mii_trace_t trace;
int trace_cpu; int trace_cpu;
mii_trap_t trap; mii_trap_t trap;
mii_signal_pool_t sig_pool; mii_signal_pool_t sig_pool; // vcd support
/* /*
* Used for debugging only * Used for debugging only
*/ */
@ -172,6 +175,7 @@ enum {
MII_INIT_NSC = (1 << 0), // Install no slot clock MII_INIT_NSC = (1 << 0), // Install no slot clock
MII_INIT_TITAN = (1 << 1), // Install Titan 'card' MII_INIT_TITAN = (1 << 1), // Install Titan 'card'
MII_INIT_SILENT = (1 << 2), // No audio, ever MII_INIT_SILENT = (1 << 2), // No audio, ever
MII_INIT_MOCKINGBOARD = (1 << 3), // Install mockingboard
// number of 256KB banks added to the ramworks // number of 256KB banks added to the ramworks
MII_INIT_RAMWORKS_BIT = 4, // bit 4 in flags. Can be up to 12 MII_INIT_RAMWORKS_BIT = 4, // bit 4 in flags. Can be up to 12
@ -355,3 +359,12 @@ mii_register_trap(
#define MII_MISH_KIND MISH_FCC('m','i','i',' ') #define MII_MISH_KIND MISH_FCC('m','i','i',' ')
#define MII_MISH(_name,_cmd) \ #define MII_MISH(_name,_cmd) \
MISH_CMD_REGISTER_KIND(_name, _cmd, 0, MII_MISH_KIND) MISH_CMD_REGISTER_KIND(_name, _cmd, 0, MII_MISH_KIND)
void
mii_cpu_step(
mii_t *mii,
uint32_t count );
void
mii_cpu_next(
mii_t *mii);

View File

@ -26,10 +26,23 @@ mii_cpu_init(
.addr = 0, .addr = 0,
.reset = 1, .reset = 1,
}; };
#if MII_65C02_DIRECT_ACCESS
#else
cpu->state = NULL; cpu->state = NULL;
#endif
return s; return s;
} }
#if MII_65C02_DIRECT_ACCESS
#define _FETCH(_val) { \
s.addr = _val; s.w = 0; cpu->cycle++; \
s = cpu->access(cpu, s); \
}
#define _STORE(_addr, _val) { \
s.addr = _addr; s.data = _val; s.w = 1; cpu->cycle++; \
s = cpu->access(cpu, s); \
}
#else
#define _FETCH(_val) { \ #define _FETCH(_val) { \
s.addr = _val; s.w = 0; cpu->cycle++; \ s.addr = _val; s.w = 0; cpu->cycle++; \
pt_yield(cpu->state); \ pt_yield(cpu->state); \
@ -38,7 +51,7 @@ mii_cpu_init(
s.addr = _addr; s.data = _val; s.w = 1; cpu->cycle++; \ s.addr = _addr; s.data = _val; s.w = 1; cpu->cycle++; \
pt_yield(cpu->state); \ pt_yield(cpu->state); \
} }
#endif
#define _NZC(_val) { \ #define _NZC(_val) { \
uint16_t v = (_val); \ uint16_t v = (_val); \
@ -60,8 +73,12 @@ mii_cpu_run(
mii_cpu_t *cpu, mii_cpu_t *cpu,
mii_cpu_state_t s) mii_cpu_state_t s)
{ {
#if MII_65C02_DIRECT_ACCESS
mii_op_desc_t d;
#else
mii_op_desc_t d = mii_cpu_op[cpu->IR].desc; mii_op_desc_t d = mii_cpu_op[cpu->IR].desc;
pt_start(cpu->state); pt_start(cpu->state);
#endif
next_instruction: next_instruction:
if (unlikely(s.reset)) { if (unlikely(s.reset)) {
s.reset = 0; s.reset = 0;
@ -71,7 +88,7 @@ next_instruction:
cpu->S = 0xFF; cpu->S = 0xFF;
MII_SET_P(cpu, 0); MII_SET_P(cpu, 0);
} }
if (unlikely(s.irq) && cpu->P.I == 0) { if (unlikely(s.irq && cpu->P.I == 0)) {
if (!cpu->IRQ) if (!cpu->IRQ)
cpu->IRQ = 1; cpu->IRQ = 1;
} }
@ -104,8 +121,12 @@ next_instruction:
d = mii_cpu_op[cpu->IR].desc; d = mii_cpu_op[cpu->IR].desc;
cpu->ir_log = (cpu->ir_log << 8) | cpu->IR; cpu->ir_log = (cpu->ir_log << 8) | cpu->IR;
s.trap = cpu->trap && (cpu->ir_log & 0xffff) == cpu->trap; s.trap = cpu->trap && (cpu->ir_log & 0xffff) == cpu->trap;
if (unlikely(s.trap)) if (unlikely(s.trap)) {
cpu->ir_log = 0; cpu->ir_log = 0;
#if MII_65C02_DIRECT_ACCESS
return s;
#endif
}
switch (d.mode) { switch (d.mode) {
case IMM: case IMM:
_FETCH(cpu->PC++); cpu->_D = s.data; _FETCH(cpu->PC++); cpu->_D = s.data;
@ -609,6 +630,7 @@ next_instruction:
/* Apparently these NOPs use 3 bytes, according to the tests */ /* Apparently these NOPs use 3 bytes, according to the tests */
case 0x5c: case 0xdc: case 0xfc: case 0x5c: case 0xdc: case 0xfc:
_FETCH(cpu->PC++); _FETCH(cpu->PC++);
// fall through
/* Apparently these NOPs use 2 bytes, according to the tests */ /* Apparently these NOPs use 2 bytes, according to the tests */
case 0x02: case 0x22: case 0x42: case 0x62: case 0x82: case 0x02: case 0x22: case 0x42: case 0x62: case 0x82:
case 0xC2: case 0xE2: case 0x44: case 0x54: case 0xD4: case 0xC2: case 0xE2: case 0x44: case 0x54: case 0xD4:
@ -626,7 +648,15 @@ next_instruction:
if (d.w) { if (d.w) {
_STORE(cpu->_P, cpu->_D); _STORE(cpu->_P, cpu->_D);
} }
#if MII_65C02_DIRECT_ACCESS
// we don't need to do anything here, the store already did it
if (likely(cpu->instruction_run)) {
cpu->instruction_run--;
goto next_instruction;
}
#else
goto next_instruction; goto next_instruction;
pt_end(cpu->state); pt_end(cpu->state);
#endif
return s; return s;
} }

View File

@ -40,7 +40,7 @@
* this will stop the current instruction and start fetching at new_pc * this will stop the current instruction and start fetching at new_pc
* *
*/ */
typedef union mii_cpu_state_t { typedef union mii_cpu_state_t {
struct { struct {
uint16_t addr; uint16_t addr;
uint8_t data; uint8_t data;
@ -50,9 +50,20 @@ typedef union mii_cpu_state_t {
irq : 1, irq : 1,
nmi : 1, nmi : 1,
trap : 1; trap : 1;
}; } __attribute__((packed));
uint32_t raw; uint32_t raw;
} mii_cpu_state_t; } mii_cpu_state_t ;
#ifndef MII_65C02_DIRECT_ACCESS
#define MII_65C02_DIRECT_ACCESS 1
#endif
#if MII_65C02_DIRECT_ACCESS
struct mii_cpu_t;
typedef mii_cpu_state_t (*mii_cpu_direct_access_cb)(
struct mii_cpu_t *cpu,
mii_cpu_state_t access );
#endif
/* CPU state machine */ /* CPU state machine */
typedef struct mii_cpu_t { typedef struct mii_cpu_t {
@ -87,9 +98,7 @@ typedef struct mii_cpu_t {
uint8_t IR; uint8_t IR;
uint8_t IRQ; // IRQ (0) or NMI (1) or BRK (2) uint8_t IRQ; // IRQ (0) or NMI (1) or BRK (2)
uint8_t cycle; // for current instruction uint8_t cycle; // for current instruction
/* State of the protothread for the CPU state machine (minipt.h) */ uint32_t instruction_run; // how many instructions to run
void * state;
/* sequence of instruction that will trigger a trap flag. /* sequence of instruction that will trigger a trap flag.
* this is used to trigger 'call backs' to the main code * this is used to trigger 'call backs' to the main code
* typically use a pair of NOPs sequence that is unlikely to exist in * typically use a pair of NOPs sequence that is unlikely to exist in
@ -99,8 +108,18 @@ typedef struct mii_cpu_t {
uint32_t ir_log; uint32_t ir_log;
uint64_t total_cycle; uint64_t total_cycle;
#if MII_65C02_DIRECT_ACCESS
mii_cpu_direct_access_cb access;
void * access_param; // typically struct mii_t*
#else
/* State of the protothread for the CPU state machine (minipt.h) */
void * state;
#endif
#ifdef MII_TEST
/* Debug only; Only used by the test units. */ /* Debug only; Only used by the test units. */
uint8_t * ram; // DEBUG uint8_t * ram; // DEBUG
#endif
} mii_cpu_t; } mii_cpu_t;
mii_cpu_state_t mii_cpu_state_t

View File

@ -136,7 +136,7 @@ mii_argv_parse(
} else if (!strcmp(arg, "--audio-off") || } else if (!strcmp(arg, "--audio-off") ||
!strcmp(arg, "--no-audio") || !strcmp(arg, "--no-audio") ||
!strcmp(arg, "--silent")) { !strcmp(arg, "--silent")) {
mii->speaker.off = true; mii->speaker.speaker_off = true;
*ioFlags |= MII_INIT_SILENT; *ioFlags |= MII_INIT_SILENT;
} else if (!strcmp(arg, "-vol") || !strcmp(arg, "--volume")) { } else if (!strcmp(arg, "-vol") || !strcmp(arg, "--volume")) {
if (i < argc-1) { if (i < argc-1) {

View File

@ -45,6 +45,23 @@ mii_bank_dispose(
bank->access = NULL; bank->access = NULL;
} }
bool
mii_bank_access(
mii_bank_t *bank,
uint16_t addr,
const uint8_t *data,
uint16_t len,
bool write)
{
uint8_t page_index = (addr - bank->base) >> 8;
if (bank->access && bank->access[page_index].cb) {
if (bank->access[page_index].cb(bank, bank->access[page_index].param,
addr, (uint8_t *)data, write))
return true;
}
return false;
}
void void
mii_bank_write( mii_bank_write(
mii_bank_t *bank, mii_bank_t *bank,
@ -52,6 +69,7 @@ mii_bank_write(
const uint8_t *data, const uint8_t *data,
uint16_t len) uint16_t len)
{ {
#if 0 // rather expensive test when profiling!
uint32_t end = bank->base + (bank->size << 8); uint32_t end = bank->base + (bank->size << 8);
if (unlikely(addr < bank->base || (addr + len) > end)) { if (unlikely(addr < bank->base || (addr + len) > end)) {
printf("%s %s INVALID write addr %04x len %d %04x:%04x\n", printf("%s %s INVALID write addr %04x len %d %04x:%04x\n",
@ -60,12 +78,9 @@ mii_bank_write(
abort(); abort();
return; return;
} }
uint8_t page_index = (addr - bank->base) >> 8; #endif
if (bank->access && bank->access[page_index].cb) { if (mii_bank_access(bank, addr, data, len, true))
if (bank->access[page_index].cb(bank, bank->access[page_index].param, return;
addr, (uint8_t *)data, true))
return;
}
uint32_t phy = bank->mem_offset + addr - bank->base; uint32_t phy = bank->mem_offset + addr - bank->base;
do { do {
bank->mem[phy++] = *data++; bank->mem[phy++] = *data++;
@ -79,7 +94,7 @@ mii_bank_read(
uint8_t *data, uint8_t *data,
uint16_t len) uint16_t len)
{ {
#if 1 // rather expensive test when profiling! #if 0 // rather expensive test when profiling!
uint32_t end = bank->base + (bank->size << 8); uint32_t end = bank->base + (bank->size << 8);
if (unlikely(addr < bank->base) || unlikely((addr + len) > end)) { if (unlikely(addr < bank->base) || unlikely((addr + len) > end)) {
printf("%s %s INVALID read addr %04x len %d %04x-%04x\n", printf("%s %s INVALID read addr %04x len %d %04x-%04x\n",
@ -88,12 +103,8 @@ mii_bank_read(
return; return;
} }
#endif #endif
uint8_t page_index = (addr - bank->base) >> 8; if (mii_bank_access(bank, addr, data, len, false))
if (bank->access && bank->access[page_index].cb) { return;
if (bank->access[page_index].cb(bank, bank->access[page_index].param,
addr, data, false))
return;
}
uint32_t phy = bank->mem_offset + addr - bank->base; uint32_t phy = bank->mem_offset + addr - bank->base;
do { do {
*data++ = bank->mem[phy++]; *data++ = bank->mem[phy++];

View File

@ -65,6 +65,13 @@ mii_bank_read(
uint16_t addr, uint16_t addr,
uint8_t *data, uint8_t *data,
uint16_t len); uint16_t len);
bool
mii_bank_access(
mii_bank_t *bank,
uint16_t addr,
const uint8_t *data,
uint16_t len,
bool write);
/* return the number of pages dirty (written into since last time) between /* return the number of pages dirty (written into since last time) between
* addr1 and addr2 (inclusive) */ * addr1 and addr2 (inclusive) */

View File

@ -81,11 +81,7 @@ show_state:
return; return;
} }
uint8_t val = strtol(argv[2], NULL, 16); uint8_t val = strtol(argv[2], NULL, 16);
if (val > MII_VIDEO_MODE_COUNT) { mii_video_set_mode(mii, val);
printf("rgb: invalid mode %d\n", val);
return;
}
mii->video.color_mode = val;
return; return;
} }
@ -389,44 +385,15 @@ _mii_mish_step(
printf("mii: can't step/next, not stopped\n"); printf("mii: can't step/next, not stopped\n");
return; return;
} }
if (argv[1]) { int count = 1;
int n = strtol(argv[1], NULL, 10); if (argv[1])
mii->trace.step_inst = n; count = strtol(argv[1], NULL, 10);
} else mii_cpu_step(mii, count);
mii->trace.step_inst = 1;
mii->state = MII_STEP;
return; return;
} }
if (argv[0][0] == 'n') { if (argv[0][0] == 'n') {
mii_t * mii = param; mii_t * mii = param;
if (mii->state != MII_STOPPED) { mii_cpu_next(mii);
printf("mii: can't step/next, not stopped\n");
return;
}
// read current opcode, find how how many bytes it take,
// then put a temporary breakpoint to the next PC.
// all of that if this is not a relative branch of course, in
// which case we use a normal 'step' behaviour
uint8_t op;
mii_mem_access(mii, mii->cpu.PC, &op, false, false);
if (op == 0x20) { // JSR here?
// set a temp breakpoint on reading 3 bytes from PC
for (int i = 0; i < (int)sizeof(mii->debug.bp_map) * 8; i++) {
if ((mii->debug.bp_map & (1 << i)))
continue;
mii->debug.bp[i].addr = mii->cpu.PC + 3;
mii->debug.bp[i].kind = MII_BP_R;
mii->debug.bp[i].size = 1;
mii->debug.bp[i].silent = 1;
mii->debug.bp_map |= 1 << i;
mii->state = MII_RUNNING;
return;
}
printf("no more breakpoints available\n");
} else {
mii->trace.step_inst = 1;
mii->state = MII_STEP;
}
return; return;
} }
if (argv[0][0] == 'c') { if (argv[0][0] == 'c') {
@ -493,6 +460,58 @@ _mii_mish_audio(
} }
} }
static void
_mii_mish_bsave(
void * param,
int argc,
const char * argv[])
{
mii_t * mii = param;
if (argc < 4) {
printf("bsave: missing argument <file> <addr> <size>\n");
return;
}
const char * file = argv[1];
uint16_t addr = strtol(argv[2], NULL, 16);
if (!strcmp(argv[0], "bsave")) {
uint16_t size = strtol(argv[3], NULL, 16);
if (addr + size > 0x10000) {
printf("bsave: size too big\n");
return;
}
FILE * f = fopen(file, "wb");
if (!f) {
printf("bsave: can't open %s\n", file);
return;
}
mii_bank_t * bank = &mii->bank[MII_BANK_MAIN];
fwrite(bank->mem + addr, size, 1, f);
fclose(f);
printf("bsave: %s saved %d bytes at %04x\n", file, size, addr);
} else if (!strcmp(argv[0], "bload")) {
FILE * f = fopen(file, "rb");
if (!f) {
printf("bsave: can't open %s\n", file);
return;
}
fseek(f, 0, SEEK_END);
uint16_t size = ftell(f);
fseek(f, 0, SEEK_SET);
if (addr + size > 0x10000) {
printf("bsave: size too big\n");
return;
}
mii_bank_t * bank = &mii->bank[MII_BANK_MAIN];
fread(bank->mem + addr, size, 1, f);
fclose(f);
printf("bsave: %s loaded %d bytes at %04x\n", file, size, addr);
} else {
printf("%s: unknown command\n", argv[0]);
return;
}
}
#include "mish.h" #include "mish.h"
MISH_CMD_NAMES(mii, "mii"); MISH_CMD_NAMES(mii, "mii");
@ -582,3 +601,12 @@ MISH_CMD_HELP(audio,
" volume: set volume (0.0 to 1.0)." " volume: set volume (0.0 to 1.0)."
); );
MII_MISH(audio, _mii_mish_audio); MII_MISH(audio, _mii_mish_audio);
MISH_CMD_NAMES(bsave, "bsave","bload");
MISH_CMD_HELP(bsave,
"bsave/bload: save/load binary data from ram",
" bsave <file> <addr> <size>: save binary data to file.",
" bload <file> <addr>: load binary data from file."
);
MII_MISH(bsave, _mii_mish_bsave);

View File

@ -41,9 +41,6 @@ typedef struct mii_slot_drv_t {
void (*reset)( void (*reset)(
mii_t * mii, mii_t * mii,
struct mii_slot_t *slot); struct mii_slot_t *slot);
void (*run)(
mii_t * mii,
struct mii_slot_t *slot);
// access to the slot's soft switches. // access to the slot's soft switches.
uint8_t (*access)( uint8_t (*access)(
mii_t * mii, mii_t * mii,

View File

@ -10,6 +10,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <unistd.h>
#include "mii.h" #include "mii.h"
#include "mii_speaker.h" #include "mii_speaker.h"
@ -99,8 +100,8 @@ mii_speaker_init(
s->timer_id = mii_timer_register(mii, s->timer_id = mii_timer_register(mii,
_mii_speaker_timer_cb, s, 0, __func__); _mii_speaker_timer_cb, s, 0, __func__);
#ifdef HAS_ALSA #ifdef HAS_ALSA
printf("%s audio is %s\n", __func__, s->off ? "off" : "on"); printf("%s audio is %s\n", __func__, s->speaker_off ? "off" : "on");
if (!s->off) if (!s->speaker_off)
_alsa_init(s); // this can/will change fsize _alsa_init(s); // this can/will change fsize
#endif #endif
mii_speaker_volume(s, 1); mii_speaker_volume(s, 1);
@ -135,7 +136,7 @@ _mii_speaker_timer_cb(
{ {
mii_speaker_t *s = (mii_speaker_t *)param; mii_speaker_t *s = (mii_speaker_t *)param;
if (s->muted || s->off) if (s->muted || s->speaker_off)
goto done; goto done;
mii_audio_frame_t *f = &s->frame[s->fplay]; mii_audio_frame_t *f = &s->frame[s->fplay];
// if the frame is empty, we mark the fact we are in underrun, // if the frame is empty, we mark the fact we are in underrun,

View File

@ -13,32 +13,32 @@
#define MII_SPEAKER_FRAME_COUNT 4 #define MII_SPEAKER_FRAME_COUNT 4
struct mii_t; struct mii_t;
struct snd_pcm_t; struct _snd_pcm;
typedef int16_t mii_audio_sample_t; typedef int16_t mii_audio_sample_t;
typedef struct mii_audio_frame_t { typedef struct mii_audio_frame_t {
// mii_cycles_t start; uint16_t fill;
uint16_t fill; mii_audio_sample_t *audio;
mii_audio_sample_t * audio;
} mii_audio_frame_t; } mii_audio_frame_t;
typedef struct mii_speaker_t { typedef struct mii_speaker_t {
struct mii_t * mii; struct mii_t *mii;
uint8_t timer_id; // timer id for the audio thread uint8_t timer_id; // timer id for the audio thread
int debug_fd; // if > 0, dump audio to this fd int debug_fd; // if > 0, dump audio to this fd
void * alsa_pcm; // alsa pcm handle struct _snd_pcm *alsa_pcm; // alsa pcm handle
bool muted; // if true, don't play anything uint muted : 1; // if true, don't play anything
bool off; // if true, don't even initialize (alsa) uint speaker_off : 1; // if true, don't even initialize (alsa)
float volume; // volume, 0.0 to 10.0 float volume; // volume, 0.0 to 10.0
float vol_multiplier; // sample multiplier, 0.0 to 1.0 float vol_multiplier; // sample multiplier, 0.0 to 1.0
float cpu_speed; // CPU speed in MHz, to calculate clk_per_sample float cpu_speed; // CPU speed in MHz, to calculate clk_per_sample
uint8_t under; // number of frames we've skipped uint8_t under; // number of frames we've skipped
uint8_t fplay; // frame we want to play uint8_t fplay; // frame we want to play
uint16_t fsize; // size in samples of a frame uint16_t fsize; // size in samples of a frame
uint8_t findex; // frame we are currently filling uint8_t findex; // frame we are currently filling
float clk_per_sample; // number of cycles per sample (at current CPU speed) // number of cycles per sample (at current CPU speed)
mii_audio_sample_t sample; // current value for the speaker output float clk_per_sample;
mii_audio_frame_t frame[MII_SPEAKER_FRAME_COUNT]; mii_audio_sample_t sample; // current value for the speaker output
mii_audio_frame_t frame[MII_SPEAKER_FRAME_COUNT];
} mii_speaker_t; } mii_speaker_t;
// Initialize the speaker with the frame size in samples // Initialize the speaker with the frame size in samples

View File

@ -106,7 +106,7 @@ mii_vcd_flush_log(
{ {
uint64_t seen = 0; uint64_t seen = 0;
uint64_t oldbase = 0; // make sure it's different uint64_t oldbase = 0; // make sure it's different
char out[48]; char out[256];
if (mii_vcd_fifo_isempty(&vcd->log) || !vcd->output) if (mii_vcd_fifo_isempty(&vcd->log) || !vcd->output)
return; return;

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,13 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
/*
* When 1, this will draw a heat map of the dirty lines alongside the video
* This is useful to see if the video rendering is efficient.
* This has no real use apart from debugging the video rendering.
*/
#define MII_VIDEO_DEBUG_HEAPMAP 0
// TODO move VRAM stuff to somewhere else // TODO move VRAM stuff to somewhere else
#define MII_VIDEO_WIDTH (280 * 2) #define MII_VIDEO_WIDTH (280 * 2)
#define MII_VIDEO_HEIGHT (192 * 2) #define MII_VIDEO_HEIGHT (192 * 2)
@ -24,28 +31,65 @@
#define MII_VRAM_HEIGHT MII_VIDEO_HEIGHT #define MII_VRAM_HEIGHT MII_VIDEO_HEIGHT
#endif #endif
enum {
MII_VIDEO_COLOR = 0,
MII_VIDEO_GREEN,
MII_VIDEO_AMBER,
MII_VIDEO_MODE_COUNT
};
struct mii_t; struct mii_t;
struct mii_video_t;
typedef void (*mii_video_line_drawing_cb)( typedef void (*mii_video_line_drawing_cb)(
mii_t *mii, uint8_t mode, bool page2 ); mii_t *mii );
typedef void (*mii_video_line_check_cb)(
struct mii_video_t *video,
uint32_t sw,
uint16_t addr);
typedef struct mii_video_cb_t {
mii_video_line_drawing_cb render;
mii_video_line_check_cb check;
} mii_video_cb_t;
typedef uint32_t mii_color_t;
/*
* Color Lookup Table fro all the modes. They default to the color
* version defined in mii_video.c, then get derived from that for
* the green and amber modes.
*/
typedef union mii_video_clut_t {
struct {
mii_color_t lores[2][16]; // lores (main, and aux page DLORES)
mii_color_t dhires[16];
mii_color_t hires[10];
// mii_color_t hires2[8];
mii_color_t text[2]; // text
mii_color_t mono[2]; // DHRES mono mode
};
mii_color_t colors[(2*16) + 16 + 10 /*+ 8*/ + 2 + 2];
} mii_video_clut_t;
typedef struct mii_video_t { typedef struct mii_video_t {
void * state; // protothread state in mii_video.c void * state; // protothread state in mii_video.c
uint8_t timer_id; // timer id for the video thread uint8_t timer_id; // timer id for the video thread
uint8_t line; // current line uint8_t line; // current line for cycle timer
uint32_t pixels[MII_VRAM_WIDTH * MII_VRAM_HEIGHT]; uint16_t base_addr; // current mode base address
uint32_t frame_count; // incremented every frame uint16_t line_addr; // VRAM address for the line we are on
uint32_t frame_drawn; uint64_t timer_max; // timer start value
uint8_t color_mode; // color, green, amber uint32_t frame_count; // incremented every frame
uint8_t color_mode; // color palette index
uint8_t monochrome; // monochrome mode
mii_video_clut_t clut; // current color table
mii_video_clut_t clut_low; // low luminance version
// function pointer to the line drawing function // function pointer to the line drawing function
mii_video_line_drawing_cb line_drawing; mii_video_cb_t line_cb;
uint8_t frame_dirty;
uint32_t frame_seed; // changed when pixels have changed for this frame
uint64_t lines_dirty[192 / 64]; // 192 lines / 64 bits
#if MII_VIDEO_DEBUG_HEAPMAP
uint8_t video_hmap[192]
__attribute__((aligned(32))) ; // line dirty heat map
#endif
// alignment is required for vector extensions
uint32_t pixels[MII_VRAM_WIDTH * MII_VRAM_HEIGHT]
__attribute__((aligned(32)));
} mii_video_t; } mii_video_t;
bool bool
@ -58,4 +102,19 @@ void
mii_video_init( mii_video_init(
mii_t *mii); mii_t *mii);
void
mii_video_set_mode(
mii_t *mii,
uint8_t mode);
/* out of bounds write check. This allow SmartPort DMA drive to
* pass down the range it writes buffers to, so the video gets
* a chance to check if the addresses are in RAM, in case the
* Prodos call is loading an image into VRAM proper */
void
mii_video_OOB_write_check(
mii_t *mii,
uint16_t addr,
uint16_t size);
uint8_t
mii_video_get_vapor(
mii_t *mii);

View File

@ -29,7 +29,7 @@
#include "mii_mui_gl.h" #include "mii_mui_gl.h"
#include "miigl_counter.h" #include "miigl_counter.h"
#define MII_ICON64_DEFINE #define MII_ICON64_DEFINE
#include "mii-icon-64.h" #include "mii_icon64.h"
/* /*
* Note: This *assumes* that the GL implementation has support for * Note: This *assumes* that the GL implementation has support for
@ -49,10 +49,6 @@ typedef struct mii_x11_t {
Display * dpy; Display * dpy;
Window win; Window win;
XVisualInfo * vis;
Colormap cmap;
XSetWindowAttributes swa;
GLXFBConfig fbc;
Atom wm_delete_window; Atom wm_delete_window;
int width, height; int width, height;
GLXContext glContext; GLXContext glContext;
@ -155,6 +151,8 @@ mii_x11_init(
if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1)) if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))
die("[X11]: Error: Invalid GLX version!\n"); die("[X11]: Error: Invalid GLX version!\n");
} }
GLXFBConfig fbc;
XVisualInfo * vis = NULL;
{ {
/* find and pick matching framebuffer visual */ /* find and pick matching framebuffer visual */
int fb_count; int fb_count;
@ -163,26 +161,24 @@ mii_x11_init(
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
None None
}; };
GLXFBConfig *fbc = glXChooseFBConfig(ui->dpy, GLXFBConfig *fbc_list = glXChooseFBConfig(ui->dpy,
DefaultScreen(ui->dpy), attr, &fb_count); DefaultScreen(ui->dpy), attr, &fb_count);
if (!fbc) if (!fbc_list)
die("[X11]: Error: failed to retrieve framebuffer configuration\n"); die("[X11]: Error: failed to retrieve framebuffer configuration\n");
{ {
/* pick framebuffer with most samples per pixel */ /* pick framebuffer with most samples per pixel */
int fb_best = -1, best_num_samples = -1; int fb_best = -1, best_num_samples = -1;
for (int i = 0; i < fb_count; ++i) { for (int i = 0; i < fb_count; ++i) {
XVisualInfo *vi = glXGetVisualFromFBConfig(ui->dpy, fbc[i]); XVisualInfo *vi = glXGetVisualFromFBConfig(ui->dpy, fbc_list[i]);
if (vi) { if (vi) {
int sample_buffer, samples; int sample_buffer, samples;
glXGetFBConfigAttrib(ui->dpy, fbc[i], glXGetFBConfigAttrib(ui->dpy, fbc_list[i],
GLX_SAMPLE_BUFFERS, &sample_buffer); GLX_SAMPLE_BUFFERS, &sample_buffer);
glXGetFBConfigAttrib(ui->dpy, fbc[i], glXGetFBConfigAttrib(ui->dpy, fbc_list[i],
GLX_SAMPLES, &samples); GLX_SAMPLES, &samples);
if ((fb_best < 0) || if ((fb_best < 0) ||
(sample_buffer && samples > best_num_samples)) (sample_buffer && samples > best_num_samples))
@ -190,34 +186,35 @@ mii_x11_init(
XFree(vi); XFree(vi);
} }
} }
ui->fbc = fbc[fb_best]; fbc = fbc_list[fb_best];
XFree(fbc); XFree(fbc_list);
ui->vis = glXGetVisualFromFBConfig(ui->dpy, ui->fbc); vis = glXGetVisualFromFBConfig(ui->dpy, fbc);
} }
} }
{ {
/* create window */ /* create window */
ui->cmap = XCreateColormap(ui->dpy, XSetWindowAttributes swa = {
RootWindow(ui->dpy, ui->vis->screen), .colormap = XCreateColormap(ui->dpy,
ui->vis->visual, AllocNone); RootWindow(ui->dpy, vis->screen),
ui->swa.colormap = ui->cmap; vis->visual, AllocNone),
ui->swa.background_pixmap = None; .background_pixmap = None,
ui->swa.border_pixel = 0; .border_pixel = 0,
ui->swa.event_mask = .event_mask =
ExposureMask | KeyPressMask | KeyReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
ButtonPress | ButtonReleaseMask | ButtonMotionMask | ButtonPress | ButtonReleaseMask | ButtonMotionMask |
Button1MotionMask | Button3MotionMask | Button1MotionMask | Button3MotionMask |
Button4MotionMask | Button5MotionMask | Button4MotionMask | Button5MotionMask |
PointerMotionMask | StructureNotifyMask | FocusChangeMask; PointerMotionMask | StructureNotifyMask | FocusChangeMask,
};
ui->win = XCreateWindow(ui->dpy, ui->win = XCreateWindow(ui->dpy,
RootWindow(ui->dpy, ui->vis->screen), 0, 0, RootWindow(ui->dpy, vis->screen), 0, 0,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, ui->vis->depth, InputOutput, WINDOW_WIDTH, WINDOW_HEIGHT, 0, vis->depth, InputOutput,
ui->vis->visual, vis->visual, CWBorderPixel | CWColormap | CWEventMask,
CWBorderPixel | CWColormap | CWEventMask, &swa);
&ui->swa);
if (!ui->win) if (!ui->win)
die("[X11]: Failed to create window\n"); die("[X11]: Failed to create window\n");
XFree(ui->vis); XFree(vis);
XFreeColormap(ui->dpy, swa.colormap);
{ {
char title[128]; char title[128];
sprintf(title, "MII //e Emulator"); sprintf(title, "MII //e Emulator");
@ -276,14 +273,15 @@ mii_x11_init(
!create_context) { !create_context) {
fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n"); fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
fprintf(stdout, "[X11]: ... using old-style GLX context\n"); fprintf(stdout, "[X11]: ... using old-style GLX context\n");
ui->glContext = glXCreateNewContext(ui->dpy, ui->fbc, GLX_RGBA_TYPE, 0, True); ui->glContext = glXCreateNewContext(
ui->dpy, fbc, GLX_RGBA_TYPE, 0, True);
} else { } else {
GLint attr[] = { GLint attr[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 2, GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2, GLX_CONTEXT_MINOR_VERSION_ARB, 0,
None None
}; };
ui->glContext = create_context(ui->dpy, ui->fbc, 0, True, attr); ui->glContext = create_context(ui->dpy, fbc, 0, True, attr);
XSync(ui->dpy, False); XSync(ui->dpy, False);
if (gl_err || !ui->glContext) { if (gl_err || !ui->glContext) {
attr[1] = 1; attr[1] = 1;
@ -291,7 +289,7 @@ mii_x11_init(
gl_err = false; gl_err = false;
fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n"); fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
fprintf(stdout, "[X11] ... using old-style GLX context!\n"); fprintf(stdout, "[X11] ... using old-style GLX context!\n");
ui->glContext = create_context(ui->dpy, ui->fbc, 0, True, attr); ui->glContext = create_context(ui->dpy, fbc, 0, True, attr);
} }
} }
XSync(ui->dpy, False); XSync(ui->dpy, False);
@ -303,6 +301,29 @@ mii_x11_init(
return 0; return 0;
} }
static void
mui_read_clipboard(
struct mui_t *mui)
{
FILE *f = popen("xclip -selection clipboard -o", "r");
if (!f) {
perror("popen xclip");
return;
}
mui_utf8_t clip = {};
char buf[1024];
size_t r = 0;
do {
r = fread(buf, 1, sizeof(buf), f);
if (r > 0)
mui_utf8_append(&clip, (uint8_t*)buf, r);
} while (r > 0);
pclose(f);
mui_utf8_free(&mui->clipboard);
mui->clipboard = clip;
}
static int static int
mii_x11_handle_event( mii_x11_handle_event(
mii_x11_t * ui, mii_x11_t * ui,
@ -400,8 +421,29 @@ mii_x11_handle_event(
case MUI_KEY_RIGHT: mii_key = 'U' - 'A' + 1; break; case MUI_KEY_RIGHT: mii_key = 'U' - 'A' + 1; break;
case MUI_KEY_LEFT: mii_key = 'H' - 'A' + 1; break; case MUI_KEY_LEFT: mii_key = 'H' - 'A' + 1; break;
} }
// printf("key %04x %4x\n", mii_key, mui->modifier_keys); // printf("key %04x %4x\n", mii_key, mui->modifier_keys);
mii_keypress(mii, mii_key); /* control shift V is hard coded! */
if (mii_key == 0x016 &&
(mui->modifier_keys & MUI_MODIFIER_SHIFT) &&
(mui->modifier_keys & MUI_MODIFIER_CTRL)) {
printf("Paste\n");
mui_read_clipboard(mui);
if (mui->clipboard.count) {
mui_utf8_add(&mui->clipboard, 0);
// convert newlines
for (uint i = 0; i < mui->clipboard.count; i++)
if (mui->clipboard.e[i] == '\n')
mui->clipboard.e[i] = '\r';
mii_th_signal_t sig = {
.cmd = SIGNAL_PASTE,
.ptr = mui->clipboard.e,
};
mui->clipboard.e = NULL;
mui->clipboard.count = mui->clipboard.size = 0;
mii_th_fifo_write(mii_thread_get_fifo(mii), sig);
}
} else
mii_keypress(mii, mii_key);
} }
XFree(code); XFree(code);
} break; } break;
@ -487,7 +529,6 @@ mii_x11_terminate(
glXMakeCurrent(ui->dpy, 0, 0); glXMakeCurrent(ui->dpy, 0, 0);
glXDestroyContext(ui->dpy, ui->glContext); glXDestroyContext(ui->dpy, ui->glContext);
XUnmapWindow(ui->dpy, ui->win); XUnmapWindow(ui->dpy, ui->win);
XFreeColormap(ui->dpy, ui->cmap);
XDestroyWindow(ui->dpy, ui->win); XDestroyWindow(ui->dpy, ui->win);
XCloseDisplay(ui->dpy); XCloseDisplay(ui->dpy);
} }
@ -502,6 +543,10 @@ static const struct {
[MII_SLOT_DRIVER_MOUSE] = { "mouse", }, [MII_SLOT_DRIVER_MOUSE] = { "mouse", },
[MII_SLOT_DRIVER_SSC] = { "ssc", }, [MII_SLOT_DRIVER_SSC] = { "ssc", },
[MII_SLOT_DRIVER_ROM1MB] = { "eecard", }, [MII_SLOT_DRIVER_ROM1MB] = { "eecard", },
[MII_SLOT_DRIVER_MOCKINGBOARD] = { "mockingboard", },
#ifdef MII_DANII
[MII_SLOT_DRIVER_DANII] = { "danii", },
#endif
}; };
void void
@ -575,6 +620,7 @@ _mii_ui_load_config(
*ioFlags |= MII_INIT_TITAN; *ioFlags |= MII_INIT_TITAN;
mii->speaker.muted = config->audio_muted; mii->speaker.muted = config->audio_muted;
mii->video.color_mode = config->video_mode; mii->video.color_mode = config->video_mode;
mii_video_set_mode(mii, config->video_mode);
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
if (config->slot[i].driver == MII_SLOT_DRIVER_NONE) if (config->slot[i].driver == MII_SLOT_DRIVER_NONE)
continue; continue;
@ -594,7 +640,7 @@ _mii_ui_load_config(
} }
// I want at least the 'silent' flags to be 'sticky' // I want at least the 'silent' flags to be 'sticky'
static uint32_t g_startup_flags = 0; uint32_t g_startup_flags = 0;
void void
mii_x11_reload_config( mii_x11_reload_config(
@ -602,7 +648,7 @@ mii_x11_reload_config(
{ {
mii_t * mii = &ui->video.mii; mii_t * mii = &ui->video.mii;
mii_machine_config_t * config = &ui->video.config; mii_machine_config_t * config = &ui->video.config;
uint32_t flags = MII_INIT_DEFAULT | (g_startup_flags & MII_INIT_SILENT); uint32_t flags = MII_INIT_DEFAULT | g_startup_flags;
if (mii->state != MII_INIT) { if (mii->state != MII_INIT) {
printf("%s mii is running, terminating thread\n", __func__); printf("%s mii is running, terminating thread\n", __func__);
@ -613,7 +659,7 @@ mii_x11_reload_config(
mii_mui_menu_slot_menu_update(&ui->video); mii_mui_menu_slot_menu_update(&ui->video);
printf("%s (re)loading config\n", __func__); printf("%s (re)loading config\n", __func__);
// if we're silent from the command line, we are *always* silent. // if we're silent from the command line, we are *always* silent.
mii->speaker.off = !!(g_startup_flags & MII_INIT_SILENT); mii->speaker.speaker_off = !!(g_startup_flags & MII_INIT_SILENT);
mii_init(mii); mii_init(mii);
_mii_ui_load_config(mii, config, &flags); _mii_ui_load_config(mii, config, &flags);
mii_prepare(mii, flags); mii_prepare(mii, flags);
@ -708,7 +754,7 @@ main(
if (evt.xclient.message_type == if (evt.xclient.message_type ==
XInternAtom(ui->dpy, "WM_PROTOCOLS", False) && XInternAtom(ui->dpy, "WM_PROTOCOLS", False) &&
(Atom)evt.xclient.data.l[0] == ui->wm_delete_window) { (Atom)evt.xclient.data.l[0] == ui->wm_delete_window) {
printf("Window close requested!\n"); // printf("Window close requested!\n");
goto cleanup; goto cleanup;
} }
} }

524
ui_gl/mii_icon64.h Normal file
View File

@ -0,0 +1,524 @@
// Autogenerated with:
// libmui/utils/png2raw.c -t unsigned long -n mii_icon64 -o ui_gl/mii_icon64.h contrib/mii-icon-64.png
// Image with a W:64px, H:64px and 4 channels
// Converted to ARGB8888 and premultiplied alpha
#pragma once
#define MII_ICON64_SIZE 4098
extern const unsigned long mii_icon64[MII_ICON64_SIZE];
#ifdef MII_ICON64_DEFINE
const unsigned long mii_icon64[MII_ICON64_SIZE] = {
64, 64, // width, height
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01000000,
0x01000000,0x03010101,0x04020203,0x04030303,0x04030303,0x05030404,0x05030404,0x05040404,
0x05040404,0x06040405,0x06040405,0x06040405,0x06040405,0x07030403,0x07010402,0x07010402,
0x07010402,0x07010402,0x07010402,0x07020402,0x06010302,0x06010302,0x06010302,0x06010302,
0x06010302,0x06010302,0x06010302,0x05010301,0x05010301,0x05010301,0x04010201,0x01000000,
0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x2f2c2c2d,0x7b757678,0xafa6a8ab,0xd0c6c8cb,0xf2e7e9ed,
0xfdf2f5f9,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,
0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xffc1dcc7,0xff5eb94e,0xff5fb94d,
0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,
0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94d,0xff5fb94e,0xfe5eb851,
0xf65bb24f,0xd34e9943,0xb1407f3a,0x7c2d592c,0x31112212,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x514c4d4e,0xcec5c6c9,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,
0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,
0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff0f4f6,0xff6fbd67,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff5fba4a,0xcd4b9443,0x511c391e,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x13111112,
0xb4abadb0,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,
0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,
0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xfff4f7fb,0xffb9d8bd,0xff60ba46,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff5fba48,0xb240803d,
0x13060d07,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x201d1e1e,0xdfd5d7da,
0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,
0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,
0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xfff4f7fb,0xfff4f6fa,0xfff4f7fb,0xffebf2f1,0xff60b951,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xdd519f47,0x1f0a150c,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x14121212,0xdfd5d7da,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f7fa,0xffa1cea2,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xdd519f48,0x12060c06,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x01000000,0xb4abacaf,0xfff4f6fa,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,
0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xfff4f6fa,0xffd5e5db,
0xff5fba47,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xb03f7e3c,0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x4f494a4b,0xfff4f6f9,0xfff4f6fa,0xfff3f6f9,
0xfff4f6f9,0xfff4f6f9,0xfff4f6fa,0xfff4f6f9,0xfff4f6f9,0xfff4f6fa,0xfff4f6f9,0xfff4f6fa,
0xfff3f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6fa,0xfff4f6f9,0xfff4f6f9,0xfff4f6fa,0xfff4f6f9,
0xfff4f6fa,0xfff3f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6fa,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,
0xff74be6d,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff5fba49,0x4919331b,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x01000000,0xccc1c3c6,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,
0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f5f9,0xfff4f6f9,0xfff4f6f9,
0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f5f9,0xfff4f6f9,
0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,0xfff4f6f9,
0xffb2d5b4,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,0xff60ba45,
0xff60ba45,0xff60ba45,0xff60ba45,0xc8488f41,0x01000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x2c272828,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff3f5f9,
0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,
0xfff3f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,
0xfff4f5f9,0xfff3f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,0xfff4f5f9,
0xffdae8e0,0xff5fb948,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,
0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,
0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,0xff60ba46,
0xff60ba46,0xff60ba46,0xff60ba46,0xff5fb94b,0x280d1b0f,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x766e6f70,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xffc7b762,0xffcab33f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,
0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,
0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb43f,
0xffcbb43f,0xffcbb43f,0xffcbb43f,0xffcbb440,0x70594c1f,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x01000000,0xa79d9d9f,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,0xfff4f5f8,
0xfff4f5f8,0xfff9cf9f,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xa29d7117,0x01000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x02000000,0xcec2c3c5,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f7,
0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,
0xfff3f4f7,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,
0xfff3f4f8,0xfff3f4f7,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,0xfff3f4f8,
0xfff3f4f8,0xfff7e2cf,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xcac68e1d,0x02000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x04000000,0xded1d2d5,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff5f1ef,0xfffbb524,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xd7d1971f,0x03000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x05000000,0xefe1e2e5,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff4f4f7,0xfffac275,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xe6e1a222,0x05000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x07000000,0xf8ebecef,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,0xfff3f4f7,
0xfff3f4f7,0xfff3f4f7,0xfff8d3ac,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xf3efab23,0x06000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x07000000,0xfdf0f2f4,0xfff2f3f6,0xfff2f4f7,0xfff2f4f7,0xfff2f3f6,
0xfff3f4f7,0xfff2f4f7,0xfff2f3f6,0xfff2f4f7,0xfff2f4f7,0xfff2f3f6,0xfff2f4f7,0xfff2f4f7,
0xfff2f3f6,0xfff3f4f7,0xfff2f4f7,0xfff2f3f6,0xfff2f4f7,0xfff2f4f7,0xfff2f3f6,0xfff2f4f7,
0xfff2f4f7,0xfff2f3f6,0xfff3f4f7,0xfff2f4f7,0xfff2f3f6,0xfff2f4f7,0xfff2f4f7,0xfff2f3f6,
0xfff2f4f7,0xfff2f4f7,0xfff6e1ce,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb625,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xf9f5b024,0x06000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f6,
0xfff2f4f6,0xfff2f4f6,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,
0xfff2f4f6,0xfff2f4f6,0xffe6e7ea,0xff878889,0xff929395,0xffedeef1,0xfff2f4f7,0xfff2f4f7,
0xfff2f4f7,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,0xfff2f4f7,
0xfff2f4f7,0xfff2f4f7,0xfff4eee9,0xfffbb625,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xffc48818,0xff81530a,0xffd6971c,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfcf9b325,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff2f4f7,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,
0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,
0xfff2f4f6,0xfff2f4f6,0xffc8cacc,0xff606061,0xff606061,0xffd8dadc,0xfff2f4f6,0xfff2f4f6,
0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,0xfff2f4f6,
0xfff2f4f6,0xfff2f4f6,0xfff3f5f7,0xfffaba52,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb625,0xff77490a,0xff643a07,0xff9c6811,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,
0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb726,0xfffcb525,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,
0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,
0xfff2f3f6,0xfff2f3f6,0xffc8cacc,0xff606061,0xff606061,0xffd6d8da,0xfff2f3f6,0xfff2f3f6,
0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,
0xfff2f3f6,0xfff2f3f6,0xfff2f3f6,0xfff8c78c,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,
0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb324,0xfe75450e,0xfe64360c,0xfe986313,0xfffcb424,
0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,
0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb525,0xfffcb323,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff2f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff2f3f6,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff2f3f6,0xffc8c9cb,0xff5f6061,0xff5f6061,0xffd6d8da,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xfff2f3f6,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1bbb2,0xfff76b3e,0xfffc6d40,0xfffd6d41,0xfffd6d41,
0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfe713517,0xfe643012,0xfe954324,0xfffd6d41,
0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,
0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d41,0xfffd6d42,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xffc8c9cb,0xff5f6061,0xff5f6061,0xffd6d7d9,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,
0xfff1f3f5,0xfff1f3f5,0xfff1f3f5,0xfff1ccca,0xfff4613f,0xfffc6441,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6643,0xff71301b,0xff642b16,0xff963e26,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,
0xfff1f3f5,0xfff1f2f5,0xfff1f2f5,0xfff1f3f5,0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,
0xfff1f2f5,0xfff1f3f5,0xffd0d1d3,0xff5f6061,0xff5f6061,0xffe0e2e4,0xfff1f2f5,0xfff1f2f5,
0xfff1f2f5,0xfff1f2f5,0xfff1f3f5,0xfff1f2f5,0xfff1f2f5,0xfff1f3f5,0xfff1f2f5,0xfff1f2f5,
0xfff1f2f5,0xfff1f2f5,0xfff1f2f5,0xfff2dfdf,0xfff2603f,0xfffb6441,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xff8c3b26,0xff642819,0xffab4830,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,
0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,
0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xffd1d2d4,0xffd7d8da,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,
0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,
0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff3eeef,0xffef5f3e,0xfffa6341,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfff06545,0xffd25c41,0xfff76746,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,
0xfff1f2f4,0xfff0f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,
0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,
0xfff1f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff1f2f4,0xfff1f2f4,0xfff1f2f4,0xfff0f2f4,
0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff2f4f5,0xffee6a50,0xfff96340,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,
0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,
0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,
0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,
0xfff0f2f4,0xfff1f2f4,0xfff0f2f4,0xfff1f2f4,0xffef8e81,0xfff86340,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,
0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,
0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f3,0xfff1f2f4,0xffee9e94,0xfff76240,0xfffc6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,
0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xfff0f1f4,0xffefb0aa,0xfff5623f,0xfffc6441,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xffeeb9b4,0xfff4613f,0xfffc6441,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,
0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6542,0xfffd6644,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f1f3,0xfff0f0f3,0xfff0f1f3,0xfff0f1f3,0xfff0f0f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f0f3,0xfff0f1f3,0xfff0f1f3,
0xfff0f0f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f0f3,0xfff0f1f3,
0xfff0f1f3,0xfff0f0f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f1f3,0xfff0f0f3,
0xfff0f1f3,0xfff0f1f3,0xfff0f0f3,0xfff0f1f3,0xfeebc6c4,0xfde85840,0xfdf05c42,0xfdf25d43,
0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,
0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,
0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfdf25d43,0xfef35f45,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,
0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f2,
0xfff0f0f3,0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,
0xfff0f0f2,0xfff0f0f3,0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f3,0xfff0f0f2,
0xfff0f0f3,0xfff0f0f2,0xfff0f0f3,0xfff0f0f3,0xffdfc4c7,0xffc5303e,0xffcd3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3543,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffe4ced0,0xffc4303d,0xffcc3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3543,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffeff0f2,0xfff0f0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffeff0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffeff0f2,
0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffeff0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,
0xffeff0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xfff0f0f2,0xffeff0f2,0xfff0f0f2,0xfff0f0f2,
0xfff0f0f2,0xffeff0f2,0xfff0f0f2,0xfff0f0f2,0xffe4cfd1,0xffc3303d,0xffcc3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3543,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xfff0f1f2,0xffcf9c9f,0xffc3303d,0xffcc3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xfece3543,0x08000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xfff0f1f2,0xffc8a7a9,0xffba888b,0xffb88486,0xffb78285,
0xffb78285,0xffb78184,0xffb77d80,0xffb5686d,0xffb52c38,0xffc4303d,0xffcc3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xfccc3542,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,0xffeff0f1,
0xffeff0f1,0xffeff0f1,0xffeff0f1,0xfff1f0f1,0xffa32833,0xffa62834,0xffa72934,0xffa72934,
0xffa72934,0xffa72934,0xffa92935,0xffb02b37,0xffbb2e3a,0xffc7303e,0xffcd3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xfbcb3442,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffefeff0,0xffeeeff0,0xffeeeff0,0xffefeff0,0xffeeeff0,
0xffefeff0,0xffeeeff0,0xffefeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffefeff0,
0xffeeeff0,0xffefeff0,0xffeeeff0,0xffefeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffefeff0,0xffeeeff0,0xffefeff0,0xfff1f1f2,0xffad2a36,0xffb42c38,0xffb72d39,0xffb72d39,
0xffb72d39,0xffb72d39,0xffb92d3a,0xffbd2e3b,0xffc4303d,0xffca313f,0xffce3240,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xfacb3442,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffe3e4e5,
0xffecedee,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffeeeff0,0xffeeeff0,0xffeeeff0,0xfff1f2f3,0xffb82e3a,0xffc22f3c,0xffc5303e,0xffc6303e,
0xffc6303e,0xffc6303e,0xffc7303e,0xffc9313e,0xffcb323f,0xffcd3240,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffce3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,
0xffcf3341,0xffcf3341,0xffcf3341,0xffcf3341,0xf8c93440,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffd9dadb,0xff616262,
0xff909191,0xffeaebec,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffeeeff0,0xffeeeff0,0xffeeeff0,0xfff1f1f3,0xffbd3140,0xffc73144,0xffcb3246,0xffcb3246,
0xffcb3246,0xffcb3246,0xffcc3247,0xffcc3347,0xffcc3347,0xffcd3347,0xffcd3347,0xffcd3347,
0xffcd3347,0xffcd3347,0xffcd3347,0xffcd3347,0xffcd3347,0xffcd3347,0xffcd3347,0xffcd3345,
0xfe872338,0xfe451731,0xffb73044,0xffcd3448,0xffcd3448,0xffcd3448,0xffcd3448,0xffcd3448,
0xffcd3448,0xffcd3448,0xffcd3448,0xffcd3448,0xf7c53649,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeef0,
0xffeeeff0,0xffeeeff0,0xffeeeff0,0xffeeeef0,0xffeeeff0,0xffeeeff0,0xffe2e2e4,0xff696a6a,
0xff5e5e5f,0xff939394,0xffe9eaeb,0xffeeeff0,0xffeeeef0,0xffeeeff0,0xffeeeff0,0xffeeeff0,
0xffeeeff0,0xffeeeef0,0xffeeeff0,0xfff1f1f2,0xff923d99,0xff943c97,0xff943c97,0xff943c97,
0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,
0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff943c97,0xff933c98,0xfe662c74,
0xfe35183c,0xfe381b40,0xff813e8e,0xff943e98,0xff943e98,0xff943e98,0xff943e98,0xff943e98,
0xff943e98,0xff943e98,0xff943e98,0xff943e98,0xfd90439b,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffeeeef0,0xffedeeef,0xffeeeef0,0xffeeeef0,0xffeeeef0,
0xffeeeef0,0xffeeeef0,0xffeeeef0,0xffeeeef0,0xffeeeef0,0xffedeeef,0xffeeeef0,0xffd5d5d6,
0xff676868,0xff5e5e5f,0xff868687,0xffe1e1e3,0xffeeeef0,0xffeeeef0,0xffedeeef,0xffeeeef0,
0xffeeeef0,0xffeeeef0,0xffeeeef0,0xfff1f1f2,0xff943c97,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff923b95,0xff622a6f,0xfe2d1a48,
0xfe311d4b,0xff773984,0xff953d97,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xfe923f97,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,
0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,
0xffd5d6d7,0xff6c6d6d,0xff5e5e5f,0xff6b6b6c,0xffc3c3c4,0xffededef,0xffedeeef,0xffedeeef,
0xffedeeef,0xffedeeef,0xffedeeef,0xffefeef0,0xff943c97,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff85378d,0xff4c2463,0xff271b4e,0xff321f54,
0xff793a88,0xff953d97,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xfe923f97,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x08000000,0xfdebeced,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,
0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,0xffedeeef,
0xffedeeef,0xffdfe0e1,0xff858686,0xff5e5e5f,0xff5e5e5f,0xff878788,0xffcccccd,0xffecedee,
0xffedeeef,0xffedeeef,0xffedeeef,0xffe9e7ec,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff893890,0xff622b73,0xff2d1c53,0xff251b50,0xff432762,0xff833d8f,
0xff953d96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xfd933e97,0x07000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x07000000,0xf9e6e7e8,0xffededee,0xffededef,0xffededef,0xffededee,
0xffededef,0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,0xffededef,0xffededef,
0xffededee,0xffededef,0xffeaebec,0xffb6b6b7,0xff656566,0xff5e5e5e,0xff5e5e5e,0xff797979,
0xffb3b4b5,0xffd5d5d7,0xffececee,0xffe1dce4,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff943c97,0xff8d3a92,
0xff793384,0xff57286c,0xff2d1c54,0xff251b51,0xff2f1f56,0xff66347b,0xff8f3f96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xfb904096,0x06000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x07000000,0xf0ddddde,0xffededee,0xffededee,0xffededee,0xffededee,
0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,
0xffededee,0xffededee,0xffededee,0xffededee,0xffe1e1e2,0xffaaaaaa,0xff666666,0xff5e5e5e,
0xff5d5d5e,0xff59595d,0xff5a5963,0xff7e7787,0xff70367c,0xff793483,0xff7e3587,0xff813589,
0xff84368a,0xff823689,0xff7f3587,0xff793384,0xff6f2f7c,0xff602a72,0xff482363,0xff2e1d55,
0xff251b51,0xff251b51,0xff322058,0xff613277,0xff883e92,0xff953d97,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xe7843a8a,0x06000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x06000000,0xdfcccccd,0xffededee,0xffededee,0xffededee,0xffededee,
0xffededee,0xffededee,0xffecedee,0xffededee,0xffededee,0xffededee,0xffededee,0xffededee,
0xffededee,0xffededee,0xffededee,0xffecedee,0xffededee,0xffededee,0xffe6e6e6,0xffbfbfc0,
0xff929293,0xff5a5a5e,0xff504e5a,0xff433f56,0xff352e53,0xff2b2251,0xff271d50,0xff261b51,
0xff271b52,0xff261b52,0xff261b51,0xff251b51,0xff251b51,0xff251b51,0xff271c52,0xff342159,
0xff542d6e,0xff743884,0xff8d3f95,0xff953d97,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xdb7c3682,0x05000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x04000000,0xd0bebebe,0xffededed,0xffececed,0xffededed,0xffececed,
0xffededed,0xffececed,0xffededed,0xffececed,0xffececed,0xffededed,0xffececed,0xffededed,
0xffececed,0xffededed,0xffececed,0xffededed,0xffececed,0xffececed,0xffededed,0xffececed,
0xffededed,0xffe7e7e8,0xffd0d0d2,0xffa095ac,0xff6e3c7f,0xff613476,0xff572f70,0xff522e6f,
0xff4e2a6a,0xff522d6e,0xff562e70,0xff5d3074,0xff69347d,0xff763885,0xff843c8e,0xff903f97,
0xff943d97,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xff953c96,
0xff953c96,0xff953c96,0xff953c96,0xff953c96,0xcf75347b,0x04000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x03000000,0xac9b9b9b,0xffededed,0xffededed,0xffededed,0xffededed,
0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,
0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,0xffededed,
0xffededed,0xffededed,0xffededed,0xffbea7c5,0xff943e97,0xff943e97,0xff943f97,0xff943f98,
0xff943f98,0xff943f98,0xff943f97,0xff943f97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,
0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,
0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xff943e97,
0xff943e97,0xff943e97,0xff943e97,0xff943e97,0xa75c2b63,0x02000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x01000000,0x7e6f6f6f,0xffededed,0xffececed,0xffededed,0xffececec,
0xffededed,0xffededed,0xffececec,0xffededed,0xffededed,0xffededed,0xffececed,0xffededed,
0xffececec,0xffededed,0xffededed,0xffececec,0xffededed,0xffededed,0xffededed,0xffececed,
0xffededed,0xffececec,0xffededed,0xff89abd8,0xff4e8acc,0xff5089cb,0xff5188cb,0xff5188cb,
0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,
0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,
0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,
0xff5188cb,0xff5188cb,0xff5188cb,0xff5188cb,0x7a2b3a5a,0x01000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x382c2c2c,0xffeceded,0xffeceded,0xffededed,0xffeceded,
0xffededed,0xffeceded,0xffeceded,0xffeceded,0xffeceded,0xffeceded,0xffeceded,0xffededed,
0xffeceded,0xffededed,0xffeceded,0xffeceded,0xffeceded,0xffeceded,0xffeceded,0xffeceded,
0xffededed,0xffeceded,0xffefefef,0xff3ca1db,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff119ada,0x340a1824,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x0b000000,0xd3c0c0c0,0xffececed,0xffececed,0xffececed,
0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,
0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,0xffececed,
0xffececed,0xffececed,0xffe0e6ec,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xcf1b78ab,0x0a000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x03000000,0x62515151,0xffececec,0xffececec,0xffececec,
0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,
0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,
0xffececec,0xffececec,0xffc6d7e9,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff089bda,0x5c0e2f45,0x02000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x0e000000,0xc0ababac,0xffececec,0xffececec,
0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,
0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,0xffececec,
0xffececec,0xffececec,0xffa4c5e4,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xbd176c9b,0x0d000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x02000000,0x2c1c1c1c,0xe5d1d1d1,0xffebebeb,
0xffececec,0xffececec,0xffebebeb,0xffebecec,0xffebebec,0xffebebeb,0xffebebec,0xffebecec,
0xffebebeb,0xffececec,0xffececec,0xffebebeb,0xffebecec,0xffebebec,0xffebebeb,0xffebebec,
0xffebecec,0xffededed,0xff65abde,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xe41487c0,0x29050f17,0x02000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x06000000,0x3c292929,0xe6d2d2d2,
0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffebebeb,0xffe2e7ec,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xe51287c1,0x39061824,0x05000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x07000000,0x331f1f1f,
0xc4aeaeae,0xffececec,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffebebeb,0xffebebeb,0xffececec,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffebebeb,0xffbad0e6,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff029cdb,0xc31370a0,
0x3005121b,0x06000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x05000000,
0x19000000,0x735d5d5d,0xdcc7c7c7,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,0xffebebeb,
0xffececec,0xff83b6e0,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,
0xff009cdb,0xff009cdb,0xff009cdb,0xff009cdb,0xff059bdb,0xdc1281b7,0x710e3a53,0x18000000,
0x04000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x02000000,0x0b000000,0x1d000000,0x553e3e3e,0x97818181,0xc4adadad,0xdec8c8c8,0xfae6e6e6,
0xffebebeb,0xffececec,0xffececec,0xffebebeb,0xffebebeb,0xffececec,0xffebebeb,0xffececec,
0xffe3e6eb,0xff059bda,0xff009cdb,0xff009cdb,0xff079bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,
0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0a9bda,
0xff0a9bda,0xff0a9bda,0xff0a9bda,0xff0b9bda,0xff0c9bda,0xff0d9bda,0xff0d9ada,0xff109ada,
0xfc1497d6,0xe31286be,0xc61172a3,0x970f5376,0x570b283b,0x1c000000,0x0b000000,0x01000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x02000000,0x07000000,0x10000000,0x18000000,0x1e000000,0x22000000,
0x26040404,0x290a0a0a,0x2a0c0c0c,0x2b0e0e0e,0x2b0e0e0e,0x2b0e0e0e,0x2b0e0e0e,0x2b0e0e0e,
0x2b0c0c0d,0x2b01080c,0x2b00080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,
0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,0x2b01080c,
0x2b01080c,0x2b01080c,0x2b01080c,0x2b02080c,0x2b02080c,0x2b02070c,0x2a01070b,0x27010507,
0x22000000,0x1e000000,0x17000000,0x0f000000,0x07000000,0x02000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01000000,0x01000000,0x02000000,
0x03000000,0x03000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,
0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,
0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,
0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x04000000,0x03000000,0x03000000,
0x02000000,0x01000000,0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
};
#endif /* MII_ICON64_DEFINE */

View File

@ -28,7 +28,7 @@ enum mii_mui_transition_e {
MII_MUI_TRANSITION_SHOW_UI, MII_MUI_TRANSITION_SHOW_UI,
}; };
#define MII_PIXEL_LAYERS 8 #define MII_PIXEL_LAYERS 9
DECLARE_C_ARRAY(float, float_array, 16); DECLARE_C_ARRAY(float, float_array, 16);
IMPLEMENT_C_ARRAY(float_array); IMPLEMENT_C_ARRAY(float_array);
@ -51,6 +51,7 @@ typedef struct mii_mui_t {
mui_event_t key; mui_event_t key;
c2_rect_t video_frame; // current video frame c2_rect_t video_frame; // current video frame
uint32_t video_drawn_seed;
float mui_alpha; float mui_alpha;
bool mui_visible; bool mui_visible;
void * transision_state; void * transision_state;
@ -69,6 +70,8 @@ typedef struct mii_mui_t {
mui_drawable_t hm_read; mui_drawable_t hm_read;
mui_drawable_t hm_write; mui_drawable_t hm_write;
} floppy[2]; } floppy[2];
// this is debug only!
mui_drawable_t video_heapmap;
}; };
mui_drawable_t v[MII_PIXEL_LAYERS]; mui_drawable_t v[MII_PIXEL_LAYERS];
} pixels; } pixels;
@ -113,3 +116,5 @@ mii_mui_get_video_position(
void void
mii_config_open_slots_dialog( mii_config_open_slots_dialog(
mii_mui_t * ui); mii_mui_t * ui);

View File

@ -117,7 +117,7 @@ _mii_check_1mb_file(
fseek(f, 512, SEEK_SET); fseek(f, 512, SEEK_SET);
fread(buf, 1, 4, f); fread(buf, 1, 4, f);
fclose(f); fclose(f);
printf("%s %02x %02x %02x %02x\n", __func__, buf[0], buf[1], buf[2], buf[3]); // printf("%s %02x %02x %02x %02x\n", __func__, buf[0], buf[1], buf[2], buf[3]);
if (buf[0] != 0x20 || buf[1] != 0x58 || buf[2] != 0xfc || buf[3] != 0xa0) { if (buf[0] != 0x20 || buf[1] != 0x58 || buf[2] != 0xfc || buf[3] != 0xa0) {
char *msg; char *msg;
asprintf(&msg, "WARNING: '%s' Lacks the 'bootloader' in block #1, " asprintf(&msg, "WARNING: '%s' Lacks the 'bootloader' in block #1, "
@ -142,7 +142,7 @@ _mii_1mb_stdfile_cb(
switch (what) { switch (what) {
case MUI_STDF_ACTION_SELECT: { case MUI_STDF_ACTION_SELECT: {
char * path = mui_stdfile_get_selected_path(w); char * path = mui_stdfile_get_selected_path(w);
printf("%s select %s\n", __func__, path); // printf("%s select %s\n", __func__, path);
if (_mii_check_1mb_file(w->ui, path) < 0) { if (_mii_check_1mb_file(w->ui, path) < 0) {
mui_control_set_title(m->fname, "Click \"Select\" to pick a file"); mui_control_set_title(m->fname, "Click \"Select\" to pick a file");
mui_control_set_state(m->fname, MUI_CONTROL_STATE_DISABLED); mui_control_set_state(m->fname, MUI_CONTROL_STATE_DISABLED);
@ -163,7 +163,7 @@ _mii_1mb_stdfile_cb(
mui_window_dispose(w); mui_window_dispose(w);
} break; } break;
case MUI_STDF_ACTION_CANCEL: case MUI_STDF_ACTION_CANCEL:
printf("%s cancel\n", __func__); // printf("%s cancel\n", __func__);
mui_window_dispose(w); mui_window_dispose(w);
break; break;
} }
@ -177,17 +177,17 @@ _mii_1mb_action_cb(
uint32_t what, uint32_t what,
void * param) // not used void * param) // not used
{ {
printf("%s %4.4s\n", __func__, (char*)&what); // printf("%s %4.4s\n", __func__, (char*)&what);
mii_mui_1mb_t * m = cb_param; mii_mui_1mb_t * m = cb_param;
uint32_t uid = mui_control_get_uid(c); uint32_t uid = mui_control_get_uid(c);
switch (what) { switch (what) {
case MUI_CONTROL_ACTION_SELECT: case MUI_CONTROL_ACTION_SELECT:
printf("%s control %4.4s\n", __func__, (char*)&uid); // printf("%s control %4.4s\n", __func__, (char*)&uid);
switch (uid) { switch (uid) {
case MII_1MB_SAVE: { case MII_1MB_SAVE: {
// save the config // save the config
printf("%s save\n", __func__); // printf("%s save\n", __func__);
if (m->dst) if (m->dst)
*m->dst = m->config; *m->dst = m->config;
mui_window_action(&m->win, MII_MUI_1MB_SAVE, m->dst); mui_window_action(&m->win, MII_MUI_1MB_SAVE, m->dst);
@ -195,12 +195,12 @@ _mii_1mb_action_cb(
} break; } break;
case MII_1MB_CANCEL: { case MII_1MB_CANCEL: {
// cancel the config // cancel the config
printf("%s cancel\n", __func__); // printf("%s cancel\n", __func__);
mui_window_dispose(&m->win); mui_window_dispose(&m->win);
} break; } break;
case MII_1MB_SELECT: { case MII_1MB_SELECT: {
// select a file // select a file
printf("%s select\n", __func__); // printf("%s select\n", __func__);
mui_window_t * w = mui_stdfile_get(m->win.ui, mui_window_t * w = mui_stdfile_get(m->win.ui,
C2_PT(0, 0), C2_PT(0, 0),
"Select a file (Exactly 1MB in size)", "Select a file (Exactly 1MB in size)",

View File

@ -14,6 +14,7 @@
#include <libgen.h> #include <libgen.h>
#include "mui.h" #include "mui.h"
#include "mii_mui_utils.h"
#include "mii_mui_settings.h" #include "mii_mui_settings.h"
enum { enum {
@ -31,10 +32,7 @@ typedef struct mii_mui_2dsk_t {
uint8_t drive_kind; uint8_t drive_kind;
mui_control_t * load; mui_control_t * load;
uint32_t selecting; uint32_t selecting;
struct { mii_mui_file_select_t drive[2];
mui_control_t *icon, *fname, *button, *wp, *warning;
} drive[2];
mii_2dsk_conf_t * dst; mii_2dsk_conf_t * dst;
mii_2dsk_conf_t config; mii_2dsk_conf_t config;
} mii_mui_2dsk_t; } mii_mui_2dsk_t;
@ -188,11 +186,11 @@ mii_mui_2dsk_load_conf(
mui_control_set_title(m->drive[i].button, "Eject"); mui_control_set_title(m->drive[i].button, "Eject");
if (check.warning) { if (check.warning) {
mui_control_set_title(m->drive[i].warning, check.warning); mui_control_set_title(m->drive[i].warning, check.warning);
mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_DISABLED); mui_control_set_state(m->drive[i].checkbox, MUI_CONTROL_STATE_DISABLED);
free(check.warning); free(check.warning);
} else { } else {
mui_control_set_title(m->drive[i].warning, ""); mui_control_set_title(m->drive[i].warning, "");
mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(m->drive[i].checkbox, MUI_CONTROL_STATE_NORMAL);
} }
} else { } else {
config->drive[i].ro_file = config->drive[i].ro_format = 0; config->drive[i].ro_file = config->drive[i].ro_format = 0;
@ -200,10 +198,10 @@ mii_mui_2dsk_load_conf(
mui_control_set_title(m->drive[i].fname, "Click \"Select\" to pick a file"); mui_control_set_title(m->drive[i].fname, "Click \"Select\" to pick a file");
mui_control_set_state(m->drive[i].icon, MUI_CONTROL_STATE_DISABLED); mui_control_set_state(m->drive[i].icon, MUI_CONTROL_STATE_DISABLED);
mui_control_set_title(m->drive[i].button, "Select…"); mui_control_set_title(m->drive[i].button, "Select…");
mui_control_set_state(m->drive[i].wp, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(m->drive[i].checkbox, MUI_CONTROL_STATE_NORMAL);
mui_control_set_title(m->drive[i].warning, ""); mui_control_set_title(m->drive[i].warning, "");
} }
mui_control_set_value(m->drive[i].wp, mui_control_set_value(m->drive[i].checkbox,
(config->drive[i].wp || config->drive[i].ro_file || (config->drive[i].wp || config->drive[i].ro_file ||
config->drive[i].ro_format) ? 1 : 0); config->drive[i].ro_format) ? 1 : 0);
} }
@ -225,7 +223,7 @@ _mii_2dsk_stdfile_cb(
case MUI_STDF_ACTION_SELECT: { case MUI_STDF_ACTION_SELECT: {
int idx = m->selecting == MII_2DSK_SELECT1 ? 0 : 1; int idx = m->selecting == MII_2DSK_SELECT1 ? 0 : 1;
char * path = mui_stdfile_get_selected_path(w); char * path = mui_stdfile_get_selected_path(w);
printf("%s select %s\n", __func__, path); // printf("%s select %s\n", __func__, path);
strncpy(m->config.drive[idx].disk, path, strncpy(m->config.drive[idx].disk, path,
sizeof(m->config.drive[idx].disk)-1); sizeof(m->config.drive[idx].disk)-1);
free(path); free(path);
@ -233,7 +231,7 @@ _mii_2dsk_stdfile_cb(
mii_mui_2dsk_load_conf(m, &m->config); mii_mui_2dsk_load_conf(m, &m->config);
} break; } break;
case MUI_STDF_ACTION_CANCEL: case MUI_STDF_ACTION_CANCEL:
printf("%s cancel\n", __func__); // printf("%s cancel\n", __func__);
mui_window_dispose(w); mui_window_dispose(w);
break; break;
} }
@ -247,7 +245,7 @@ _mii_2dsk_action_cb(
uint32_t what, uint32_t what,
void * param) // not used void * param) // not used
{ {
printf("%s %4.4s\n", __func__, (char*)&what); // printf("%s %4.4s\n", __func__, (char*)&what);
mii_mui_2dsk_t * m = cb_param; mii_mui_2dsk_t * m = cb_param;
uint32_t uid = mui_control_get_uid(c); uint32_t uid = mui_control_get_uid(c);
@ -257,7 +255,7 @@ _mii_2dsk_action_cb(
switch (uid) { switch (uid) {
case MII_2DSK_SAVE: { case MII_2DSK_SAVE: {
// save the config // save the config
printf("%s save\n", __func__); // printf("%s save\n", __func__);
if (m->dst) if (m->dst)
*m->dst = m->config; *m->dst = m->config;
mui_window_action(&m->win, mui_window_action(&m->win,
@ -269,7 +267,7 @@ _mii_2dsk_action_cb(
} break; } break;
case MII_2DSK_CANCEL: { case MII_2DSK_CANCEL: {
// cancel the config // cancel the config
printf("%s cancel\n", __func__); // printf("%s cancel\n", __func__);
mui_window_dispose(&m->win); mui_window_dispose(&m->win);
} break; } break;
case MII_2DSK_SELECT1: case MII_2DSK_SELECT1:
@ -279,11 +277,11 @@ _mii_2dsk_action_cb(
m->selecting = uid; // remember which drive we're selecting m->selecting = uid; // remember which drive we're selecting
int idx = uid == MII_2DSK_SELECT1 ? 0 : 1; int idx = uid == MII_2DSK_SELECT1 ? 0 : 1;
if (config->drive[idx].disk[0]) { if (config->drive[idx].disk[0]) {
printf("%s eject %d\n", __func__, idx); // printf("%s eject %d\n", __func__, idx);
config->drive[idx].disk[0] = 0; config->drive[idx].disk[0] = 0;
mii_mui_2dsk_load_conf(m, config); mii_mui_2dsk_load_conf(m, config);
} else { } else {
printf("%s select %d\n", __func__, idx); // printf("%s select %d\n", __func__, idx);
mui_window_t * w = mui_stdfile_get(m->win.ui, mui_window_t * w = mui_stdfile_get(m->win.ui,
C2_PT(0, 0), C2_PT(0, 0),
m->drive_kind == MII_2DSK_SMARTPORT ? m->drive_kind == MII_2DSK_SMARTPORT ?
@ -355,59 +353,31 @@ mii_mui_load_2dsk(
c->key_equ = MUI_KEY_EQU(0, 27); c->key_equ = MUI_KEY_EQU(0, 27);
c2_rect_set(&cf, margin, (margin / 2), c2_rect_set(&cf, margin, (margin / 2),
c2_rect_width(&w->frame) - margin - 120, c2_rect_width(&w->frame) - margin,
(margin/2) + base_size); (margin / 2) + base_size);
c2_rect_t cp = cf; c2_rect_t cp = cf;
cp.l -= margin * 0.2; cp.l -= margin * 0.2;
cp.b += base_size * 1.3; cp.b += base_size * 1.3;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
char buf[32]; mii_mui_file_select_t * fs = &m->drive[i];
snprintf(buf, sizeof(buf), "Drive %d:", i+1); mii_mui_fileselect_widget(fs, w, &cp,
c = mui_groupbox_new(w, cp, buf, MUI_CONTROL_TEXTBOX_FRAME); i == 0 ? "Drive 1:" : "Drive 2:",
"Select…",
float icons_size = mui_font_find(ui, "icon_small")->size; "Write Protect");
c2_rect_bottom_of(&cf, cp.t, base_size); m->drive[i].button->uid = i == 0 ? MII_2DSK_SELECT1 : MII_2DSK_SELECT2;
c2_rect_right_of(&cf, cp.l, margin * 0.5); m->drive[i].button->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, '1' + i);
cf.b = cf.t + icons_size;
cf.r = cf.l + icons_size;
m->drive[i].icon = c = mui_textbox_new(w, cf,
MUI_ICON_FILE, "icon_small",
MUI_TEXT_ALIGN_MIDDLE | MUI_TEXT_ALIGN_CENTER | 0);
c->state = MUI_CONTROL_STATE_DISABLED;
cf.l = cf.r;
cf.r = cp.r - margin * 0.5;
m->drive[i].fname = c = mui_textbox_new(w, cf,
"Click \"Select\" to pick a file", NULL, 0);
c->state = MUI_CONTROL_STATE_DISABLED;
c2_rect_right_of(&cf, cp.r, margin * 0.8);
cf.r = c2_rect_width(&w->frame) - margin * 1.2;
c2_rect_inset(&cf, -4,-4);
m->drive[i].button = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL,
"Select…" , i == 0 ?
MII_2DSK_SELECT1 : MII_2DSK_SELECT2);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, '1' + i);
c2_rect_bottom_of(&cf, cp.b, margin * 0.4);
cf.l = cp.l + (margin * 0.7);
cf.r = cf.l + 200;
cf.b = cf.t + base_size;
m->drive[i].wp = c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_CHECKBOX,
"Write Protect",
i == 0 ? MII_2DSK_WP1 : MII_2DSK_WP2);
// Smartport don't support write protect right now
if (drive_kind == MII_2DSK_SMARTPORT) if (drive_kind == MII_2DSK_SMARTPORT)
c->state = MUI_CONTROL_STATE_DISABLED; m->drive[i].checkbox->state = MUI_CONTROL_STATE_DISABLED;
c2_rect_right_of(&cf, cf.r, margin * 0.5); else {
cf.r = c2_rect_width(&w->frame) - margin * 1.2; mui_control_set_title(m->drive[i].icon, MUI_ICON_FLOPPY5);
m->drive[i].warning = c = mui_textbox_new(w, cf, }
"", NULL, m->drive[i].checkbox->uid = i == 0 ? MII_2DSK_WP1 : MII_2DSK_WP2;
MUI_TEXT_ALIGN_MIDDLE|MUI_TEXT_ALIGN_RIGHT);
c2_rect_bottom_of(&cp, cp.b + (base_size * 2), margin * 0.2); c2_rect_bottom_of(&cp, cp.b, margin);
} }
c2_rect_top_of(&cp, cp.t, margin * 3.5); cp = m->drive[1].box->frame;
cp.b = cp.t + 2;
c2_rect_top_of(&cp, m->drive[1].box->frame.t, margin * 0.4);
cp.l = margin * 4; cp.l = margin * 4;
cp.r = c2_rect_width(&w->frame) - margin * 4; cp.r = c2_rect_width(&w->frame) - margin * 4;
c = mui_separator_new(w, cp); c = mui_separator_new(w, cp);

View File

@ -12,7 +12,7 @@
#include <string.h> #include <string.h>
#include "mui.h" #include "mui.h"
#include "mii-icon-64.h" #include "mii_icon64.h"
extern const unsigned char mui_geneva_font_data[]; extern const unsigned char mui_geneva_font_data[];
extern const unsigned int mui_geneva_font_size; extern const unsigned int mui_geneva_font_size;
@ -60,7 +60,7 @@ _mii_about_button_cb(
uint32_t what, uint32_t what,
void * param) // not used void * param) // not used
{ {
printf("%s %4.4s\n", __func__, (char*)&what); // printf("%s %4.4s\n", __func__, (char*)&what);
mii_mui_about_t * m = cb_param; mii_mui_about_t * m = cb_param;
uint32_t uid = mui_control_get_uid(c); uint32_t uid = mui_control_get_uid(c);
@ -84,7 +84,7 @@ _mii_about_action_cb(
uint32_t what, uint32_t what,
void * param) // not used void * param) // not used
{ {
printf("%s %4.4s\n", __func__, (char*)&what); // printf("%s %4.4s\n", __func__, (char*)&what);
mii_mui_about_t * m = cb_param; mii_mui_about_t * m = cb_param;
switch (what) { switch (what) {
@ -134,7 +134,7 @@ mii_mui_about(
mui_window_select(w); mui_window_select(w);
return w; return w;
} }
printf("%s version: '%s'\n", __func__, MII_VERSION); // printf("%s version: '%s'\n", __func__, MII_VERSION);
c2_pt_t where = {}; c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 500, 255); c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 500, 255);
if (where.x == 0 && where.y == 0) if (where.x == 0 && where.y == 0)

View File

@ -1,8 +1,12 @@
// Autogenerated from docs/Apple_logo_rainbow_version2_28x28.png with utils/png2raw.c // Autogenerated with:
// libmui/utils/png2raw.c -n mii_mui_apple_logo -o ui_gl/mii_mui_apple_logo.h docs/Apple_logo_rainbow_version2_28x28.png
// Image with a W:28px, H:28px and 4 channels // Image with a W:28px, H:28px and 4 channels
// Converted to ARGB8888 and premultiplied alpha // Converted to ARGB8888 and premultiplied alpha
#pragma once #pragma once
static const uint32_t mii_color_apple_pixels[] = { #define MII_MUI_APPLE_LOGO_SIZE 786
extern const uint32_t mii_mui_apple_logo[MII_MUI_APPLE_LOGO_SIZE];
#ifdef MII_MUI_APPLE_LOGO_DEFINE
const uint32_t mii_mui_apple_logo[MII_MUI_APPLE_LOGO_SIZE] = {
28, 28, // width, height 28, 28, // width, height
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
@ -103,3 +107,4 @@ static const uint32_t mii_color_apple_pixels[] = {
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
}; };
#endif /* MII_MUI_APPLE_LOGO_DEFINE */

View File

@ -10,33 +10,26 @@
* This contains OpenGL code, no x11 or GLx allowed in here, this is to be * This contains OpenGL code, no x11 or GLx allowed in here, this is to be
* used by a native windowing system, or a portable one like SDL2 or GLFW * used by a native windowing system, or a portable one like SDL2 or GLFW
*/ */
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <GL/gl.h> #include <GL/gl.h>
#ifdef __SSE2__ #if defined(__AVX2__)
#include <emmintrin.h> // SSE2 intrinsics #include <immintrin.h>
#endif
#if defined(__SSE2__)
#include <emmintrin.h>
#endif #endif
#include "mii_mui_gl.h" #include "mii_mui_gl.h"
#include "mii_floppy.h" #include "mii_floppy.h"
typedef struct c2_rect_f {
float l,t,r,b;
} c2_rect_f;
#define MII_GL_FLOPPY_SEGMENT_COUNT 32 #define MII_GL_FLOPPY_SEGMENT_COUNT 32
#define MII_GL_FLOPPY_DISC_RADIUS_IN 1.8 #define MII_GL_FLOPPY_DISC_RADIUS_IN 1.8
#define MII_GL_FLOPPY_DISC_RADIUS_OUT 10 #define MII_GL_FLOPPY_DISC_RADIUS_OUT 10
#define MII_GL_FLOPPY_FLUX_RADIUS_IN 2.0 #define MII_GL_FLOPPY_FLUX_RADIUS_IN 2.0
#define MII_GL_FLOPPY_FLUX_RADIUS_OUT 9.8 #define MII_GL_FLOPPY_FLUX_RADIUS_OUT 9.8
#include <math.h>
static void static void
mii_gl_make_disc( mii_gl_make_disc(
float_array_t * pos, float_array_t * pos,
@ -159,10 +152,10 @@ mii_mui_gl_prepare_textures(
// disable the repeat of textures // disable the repeat of textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
dr->texture.kind = GL_RGBA; dr->texture.kind = GL_RGBA;// note RGBA here, it's quicker!!
glTexImage2D(GL_TEXTURE_2D, 0, 4, glTexImage2D(GL_TEXTURE_2D, 0, 4,
MII_VRAM_WIDTH, MII_VRAM_WIDTH,
MII_VRAM_HEIGHT, 0, dr->texture.kind, // note RGBA here, it's quicker!! MII_VRAM_HEIGHT, 0, dr->texture.kind,
GL_UNSIGNED_BYTE, // GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE, // GL_UNSIGNED_INT_8_8_8_8_REV
mii->video.pixels); mii->video.pixels);
@ -173,7 +166,7 @@ mii_mui_gl_prepare_textures(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// here we use GL_BGRA, as the pixman/libmui uses that.
dr->texture.kind = GL_BGRA; dr->texture.kind = GL_BGRA;
glTexImage2D(GL_TEXTURE_2D, 0, 4, glTexImage2D(GL_TEXTURE_2D, 0, 4,
dr->pix.row_bytes / 4, // already power of two. dr->pix.row_bytes / 4, // already power of two.
@ -181,6 +174,14 @@ mii_mui_gl_prepare_textures(
GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_8_8_8_8_REV,
dr->pix.pixels); dr->pix.pixels);
#if MII_VIDEO_DEBUG_HEAPMAP
dr = &ui->pixels.video_heapmap;
unsigned int tex = dr->texture.id;
mui_drawable_init(dr, C2_PT(192, 1), 8, mii->video.video_hmap, 192);
dr->texture.id = tex;
_prep_grayscale_texture(dr);
#endif
// ask MII for floppies -- we'll only use the first two (TODO?)
mii_floppy_t * floppy[2] = {}; mii_floppy_t * floppy[2] = {};
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
if (mii_slot_command(mii, i, MII_SLOT_D2_GET_FLOPPY, floppy) == 0) if (mii_slot_command(mii, i, MII_SLOT_D2_GET_FLOPPY, floppy) == 0)
@ -199,8 +200,15 @@ mii_mui_gl_prepare_textures(
8, floppy[fi]->track_data, MII_FLOPPY_DEFAULT_TRACK_SIZE); 8, floppy[fi]->track_data, MII_FLOPPY_DEFAULT_TRACK_SIZE);
dr->texture.id = tex; dr->texture.id = tex;
_prep_grayscale_texture(dr); _prep_grayscale_texture(dr);
if (!f->heat) if (!f->heat) {
#if defined(__AVX2__)
posix_memalign((void**)&f->heat, 32, sizeof(*f->heat));
#elif defined(__SSE2__)
posix_memalign((void**)&f->heat, 16, sizeof(*f->heat));
#else
f->heat = calloc(1, sizeof(*f->heat)); f->heat = calloc(1, sizeof(*f->heat));
#endif
}
dr = &ui->pixels.floppy[fi].hm_read; dr = &ui->pixels.floppy[fi].hm_read;
tex = dr->texture.id; tex = dr->texture.id;
mui_drawable_init(dr, mui_drawable_init(dr,
@ -233,26 +241,55 @@ mii_mui_gl_prepare_textures(
} }
} }
typedef uint8_t u8_v __attribute__((vector_size(16)));
static void /* Heatmaps 'decay' by a gradient each frame until fully transparent */
_mii_decay_heatmap_one( static inline int
mii_track_heatmap_t *hm) _mii_decay_buffer(
uint8_t *buffer,
int size)
{ {
uint32_t count = 0; uint32_t count = 0;
const int decay = 4; const uint8_t decay = 4; // totally arbitrary
#ifdef __SSE2__ #if defined(__AVX2__)
const int size = (MII_FLOPPY_TRACK_COUNT * MII_FLOPPY_HM_TRACK_SIZE) / 16; size /= 32;
__m128i * hmw = (__m128i*)&hm->map[0]; __m256i * hmw = (__m256i*)buffer;
const __m256i s = _mm256_set1_epi8(decay);
for (int i = 0; i < size; i++) {
__m256i b = _mm256_load_si256(hmw + i);
__m256i c = _mm256_subs_epu8(b, s);
hmw[i] = c;
// add 1 to count if c is non zero
count += !!_mm256_movemask_epi8(
_mm256_cmpeq_epi8(c, _mm256_setzero_si256()));
}
#elif defined(__SSE2__)
size /= 16;
__m128i * hmw = (__m128i*)buffer;
const __m128i s = _mm_set1_epi8(decay); const __m128i s = _mm_set1_epi8(decay);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
__m128i b = _mm_load_si128(hmw + i); __m128i b = _mm_load_si128(hmw + i);
__m128i c = _mm_subs_epu8(b, s); __m128i c = _mm_subs_epu8(b, s);
hmw[i] = c; hmw[i] = c;
count += _mm_movemask_epi8(_mm_cmpgt_epi8(c, _mm_setzero_si128())); // add 1 to count if c is non zero
count += !!_mm_movemask_epi8(
_mm_cmpeq_epi8(c, _mm_setzero_si128()));
} }
#else #else
const int size = MII_FLOPPY_TRACK_COUNT * MII_FLOPPY_HM_TRACK_SIZE; #if 1 // generic vector code, NEON or WASM?
uint8_t * hmb = (uint8_t*)&hm->map[0]; size /= sizeof(u8_v);
u8_v * hmb = (u8_v*)buffer;
for (int i = 0; i < size; i++) {
u8_v b = hmb[i];
u8_v c;
for (uint j = 0; j < sizeof(c); j++)
c[j] = b[j] > decay ? b[j] - decay : 0;
hmb[i] = c;
uint64_t * w = (uint64_t*)&c;
count += w[0] || w[1];
}
#else
uint8_t * hmb = buffer;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
uint8_t b = hmb[i]; uint8_t b = hmb[i];
b = b > decay ? b - decay : 0; b = b > decay ? b - decay : 0;
@ -260,6 +297,16 @@ _mii_decay_heatmap_one(
count += !!b; count += !!b;
} }
#endif #endif
#endif
return count;
}
static void
_mii_decay_heatmap_one(
mii_track_heatmap_t *hm)
{
const int size = MII_FLOPPY_TRACK_COUNT * MII_FLOPPY_HM_TRACK_SIZE;
uint32_t count = _mii_decay_buffer((uint8_t*)&hm->map[0], size);
hm->cleared = count == 0; hm->cleared = count == 0;
} }
@ -287,6 +334,8 @@ mii_mui_gl_run(
mui_run(mui); mui_run(mui);
bool draw = false; bool draw = false;
if (ui->transition.state != MII_MUI_TRANSITION_NONE)
draw = true;
if (pixman_region32_not_empty(&mui->inval)) { if (pixman_region32_not_empty(&mui->inval)) {
draw = true; draw = true;
mui_drawable_t * dr = &ui->pixels.mui; mui_drawable_t * dr = &ui->pixels.mui;
@ -314,11 +363,11 @@ mii_mui_gl_run(
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
pixman_region32_clear(&mui->redraw); pixman_region32_clear(&mui->redraw);
} }
uint32_t current_frame = mii->video.frame_count; uint32_t current_seed = mii->video.frame_seed;
if (current_frame != mii->video.frame_drawn) { if (current_seed != ui->video_drawn_seed) {
// miigl_counter_tick(&ui->videoc, miigl_get_time()); // miigl_counter_tick(&ui->videoc, miigl_get_time());
draw = true; draw = true;
mii->video.frame_drawn = current_frame; ui->video_drawn_seed = current_seed;
// update the whole texture // update the whole texture
mui_drawable_t * dr = &ui->pixels.mii; mui_drawable_t * dr = &ui->pixels.mii;
glBindTexture(GL_TEXTURE_2D, dr->texture.id); glBindTexture(GL_TEXTURE_2D, dr->texture.id);
@ -328,16 +377,30 @@ mii_mui_gl_run(
GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_8_8_8_8_REV,
mii->video.pixels); mii->video.pixels);
} }
#if MII_VIDEO_DEBUG_HEAPMAP
if (ui->mii.state == MII_RUNNING) {
int cnt = _mii_decay_buffer(ui->mii.video.video_hmap, 192);
if (cnt) {
draw = true;
mui_drawable_t * dr = &ui->pixels.video_heapmap;
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
dr->pix.row_bytes, dr->pix.size.y,
dr->texture.kind, GL_UNSIGNED_BYTE,
dr->pix.pixels);
}
}
#endif
for (int fi = 0; fi < 2; fi++) { for (int fi = 0; fi < 2; fi++) {
if (!ui->floppy[fi].floppy) if (!ui->floppy[fi].floppy)
continue; continue;
mui_drawable_t * dr = NULL; mui_drawable_t * dr = NULL;
mii_floppy_t * f = ui->floppy[fi].floppy; mii_floppy_t * f = ui->floppy[fi].floppy;
dr = &ui->pixels.floppy[fi].bits;
if (ui->floppy[fi].seed_load != f->seed_dirty) { if (ui->floppy[fi].seed_load != f->seed_dirty) {
draw = true; draw = true;
ui->floppy[fi].seed_load = f->seed_dirty; ui->floppy[fi].seed_load = f->seed_dirty;
// printf("Floppy %d: Reloading texture\n", fi); // printf("Floppy %d: Reloading texture\n", fi);
dr = &ui->pixels.floppy[fi].bits;
int bc = (f->tracks[0].bit_count + 7) / 8; int bc = (f->tracks[0].bit_count + 7) / 8;
int max = MII_FLOPPY_DEFAULT_TRACK_SIZE; int max = MII_FLOPPY_DEFAULT_TRACK_SIZE;
ui->floppy[fi].max_width = (double)bc / (double)max; ui->floppy[fi].max_width = (double)bc / (double)max;
@ -349,6 +412,9 @@ mii_mui_gl_run(
// dont recalculate the vertices, just the texture coordinates // dont recalculate the vertices, just the texture coordinates
mii_gl_make_floppy(&ui->floppy[fi].vtx, mii_gl_make_floppy(&ui->floppy[fi].vtx,
ui->floppy[fi].max_width, false, true); ui->floppy[fi].max_width, false, true);
} else if (dr->texture.opacity > 0.0f ||
ui->floppy[fi].floppy->motor) {// still animating
draw = true;
} }
int rm = f->heat->read.tex != f->heat->read.seed || int rm = f->heat->read.tex != f->heat->read.seed ||
!f->heat->read.cleared; !f->heat->read.cleared;
@ -410,143 +476,163 @@ mii_mui_gl_render(
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
// This (was) the recommended way to handle pixel alignment in glOrtho
// mode, but this seems to have changed -- now it looks like Linear filtering /* draw mii texture */
// glTranslatef(0.375f, 0.375f, 0.0f); glColor3f(1.0f, 1.0f, 1.0f);
{ mui_drawable_t * dr = &ui->pixels.mii;
/* draw mii texture */ glEnable(GL_TEXTURE_2D);
glColor3f(1.0f, 1.0f, 1.0f); glBindTexture(GL_TEXTURE_2D, dr->texture.id);
mui_drawable_t * dr = &ui->pixels.mii; glBegin(GL_QUADS);
c2_rect_t r = ui->video_frame;
glTexCoord2f(0, 0);
glVertex2f(r.l, r.t);
glTexCoord2f(MII_VIDEO_WIDTH / (double)MII_VRAM_WIDTH, 0);
glVertex2f(r.r, r.t);
glTexCoord2f(MII_VIDEO_WIDTH / (double)MII_VRAM_WIDTH,
MII_VIDEO_HEIGHT / (double)MII_VRAM_HEIGHT);
glVertex2f(r.r, r.b);
glTexCoord2f(0,
MII_VIDEO_HEIGHT / (double)MII_VRAM_HEIGHT);
glVertex2f(r.l, r.b);
glEnd();
#if MII_VIDEO_DEBUG_HEAPMAP
/* draw video heatmap */
dr = &ui->pixels.video_heapmap;
if (dr->pix.pixels) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
// draw a vertical quad on the left side of the video to show
// what's being updated
glBegin(GL_QUADS);
c2_rect_t r = ui->video_frame;
glTexCoord2f(0, 1);
glVertex2f(r.l - 10, r.t);
glTexCoord2f(0, 0);
glVertex2f(r.l + 0, r.t);
glTexCoord2f(1, 0);
glVertex2f(r.l + 0, r.b);
glTexCoord2f(1, 1);
glVertex2f(r.l - 10, r.b);
glEnd();
glPopMatrix();
}
#endif
/* draw floppies. First the disk, then the texture, then the heatmap */
for (int i = 0; i < 2; i++) {
dr = &ui->pixels.floppy[i].bits;
mii_floppy_t *f = ui->floppy[i].floppy;
if (!f || !dr->pix.pixels)
continue;
if (ui->mii.state == MII_RUNNING) {
if (f->motor) {
if (dr->texture.opacity < 1.0f)
dr->texture.opacity += 0.10f;
if (dr->texture.opacity > 1.0f)
dr->texture.opacity = 1.0f;
} else {
if (dr->texture.opacity > 0.0f)
dr->texture.opacity -= 0.01f;
if (dr->texture.opacity < 0.0f)
dr->texture.opacity = 0.0f;
}
}
float main_opacity = dr->texture.opacity;
if (main_opacity <= 0.0f)
continue;
const float angle_offset = 60; // head angle offset on display
{
glPushMatrix();
// make floppy slide in/out with opacity
glTranslatef(-10 - (100.0 * ( 1.0f - main_opacity) ),
200 + (i * 350), 0);
glScalef(15, 15, 1);
{
glColor4f(0.0f, 0.0f, 0.0f, main_opacity);
glDisable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ui->floppy_base.e);
int element_count = ui->floppy_base.count / 2;
glDrawArrays(GL_TRIANGLES, 0, element_count);
}
int track_id = f->track_id[f->qtrack];
double bc = (double)f->bit_position /
(double)f->tracks[track_id].bit_count;
bc = 360 - (bc * 360.0);
bc += angle_offset;
if (bc >= 360.0)
bc -= 360.0;
glRotatef(bc, 0, 0, 1);
dr = &ui->pixels.floppy[i].bits;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, main_opacity);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ui->floppy[i].vtx.pos.e);
glTexCoordPointer(2, GL_FLOAT, 0, ui->floppy[i].vtx.tex.e);
int element_count = ui->floppy[i].vtx.pos.count / 2;
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
// draw heatmap and head with full opacity
// otherwise we get wierd artifacts
if (f->heat) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
dr = &ui->pixels.floppy[i].hm_read;
glColor4f(0.0f, 1.0f, 0.0f, 1.0);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
dr = &ui->pixels.floppy[i].hm_write;
glColor4f(1.0f, 0.0f, 0.0f, 1.0);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (main_opacity > 0.8f) {
// Draw head small rectangle
dr = &ui->pixels.floppy[i].bits;
track_id = f->qtrack / 4;
glDisable(GL_TEXTURE_2D);
glRotatef(-bc + angle_offset, 0, 0, 1);
glTranslatef(MII_GL_FLOPPY_FLUX_RADIUS_IN +
(((35 - track_id) / 35.0) *
(MII_GL_FLOPPY_FLUX_RADIUS_OUT-
MII_GL_FLOPPY_FLUX_RADIUS_IN)), 0, 0);
const float r = 0.3;
glColor4f(1.0f, 0.0f, 0.0f, main_opacity);
glBegin(GL_QUADS);
glVertex2f(-r, -r); glVertex2f(-r, r);
glVertex2f(r, r); glVertex2f(r, -r);
glEnd();
}
glPopMatrix();
}
}
/* draw mui texture */
if (ui->mui_alpha > 0.0f) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, ui->mui_alpha);
dr = &ui->pixels.mui;
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dr->texture.id); glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glBegin(GL_QUADS); glBegin(GL_QUADS);
c2_rect_t r = ui->video_frame; glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(0, 0); glTexCoord2f(
glVertex2f(r.l, r.t); ui->window_size.x / (double)(dr->pix.row_bytes / 4), 0);
glTexCoord2f(MII_VIDEO_WIDTH / (double)MII_VRAM_WIDTH, 0); glVertex2f(ui->window_size.x, 0);
glVertex2f(r.r, r.t); glTexCoord2f(ui->window_size.x / (double)(dr->pix.row_bytes / 4),
glTexCoord2f(MII_VIDEO_WIDTH / (double)MII_VRAM_WIDTH, ui->window_size.y / (double)(dr->texture.size.y));
MII_VIDEO_HEIGHT / (double)MII_VRAM_HEIGHT); glVertex2f(ui->window_size.x, ui->window_size.y);
glVertex2f(r.r, r.b);
glTexCoord2f(0, glTexCoord2f(0,
MII_VIDEO_HEIGHT / (double)MII_VRAM_HEIGHT); ui->window_size.y / (double)(dr->texture.size.y));
glVertex2f(r.l, r.b); glVertex2f(0, ui->window_size.y);
glEnd(); glEnd();
/* draw floppy textures, floppy 0 is left of the screen,
floppy 1 is right */
for (int i = 0; i < 2; i++) {
dr = &ui->pixels.floppy[i].bits;
mii_floppy_t *f = ui->floppy[i].floppy;
if (!f || !dr->pix.pixels)
continue;
if (ui->mii.state == MII_RUNNING) {
if (f->motor) {
if (dr->texture.opacity < 1.0f)
dr->texture.opacity += 0.10f;
if (dr->texture.opacity > 1.0f)
dr->texture.opacity = 1.0f;
} else {
if (dr->texture.opacity > 0.0f)
dr->texture.opacity -= 0.01f;
if (dr->texture.opacity < 0.0f)
dr->texture.opacity = 0.0f;
}
}
float main_opacity = dr->texture.opacity;
if (main_opacity <= 0.0f)
continue;
const float angle_offset = 60; // head angle offset on display
if (1) {
glPushMatrix();
// make floppy slide in/out with opacity
glTranslatef(-10 - (100.0 * ( 1.0f - main_opacity) ),
200 + (i * 350), 0);
glScalef(15, 15, 1);
{
glColor4f(0.0f, 0.0f, 0.0f, main_opacity);
glDisable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ui->floppy_base.e);
int element_count = ui->floppy_base.count / 2;
glDrawArrays(GL_TRIANGLES, 0, element_count);
}
int track_id = f->track_id[f->qtrack];
double bc = (double)f->bit_position /
(double)f->tracks[track_id].bit_count;
bc = 360 - (bc * 360.0);
bc += angle_offset;
if (bc >= 360.0)
bc -= 360.0;
glRotatef(bc, 0, 0, 1);
dr = &ui->pixels.floppy[i].bits;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, main_opacity);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, ui->floppy[i].vtx.pos.e);
glTexCoordPointer(2, GL_FLOAT, 0, ui->floppy[i].vtx.tex.e);
int element_count = ui->floppy[i].vtx.pos.count / 2;
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
// draw heatmap and head with full opacity
// otherwise we get wierd artifacts
if (f->heat) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
dr = &ui->pixels.floppy[i].hm_read;
glColor4f(0.0f, 1.0f, 0.0f, 1.0);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
dr = &ui->pixels.floppy[i].hm_write;
glColor4f(1.0f, 0.0f, 0.0f, 1.0);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glDrawArrays(ui->floppy[i].vtx.kind, 0, element_count);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (main_opacity > 0.8f) {
// Draw head small rectangle
dr = &ui->pixels.floppy[i].bits;
track_id = f->qtrack / 4;
glDisable(GL_TEXTURE_2D);
glRotatef(-bc + angle_offset, 0, 0, 1);
glTranslatef(MII_GL_FLOPPY_FLUX_RADIUS_IN +
(((35 - track_id) / 35.0) *
(MII_GL_FLOPPY_FLUX_RADIUS_OUT-
MII_GL_FLOPPY_FLUX_RADIUS_IN)), 0, 0);
const float r = 0.3;
glColor4f(1.0f, 0.0f, 0.0f, main_opacity);
glBegin(GL_QUADS);
glVertex2f(-r, -r); glVertex2f(-r, r);
glVertex2f(r, r); glVertex2f(r, -r);
glEnd();
}
glPopMatrix();
}
}
/* draw mui texture */
if (ui->mui_alpha > 0.0f) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 1.0f, 1.0f, ui->mui_alpha);
dr = &ui->pixels.mui;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, dr->texture.id);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(
ui->window_size.x / (double)(dr->pix.row_bytes / 4), 0);
glVertex2f(ui->window_size.x, 0);
glTexCoord2f(ui->window_size.x / (double)(dr->pix.row_bytes / 4),
ui->window_size.y / (double)(dr->texture.size.y));
glVertex2f(ui->window_size.x, ui->window_size.y);
glTexCoord2f(0,
ui->window_size.y / (double)(dr->texture.size.y));
glVertex2f(0, ui->window_size.y);
glEnd();
}
} }
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);

View File

@ -12,18 +12,24 @@
#include "mui.h" #include "mui.h"
#include "mii_mui_settings.h" #include "mii_mui_settings.h"
#include "mii_mui_utils.h"
enum { enum {
MII_LBIN_WINDOW_ID = FCC('l','b','i','n'), MII_LBIN_WINDOW_ID = FCC('l','b','i','n'),
MII_LBIN_SAVE = FCC('s','a','v','e'), MII_LBIN_SAVE = FCC('s','a','v','e'),
MII_LBIN_CANCEL = FCC('c','a','n','c'), MII_LBIN_CANCEL = FCC('c','a','n','c'),
MII_LBIN_SELECT = FCC('s','e','l','e'), MII_LBIN_SELECT = FCC('s','e','l','e'),
}; MII_LBIN_AUTO_RELOAD = FCC('a','u','t','o'),
MII_LBIN_ADDR_0300 = FCC('a','d','d','0'),
MII_LBIN_ADDR_0800 = FCC('a','d','d','1'),
MII_LBIN_ADDR_2000 = FCC('a','d','d','2'),
};
typedef struct mii_mui_loadbin_t { typedef struct mii_mui_loadbin_t {
mui_window_t win; mui_window_t win;
mui_control_t * load, *icon, *fname; mii_mui_file_select_t file;
mui_control_t * load;
mii_loadbin_conf_t * dst, config; mii_loadbin_conf_t * dst, config;
} mii_mui_loadbin_t; } mii_mui_loadbin_t;
@ -39,11 +45,12 @@ _mii_loadbin_stdfile_cb(
case MUI_STDF_ACTION_SELECT: { case MUI_STDF_ACTION_SELECT: {
char * path = mui_stdfile_get_selected_path(w); char * path = mui_stdfile_get_selected_path(w);
printf("%s select %s\n", __func__, path); printf("%s select %s\n", __func__, path);
mui_control_set_state(m->fname, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(m->file.fname, MUI_CONTROL_STATE_NORMAL);
strncpy(m->config.path, path, sizeof(m->config.path)-1);
char *dup = strdup(path); char *dup = strdup(path);
mui_control_set_title(m->fname, basename(dup)); mui_control_set_title(m->file.fname, basename(dup));
free(dup); free(dup);
mui_control_set_state(m->icon, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(m->file.icon, MUI_CONTROL_STATE_NORMAL);
mui_control_set_state(m->load, MUI_CONTROL_STATE_NORMAL); mui_control_set_state(m->load, MUI_CONTROL_STATE_NORMAL);
mui_window_dispose(w); mui_window_dispose(w);
} break; } break;
@ -94,6 +101,19 @@ _mii_loadbin_action_cb(
MUI_STDF_FLAG_REGEXP); MUI_STDF_FLAG_REGEXP);
mui_window_set_action(w, _mii_loadbin_stdfile_cb, m); mui_window_set_action(w, _mii_loadbin_stdfile_cb, m);
} break; } break;
case MII_LBIN_AUTO_RELOAD: {
// toggle auto reload
m->config.auto_reload = !!mui_control_get_value(c);
printf("%s auto reload %d\n", __func__, m->config.auto_reload);
} break;
case MII_LBIN_ADDR_0300:
case MII_LBIN_ADDR_0800:
case MII_LBIN_ADDR_2000: {
int idx = FCC_INDEX(uid);
static const uint16_t addrs[] = { 0x0300, 0x0800, 0x2000 };
m->config.addr = addrs[idx];
printf("%s load addr $%04x\n", __func__, m->config.addr);
} break;
} }
break; break;
} }
@ -114,7 +134,7 @@ mii_mui_load_binary(
return w; return w;
} }
c2_pt_t where = {}; c2_pt_t where = {};
c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 480, 294); c2_rect_t wpos = C2_RECT_WH(where.x, where.y, 580, 294);
if (where.x == 0 && where.y == 0) if (where.x == 0 && where.y == 0)
c2_rect_offset(&wpos, c2_rect_offset(&wpos,
(ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2), (ui->screen_size.x / 2) - (c2_rect_width(&wpos) / 2),
@ -144,42 +164,47 @@ mii_mui_load_binary(
"Cancel", MII_LBIN_CANCEL); "Cancel", MII_LBIN_CANCEL);
c->key_equ = MUI_KEY_EQU(0, 27); c->key_equ = MUI_KEY_EQU(0, 27);
c2_rect_right_of(&cf, 0, margin);
c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_NORMAL,
"Select…" , MII_LBIN_SELECT);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 's');
cf.b = cf.t + base_size; cf.b = cf.t + base_size;
c2_rect_top_of(&cf, cf.t, margin); c2_rect_top_of(&cf, cf.t, margin);
c2_rect_right_of(&cf, 0, margin); c2_rect_right_of(&cf, 0, margin);
cf.r = cf.l + 200; cf.r = cf.l + 200;
c = mui_button_new(w, c = mui_button_new(w,
cf, MUI_BUTTON_STYLE_CHECKBOX, cf, MUI_BUTTON_STYLE_CHECKBOX,
"Auto Reload", 0); "Auto Reload", MII_LBIN_AUTO_RELOAD);
c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 'r'); c->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 'r');
// this tell libmui that it can clear the radio values of the 'sister' // this tell libmui that it can clear the radio values of the 'sister'
// radio buttons when one matching the uid&mask is selected // radio buttons when one matching the uid&mask is selected
uint32_t uid_mask = FCC(0xff,0xff,0xff,0); uint32_t uid_mask = FCC(0xff,0xff,0xff,0);
c2_rect_top_of(&cf, cf.t, 10); c2_rect_top_of(&cf, cf.t, 10);
cf.l += margin * 2; // cf.l += margin * 2;
cf.r = cf.l + 110; cf.r = cf.l + 110;
c = mui_button_new(w, c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
cf, MUI_BUTTON_STYLE_RADIO, "$0300", MII_LBIN_ADDR_0300);
"$0300", FCC('a','d','d','0'));
c->uid_mask = uid_mask; c->uid_mask = uid_mask;
c->value = 1; c->value = 1;
c2_rect_right_of(&cf, cf.r, margin); int inter_button_margin = margin/3;
c = mui_button_new(w, c2_rect_right_of(&cf, cf.r, inter_button_margin);
cf, MUI_BUTTON_STYLE_RADIO, c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
"$0800", FCC('a','d','d','1')); "$0800", MII_LBIN_ADDR_0800);
c->uid_mask = uid_mask; c->uid_mask = uid_mask;
c2_rect_right_of(&cf, cf.r, margin); c2_rect_right_of(&cf, cf.r, inter_button_margin);
c = mui_button_new(w, c = mui_button_new(w, cf, MUI_BUTTON_STYLE_RADIO,
cf, MUI_BUTTON_STYLE_RADIO, "$2000", MII_LBIN_ADDR_2000);
"$2000", FCC('a','d','d','2'));
c->uid_mask = uid_mask; c->uid_mask = uid_mask;
c2_rect_right_of(&cf, cf.r, inter_button_margin);
cf.r = cf.l + 90;
c = mui_textbox_new(w, cf, "Other: $", NULL, 0);
c->state = MUI_CONTROL_STATE_DISABLED;
c2_rect_right_of(&cf, cf.r, 4);
c2_rect_t tbf = cf;
tbf.r = c2_rect_width(&w->frame) - margin*2;
tbf.b = cf.t + base_size * 1.3;
c2_rect_bottom_of(&tbf, cf.t, -margin/4);
c = mui_textedit_control_new(w, tbf, MUI_CONTROL_TEXTBOX_FRAME);
mui_textedit_set_text(c, "4000");
c->state = MUI_CONTROL_STATE_DISABLED;
c2_rect_right_of(&cf, 0, margin); c2_rect_right_of(&cf, 0, margin);
c2_rect_top_of(&cf, cf.t, margin / 2); c2_rect_top_of(&cf, cf.t, margin / 2);
cf.r = cf.l + 200; cf.r = cf.l + 200;
@ -190,19 +215,10 @@ mii_mui_load_binary(
c2_rect_t cp = cf; c2_rect_t cp = cf;
cp.l -= margin * 0.2; cp.l -= margin * 0.2;
cp.b += base_size * 1.3; cp.b += base_size * 1.3;
c = mui_groupbox_new(w, cp, "File to load:", MUI_CONTROL_TEXTBOX_FRAME);
float icons_size = mui_font_find(ui, "icon_small")->size; mii_mui_fileselect_widget(&m->file, w, &cf, "Device:", "Select…", NULL);
c2_rect_bottom_of(&cf, cf.b, 0); m->file.button->uid = MII_LBIN_SELECT;
cf.b = cf.t + icons_size; m->file.button->key_equ = MUI_KEY_EQU(MUI_MODIFIER_ALT, 's');
cf.r = cf.l + icons_size;
m->icon = c = mui_textbox_new(w, cf, MUI_ICON_FILE, "icon_small",
MUI_TEXT_ALIGN_MIDDLE | MUI_TEXT_ALIGN_CENTER | 0);
c->state = MUI_CONTROL_STATE_DISABLED;
cf.l = cf.r;
cf.r = c2_rect_width(&w->content) - margin;
m->fname = c = mui_textbox_new(w, cf, "Click \"Select\" to pick a file", NULL, 0);
c->state = MUI_CONTROL_STATE_DISABLED;
c = NULL; c = NULL;
TAILQ_FOREACH(c, &w->controls, self) { TAILQ_FOREACH(c, &w->controls, self) {
@ -210,7 +226,41 @@ mii_mui_load_binary(
continue; continue;
mui_control_set_action(c, _mii_loadbin_action_cb, m); mui_control_set_action(c, _mii_loadbin_action_cb, m);
} }
m->config = *config;
if (m->config.path[0]) {
char * path = m->config.path;
mui_control_set_state(m->file.fname, MUI_CONTROL_STATE_NORMAL);
char *dup = strdup(path);
mui_control_set_title(m->file.fname, basename(dup));
free(dup);
mui_control_set_state(m->file.icon, MUI_CONTROL_STATE_NORMAL);
mui_control_set_state(m->load, MUI_CONTROL_STATE_NORMAL);
} else {
m->config.path[0] = 0;
// mui_control_set_state(m->load, MUI_CONTROL_STATE_NORMAL);
}
switch (m->config.addr) {
case 0x0300:
mui_control_set_value(
mui_control_get_by_id(w,
FCC_INDEXED(MII_LBIN_ADDR_0300, 0)), 1);
break;
case 0x0800:
mui_control_set_value(
mui_control_get_by_id(w,
FCC_INDEXED(MII_LBIN_ADDR_0300, 1)), 1);
break;
case 0x2000:
mui_control_set_value(
mui_control_get_by_id(w,
FCC_INDEXED(MII_LBIN_ADDR_0300, 2)), 1);
break;
}
// now check the auto reload
mui_control_set_value(
mui_control_get_by_id(w, MII_LBIN_AUTO_RELOAD),
m->config.auto_reload);
return w; return w;
} }

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