Compare commits
No commits in common. "009cc7d3a2548e8322b372f93e8c6165043f42eb" and "920f1f010284d59bad86f78355ed90ac2f3e1d2c" have entirely different histories.
009cc7d3a2
...
920f1f0102
84 changed files with 1266 additions and 1784 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.h gitlab-language=c
|
||||||
|
*.c gitlab-language=c
|
5
bochsrc
Normal file
5
bochsrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
ata0-master: type=disk, mode=flat, path=out/disk.img
|
||||||
|
boot: disk
|
||||||
|
megs: 512
|
||||||
|
|
||||||
|
com1: enabled=1, mode=socket-server, dev=localhost:2345
|
|
@ -1,9 +0,0 @@
|
||||||
header:
|
|
||||||
uint32_t: number of entries
|
|
||||||
|
|
||||||
for each entry:
|
|
||||||
uint32_t: uid
|
|
||||||
uint8_t: prefix length
|
|
||||||
chars: prefix
|
|
||||||
prefix has a trailing / if necessary
|
|
||||||
prefix does not have a leading /
|
|
|
@ -33,19 +33,19 @@ table 1:
|
||||||
|
|
||||||
function | eax | eax out | ebx | ecx | edx | esi | edi
|
function | eax | eax out | ebx | ecx | edx | esi | edi
|
||||||
-------------------|------|-----------------|----------------|----------------|--------------|--------------|--------------
|
-------------------|------|-----------------|----------------|----------------|--------------|--------------|--------------
|
||||||
open file | 0x00 | handle | path | | | |
|
open file | 0x00 | handle | drive number | path | | |
|
||||||
close file | 0x01 | | handle | | | |
|
close file | 0x01 | | handle | | | |
|
||||||
file read | 0x02 | read | handle | file offset | count | buffer |
|
file read | 0x02 | read | handle | file offset | count | buffer |
|
||||||
get file size | 0x03 | size | handle | | | |
|
get file size | 0x03 | size | handle | | | |
|
||||||
start task | 0x04 | handle | path | passed sz | passed dword | |
|
start task | 0x04 | handle | drive number | path | passed sz | passed dword |
|
||||||
ipc send | 0x05 | written | task handle | max count | buffer | |
|
ipc send | 0x05 | written | task handle | max count | buffer | |
|
||||||
ipc read | 0x06 | read | task handle | max count | buffer | |
|
ipc read | 0x06 | read | task handle | max count | buffer | |
|
||||||
allocate ram | 0x07 | start pointer | pages | | | |
|
allocate ram | 0x07 | start pointer | pages | | | |
|
||||||
memory info | 0x08 | see table 2 | see table 2 | | | |
|
memory info | 0x08 | see table 2 | see table 2 | | | |
|
||||||
wait for task | 0x09 | | handle | | | |
|
wait for task | 0x09 | | handle | | | |
|
||||||
enumerate dir | 0x0a | count | path | see table 3 | max | |
|
enumerate dir | 0x0a | count | drive number | path | see table 3 | max |
|
||||||
system log | 0x0b | | message sz | | | |
|
system log | 0x0b | | message sz | | | |
|
||||||
count of dir | 0x0c | number of files | path | | | |
|
count of dir | 0x0c | number of files | drive number | path | | |
|
||||||
new window | 0x0d | window handle | width | height | pixel buffer | |
|
new window | 0x0d | window handle | width | height | pixel buffer | |
|
||||||
delete window | 0x0e | | window handle | | | |
|
delete window | 0x0e | | window handle | | | |
|
||||||
resize window | 0x0f | | window handle | width | height | pixel buffer |
|
resize window | 0x0f | | window handle | width | height | pixel buffer |
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
/bin/mkpopup Welcome to Portland OS!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Alt+F4 to close this window.
|
bin/mkpopup Welcome to Portland OS v0.0.11!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Escape to close this window.
|
|
@ -1 +1 @@
|
||||||
/bin/terminal /bin/highway
|
bin/terminal bin/highway
|
|
@ -1 +1 @@
|
||||||
set _path /bin/
|
set _path bin/
|
51
makefile
51
makefile
|
@ -5,7 +5,6 @@ nasmargs = -f elf32
|
||||||
partlink = -r -m elf_i386
|
partlink = -r -m elf_i386
|
||||||
clink = -T src/user/runtimes/c/elf.ld
|
clink = -T src/user/runtimes/c/elf.ld
|
||||||
cxxlink = ${clink} src/user/runtimes/cxx/extra.ld
|
cxxlink = ${clink} src/user/runtimes/cxx/extra.ld
|
||||||
asmlink = -T src/user/runtimes/asm/elf.ld
|
|
||||||
|
|
||||||
out/disk.vdi: out/disk.img
|
out/disk.vdi: out/disk.img
|
||||||
rm out/disk.vdi || true
|
rm out/disk.vdi || true
|
||||||
|
@ -14,11 +13,9 @@ out/disk.vdi: out/disk.img
|
||||||
out/disk.img: out/kernel.bin out/boot.bin out/fs
|
out/disk.img: out/kernel.bin out/boot.bin out/fs
|
||||||
mkdir -p obj
|
mkdir -p obj
|
||||||
mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 129 -s 1 -S 512 obj/shadow.img 8192
|
mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 129 -s 1 -S 512 obj/shadow.img 8192
|
||||||
echo -n -e '\x01\x00\x00\x00uid \x00\x00\x00\x00' > out/fs/_fstab
|
|
||||||
dd if=obj/shadow.img of=out/fs/_fstab bs=1 seek=4 skip=39 count=4 conv=notrunc
|
|
||||||
echo -n -e '\xeb\x3c' > obj/jmp.bin
|
echo -n -e '\xeb\x3c' > obj/jmp.bin
|
||||||
dd if=obj/jmp.bin of=obj/shadow.img bs=1 conv=notrunc
|
dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc
|
||||||
dd if=out/boot.bin of=obj/shadow.img bs=1 seek=62 conv=notrunc
|
dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc
|
||||||
dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc
|
dd if=out/kernel.bin of=obj/shadow.img seek=1 conv=notrunc
|
||||||
mv obj/shadow.img out/disk.img
|
mv obj/shadow.img out/disk.img
|
||||||
mcopy -i out/disk.img -s out/fs/* ::/
|
mcopy -i out/disk.img -s out/fs/* ::/
|
||||||
|
@ -26,11 +23,11 @@ out/disk.img: out/kernel.bin out/boot.bin out/fs
|
||||||
clean:
|
clean:
|
||||||
rm -r obj out || true
|
rm -r obj out || true
|
||||||
|
|
||||||
gdb: out/disk.img
|
qemu: out/disk.img
|
||||||
gdb -x qemu.gdb
|
gdb -x qemu.gdb
|
||||||
|
|
||||||
ddd: out/disk.img
|
bochs: out/disk.img
|
||||||
ddd --debugger 'gdb -x qemu.gdb'
|
bochs -q
|
||||||
|
|
||||||
out/fs/bin/%: obj/%.elf
|
out/fs/bin/%: obj/%.elf
|
||||||
mkdir -p $(shell dirname $@)
|
mkdir -p $(shell dirname $@)
|
||||||
|
@ -42,8 +39,8 @@ out/fs/bin/%: obj/%.elf
|
||||||
|
|
||||||
out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo \
|
out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo \
|
||||||
out/fs/bin/terminal out/fs/bin/hello out/fs/bin/mkpopup \
|
out/fs/bin/terminal out/fs/bin/hello out/fs/bin/mkpopup \
|
||||||
out/fs/bin/dirlist out/fs/bin/time \
|
out/fs/bin/dirlist out/fs/bin/ttt out/fs/bin/time \
|
||||||
out/fs/bin/filetest out/fs/bin/settings
|
out/fs/bin/filetest out/fs/bin/mdemo out/fs/bin/rhello
|
||||||
touch out/fs
|
touch out/fs
|
||||||
cp -r fs-skel/* out/fs/
|
cp -r fs-skel/* out/fs/
|
||||||
|
|
||||||
|
@ -102,14 +99,14 @@ obj/libfont.so: obj/libfont/bdf.o obj/libfont/pbf.o obj/libfont/fonts.o \
|
||||||
obj/libfont/filist.o
|
obj/libfont/filist.o
|
||||||
ld ${partlink} $^ -o $@
|
ld ${partlink} $^ -o $@
|
||||||
|
|
||||||
|
obj/popups.so: obj/popups/info.o obj/popups/popup.o
|
||||||
|
ld ${partlink} $^ -o $@
|
||||||
|
|
||||||
obj/raleigh.so: obj/raleigh/runtime.po obj/raleigh/window.po \
|
obj/raleigh.so: obj/raleigh/runtime.po obj/raleigh/window.po \
|
||||||
obj/raleigh/widget.po obj/raleigh/util.po \
|
obj/raleigh/widget.po obj/raleigh/util.po \
|
||||||
obj/raleigh/w/padding.po obj/raleigh/w/button.po \
|
obj/raleigh/w/padding.po obj/raleigh/w/button.po \
|
||||||
obj/raleigh/w/vbox.po obj/raleigh/w/entry.po \
|
obj/raleigh/w/vbox.po obj/raleigh/w/entry.po \
|
||||||
obj/raleigh/w/label.po obj/raleigh/w/colorpicker.po \
|
obj/raleigh/w/label.po obj/raleigh/w/colorpicker.po
|
||||||
obj/raleigh/w/hbox.po obj/raleigh/w/multicontainer.po \
|
|
||||||
obj/raleigh/d/dialog.po obj/raleigh/d/saving_window.po \
|
|
||||||
obj/raleigh/s/text_flower.po
|
|
||||||
ld ${partlink} $^ -o $@
|
ld ${partlink} $^ -o $@
|
||||||
|
|
||||||
obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto
|
obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto
|
||||||
|
@ -120,8 +117,8 @@ obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \
|
||||||
obj/c.rto
|
obj/c.rto
|
||||||
ld ${clink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/meminfo.elf: obj/meminfo/meminfo.po obj/raleigh.so obj/libfont.so \
|
obj/meminfo.elf: obj/meminfo/meminfo.po obj/raleigh.so obj/popups.so \
|
||||||
obj/knob.so obj/cxx.rto
|
obj/libfont.so obj/knob.so obj/cxx.rto
|
||||||
ld ${cxxlink} $^ -o $@
|
ld ${cxxlink} $^ -o $@
|
||||||
|
|
||||||
obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \
|
obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \
|
||||||
|
@ -129,16 +126,20 @@ obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \
|
||||||
ld ${clink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/hello.elf: obj/hello/hello.ao
|
obj/hello.elf: obj/hello/hello.ao
|
||||||
ld ${asmlink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/mkpopup.elf: obj/mkpopup/main.po obj/raleigh.so obj/libfont.so \
|
obj/mkpopup.elf: obj/mkpopup/main.o obj/popups.so obj/libfont.so \
|
||||||
obj/knob.so obj/cxx.rto
|
obj/knob.so obj/c.rto
|
||||||
ld ${cxxlink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/dirlist.elf: obj/dirlist/main.o obj/libterm.so obj/knob.so \
|
obj/dirlist.elf: obj/dirlist/main.o obj/libterm.so obj/knob.so \
|
||||||
obj/c.rto
|
obj/c.rto
|
||||||
ld ${clink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
|
obj/ttt.elf: obj/ttt/main.o obj/popups.so obj/libfont.so \
|
||||||
|
obj/knob.so obj/c.rto
|
||||||
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/time.elf: obj/time/time.o obj/libterm.so obj/knob.so \
|
obj/time.elf: obj/time/time.o obj/libterm.so obj/knob.so \
|
||||||
obj/c.rto
|
obj/c.rto
|
||||||
ld ${clink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
@ -147,8 +148,10 @@ obj/filetest.elf: obj/filetest/filetest.o obj/libterm.so obj/knob.so \
|
||||||
obj/c.rto
|
obj/c.rto
|
||||||
ld ${clink} $^ -o $@
|
ld ${clink} $^ -o $@
|
||||||
|
|
||||||
obj/settings.elf: obj/settings/main.po obj/settings/model.po \
|
obj/mdemo.elf: obj/mdemo/main.o obj/popups.so obj/libfont.so \
|
||||||
obj/settings/string_kind.po obj/settings/color_kind.po \
|
obj/knob.so obj/c.rto
|
||||||
obj/raleigh.so obj/libfont.so \
|
ld ${clink} $^ -o $@
|
||||||
obj/knob.so obj/cxx.rto
|
|
||||||
|
obj/rhello.elf: obj/rhello/main.po obj/raleigh.so obj/popups.so \
|
||||||
|
obj/libfont.so obj/knob.so obj/cxx.rto
|
||||||
ld ${cxxlink} $^ -o $@
|
ld ${cxxlink} $^ -o $@
|
|
@ -1,7 +1,5 @@
|
||||||
#include "drive.h"
|
#include "drive.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "pmap.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "fat.h"
|
#include "fat.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
@ -42,7 +40,6 @@ static inline void determine_fs(struct drive *d) {
|
||||||
if (try_fat_init_drive(d))
|
if (try_fat_init_drive(d))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d->mapped_to = 0;
|
|
||||||
d->fs_type = "Unknown";
|
d->fs_type = "Unknown";
|
||||||
d->get_file = &unknown_get_file;
|
d->get_file = &unknown_get_file;
|
||||||
d->free_file = &unknown_no_call;
|
d->free_file = &unknown_no_call;
|
||||||
|
@ -61,83 +58,7 @@ static inline void determine_fs(struct drive *d) {
|
||||||
//do not need to make ready or done
|
//do not need to make ready or done
|
||||||
void commit_drive(struct drive data) {
|
void commit_drive(struct drive data) {
|
||||||
determine_fs(&data);
|
determine_fs(&data);
|
||||||
data.mapped_to = 0;
|
|
||||||
drives[n_drives] = data;
|
drives[n_drives] = data;
|
||||||
data.done(drives + n_drives);
|
data.done(drives + n_drives);
|
||||||
++n_drives;
|
++n_drives;
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_path(const char *full, struct drive **d, const char **path) {
|
|
||||||
*d = 0;
|
|
||||||
*path = 0;
|
|
||||||
|
|
||||||
switch (full[0]) {
|
|
||||||
case '/':
|
|
||||||
for (struct drive *i = drives; i < drives + n_drives; ++i) {
|
|
||||||
if (!i->mapped_to)
|
|
||||||
continue;
|
|
||||||
uint32_t j = 0;
|
|
||||||
while (1) {
|
|
||||||
if (!i->mapped_to[j]) {
|
|
||||||
if (!*path || (j >= *path - full)) {
|
|
||||||
*path = full + j + 1;
|
|
||||||
*d = i;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (i->mapped_to[j] != full[j + 1])
|
|
||||||
break;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t id;
|
|
||||||
case ':':
|
|
||||||
id = 0;
|
|
||||||
for (uint32_t i = 1; i < 9; ++i) {
|
|
||||||
id *= 16;
|
|
||||||
const char c = full[i];
|
|
||||||
if ((c >= '0') && (c <= '9'))
|
|
||||||
id += c - '0';
|
|
||||||
else if ((c >= 'a') && (c <= 'f'))
|
|
||||||
id += c - 'a' + 10;
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (full[9] != ':')
|
|
||||||
return;
|
|
||||||
for (struct drive *i = drives; i < drives + n_drives; ++i)
|
|
||||||
if (i->uid == id) {
|
|
||||||
*d = i;
|
|
||||||
*path = full + 10;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void map_drives() {
|
|
||||||
for (struct drive *d = drives; d < drives + n_drives; ++d) {
|
|
||||||
file_id_t fid = d->get_file(d, "_fstab");
|
|
||||||
if (!fid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const uint32_t len = d->get_file_length(d, fid);
|
|
||||||
void *fstab = allocate_kernel_pages(len / 512 + 1);
|
|
||||||
fmcpy(fstab, d, fid, 0, len);
|
|
||||||
d->free_file(d, fid);
|
|
||||||
const uint32_t n_entries = *(uint32_t *)fstab;
|
|
||||||
|
|
||||||
uint32_t next_id = *(uint32_t *)(fstab + 4);
|
|
||||||
fstab += 8;
|
|
||||||
for (uint32_t i = 0; i < n_entries; ++i) {
|
|
||||||
for (struct drive *dd = drives; dd < drives + n_drives; ++dd)
|
|
||||||
if (dd->uid == next_id)
|
|
||||||
dd->mapped_to = fstab + 4;
|
|
||||||
const uint32_t plen = *(uint32_t *)fstab;
|
|
||||||
next_id = *(uint32_t *)(fstab + 4 + plen);
|
|
||||||
*(char *)(fstab + 4 + plen) = '\0';
|
|
||||||
fstab += 8 + plen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,8 +22,6 @@ struct directory_content_info {
|
||||||
struct drive {
|
struct drive {
|
||||||
char *drive_type;
|
char *drive_type;
|
||||||
char *fs_type;
|
char *fs_type;
|
||||||
char *mapped_to;
|
|
||||||
uint32_t uid;
|
|
||||||
|
|
||||||
uint32_t (*read_sectors) (const struct drive *d, uint32_t start, uint32_t count, void *buffer);
|
uint32_t (*read_sectors) (const struct drive *d, uint32_t start, uint32_t count, void *buffer);
|
||||||
uint32_t (*write_sectors)(const struct drive *d, uint32_t start, uint32_t count, const void *buffer);
|
uint32_t (*write_sectors)(const struct drive *d, uint32_t start, uint32_t count, const void *buffer);
|
||||||
|
@ -45,14 +43,11 @@ struct drive {
|
||||||
fs_id_t fs_id;
|
fs_id_t fs_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
void map_path(const char *full, struct drive **d, const char **path);
|
|
||||||
|
|
||||||
extern uint8_t n_drives;
|
extern uint8_t n_drives;
|
||||||
extern struct drive drives[MAX_DRIVES];
|
extern struct drive drives[MAX_DRIVES];
|
||||||
|
|
||||||
void init_drives();
|
void init_drives();
|
||||||
void commit_drive(struct drive data);
|
void commit_drive(struct drive data);
|
||||||
void map_drives();
|
|
||||||
|
|
||||||
extern bool ignore_already_open;
|
extern bool ignore_already_open;
|
||||||
|
|
||||||
|
|
|
@ -521,7 +521,6 @@ bool try_fat_init_drive(struct drive *d) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
d->fs_type = "FAT16";
|
d->fs_type = "FAT16";
|
||||||
d->uid = next_fi->volume_id;
|
|
||||||
d->get_file = &fat_get_file;
|
d->get_file = &fat_get_file;
|
||||||
d->free_file = &fat_free_file;
|
d->free_file = &fat_free_file;
|
||||||
d->load_sector = &fat_load_sector;
|
d->load_sector = &fat_load_sector;
|
||||||
|
|
105
src/kernel/idt.c
105
src/kernel/idt.c
|
@ -34,95 +34,60 @@ struct {
|
||||||
.start = (uint32_t)idt
|
.start = (uint32_t)idt
|
||||||
};
|
};
|
||||||
|
|
||||||
bool verify_file_handle(uint32_t handle, struct drive **d, uint32_t *f) {
|
//file handles as (drive_number << 8) + file_id_t
|
||||||
*d = drives + (handle >> 24);
|
|
||||||
*f = handle & 0x00ffffff;
|
|
||||||
|
|
||||||
if (!*f || (*d >= drives + n_drives)) {
|
uint32_t sc_open_file(uint32_t drive_number, char *path) {
|
||||||
logf(LOG_WARN, "syscall with file handle 0x%h", handle);
|
return (drive_number << 8) + drives[drive_number].get_file(drives + drive_number, path);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t sc_open_file(const char *path) {
|
|
||||||
struct drive *did;
|
|
||||||
const char *sub;
|
|
||||||
map_path(path, &did, &sub);
|
|
||||||
if (!did)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const file_id_t fid = did->get_file(did, sub);
|
|
||||||
return fid ? ((did - drives) << 24) + fid : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sc_close_file(uint32_t handle) {
|
void sc_close_file(uint32_t handle) {
|
||||||
struct drive *d;
|
if (!handle)
|
||||||
uint32_t f;
|
return;
|
||||||
if (verify_file_handle(handle, &d, &f))
|
drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff);
|
||||||
d->free_file(d, f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_file_get_size(uint32_t handle) {
|
uint32_t sc_file_get_size(uint32_t handle) {
|
||||||
struct drive *d;
|
if (!handle)
|
||||||
uint32_t f;
|
|
||||||
if (verify_file_handle(handle, &d, &f))
|
|
||||||
return d->get_file_length(d, f);
|
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
|
return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sc_file_set_size(uint32_t handle, uint32_t new_size) {
|
void sc_file_set_size(uint32_t handle, uint32_t new_size) {
|
||||||
struct drive *d;
|
if (!handle)
|
||||||
uint32_t f;
|
return;
|
||||||
if (verify_file_handle(handle, &d, &f))
|
drives[handle >> 8].set_file_length(drives + (handle >> 8), handle & 0xff, new_size);
|
||||||
d->set_file_length(d, f, new_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
|
uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
|
||||||
struct drive *d;
|
if (!handle)
|
||||||
uint32_t f;
|
|
||||||
if (verify_file_handle(handle, &d, &f)) {
|
|
||||||
const uint32_t l = d->get_file_length(d, f);
|
|
||||||
if (file_offset >= l)
|
|
||||||
return 0;
|
return 0;
|
||||||
if (file_offset + count > l)
|
uint32_t len = sc_file_get_size(handle);
|
||||||
count = l - file_offset;
|
if (file_offset + count > len)
|
||||||
fmcpy(buffer, d, f, file_offset, count);
|
count = len - file_offset;
|
||||||
|
fmcpy(buffer, drives + (handle >> 8), handle & 0xff, file_offset, count);
|
||||||
return count;
|
return count;
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_file_write(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
|
uint32_t sc_file_write(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
|
||||||
struct drive *d;
|
if (!handle)
|
||||||
uint32_t f;
|
|
||||||
if (verify_file_handle(handle, &d, &f)) {
|
|
||||||
if (!d->is_writable(d, f))
|
|
||||||
return 0;
|
return 0;
|
||||||
const uint32_t l = d->get_file_length(d, f);
|
const struct drive *const d = drives + (handle >> 8);
|
||||||
if (file_offset >= l)
|
const fs_id_t fid = handle & 0xff;
|
||||||
|
|
||||||
|
if (!d->is_writable(d, fid))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
const uint32_t l = d->get_file_length(d, fid);
|
||||||
if (file_offset + count > l)
|
if (file_offset + count > l)
|
||||||
count = l - file_offset;
|
count = l - file_offset;
|
||||||
mfcpy(d, f, file_offset, buffer, count);
|
|
||||||
return l;
|
mfcpy(d, fid, file_offset, buffer, count);
|
||||||
}
|
return count;
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_start_task(char *path, const char *pass, uint32_t io_task) {
|
uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) {
|
||||||
struct drive *d;
|
|
||||||
const char *f;
|
|
||||||
map_path(path, &d, &f);
|
|
||||||
if (!d)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch_to_kernel_cr3();
|
switch_to_kernel_cr3();
|
||||||
uint32_t process_id = try_elf_run(d, vma_to_pma(active_task->page_directory, f), pass, io_task);
|
uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task);
|
||||||
switch_to_task_cr3();
|
switch_to_task_cr3();
|
||||||
return process_id;
|
return process_id;
|
||||||
}
|
}
|
||||||
|
@ -161,18 +126,12 @@ void sc_wait_for_task(uint32_t handle) {
|
||||||
add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1});
|
add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_enumerate_dir(const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi
|
uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi
|
||||||
struct drive *d;
|
return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries);
|
||||||
const char *f;
|
|
||||||
map_path(path, &d, &f);
|
|
||||||
return d ? d->enumerate_dir(d, f, buffer, max_entries) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sc_count_of_dir(const char *path) {
|
uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) {
|
||||||
struct drive *d;
|
return drives[drive_number].n_dir_entries(drives + drive_number, path);
|
||||||
const char *f;
|
|
||||||
map_path(path, &d, &f);
|
|
||||||
return d ? d->n_dir_entries(d, f) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sc_get_next_window_action(struct window *w, struct window_action *action) {
|
void sc_get_next_window_action(struct window *w, struct window_action *action) {
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include "kbd.h"
|
#include "kbd.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define SCANTAB_DIR "/sys/scantabs/"
|
#define SCANTAB_DIR "sys/scantabs/"
|
||||||
#define SCANTAB_DIR_LEN 14
|
#define SCANTAB_DIR_LEN 13
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PS2_CMD = 0x64,
|
PS2_CMD = 0x64,
|
||||||
|
@ -97,10 +97,7 @@ void init_kbd() {
|
||||||
scantab_path[SCANTAB_DIR_LEN + layout_len + 3] = 't';
|
scantab_path[SCANTAB_DIR_LEN + layout_len + 3] = 't';
|
||||||
scantab_path[SCANTAB_DIR_LEN + layout_len + 4] = '\0';
|
scantab_path[SCANTAB_DIR_LEN + layout_len + 4] = '\0';
|
||||||
logf(LOG_INFO, "Using scantab file at \"%s\".", scantab_path);
|
logf(LOG_INFO, "Using scantab file at \"%s\".", scantab_path);
|
||||||
struct drive *d;
|
file_id_t stf = drives->get_file(drives, scantab_path);
|
||||||
const char *f;
|
|
||||||
map_path(scantab_path, &d, &f);
|
|
||||||
file_id_t stf = drives->get_file(d, f);
|
|
||||||
if (!stf)
|
if (!stf)
|
||||||
PANIC("could not load scantab file.");
|
PANIC("could not load scantab file.");
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#define LOG_COM COM1
|
#define LOG_COM COM1
|
||||||
|
|
||||||
void init_log() {
|
void init_log() {
|
||||||
//TODO: move old "/sys/current.log"
|
//TODO: move old "sys/current.log"
|
||||||
//TODO: open new "/sys/current.log"
|
//TODO: open new "sys/current.log"
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const log_prefixes[] = {
|
static const char *const log_prefixes[] = {
|
||||||
|
|
|
@ -40,8 +40,6 @@ void main() {
|
||||||
|
|
||||||
ignore_already_open = true;
|
ignore_already_open = true;
|
||||||
|
|
||||||
map_drives();
|
|
||||||
|
|
||||||
init_log();
|
init_log();
|
||||||
init_settings();
|
init_settings();
|
||||||
|
|
||||||
|
@ -49,8 +47,6 @@ void main() {
|
||||||
init_idt();
|
init_idt();
|
||||||
init_win();
|
init_win();
|
||||||
|
|
||||||
close_settings();
|
|
||||||
|
|
||||||
logf(LOG_INFO, "Kernel initialization done.");
|
logf(LOG_INFO, "Kernel initialization done.");
|
||||||
logf(LOG_INFO, "Available kernel memory: %dk", kernel_pages_left * 4);
|
logf(LOG_INFO, "Available kernel memory: %dk", kernel_pages_left * 4);
|
||||||
logf(LOG_INFO, "Available user memory: %dk", user_pages_left * 4);
|
logf(LOG_INFO, "Available user memory: %dk", user_pages_left * 4);
|
||||||
|
@ -66,15 +62,10 @@ void main() {
|
||||||
logf(LOG_INFO, "");
|
logf(LOG_INFO, "");
|
||||||
|
|
||||||
logf(LOG_INFO, "Drives:");
|
logf(LOG_INFO, "Drives:");
|
||||||
for (struct drive *d = drives; d < drives + n_drives; ++d) {
|
for (uint8_t i = 0; i < n_drives; ++i) {
|
||||||
|
const struct drive *d = &drives[i];
|
||||||
const uint32_t free = d->get_free_sectors(d);
|
const uint32_t free = d->get_free_sectors(d);
|
||||||
logf(LOG_INFO, " :%h:", d->uid);
|
logf(LOG_INFO, " %s: %d%sk, %s (%d%sk free)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : "", d->fs_type, free / 2, free % 2 ? ".5" : "");
|
||||||
logf(LOG_INFO, " %s (%d%skB free)", d->fs_type, free / 2, free % 2 ? ".5" : "");
|
|
||||||
logf(LOG_INFO, " on %s (%d%skB)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : "");
|
|
||||||
if (d->mapped_to)
|
|
||||||
logf(LOG_INFO, " mapped to /%s", d->mapped_to);
|
|
||||||
else
|
|
||||||
logf(LOG_INFO, " not mapped");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logf(LOG_INFO, "");
|
logf(LOG_INFO, "");
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define SETTINGS_FILE "/sys/settings.pls"
|
#define SETTINGS_FILE "sys/settings.pls"
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
uint32_t main_start;
|
uint32_t main_start;
|
||||||
|
@ -36,18 +36,8 @@ struct main_entry {
|
||||||
static file_id_t fid;
|
static file_id_t fid;
|
||||||
static uint32_t main_end;
|
static uint32_t main_end;
|
||||||
|
|
||||||
void close_settings() {
|
|
||||||
drives->free_file(drives, fid);
|
|
||||||
fid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void init_settings() {
|
void init_settings() {
|
||||||
struct drive *d;
|
fid = drives->get_file(drives, SETTINGS_FILE);
|
||||||
const char *f;
|
|
||||||
map_path(SETTINGS_FILE, &d, &f);
|
|
||||||
fid = drives->get_file(d, f);
|
|
||||||
if (!fid)
|
if (!fid)
|
||||||
PANIC("could not open settings file at \"" SETTINGS_FILE "\".");
|
PANIC("could not open settings file at \"" SETTINGS_FILE "\".");
|
||||||
|
|
||||||
|
@ -57,9 +47,6 @@ void init_settings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_find_setting(const char *name, struct main_entry *entry_out) {
|
bool try_find_setting(const char *name, struct main_entry *entry_out) {
|
||||||
if (!fid)
|
|
||||||
PANIC("setting requested after settings file closed");
|
|
||||||
|
|
||||||
uint16_t name_len = 0;
|
uint16_t name_len = 0;
|
||||||
while (name[name_len])
|
while (name[name_len])
|
||||||
if (++name_len == 256)
|
if (++name_len == 256)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void init_settings();
|
void init_settings();
|
||||||
void close_settings();
|
|
||||||
|
|
||||||
//lengths do not include null terminator. if setting value is too long, it is cropped.
|
//lengths do not include null terminator. if setting value is too long, it is cropped.
|
||||||
bool try_get_sz_setting(const char *name, char *out, uint32_t max_len, uint32_t *len_out);
|
bool try_get_sz_setting(const char *name, char *out, uint32_t max_len, uint32_t *len_out);
|
||||||
|
|
|
@ -330,14 +330,8 @@ got_window:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void del_no_paint(struct window *w) {
|
static void del_no_paint(struct window *w) {
|
||||||
if ((w < windows) || (w >= windows + MAX_WINDOWS) || (((void *)w - (void *)windows) % sizeof(struct window))) {
|
|
||||||
logf(LOG_WARN, "Refusing to delete bad window pointer 0x%h", w);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w == top_window) {
|
if (w == top_window) {
|
||||||
top_window = w->below;
|
top_window = w->below;
|
||||||
if (top_window)
|
|
||||||
send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER});
|
send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER});
|
||||||
}
|
}
|
||||||
if (w == bottom_window)
|
if (w == bottom_window)
|
||||||
|
@ -409,7 +403,7 @@ struct window_action next_window_action(struct window *w) {
|
||||||
return *action;
|
return *action;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RUN_COMMAND_FILE "/sys/winspace.rc"
|
#define RUN_COMMAND_FILE "sys/winspace.rc"
|
||||||
|
|
||||||
enum wm_action {
|
enum wm_action {
|
||||||
WM_MOVE_LEFT,
|
WM_MOVE_LEFT,
|
||||||
|
@ -462,10 +456,7 @@ void init_win() {
|
||||||
mouse_y = (VBE_MODE_INFO->height - MOUSE_HEIGHT) / 2;
|
mouse_y = (VBE_MODE_INFO->height - MOUSE_HEIGHT) / 2;
|
||||||
blit_mouse();
|
blit_mouse();
|
||||||
|
|
||||||
const struct drive *d;
|
const file_id_t fid = drives->get_file(drives, RUN_COMMAND_FILE);
|
||||||
const char *f;
|
|
||||||
map_path(RUN_COMMAND_FILE, &d, &f);
|
|
||||||
const file_id_t fid = drives->get_file(d, f);
|
|
||||||
if (!fid)
|
if (!fid)
|
||||||
PANIC("Couldn't open " RUN_COMMAND_FILE ".");
|
PANIC("Couldn't open " RUN_COMMAND_FILE ".");
|
||||||
|
|
||||||
|
@ -522,11 +513,8 @@ void on_action(struct window_action packet) {
|
||||||
paint_all();
|
paint_all();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
const struct drive *d;
|
|
||||||
const char *f;
|
|
||||||
case WM_RUN_COMMAND:
|
case WM_RUN_COMMAND:
|
||||||
map_path(run_command, &d, &f);
|
if (!try_elf_run(drives, run_command, run_command_pass, 0))
|
||||||
if (!try_elf_run(d, f, run_command_pass, 0))
|
|
||||||
logf(LOG_ERROR, "Couldn't run program listed in " RUN_COMMAND_FILE ".");
|
logf(LOG_ERROR, "Couldn't run program listed in " RUN_COMMAND_FILE ".");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <libterm/terminal.h>
|
#include <libterm/terminal.h>
|
||||||
#include <knob/file.h>
|
#include <knob/file.h>
|
||||||
|
|
||||||
#define TEST_FILE "/user/test.txt"
|
#define TEST_FILE "user/test.txt"
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
struct file *f = open_file(TEST_FILE);
|
struct file *f = open_file(TEST_FILE);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "vars.h"
|
#include "vars.h"
|
||||||
|
|
||||||
void main(const char *arg) {
|
void main(const char *arg) {
|
||||||
source(*arg ? arg : "/user/default.rc");
|
source(*arg ? arg : "user/default.rc");
|
||||||
ensure_color();
|
ensure_color();
|
||||||
|
|
||||||
term_add_sz("Portland Highway\nType \"help\" for help.\n");
|
term_add_sz("Portland Highway\nType \"help\" for help.\n");
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
#ifndef RALEIGH_D_DIALOG_H
|
|
||||||
#define RALEIGH_D_DIALOG_H
|
|
||||||
|
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
#include <raleigh/window.h>
|
|
||||||
#include <structs/alist.h>
|
|
||||||
#include <structs/duple.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
typedef uint32_t diag_result_t;
|
|
||||||
enum : diag_result_t {
|
|
||||||
NONE = 0,
|
|
||||||
YES,
|
|
||||||
NO,
|
|
||||||
CANCEL,
|
|
||||||
RETRY,
|
|
||||||
OKAY
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef alist<duple<const char *, diag_result_t>> button_list;
|
|
||||||
extern button_list &yes_no_cancel;
|
|
||||||
extern button_list &yes_no_retry;
|
|
||||||
extern button_list &okay_cancel;
|
|
||||||
extern button_list &okay;
|
|
||||||
|
|
||||||
class dialog : public window {
|
|
||||||
public:
|
|
||||||
//button names are copied
|
|
||||||
//alist isn't needed past constructor
|
|
||||||
dialog(widget &top_part, button_list buttons);
|
|
||||||
|
|
||||||
//zero means not set yet
|
|
||||||
diag_result_t result;
|
|
||||||
|
|
||||||
void show_modal();
|
|
||||||
|
|
||||||
private:
|
|
||||||
vbox *main_box;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef RALEIGH_D_SAVING_WINDOW_H
|
|
||||||
#define RALEIGH_D_SAVING_WINDOW_H
|
|
||||||
|
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
#include <raleigh/window.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
typedef void *save_tag_t;
|
|
||||||
class saving_window : public window {
|
|
||||||
public:
|
|
||||||
//save_func returns true if saving was successful
|
|
||||||
saving_window(bool (*save_func)(save_tag_t), save_tag_t save_tag, widget &root, _pixel_t bg_color=RGB(bf, bf, bf));
|
|
||||||
bool is_saved;
|
|
||||||
|
|
||||||
bool (*save_func)(save_tag_t);
|
|
||||||
save_tag_t save_tag;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -7,7 +7,6 @@
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
void start_runtime() __attribute__ ((noreturn));
|
void start_runtime() __attribute__ ((noreturn));
|
||||||
extern dllist<window &> open_windows;
|
extern dllist<window &> open_windows;
|
||||||
extern dllist<window &> to_be_deleted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,40 +0,0 @@
|
||||||
#ifndef RALEIGH_S_TEXT_FLOWER_H
|
|
||||||
#define RALEIGH_S_TEXT_FLOWER_H
|
|
||||||
|
|
||||||
#include <libfont/fonts.h>
|
|
||||||
#include <structs/alist.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
class text_flower {
|
|
||||||
public:
|
|
||||||
//max_rows or cols 0 means no limit
|
|
||||||
//s is not copied
|
|
||||||
text_flower(const char *s, uint32_t cols=50, uint32_t max_rows=0);
|
|
||||||
|
|
||||||
uint32_t get_n_lines() __attribute__ ((pure));
|
|
||||||
//not a copy
|
|
||||||
char *get_nth_line(uint32_t n) __attribute__ ((pure));
|
|
||||||
uint32_t get_line_offset(uint32_t n) __attribute__ ((pure));
|
|
||||||
|
|
||||||
void draw_text(_pixel_t *start, uint32_t pitch, const struct font_info *fi, _pixel_t color);
|
|
||||||
void flow_text();
|
|
||||||
|
|
||||||
//call flow_text after any changes
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
private:
|
|
||||||
alist<char *> lines;
|
|
||||||
alist<uint32_t> offsets;
|
|
||||||
|
|
||||||
uint32_t max_rows;
|
|
||||||
uint32_t cols;
|
|
||||||
|
|
||||||
//for use inside flow_text
|
|
||||||
const char *on_char;
|
|
||||||
const char *line_start;
|
|
||||||
uint32_t row_len;
|
|
||||||
void push_line();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -5,9 +5,6 @@
|
||||||
|
|
||||||
#define RGB(R, G, B) ((_pixel_t){.r = 0x##R, .g = 0x##G, .b = 0x##B})
|
#define RGB(R, G, B) ((_pixel_t){.r = 0x##R, .g = 0x##G, .b = 0x##B})
|
||||||
|
|
||||||
#define RALEIGH_FG RGB(00, 00, 00)
|
|
||||||
#define RALEIGH_BG RGB(bf, bf, bf)
|
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
struct coord {
|
struct coord {
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
|
@ -17,7 +14,6 @@ namespace raleigh {
|
||||||
};
|
};
|
||||||
|
|
||||||
void show_error_and_quitf(const char *fmt, ...) __attribute__ ((noreturn));
|
void show_error_and_quitf(const char *fmt, ...) __attribute__ ((noreturn));
|
||||||
void show_error_popup_and_quitf(const char *fmt, ...) __attribute__ ((noreturn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -4,22 +4,20 @@
|
||||||
#include <raleigh/widget.h>
|
#include <raleigh/widget.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
typedef void *button_tag_t;
|
|
||||||
class button : public widget {
|
class button : public widget {
|
||||||
public:
|
public:
|
||||||
button(widget &inner, void (*on_click)(button_tag_t), button_tag_t tag=0,
|
button(widget &inner, void (*on_click)(button &), _pixel_t border_color=RGB(00, 00, 00),
|
||||||
_pixel_t border_color=RGB(00, 00, 00), _pixel_t bg_color=RGB(bf, bf, bf),
|
_pixel_t bg_color=RGB(bf, bf, bf), _pixel_t pressed_color=RGB(9f, 9f, 9f));
|
||||||
_pixel_t pressed_color=RGB(9f, 9f, 9f));
|
|
||||||
|
|
||||||
void notify_window_change() override;
|
void notify_window_change() override;
|
||||||
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
||||||
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
||||||
void notify_child_size_change(widget &child, coord old_size) override;
|
void notify_child_size_change(widget &child, coord old_size) override;
|
||||||
void notify_has_opaque_parent(widget *parent) override;
|
void notify_has_opaque_parent(widget *parent) override;
|
||||||
|
void on_mouse_move(coord window_coords) override;
|
||||||
private:
|
private:
|
||||||
widget &inner;
|
widget &inner;
|
||||||
void (*on_click)(button_tag_t);
|
void (*on_click)(button &);
|
||||||
button_tag_t tag;
|
|
||||||
_pixel_t border_color;
|
_pixel_t border_color;
|
||||||
_pixel_t bg_color;
|
_pixel_t bg_color;
|
||||||
_pixel_t pressed_color;
|
_pixel_t pressed_color;
|
||||||
|
|
|
@ -8,7 +8,6 @@ namespace raleigh {
|
||||||
public:
|
public:
|
||||||
colorpicker(_pixel_t default_color=RGB(20, 70, 30), uint8_t resolution=4);
|
colorpicker(_pixel_t default_color=RGB(20, 70, 30), uint8_t resolution=4);
|
||||||
_pixel_t get_picked_color() __attribute__ ((pure));
|
_pixel_t get_picked_color() __attribute__ ((pure));
|
||||||
void set_picked_color(_pixel_t c);
|
|
||||||
|
|
||||||
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
||||||
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
||||||
|
@ -20,7 +19,7 @@ namespace raleigh {
|
||||||
uint8_t resolution;
|
uint8_t resolution;
|
||||||
uint8_t inv_res;
|
uint8_t inv_res;
|
||||||
|
|
||||||
enum {R, G, B} selected;
|
enum {NO, R, G, B} selected;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,61 +1,68 @@
|
||||||
#ifndef RALEIGH_W_ENTRY_H
|
#ifndef RALEIGH_W_ENTRY_H
|
||||||
#define RALEIGH_W_ENTRY_H
|
#define RALEIGH_W_ENTRY_H
|
||||||
|
|
||||||
#include <raleigh/s/text_flower.h>
|
|
||||||
#include <raleigh/widget.h>
|
#include <raleigh/widget.h>
|
||||||
#include <libfont/fonts.h>
|
#include <libfont/fonts.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
class entry : public widget {
|
class entry : public widget {
|
||||||
public:
|
public:
|
||||||
entry(uint32_t rows=25, uint32_t cols=25, const char *default_text="",
|
//default_text's data is copied, so it's okay if it changes or if the memory is freed
|
||||||
const struct font_info *fi=get_font("fixed-10"), _pixel_t bg=RGB(ff, ff, ff),
|
entry(uint32_t rows, uint32_t cols, const char *default_text="",
|
||||||
|
const char *font="fixed-10", _pixel_t bg=RGB(ff, ff, ff),
|
||||||
_pixel_t fg=RGB(00, 00, 00), _pixel_t border_color=RGB(00, 00, 00));
|
_pixel_t fg=RGB(00, 00, 00), _pixel_t border_color=RGB(00, 00, 00));
|
||||||
|
|
||||||
//not a copy
|
void notify_window_change() override;
|
||||||
const char *get_contents() __attribute__ ((pure));
|
|
||||||
//s is copied
|
|
||||||
void set_contents(const char *s);
|
|
||||||
|
|
||||||
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
||||||
void notify_has_opaque_parent(widget *parent) override;
|
|
||||||
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
||||||
|
void notify_has_opaque_parent(widget *parent) override;
|
||||||
void handle_key(struct key_packet kp) override;
|
void handle_key(struct key_packet kp) override;
|
||||||
void on_focus() override;
|
void on_focus() override;
|
||||||
void on_unfocus() override;
|
void on_unfocus() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const struct font_info *fi;
|
|
||||||
_pixel_t border_color;
|
|
||||||
_pixel_t fg;
|
|
||||||
_pixel_t bg;
|
|
||||||
uint32_t rows;
|
uint32_t rows;
|
||||||
uint32_t cols;
|
uint32_t cols;
|
||||||
|
_pixel_t bg;
|
||||||
|
_pixel_t fg;
|
||||||
|
_pixel_t border_color;
|
||||||
|
|
||||||
void left();
|
struct font_info *fi;
|
||||||
void right();
|
char *data;
|
||||||
void up();
|
//line_indices[end_y + 1] == end_d
|
||||||
void down();
|
uint32_t *line_indices;
|
||||||
|
|
||||||
void check_y();
|
|
||||||
void check_x();
|
|
||||||
|
|
||||||
void on_text_change();
|
|
||||||
void on_cursor_change();
|
|
||||||
|
|
||||||
alist<char> text_back;
|
|
||||||
text_flower flower;
|
|
||||||
|
|
||||||
bool text_change;
|
|
||||||
bool cursor_change;
|
|
||||||
|
|
||||||
bool was_cur_before;
|
|
||||||
uint32_t old_cur_x;
|
|
||||||
uint32_t old_cur_y;
|
|
||||||
|
|
||||||
bool is_cur;
|
|
||||||
uint32_t cur_x;
|
|
||||||
uint32_t cur_y;
|
uint32_t cur_y;
|
||||||
|
uint32_t cur_x;
|
||||||
|
uint32_t cur_d;
|
||||||
|
|
||||||
|
//the row of the last character
|
||||||
|
uint32_t end_y;
|
||||||
|
//the column after the last character
|
||||||
|
uint32_t end_x;
|
||||||
|
//the index of the null terminator
|
||||||
|
uint32_t end_d;
|
||||||
|
|
||||||
|
bool first_paint;
|
||||||
|
bool has_focus;
|
||||||
|
bool had_focus_last_paint;
|
||||||
|
bool text_changed_since_last_paint;
|
||||||
|
uint32_t cur_y_last_paint;
|
||||||
|
uint32_t cur_x_last_paint;
|
||||||
|
uint32_t cur_d_last_paint;
|
||||||
|
|
||||||
|
//uses cur_x, not cur_d; sets both
|
||||||
|
//will not modify cur_y
|
||||||
|
void ensure_cursor_in_line();
|
||||||
|
|
||||||
|
void paint_text(_pixel_t *pixbuf, uint32_t pitch);
|
||||||
|
//sets line_indices[from_y + 1 .. end_y + 1], end_y, end_x and end_d
|
||||||
|
void get_indices(uint32_t from_y, uint32_t from_x, uint32_t from_d);
|
||||||
|
|
||||||
|
//these four return true on success, and do not send a paint request to the window
|
||||||
|
bool cursor_left();
|
||||||
|
bool cursor_right();
|
||||||
|
bool cursor_up();
|
||||||
|
bool cursor_down();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#ifndef RALEIGH_W_HBOX_H
|
|
||||||
#define RALEIGH_W_HBOX_H
|
|
||||||
|
|
||||||
#include <raleigh/w/multicontainer.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
class hbox : public multicontainer {
|
|
||||||
public:
|
|
||||||
//do not modify this list afterward
|
|
||||||
hbox(dllist<widget &> widgets);
|
|
||||||
|
|
||||||
private:
|
|
||||||
coord determine_size() override;
|
|
||||||
void set_child_offsets() override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef RALEIGH_W_LABEL_H
|
#ifndef RALEIGH_W_LABEL_H
|
||||||
#define RALEIGH_W_LABEL_H
|
#define RALEIGH_W_LABEL_H
|
||||||
|
|
||||||
#include <raleigh/s/text_flower.h>
|
|
||||||
#include <raleigh/widget.h>
|
#include <raleigh/widget.h>
|
||||||
#include <libfont/fonts.h>
|
#include <libfont/fonts.h>
|
||||||
|
|
||||||
|
@ -9,27 +8,20 @@ namespace raleigh {
|
||||||
class label : public widget {
|
class label : public widget {
|
||||||
public:
|
public:
|
||||||
//value's data is copied
|
//value's data is copied
|
||||||
label(const char *value, const char *font="fixed-10",
|
label(const char *value, const char *font="fixed-10", bool bg_transparent=true,
|
||||||
uint32_t cols=0, bool bg_transparent=true,
|
_pixel_t fg=RGB(00, 00, 00), _pixel_t bg=RGB(bf, bf, bf));
|
||||||
_pixel_t fg=RALEIGH_FG, _pixel_t bg=RALEIGH_BG);
|
|
||||||
|
|
||||||
~label();
|
|
||||||
|
|
||||||
//new_value's data is copied
|
|
||||||
void change_value(const char *new_value);
|
void change_value(const char *new_value);
|
||||||
|
|
||||||
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
||||||
void notify_has_opaque_parent(widget *parent) override;
|
void notify_has_opaque_parent(widget *parent) override;
|
||||||
private:
|
private:
|
||||||
|
char *value;
|
||||||
|
uint32_t v_size;
|
||||||
const struct font_info *const fi;
|
const struct font_info *const fi;
|
||||||
uint32_t cols;
|
|
||||||
bool bg_transparent;
|
bool bg_transparent;
|
||||||
const _pixel_t fg;
|
const _pixel_t fg;
|
||||||
const _pixel_t bg;
|
const _pixel_t bg;
|
||||||
|
|
||||||
text_flower tf;
|
|
||||||
|
|
||||||
coord determine_size();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
#ifndef RALEIGH_W_MULTICONTAINER_H
|
|
||||||
#define RALEIGH_W_MULTICONTAINER_H
|
|
||||||
|
|
||||||
#include <raleigh/widget.h>
|
|
||||||
#include <structs/dllist.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
class multicontainer : public widget {
|
|
||||||
public:
|
|
||||||
void add_end(widget &w);
|
|
||||||
void add_start(widget &w);
|
|
||||||
|
|
||||||
void notify_window_change() override;
|
|
||||||
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
|
||||||
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
|
||||||
void notify_has_opaque_parent(widget *parent) override;
|
|
||||||
void notify_child_size_change(widget &from, coord old_size) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//do not modify this list afterward
|
|
||||||
//set size to determine_size() in derived constructor
|
|
||||||
multicontainer(dllist<widget &> widgets);
|
|
||||||
|
|
||||||
virtual coord determine_size() = 0;
|
|
||||||
virtual void set_child_offsets() = 0;
|
|
||||||
|
|
||||||
dllist<widget &> widgets;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -13,6 +13,7 @@ namespace raleigh {
|
||||||
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
||||||
void notify_has_opaque_parent(widget *parent) override;
|
void notify_has_opaque_parent(widget *parent) override;
|
||||||
void notify_child_size_change(widget &child, coord old_size) override;
|
void notify_child_size_change(widget &child, coord old_size) override;
|
||||||
|
void on_mouse_move(coord window_coords) override;
|
||||||
private:
|
private:
|
||||||
widget &inner;
|
widget &inner;
|
||||||
uint32_t pad_by;
|
uint32_t pad_by;
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
#ifndef RALEIGH_W_VBOX_H
|
#ifndef RALEIGH_W_VBOX_H
|
||||||
#define RALEIGH_W_VBOX_H
|
#define RALEIGH_W_VBOX_H
|
||||||
|
|
||||||
#include <raleigh/w/multicontainer.h>
|
#include <raleigh/widget.h>
|
||||||
|
#include <structs/dllist.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
class vbox : public multicontainer {
|
class vbox : public widget {
|
||||||
public:
|
public:
|
||||||
//do not modify this list afterward
|
//do not modify this list afterward
|
||||||
vbox(dllist<widget &> widgets=dllist<widget &>());
|
vbox(dllist<widget &> widgets);
|
||||||
|
|
||||||
|
void notify_window_change() override;
|
||||||
|
void paint(_pixel_t *pixbuf, uint32_t pitch) override;
|
||||||
|
void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override;
|
||||||
|
void notify_has_opaque_parent(widget *parent) override;
|
||||||
|
void notify_child_size_change(widget &from, coord old_size) override;
|
||||||
|
void on_mouse_move(coord window_coords) override;
|
||||||
private:
|
private:
|
||||||
coord determine_size() override;
|
dllist<widget &> widgets;
|
||||||
void set_child_offsets() override;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,10 @@ namespace raleigh {
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
class widget {
|
class widget {
|
||||||
public:
|
public:
|
||||||
//these four are set by window class (or parent widget)
|
//these three are set by window class (or parent widget)
|
||||||
widget *parent;//set to zero when root widget
|
widget *parent;//set to zero when root widget
|
||||||
window *w;
|
window *w;
|
||||||
coord window_offset;
|
coord window_offset;
|
||||||
bool next_paint_full;
|
|
||||||
|
|
||||||
//derived classes should not set this outside of the initializer
|
//derived classes should not set this outside of the initializer
|
||||||
//instead, they should call widget::set_size(coord)
|
//instead, they should call widget::set_size(coord)
|
||||||
|
|
|
@ -1,50 +1,42 @@
|
||||||
#ifndef RALEIGH_WINDOW_H
|
#ifndef RALEIGH_WINDOW_H
|
||||||
#define RALEIGH_WINDOW_H
|
#define RALEIGH_WINDOW_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
class window;
|
class window;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <raleigh/runtime.h>
|
#include <raleigh/runtime.h>
|
||||||
#include <raleigh/widget.h>
|
#include <raleigh/widget.h>
|
||||||
|
#include <structs/dllist.h>
|
||||||
|
#include <structs/duple.h>
|
||||||
#include <pland/syscall.h>
|
#include <pland/syscall.h>
|
||||||
#include <raleigh/util.h>
|
#include <raleigh/util.h>
|
||||||
#include <structs/map.h>
|
|
||||||
#include <knob/key.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
typedef void *window_tag_t;
|
|
||||||
class window {
|
class window {
|
||||||
friend void start_runtime();
|
friend void start_runtime();
|
||||||
public:
|
public:
|
||||||
//pass on_close to specify a close handler. if on_close returns false, the window will not be closed.
|
//pass on_close to specify a close handler. if on_close returns false, the window will not be closed.
|
||||||
window(widget &root, _pixel_t bg_color=RALEIGH_BG, bool (*on_close)(window_tag_t)=0, window_tag_t tag=0);
|
window(widget &root, _pixel_t bg_color=RGB(bf, bf, bf), bool (*on_close)(window &)=0);
|
||||||
void add_keybind(struct key_packet kp, void (*handler)(window_tag_t));
|
void add_keybind(struct key_packet kp, void (*handler)(window &));
|
||||||
|
|
||||||
void notify_needs_paint(widget &from);
|
void notify_needs_paint(widget &from);
|
||||||
void notify_widget_size_change(widget &from, coord old_size);
|
void notify_widget_size_change(widget &from, coord old_size);
|
||||||
void notify_wants_movements(widget &from, enum mouse_packet::mouse_button while_down);
|
enum try_actions_return_t {NONE, GOOD, DELETE};
|
||||||
void consume_actions();
|
try_actions_return_t try_actions();
|
||||||
void show();
|
void show();
|
||||||
void focus(widget &w);
|
void focus(widget &w);
|
||||||
|
|
||||||
protected:
|
|
||||||
widget &root;
|
|
||||||
private:
|
private:
|
||||||
_window_handle_t handle;
|
_window_handle_t handle;
|
||||||
_pixel_t *pixbuf;
|
_pixel_t *pixbuf;
|
||||||
coord size;
|
coord size;
|
||||||
|
widget &root;
|
||||||
widget *focussed;
|
widget *focussed;
|
||||||
widget *drag_reciever;
|
|
||||||
enum mouse_packet::mouse_button drag_until;
|
|
||||||
_pixel_t bg_color;
|
_pixel_t bg_color;
|
||||||
bool needs_repaint;
|
bool needs_repaint;
|
||||||
void paint_full();
|
void paint_full();
|
||||||
bool (*on_close)(window_tag_t);
|
bool (*on_close)(window &);
|
||||||
window_tag_t tag;
|
dllist<duple<struct key_packet, void (*)(window &)>> keybinds;
|
||||||
map<struct key_packet, void (*)(window_tag_t), &match_side_agnostic> keybinds;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
#ifndef STRUCTS_ALIST_H
|
|
||||||
#define STRUCTS_ALIST_H
|
|
||||||
|
|
||||||
#include <knob/format.h>
|
|
||||||
#include <knob/block.h>
|
|
||||||
#include <knob/panic.h>
|
|
||||||
#include <knob/heap.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
template<class data>
|
|
||||||
class alist {
|
|
||||||
public:
|
|
||||||
uint32_t n_entries;
|
|
||||||
uint32_t buf_size;
|
|
||||||
uint32_t expand_by;
|
|
||||||
data *buf;
|
|
||||||
|
|
||||||
alist(uint32_t default_size = 10, uint32_t expand_by = 10)
|
|
||||||
: n_entries(0), buf_size(default_size), expand_by(expand_by),
|
|
||||||
buf(new data[default_size]) {}
|
|
||||||
|
|
||||||
//from is copied
|
|
||||||
alist(const data *from, uint32_t count, uint32_t extra_size = 10, uint32_t expand_by = 10)
|
|
||||||
: n_entries(count), buf_size(count + extra_size), expand_by(expand_by),
|
|
||||||
buf(new data[count + extra_size]) {
|
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
|
||||||
buf[i] = from[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
~alist() {
|
|
||||||
delete[] buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_from(const data *from, uint32_t count) {
|
|
||||||
expand_to(count);
|
|
||||||
n_entries = count;
|
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
|
||||||
buf[i] = from[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void expand_to(uint32_t size) {
|
|
||||||
if (size <= buf_size)
|
|
||||||
return;
|
|
||||||
data *const new_buf = new data[size * sizeof(data)];
|
|
||||||
for (uint32_t i = 0; i < buf_size; ++i)
|
|
||||||
new_buf[i] = buf[i];
|
|
||||||
delete[] buf;
|
|
||||||
buf = new_buf;
|
|
||||||
buf_size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_from(const alist<data> &other) {
|
|
||||||
expand_to(n_entries = other.n_entries);
|
|
||||||
for (uint32_t i = 0; i < n_entries; ++i)
|
|
||||||
buf[i] = other.buf[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_back(data d) {
|
|
||||||
if (n_entries == buf_size)
|
|
||||||
expand_to(buf_size + expand_by);
|
|
||||||
buf[n_entries++] = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(uint32_t i, data d) {
|
|
||||||
if (n_entries == buf_size)
|
|
||||||
expand_to(buf_size + expand_by);
|
|
||||||
for (uint32_t n = n_entries; n > i; --n)
|
|
||||||
buf[n] = buf[n - 1];
|
|
||||||
buf[i] = d;
|
|
||||||
++n_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(uint32_t i) {
|
|
||||||
--n_entries;
|
|
||||||
for (uint32_t n = i; n < n_entries; ++n)
|
|
||||||
buf[n] = buf[n + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
//returns -1 if not found
|
|
||||||
uint32_t index_of(data d) {
|
|
||||||
for (uint32_t i = 0; i < n_entries; ++i)
|
|
||||||
if (buf[i] == d)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,8 +1,6 @@
|
||||||
#ifndef STRUCTS_DLLIST_H
|
#ifndef STRUCTS_DLLIST_H
|
||||||
#define STRUCTS_DLLIST_H
|
#define STRUCTS_DLLIST_H
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
template<class data>
|
template<class data>
|
||||||
class dllist {
|
class dllist {
|
||||||
public:
|
public:
|
||||||
|
@ -15,34 +13,20 @@ public:
|
||||||
: next(next), prev(prev), d(d) {}
|
: next(next), prev(prev), d(d) {}
|
||||||
};
|
};
|
||||||
node *first;
|
node *first;
|
||||||
node *last;
|
|
||||||
|
|
||||||
dllist() : first(0), last(0) {}
|
dllist() : first(0) {}
|
||||||
|
|
||||||
void add_front(data d) {
|
void add_front(data d) {
|
||||||
node *const n = new node(first, 0, d);
|
node *const n = new node(first, 0, d);
|
||||||
if (first)
|
if (first)
|
||||||
first->prev = n;
|
first->prev = n;
|
||||||
first = n;
|
first = n;
|
||||||
if (!last)
|
|
||||||
last = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_back(data d) {
|
|
||||||
node *const n = new node(0, last, d);
|
|
||||||
if (last)
|
|
||||||
last->next = n;
|
|
||||||
last = n;
|
|
||||||
if (!first)
|
|
||||||
first = n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//return previous, or zero if this is the first
|
//return previous, or zero if this is the first
|
||||||
node *remove_in_place(node *n) {
|
node *remove_in_place(node *n) {
|
||||||
if (n == first)
|
if (n == first)
|
||||||
first = n->next;
|
first = n->next;
|
||||||
if (n == last)
|
|
||||||
last = n->prev;
|
|
||||||
if (n->next)
|
if (n->next)
|
||||||
n->next->prev = n->prev;
|
n->next->prev = n->prev;
|
||||||
if (n->prev)
|
if (n->prev)
|
||||||
|
@ -50,26 +34,6 @@ public:
|
||||||
delete n;
|
delete n;
|
||||||
return n->prev;
|
return n->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_remove_by_ref(data d) {
|
|
||||||
for (node *n = first; n; n = n->next)
|
|
||||||
if (&n->d == &d) {
|
|
||||||
remove_in_place(n);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//returns -1 if it isn't found
|
|
||||||
uint32_t index_of(data d) {
|
|
||||||
uint32_t i = 0;
|
|
||||||
for (const node *n = first; n; n = n->next)
|
|
||||||
if (d == n->d)
|
|
||||||
return i;
|
|
||||||
else
|
|
||||||
++i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -4,7 +4,6 @@
|
||||||
template<class at, class bt>
|
template<class at, class bt>
|
||||||
class duple {
|
class duple {
|
||||||
public:
|
public:
|
||||||
duple() : a(), b() {}
|
|
||||||
duple(at a, bt b)
|
duple(at a, bt b)
|
||||||
: a(a), b(b) {}
|
: a(a), b(b) {}
|
||||||
at a;
|
at a;
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef STRUCTS_MAP_H
|
|
||||||
#define STRUCTS_MAP_H
|
|
||||||
|
|
||||||
#include <structs/alist.h>
|
|
||||||
|
|
||||||
template<class key, class value, bool (*equals)(key, key) = &key::operator==>
|
|
||||||
class map {
|
|
||||||
public:
|
|
||||||
alist<key> keys;
|
|
||||||
alist<value> values;
|
|
||||||
|
|
||||||
map(uint32_t default_size=10, uint32_t expand_by=10)
|
|
||||||
: keys(default_size, expand_by), values(default_size, expand_by) {}
|
|
||||||
|
|
||||||
void add_pair(key k, value v) {
|
|
||||||
for (key *i = keys.buf; i < keys.buf + keys.n_entries; ++i)
|
|
||||||
if (equals(k, *i)) {
|
|
||||||
values.buf[i - keys.buf] = v;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
keys.add_back(k);
|
|
||||||
values.add_back(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((pure))
|
|
||||||
value transform(key k, value fallback=value()) {
|
|
||||||
for (key *i = keys.buf; i < keys.buf + keys.n_entries; ++i)
|
|
||||||
if (equals(k, *i))
|
|
||||||
return values.buf[i - keys.buf];
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -16,7 +16,6 @@ uint32_t strcpy(char *to, const char *from);
|
||||||
|
|
||||||
//allocates new memory
|
//allocates new memory
|
||||||
char *strdup(const char *from);
|
char *strdup(const char *from);
|
||||||
char *strndup(const char *from, uint32_t new_len);
|
|
||||||
|
|
||||||
//without null-terminator
|
//without null-terminator
|
||||||
uint32_t strlen(const char *str) __attribute__ ((pure));
|
uint32_t strlen(const char *str) __attribute__ ((pure));
|
||||||
|
|
|
@ -1,34 +1,27 @@
|
||||||
#ifndef KNOB_FILE_H
|
#ifndef KNOB_FILE_H
|
||||||
#define KNOB_FILE_H
|
#define KNOB_FILE_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pland/syscall.h>
|
#include <pland/syscall.h>
|
||||||
|
|
||||||
struct file;
|
struct file;
|
||||||
|
|
||||||
|
const char *remove_prefix(const char *path, uint8_t *dn_out);
|
||||||
|
|
||||||
struct file *open_file(const char *path);
|
struct file *open_file(const char *path);
|
||||||
void close_file(struct file *f);
|
void close_file(struct file *f);
|
||||||
|
|
||||||
uint32_t read_from_file(struct file *f, uint32_t max, void *buf);
|
uint32_t read_from_file(struct file *f, uint32_t max, void *buf);
|
||||||
uint32_t write_to_file(struct file *f, uint32_t max, const void *buf);
|
uint32_t write_to_file(struct file *f, uint32_t max, void *buf);
|
||||||
//return value and max_length don't include null terminator
|
//return value and max_length don't include null terminator
|
||||||
uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length);
|
uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length);
|
||||||
uint32_t seek_file_to(struct file *f, uint32_t to);
|
uint32_t seek_file_to(struct file *f, uint32_t to);
|
||||||
int32_t seek_file_by(struct file *f, int32_t by);
|
int32_t seek_file_by(struct file *f, int32_t by);
|
||||||
|
|
||||||
uint32_t get_file_pos(struct file *f) __attribute__ ((pure));
|
|
||||||
uint32_t file_size(struct file *f) __attribute__ ((pure));
|
uint32_t file_size(struct file *f) __attribute__ ((pure));
|
||||||
void trunc_file(struct file *f);
|
void trunc_file(struct file *f);
|
||||||
|
|
||||||
//return value must be manually freed, unless it is a null pointer
|
//return value must be manually freed, unless it is a null pointer
|
||||||
_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out);
|
_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -8,7 +8,7 @@ extern "C" {
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void *get_block(uint32_t bytes) __attribute__ ((malloc));
|
void *get_block(uint32_t bytes) __attribute__ ((malloc));
|
||||||
void free_block(const void *block);
|
void free_block(void *block);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#ifndef LIBTERM_TERMINAL_H
|
#ifndef LIBTERM_TERMINAL_H
|
||||||
#define LIBTERM_TERMINAL_H
|
#define LIBTERM_TERMINAL_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pland/syscall.h>
|
#include <pland/syscall.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -36,8 +32,4 @@ void term_addf(const char *fmt, ...);
|
||||||
|
|
||||||
struct key_packet term_get_key_blocking();
|
struct key_packet term_get_key_blocking();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -9,12 +9,12 @@ extern "C" {
|
||||||
|
|
||||||
#define BEFORE_MAIN(f) \
|
#define BEFORE_MAIN(f) \
|
||||||
__attribute__ ((section (".__pcrt_before_main"))) \
|
__attribute__ ((section (".__pcrt_before_main"))) \
|
||||||
__attribute__ ((used)) \
|
__attribute__ ((unused)) \
|
||||||
void (*const __pcrt_bm_##f)() = &f;
|
void (*const __pcrt_bm_##f)() = &f;
|
||||||
|
|
||||||
#define BEFORE_QUIT(f) \
|
#define BEFORE_QUIT(f) \
|
||||||
__attribute__ ((section (".__pcrt_before_quit"))) \
|
__attribute__ ((section (".__pcrt_before_quit"))) \
|
||||||
__attribute__ ((used)) \
|
__attribute__ ((unused)) \
|
||||||
void (*const __pcrt_bq_##f)() = &f;
|
void (*const __pcrt_bq_##f)() = &f;
|
||||||
|
|
||||||
void __pcrt_quit() __attribute__ ((noreturn));
|
void __pcrt_quit() __attribute__ ((noreturn));
|
||||||
|
|
|
@ -127,8 +127,8 @@ static inline void _exit_task() {
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _file_handle_t _open_file(const char *path) {
|
static inline _file_handle_t _open_file(_drive_number_t drive_number, const char *path) {
|
||||||
return (_file_handle_t)_sc1(_SCN_OPEN_FILE, (uint32_t)path);
|
return (_file_handle_t)_sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _close_file(_file_handle_t handle) {
|
static inline void _close_file(_file_handle_t handle) {
|
||||||
|
@ -143,8 +143,8 @@ static inline uint32_t _file_size(_file_handle_t handle) {
|
||||||
return _sc1(_SCN_FILE_SIZE, handle);
|
return _sc1(_SCN_FILE_SIZE, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _task_handle_t _start_task(const char *path, const char *pass, _task_handle_t stdio_task) {
|
static inline _task_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass, _task_handle_t stdio_task) {
|
||||||
return (_task_handle_t)_sc3(_SCN_START_TASK, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task);
|
return (_task_handle_t)_sc4(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) {
|
static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) {
|
||||||
|
@ -183,12 +183,12 @@ static inline void _wait_for_task(_task_handle_t handle) {
|
||||||
_sc1(_SCN_WAIT_FOR_TASK, handle);
|
_sc1(_SCN_WAIT_FOR_TASK, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t _enumerate_dir(const char *path, _dir_info_entry_t *buffer, uint32_t max_count) {
|
static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *path, _dir_info_entry_t *buffer, uint32_t max_count) {
|
||||||
return _sc3(_SCN_ENUMERATE_DIR, (uint32_t)path, (uint32_t)buffer, max_count);
|
return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t _count_of_dir(const char *path) {
|
static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) {
|
||||||
return _sc1(_SCN_COUNT_OF_DIR, (uint32_t)path);
|
return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline _window_handle_t _new_window(uint16_t width, uint16_t height, _pixel_t *pixel_buffer) {
|
static inline _window_handle_t _new_window(uint16_t width, uint16_t height, _pixel_t *pixel_buffer) {
|
||||||
|
|
22
src/user/include/popups/info.h
Normal file
22
src/user/include/popups/info.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef POPUPS_INFO_H
|
||||||
|
#define POPUPS_INFO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <popups/popup.h>
|
||||||
|
|
||||||
|
#include <pland/syscall.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
void info_popup(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg);
|
||||||
|
void info_popupf(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, ...);
|
||||||
|
void info_popupf_v(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, va_list args);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
22
src/user/include/popups/popup.h
Normal file
22
src/user/include/popups/popup.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef POPUPS_POPUP_H
|
||||||
|
#define POPUPS_POPUP_H
|
||||||
|
|
||||||
|
#include <pland/syscall.h>
|
||||||
|
|
||||||
|
struct popup {
|
||||||
|
_window_handle_t handle;
|
||||||
|
_pixel_t *pixbuf;
|
||||||
|
|
||||||
|
bool has_quit;
|
||||||
|
struct key_packet quit_as;
|
||||||
|
|
||||||
|
//terminated by one with .key_id == 0
|
||||||
|
const struct key_packet *quit_binds;
|
||||||
|
};
|
||||||
|
|
||||||
|
void handle_actions(struct popup *p);
|
||||||
|
//deletes popup before returning
|
||||||
|
void make_modal(struct popup *p);
|
||||||
|
void delete_popup(struct popup *p);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,8 +1,7 @@
|
||||||
#include <knob/block.h>
|
|
||||||
#include <knob/file.h>
|
#include <knob/file.h>
|
||||||
#include <knob/task.h>
|
#include <knob/task.h>
|
||||||
|
|
||||||
#define STARTUP_FILE_PATH "/sys/startup.rc"
|
#define STARTUP_FILE_PATH "sys/startup.rc"
|
||||||
#define CMD_BUF_LEN 1024
|
#define CMD_BUF_LEN 1024
|
||||||
|
|
||||||
char cmdbuf[CMD_BUF_LEN];
|
char cmdbuf[CMD_BUF_LEN];
|
||||||
|
@ -17,9 +16,11 @@ void main() {
|
||||||
while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) {
|
while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) {
|
||||||
if (cmdbuf[0] == '#')
|
if (cmdbuf[0] == '#')
|
||||||
continue;
|
continue;
|
||||||
bool started = (bool)run_command(cmdbuf, 0);
|
//syslogf(run_command(cmdbuf)
|
||||||
str_trunc_fill(cmdbuf, 30);
|
// ? "[init] Started %s."
|
||||||
syslogf(started ? "Started %s" : "Could not start %s", cmdbuf);
|
// : "[init] Could not run %s."
|
||||||
|
//, cmdbuf);
|
||||||
|
run_command(cmdbuf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
close_file(f);
|
close_file(f);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#include <knob/panic.h>
|
|
||||||
#include <knob/block.h>
|
|
||||||
#include <knob/heap.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <knob/heap.h>
|
||||||
|
|
||||||
//unsophisticated, should copy by dwords where available
|
//unsophisticated, should copy by dwords where available
|
||||||
void blockcpy(void *to, const void *from, uint32_t size) {
|
void blockcpy(void *to, const void *from, uint32_t size) {
|
||||||
|
@ -29,22 +27,11 @@ uint32_t strcpy(char *to, const char *from) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strdup(const char *from) {
|
char *strdup(const char *from) {
|
||||||
const uint32_t len = strlen(from) + 1;
|
const char *end = from;
|
||||||
char *buf = get_block(len);
|
while (*(end++))
|
||||||
blockcpy(buf, from, len);
|
;
|
||||||
return buf;
|
char *buf = get_block(end - from);
|
||||||
}
|
blockcpy(buf, from, end - from);
|
||||||
|
|
||||||
char *strndup(const char *from, uint32_t n) {
|
|
||||||
uint32_t len = strlen(from) + 1;
|
|
||||||
if (n < len) {
|
|
||||||
char *buf = get_block(n + 1);
|
|
||||||
blockcpy(buf, from, n);
|
|
||||||
buf[n] = '\0';
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
char *buf = get_block(len);
|
|
||||||
blockcpy(buf, from, len);
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct file {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file *open_file(const char *path) {
|
struct file *open_file(const char *path) {
|
||||||
_file_handle_t h = _open_file(path);
|
_file_handle_t h = _open_file(0, path);
|
||||||
if (!h)
|
if (!h)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ uint32_t read_from_file(struct file *f, uint32_t max, void *buf) {
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t write_to_file(struct file *f, uint32_t max, const void *buf) {
|
uint32_t write_to_file(struct file *f, uint32_t max, void *buf) {
|
||||||
if (f->position + max > f->length)
|
if (f->position + max > f->length)
|
||||||
_set_file_size(f->handle, f->length = f->position + max);
|
_set_file_size(f->handle, f->length = f->position + max);
|
||||||
|
|
||||||
|
@ -109,11 +109,6 @@ int32_t seek_file_by(struct file *f, int32_t by) {
|
||||||
return to - old;
|
return to - old;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((pure))
|
|
||||||
uint32_t get_file_pos(struct file *f) {
|
|
||||||
return f->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((pure))
|
__attribute__ ((pure))
|
||||||
uint32_t file_size(struct file *f) {
|
uint32_t file_size(struct file *f) {
|
||||||
return f->length;
|
return f->length;
|
||||||
|
@ -125,13 +120,13 @@ void trunc_file(struct file *f) {
|
||||||
|
|
||||||
//return value must be manually freed, unless it is a null pointer
|
//return value must be manually freed, unless it is a null pointer
|
||||||
_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out) {
|
_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out) {
|
||||||
uint32_t count = _count_of_dir(path);
|
uint32_t count = _count_of_dir(0, path);
|
||||||
if (!count) {
|
if (!count) {
|
||||||
*count_out = 0;
|
*count_out = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dir_info_entry_t *buffer = get_block(count * sizeof(_dir_info_entry_t));
|
_dir_info_entry_t *buffer = get_block(count * sizeof(_dir_info_entry_t));
|
||||||
*count_out = _enumerate_dir(path, buffer, count);
|
*count_out = _enumerate_dir(0, path, buffer, count);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
|
@ -1,141 +1,114 @@
|
||||||
|
#include <knob/format.h>
|
||||||
|
|
||||||
#include <pland/syscall.h>
|
#include <pland/syscall.h>
|
||||||
#include <pland/pcrt.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MIN_NEW_CHUNK_PAGES 16
|
//structure appears at the start of each block
|
||||||
|
struct block_header {
|
||||||
|
struct block_header *next;
|
||||||
|
struct block_header *prev;
|
||||||
|
|
||||||
struct desc_page_head {
|
//does not include header
|
||||||
void *next_page;//0 for last one
|
uint32_t length;
|
||||||
|
bool allocated;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chunk_desc {
|
static struct block_header *first_block = 0;
|
||||||
void *start;//0 for a desc not in use
|
|
||||||
uint32_t length;
|
|
||||||
bool available;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
//without packing, it is 12 bytes and we get 341 per page
|
|
||||||
//with packing, it is 9 bytes and we get 454 per page
|
|
||||||
//maybe i should make available just the top bit of length
|
|
||||||
//then we get 511 per page, but length has a max of 2^31-1
|
|
||||||
|
|
||||||
static struct desc_page_head *first_desc_page = 0;
|
static void add_header(struct block_header *bh) {
|
||||||
static struct desc_page_head *last_desc_page = 0;
|
bh->next = first_block;
|
||||||
|
bh->prev = 0;
|
||||||
#define DESCS_PER_PAGE ((4096 - sizeof(struct desc_page_head)) / sizeof(struct chunk_desc))
|
if (first_block)
|
||||||
#define PAGE_AS_ARRAY(p) ((struct chunk_desc *)((void *)p + sizeof(struct desc_page_head)))
|
first_block->prev = bh;
|
||||||
|
first_block = bh;
|
||||||
static char size_was_buf[] = "size was ......... kB";
|
|
||||||
//kb should be < 1 000 000 000
|
|
||||||
static void log_size_was(uint32_t kb) {
|
|
||||||
for (int8_t d = 9; d != -1; --d) {
|
|
||||||
size_was_buf[9 + d] = (kb % 10) + '0';
|
|
||||||
kb /= 10;
|
|
||||||
}
|
|
||||||
_system_log(size_was_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *const hextab = "0123456789abcdef";
|
|
||||||
static char caller_was_buf[] = "return address is 0x........";
|
|
||||||
static void log_caller_was(void *addr) {
|
|
||||||
const uint32_t as_int = (uint32_t)addr;
|
|
||||||
for (uint8_t i = 0; i < 8; ++i)
|
|
||||||
caller_was_buf[27 - i] = hextab[(as_int >> (4 * i)) & 0xf];
|
|
||||||
_system_log(caller_was_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct desc_page_head *new_desc_page() {
|
|
||||||
struct desc_page_head *dph = _allocate_ram(1);
|
|
||||||
if (!dph) {
|
|
||||||
_system_log("knob heap could not allocate new descriptor page");
|
|
||||||
log_size_was(4);
|
|
||||||
__pcrt_quit();
|
|
||||||
}
|
|
||||||
dph->next_page = 0;
|
|
||||||
if (last_desc_page)
|
|
||||||
last_desc_page->next_page = dph;
|
|
||||||
last_desc_page = dph;
|
|
||||||
|
|
||||||
struct chunk_desc *const a = PAGE_AS_ARRAY(dph);
|
|
||||||
for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i)
|
|
||||||
a[i].start = 0;
|
|
||||||
|
|
||||||
return dph;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct chunk_desc *unused_desc() {
|
|
||||||
for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) {
|
|
||||||
struct chunk_desc *const a = PAGE_AS_ARRAY(i);
|
|
||||||
for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i)
|
|
||||||
if (!a[i].start)
|
|
||||||
return a + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PAGE_AS_ARRAY(new_desc_page());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((malloc))
|
__attribute__ ((malloc))
|
||||||
void *get_block(uint32_t bytes) {
|
void *get_block(uint32_t bytes) {
|
||||||
if (!first_desc_page)
|
struct block_header *header = 0;
|
||||||
first_desc_page = new_desc_page();
|
for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) {
|
||||||
|
if (ptr->allocated)
|
||||||
struct chunk_desc *best_fit = 0;
|
|
||||||
|
|
||||||
for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) {
|
|
||||||
struct chunk_desc *const a = PAGE_AS_ARRAY(i);
|
|
||||||
for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i) {
|
|
||||||
if (!a[i].start || !a[i].available || (a[i].length < bytes))
|
|
||||||
continue;
|
continue;
|
||||||
if (a[i].length == bytes) {
|
if (ptr->length == bytes) {
|
||||||
a[i].available = false;
|
header = ptr;
|
||||||
return a[i].start;
|
break;
|
||||||
}
|
}
|
||||||
if (!best_fit || (a[i].length < best_fit->length))
|
if (ptr->length > bytes + sizeof(struct block_header)) {
|
||||||
best_fit = a + i;
|
struct block_header *bh = (void *)ptr + sizeof(struct block_header) + bytes;
|
||||||
|
|
||||||
|
bh->length = ptr->length - sizeof(struct block_header) - bytes;
|
||||||
|
bh->allocated = false;
|
||||||
|
add_header(bh);
|
||||||
|
|
||||||
|
ptr->length = bytes;
|
||||||
|
header = ptr;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!best_fit) {
|
if (!header) {
|
||||||
const uint32_t pages_needed = (bytes - 1) / 4096 + 1;
|
uint32_t size_with_header = bytes + sizeof(struct block_header);
|
||||||
const uint32_t allocating = pages_needed < MIN_NEW_CHUNK_PAGES ? MIN_NEW_CHUNK_PAGES : pages_needed;
|
if (!(size_with_header % 4096)) {
|
||||||
void *const new_chunk = _allocate_ram(allocating);
|
header = _allocate_ram(size_with_header / 4096);
|
||||||
if (!new_chunk) {
|
if (!header)
|
||||||
_system_log("knob heap could not allocate new chunk");
|
return 0;
|
||||||
log_size_was(allocating * 4);
|
header->length = bytes;
|
||||||
log_caller_was(__builtin_return_address(0));
|
add_header(header);
|
||||||
__pcrt_quit();
|
|
||||||
}
|
}
|
||||||
best_fit = unused_desc();
|
else {
|
||||||
best_fit->start = new_chunk;
|
uint32_t pages = (bytes + sizeof(struct block_header) * 2) / 4096 + 1;
|
||||||
best_fit->length = allocating * 4096;
|
header = _allocate_ram(pages);
|
||||||
|
if (!header)
|
||||||
|
return 0;
|
||||||
|
header->length = bytes;
|
||||||
|
add_header(header);
|
||||||
|
|
||||||
if (bytes == allocating * 4096) {
|
struct block_header *bh = (void *)header + sizeof(struct block_header) + bytes;
|
||||||
best_fit->available = false;
|
bh->length = pages * 4096 - bytes - 2 * sizeof(struct block_header);
|
||||||
return new_chunk;
|
bh->allocated = false;
|
||||||
|
add_header(bh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *const old_end = best_fit->start + best_fit->length;
|
header->allocated = true;
|
||||||
void *const new_end = best_fit->start + bytes;
|
return (void *)header + sizeof(struct block_header);
|
||||||
|
|
||||||
best_fit->length = bytes;
|
|
||||||
best_fit->available = false;
|
|
||||||
|
|
||||||
struct chunk_desc *const leftover = unused_desc();
|
|
||||||
leftover->start = new_end;
|
|
||||||
leftover->length = old_end - new_end;
|
|
||||||
|
|
||||||
return best_fit->start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_block(const void *block) {
|
static void remove_header(struct block_header *bh) {
|
||||||
for (struct desc_page_head *i = first_desc_page; i; i = i->next_page) {
|
if (bh == first_block)
|
||||||
struct chunk_desc *const a = PAGE_AS_ARRAY(i);
|
first_block = bh->next;
|
||||||
for (uint32_t i = 0; i < DESCS_PER_PAGE; ++i)
|
if (bh->prev)
|
||||||
if (a[i].start == block) {
|
bh->prev->next = bh->next;
|
||||||
//TODO: consolidate this with surrounding free chunks
|
if (bh->next)
|
||||||
a[i].available = true;
|
bh->next->prev = bh->prev;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
void free_block(void *block) {
|
||||||
|
struct block_header *header = block - sizeof(struct block_header);
|
||||||
|
|
||||||
|
header->allocated = false;
|
||||||
|
|
||||||
|
void *after = block + header->length;
|
||||||
|
for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) {
|
||||||
|
if (ptr == after) {
|
||||||
|
if (!ptr->allocated) {
|
||||||
|
header->length += ptr->length + sizeof(struct block_header);
|
||||||
|
remove_header(ptr);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//we traverse the linked list twice. it would probably be more efficient
|
||||||
|
//to do both finding the after and finding the before in the same loop.
|
||||||
|
for (struct block_header *ptr = first_block; ptr; ptr = ptr->next)
|
||||||
|
if ((void *)ptr + sizeof(struct block_header) + ptr->length == header) {
|
||||||
|
if (!ptr->allocated) {
|
||||||
|
ptr->length += sizeof(struct block_header) + header->length;
|
||||||
|
remove_header(header);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,12 +14,12 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
|
||||||
blockcpy(new_path, path, ptr - path);
|
blockcpy(new_path, path, ptr - path);
|
||||||
new_path[ptr - path] = '\0';
|
new_path[ptr - path] = '\0';
|
||||||
|
|
||||||
_task_handle_t handle = _start_task(new_path, ptr + 1, stdio_task);
|
_task_handle_t handle = _start_task(0, new_path, ptr + 1, stdio_task);
|
||||||
free_block(new_path);
|
free_block(new_path);
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _start_task(path, "", stdio_task);
|
return _start_task(0, path, "", stdio_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) {
|
bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) {
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include "bdf.h"
|
#include "bdf.h"
|
||||||
#include "pbf.h"
|
#include "pbf.h"
|
||||||
|
|
||||||
#define FONT_PATH "/fonts/"
|
#define FONT_PATH "fonts/"
|
||||||
#define FONT_PATH_L 7
|
#define FONT_PATH_L 6
|
||||||
|
|
||||||
struct font_loader_t {
|
struct font_loader_t {
|
||||||
const char *ext;
|
const char *ext;
|
||||||
|
|
42
src/user/mdemo/main.c
Normal file
42
src/user/mdemo/main.c
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include <pland/syscall.h>
|
||||||
|
#include <popups/info.h>
|
||||||
|
|
||||||
|
#define TEXT_COLOR ((_pixel_t){.r = 0x00, .g = 0x00, .b = 0x00})
|
||||||
|
#define BG_COLOR ((_pixel_t){.r = 0xbf, .g = 0xbf, .b = 0xbf})
|
||||||
|
|
||||||
|
static const char *const mb_names[] = {
|
||||||
|
"left", "right", "middle"
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
struct popup main_win;
|
||||||
|
info_popup(&main_win, "Click me!", TEXT_COLOR, BG_COLOR);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct window_action winact;
|
||||||
|
_get_win_action(main_win.handle, &winact);
|
||||||
|
|
||||||
|
switch (winact.action_type) {
|
||||||
|
struct popup modal;
|
||||||
|
case NOT_READY:
|
||||||
|
_wait_for_action();
|
||||||
|
_yield_task();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case KEY_DOWN:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case MOUSE_DOWN:
|
||||||
|
info_popupf(&modal,
|
||||||
|
"Got %s click at (%d, %d)!",
|
||||||
|
TEXT_COLOR, BG_COLOR,
|
||||||
|
mb_names[winact.as_mouse.which],
|
||||||
|
winact.as_mouse.x, winact.as_mouse.y);
|
||||||
|
make_modal(&modal);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,50 @@
|
||||||
|
#include <raleigh/w/padding.h>
|
||||||
|
#include <raleigh/w/vbox.h>
|
||||||
#include <raleigh/w/label.h>
|
#include <raleigh/w/label.h>
|
||||||
|
|
||||||
#include <raleigh/runtime.h>
|
#include <raleigh/runtime.h>
|
||||||
#include <raleigh/window.h>
|
#include <raleigh/window.h>
|
||||||
|
|
||||||
#include <pland/syscall.h>
|
#include <pland/syscall.h>
|
||||||
#include <knob/format.h>
|
#include <knob/format.h>
|
||||||
|
#include <pland/pcrt.h>
|
||||||
|
|
||||||
using namespace raleigh;
|
using namespace raleigh;
|
||||||
|
|
||||||
label *l;
|
label *kmem;
|
||||||
|
label *umem;
|
||||||
|
|
||||||
void refresh(window_tag_t) {
|
void refresh(window &w) {
|
||||||
char *fmt = format("Kernel memory free: %ukB\nUser memory free: %ukB\nF5 to refresh, Alt+F4 to quit", _kernel_dynamic_area_left() * 4, _total_userspace_left() * 4);
|
char *const kstr = format("kernel memory free: %uk", _kernel_dynamic_area_left() * 4);
|
||||||
l->change_value(fmt);
|
char *const ustr = format("userspace memory free: %uk / %uk", _total_userspace_left() * 4, _total_userspace_size() * 4);
|
||||||
free_block(fmt);
|
|
||||||
|
kmem->change_value(kstr);
|
||||||
|
umem->change_value(ustr);
|
||||||
|
|
||||||
|
free_block(kstr);
|
||||||
|
free_block(ustr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
l = new label("");
|
kmem = new label("");
|
||||||
|
umem = new label("");
|
||||||
|
label msg("press Alt+F4 to quit, or F5 to refresh");
|
||||||
|
|
||||||
window w(*l);
|
padding pkmem(*kmem, 1);
|
||||||
w.add_keybind((key_packet){.key_id = key_packet::KEY_F5, .modifiers = key_packet::NO_MODS}, &refresh);
|
padding pumem(*umem, 1);
|
||||||
refresh(0);
|
padding pmsg(msg, 1);
|
||||||
|
|
||||||
|
dllist<widget &> ll;
|
||||||
|
ll.add_front(pmsg);
|
||||||
|
ll.add_front(pumem);
|
||||||
|
ll.add_front(pkmem);
|
||||||
|
vbox box(ll);
|
||||||
|
|
||||||
|
padding pbox(box, 3);
|
||||||
|
window w(pbox, RGB(bf, bf, bf), (bool (*)(window &))&__pcrt_quit);
|
||||||
|
w.add_keybind((struct key_packet){.key_id = key_packet::KEY_F5, .modifiers = key_packet::NO_MODS}, &refresh);
|
||||||
|
|
||||||
|
refresh(w);
|
||||||
|
|
||||||
w.show();
|
w.show();
|
||||||
start_runtime();
|
start_runtime();
|
||||||
|
|
36
src/user/mkpopup/main.c
Normal file
36
src/user/mkpopup/main.c
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include <popups/info.h>
|
||||||
|
|
||||||
|
#include <knob/heap.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void main(const char *text) {
|
||||||
|
uint32_t required_new_length = 0;
|
||||||
|
bool needs_new = false;
|
||||||
|
for (const char *c = text; c[0]; ++c) {
|
||||||
|
++required_new_length;
|
||||||
|
if ((c[0] == '\\') && (c[1] == 'n')) {
|
||||||
|
++c;
|
||||||
|
needs_new = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needs_new) {
|
||||||
|
char *new_text = get_block(required_new_length);
|
||||||
|
const char *ci;
|
||||||
|
char *co;
|
||||||
|
for (ci = text, co = new_text; *ci; ++ci, ++co)
|
||||||
|
if ((ci[0] == '\\') && (ci[1] == 'n')) {
|
||||||
|
*co = '\n';
|
||||||
|
++ci;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*co = *ci;
|
||||||
|
text = new_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct popup p;
|
||||||
|
info_popup(&p, text, (_pixel_t){.r = 0, .g = 0, .b = 0}, (_pixel_t){.r = 0xbf, .g = 0xbf, .b = 0xbf});
|
||||||
|
make_modal(&p);
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
#include <raleigh/w/padding.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/window.h>
|
|
||||||
|
|
||||||
using namespace raleigh;
|
|
||||||
|
|
||||||
void main(const char *text) {
|
|
||||||
char *unescaped = new char[strlen(text) + 1];
|
|
||||||
char *ui = unescaped;
|
|
||||||
while (1) {
|
|
||||||
const uint32_t len = str_find_any(text, "\\");
|
|
||||||
if (len) {
|
|
||||||
blockcpy(ui, text, len);
|
|
||||||
text += len;
|
|
||||||
ui += len;
|
|
||||||
}
|
|
||||||
if (!*text)
|
|
||||||
break;
|
|
||||||
if (text[1] == 'n') {
|
|
||||||
*(ui++) = '\n';
|
|
||||||
text += 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*(ui++) = '\\';
|
|
||||||
++text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*ui = '\0';
|
|
||||||
|
|
||||||
label l(unescaped);
|
|
||||||
delete[] unescaped;
|
|
||||||
padding p(l, 4);
|
|
||||||
window w(p);
|
|
||||||
|
|
||||||
w.show();
|
|
||||||
start_runtime();
|
|
||||||
}
|
|
77
src/user/popups/info.c
Normal file
77
src/user/popups/info.c
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <popups/popup.h>
|
||||||
|
|
||||||
|
#include <libfont/fonts.h>
|
||||||
|
|
||||||
|
#include <knob/format.h>
|
||||||
|
#include <knob/heap.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define PADDING 6
|
||||||
|
#define FONT "fixed-10"
|
||||||
|
|
||||||
|
static const struct font_info *info_font = 0;
|
||||||
|
|
||||||
|
static const struct key_packet info_quits[] = {
|
||||||
|
{ .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
|
||||||
|
{ .key_id = 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
void info_popup(struct popup *into, const char *msg, _pixel_t fg, _pixel_t bg) {
|
||||||
|
if (!info_font)
|
||||||
|
info_font = get_font(FONT);
|
||||||
|
|
||||||
|
uint32_t w = 0, h = 1, lw = 0;
|
||||||
|
for (const char *i = msg; *i; ++i)
|
||||||
|
if (*i == '\n') {
|
||||||
|
++h;
|
||||||
|
if (lw > w)
|
||||||
|
w = lw;
|
||||||
|
lw = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++lw;
|
||||||
|
if (lw > w)
|
||||||
|
w = lw;
|
||||||
|
|
||||||
|
into->has_quit = false;
|
||||||
|
into->quit_binds = (struct key_packet *)info_quits;
|
||||||
|
|
||||||
|
const uint32_t pitch = info_font->space_width * w + 2 * PADDING;
|
||||||
|
const uint32_t height = info_font->space_height * h + 2 * PADDING;
|
||||||
|
|
||||||
|
_pixel_t *const pixbuf = get_block(pitch * height * 4);
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < height; ++y)
|
||||||
|
for (uint32_t x = 0; x < pitch; ++x)
|
||||||
|
pixbuf[y * pitch + x] = bg;
|
||||||
|
|
||||||
|
uint32_t my = 0;
|
||||||
|
uint32_t mx = 0;
|
||||||
|
--msg;
|
||||||
|
while (*++msg) {
|
||||||
|
if (*msg == '\n') {
|
||||||
|
++my;
|
||||||
|
mx = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
put_char(info_font, *msg, pixbuf + (my * info_font->space_height + PADDING) * pitch + mx++ * info_font->space_width + PADDING, pitch, bg, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
into->pixbuf = pixbuf;
|
||||||
|
into->handle = _new_window(pitch, height, pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void info_popupf_v(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, va_list args) {
|
||||||
|
char *const msg = format_v(text, args);
|
||||||
|
info_popup(into, msg, fg, bg);
|
||||||
|
free_block(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void info_popupf(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, bg);
|
||||||
|
info_popupf_v(into, text, fg, bg, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
43
src/user/popups/popup.c
Normal file
43
src/user/popups/popup.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <popups/popup.h>
|
||||||
|
|
||||||
|
#include <knob/format.h>
|
||||||
|
#include <knob/heap.h>
|
||||||
|
|
||||||
|
#include <pland/syscall.h>
|
||||||
|
|
||||||
|
void handle_actions(struct popup *p) {
|
||||||
|
if (p->has_quit)
|
||||||
|
return;
|
||||||
|
struct window_action a;
|
||||||
|
while (1) {
|
||||||
|
_get_win_action(p->handle, &a);
|
||||||
|
if (a.action_type == NOT_READY)
|
||||||
|
return;
|
||||||
|
if ((a.action_type == KEY_DOWN)) {
|
||||||
|
//syslogf("got key 0x%2x, 0x%3x", a.as_key.key_id, a.as_key.modifiers);
|
||||||
|
for (const struct key_packet *kp = p->quit_binds; kp->key_id; ++kp) {
|
||||||
|
//syslogf("checking against 0x%2x, 0x%3x", kp->key_id, kp->modifiers);
|
||||||
|
if ((a.as_key.key_id == kp->key_id) && (a.as_key.modifiers == kp->modifiers)) {
|
||||||
|
p->has_quit = true;
|
||||||
|
p->quit_as = a.as_key;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_popup(struct popup *p) {
|
||||||
|
_delete_window(p->handle);
|
||||||
|
free_block(p->pixbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_modal(struct popup *p) {
|
||||||
|
handle_actions(p);
|
||||||
|
while (!p->has_quit) {
|
||||||
|
_wait_for_action();
|
||||||
|
_yield_task();
|
||||||
|
handle_actions(p);
|
||||||
|
}
|
||||||
|
delete_popup(p);
|
||||||
|
}
|
|
@ -1,89 +0,0 @@
|
||||||
#include <raleigh/d/dialog.h>
|
|
||||||
|
|
||||||
#include <raleigh/w/padding.h>
|
|
||||||
#include <raleigh/w/button.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/w/hbox.h>
|
|
||||||
|
|
||||||
using namespace raleigh;
|
|
||||||
|
|
||||||
void dialog::show_modal() {
|
|
||||||
show();
|
|
||||||
do {
|
|
||||||
_wait_for_action();
|
|
||||||
_yield_task();
|
|
||||||
consume_actions();
|
|
||||||
} while (!result);
|
|
||||||
to_be_deleted.add_back(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool on_diag_close(window_tag_t) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct diag_and_result {
|
|
||||||
dialog *d;
|
|
||||||
diag_result_t r;
|
|
||||||
diag_and_result(dialog *d, diag_result_t r)
|
|
||||||
: d(d), r(r) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void set_diag_result(button_tag_t tag) {
|
|
||||||
const diag_and_result *const cast = (const diag_and_result *)tag;
|
|
||||||
cast->d->result = cast->r;
|
|
||||||
//TODO: go through all of raleigh and add destructors
|
|
||||||
//in this case, delete all of these tags when the window is closed
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog::dialog(widget &top_part, alist<duple<const char *, diag_result_t>> buttons)
|
|
||||||
: window(*new vbox(), RGB(bf, bf, bf), &on_diag_close), result(0), main_box((vbox *)&root) {
|
|
||||||
dllist<widget &> *button_row = new dllist<widget &>();
|
|
||||||
for (duple<const char *, diag_result_t> *i = buttons.buf; i < buttons.buf + buttons.n_entries; ++i) {
|
|
||||||
label *l = new label(i->a);
|
|
||||||
padding *p = new padding(*l, 4);
|
|
||||||
button *b = new button(*p, &set_diag_result, new diag_and_result(this, i->b));
|
|
||||||
padding *pb = new padding(*b, 2);
|
|
||||||
button_row->add_back(*pb);
|
|
||||||
}
|
|
||||||
hbox *button_box = new hbox(*button_row);
|
|
||||||
|
|
||||||
padding *ptop = new padding(top_part, 2);
|
|
||||||
padding *pbot = new padding(*button_box, 2);
|
|
||||||
|
|
||||||
main_box->add_end(*ptop);
|
|
||||||
main_box->add_end(*pbot);
|
|
||||||
}
|
|
||||||
|
|
||||||
button_list &mk_yes_no_cancel() {
|
|
||||||
button_list *list = new button_list(3, 1);
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Yes", YES));
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("No", NO));
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL));
|
|
||||||
return *list;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_list &mk_yes_no_retry() {
|
|
||||||
button_list *list = new button_list(3, 1);
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Yes", YES));
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("No", NO));
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Retry", RETRY));
|
|
||||||
return *list;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_list &mk_okay_cancel() {
|
|
||||||
button_list *list = new button_list(2, 1);
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Okay", OKAY));
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL));
|
|
||||||
return *list;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_list &mk_okay() {
|
|
||||||
button_list *list = new button_list(1, 1);
|
|
||||||
list->add_back(duple<const char *, diag_result_t>("Okay", OKAY));
|
|
||||||
return *list;
|
|
||||||
}
|
|
||||||
|
|
||||||
button_list &raleigh::yes_no_cancel(mk_yes_no_cancel());
|
|
||||||
button_list &raleigh::yes_no_retry(mk_yes_no_retry());
|
|
||||||
button_list &raleigh::okay_cancel(mk_okay_cancel());
|
|
||||||
button_list &raleigh::okay(mk_okay());
|
|
|
@ -1,55 +0,0 @@
|
||||||
#include <raleigh/d/saving_window.h>
|
|
||||||
#include <raleigh/d/dialog.h>
|
|
||||||
|
|
||||||
#include <raleigh/w/padding.h>
|
|
||||||
#include <raleigh/w/button.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/w/hbox.h>
|
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
|
|
||||||
#include <structs/dllist.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
bool on_saving_window_close(window_tag_t tag) {
|
|
||||||
saving_window *const sw = (saving_window *)tag;
|
|
||||||
if (sw->is_saved)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
label text("There is unsaved content in this window.");
|
|
||||||
label text2("Would you like to save before closing it?");
|
|
||||||
|
|
||||||
dllist<widget &> rows;
|
|
||||||
rows.add_back(text);
|
|
||||||
rows.add_back(text2);
|
|
||||||
vbox vb(rows);
|
|
||||||
padding vbp(vb, 2);
|
|
||||||
|
|
||||||
dialog diag(vbp, yes_no_cancel);
|
|
||||||
diag.show_modal();
|
|
||||||
|
|
||||||
switch (diag.result) {
|
|
||||||
case YES:
|
|
||||||
save:
|
|
||||||
if (!sw->save_func(sw->save_tag)) {
|
|
||||||
label text3("Failing saved. Still quit?");
|
|
||||||
dialog diag2(text3, yes_no_retry);
|
|
||||||
diag2.show_modal();
|
|
||||||
switch (diag2.result) {
|
|
||||||
case YES:
|
|
||||||
return true;
|
|
||||||
case RETRY:
|
|
||||||
goto save;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case NO:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
saving_window::saving_window(bool (*save_func)(save_tag_t), save_tag_t save_tag, widget &root, _pixel_t bg_color)
|
|
||||||
: window(root, bg_color, &on_saving_window_close, (window_tag_t)this), is_saved(true), save_func(save_func), save_tag(save_tag) {}
|
|
||||||
}
|
|
|
@ -4,24 +4,19 @@
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
dllist<window &> open_windows;
|
dllist<window &> open_windows;
|
||||||
dllist<window &> to_be_deleted;
|
|
||||||
|
|
||||||
__attribute__ ((noreturn))
|
__attribute__ ((noreturn))
|
||||||
void start_runtime() {
|
void start_runtime() {
|
||||||
while (1) {
|
while (1) {
|
||||||
for (dllist<window &>::node *w = open_windows.first; w; w = w->next)
|
|
||||||
w->d.consume_actions();
|
|
||||||
l:
|
|
||||||
for (dllist<window &>::node *w = to_be_deleted.first; w; w = w->next) {
|
|
||||||
_delete_window(w->d.handle);
|
|
||||||
w->d.handle = 0;
|
|
||||||
open_windows.try_remove_by_ref(w->d);
|
|
||||||
w = to_be_deleted.remove_in_place(w);
|
|
||||||
if (!w)
|
|
||||||
goto l;
|
|
||||||
}
|
|
||||||
if (!open_windows.first)
|
if (!open_windows.first)
|
||||||
__pcrt_quit();
|
__pcrt_quit();
|
||||||
|
for (dllist<window &>::node *w = open_windows.first; w; w = w->next)
|
||||||
|
if (w->d.try_actions() == window::DELETE) {
|
||||||
|
_delete_window(w->d.handle);
|
||||||
|
w->d.handle = 0;
|
||||||
|
if (!(w = open_windows.remove_in_place(w)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
_wait_for_action();
|
_wait_for_action();
|
||||||
_yield_task();
|
_yield_task();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
#include <raleigh/s/text_flower.h>
|
|
||||||
#include <knob/block.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
text_flower::text_flower(const char *s, uint32_t cols, uint32_t max_rows)
|
|
||||||
: s(s), lines(max_rows ? max_rows : 10), offsets(max_rows ? max_rows : 10),
|
|
||||||
max_rows(max_rows), cols(cols) {
|
|
||||||
flow_text();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((pure))
|
|
||||||
uint32_t text_flower::get_n_lines() {
|
|
||||||
return lines.n_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((pure))
|
|
||||||
char *text_flower::get_nth_line(uint32_t n) {
|
|
||||||
return lines.buf[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((pure))
|
|
||||||
uint32_t text_flower::get_line_offset(uint32_t n) {
|
|
||||||
return offsets.buf[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
void text_flower::draw_text(_pixel_t *start, uint32_t pitch, const struct font_info *fi, _pixel_t color) {
|
|
||||||
for (uint32_t y = 0; y < lines.n_entries; ++y) {
|
|
||||||
const char *line = lines.buf[y];
|
|
||||||
for (uint32_t x = 0; line[x]; ++x)
|
|
||||||
put_char_no_bg(fi, line[x], start + y * fi->space_height * pitch + x * fi->space_width, pitch, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void text_flower::push_line() {
|
|
||||||
lines.add_back(strndup(line_start, row_len));
|
|
||||||
offsets.add_back(line_start - s);
|
|
||||||
line_start = on_char;
|
|
||||||
row_len = 0;
|
|
||||||
if (max_rows && (lines.n_entries == max_rows))
|
|
||||||
on_char = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void text_flower::flow_text() {
|
|
||||||
for (uint32_t i = 0; i < lines.n_entries; ++i)
|
|
||||||
free_block(lines.buf[i]);
|
|
||||||
|
|
||||||
lines.n_entries = 0;
|
|
||||||
offsets.n_entries = 0;
|
|
||||||
line_start = on_char = s;
|
|
||||||
row_len = 0;
|
|
||||||
|
|
||||||
while (*on_char) {
|
|
||||||
if (*on_char == '\n') {
|
|
||||||
++on_char;
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (*on_char == ' ') {
|
|
||||||
++on_char;
|
|
||||||
if (row_len != 0) {
|
|
||||||
if (++row_len == cols)
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++line_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
uint32_t word_len = str_find_any(on_char, " \n");
|
|
||||||
if (!cols) {
|
|
||||||
row_len += word_len;
|
|
||||||
on_char += word_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (row_len + word_len <= cols) {
|
|
||||||
row_len += word_len;
|
|
||||||
on_char += word_len;
|
|
||||||
if (row_len == cols)
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (word_len > cols) {
|
|
||||||
on_char += cols - row_len;
|
|
||||||
row_len = cols;
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (row_len && (!max_rows || (lines.n_entries != max_rows)))
|
|
||||||
push_line();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include <raleigh/d/dialog.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/util.h>
|
#include <raleigh/util.h>
|
||||||
#include <knob/format.h>
|
#include <popups/info.h>
|
||||||
#include <pland/pcrt.h>
|
#include <pland/pcrt.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
|
@ -15,21 +13,9 @@ namespace raleigh {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
||||||
syslogf_v(fmt, args);
|
struct popup info;
|
||||||
|
info_popupf_v(&info, fmt, RGB(7f, 00, 00), RGB(bf, bf, bf), args);
|
||||||
__pcrt_quit();
|
make_modal(&info);
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((noreturn))
|
|
||||||
void show_error_popup_and_quitf(const char *fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
char *ch = format_v(fmt, args);
|
|
||||||
label l(ch);
|
|
||||||
|
|
||||||
dialog d(l, okay);
|
|
||||||
d.show_modal();
|
|
||||||
|
|
||||||
__pcrt_quit();
|
__pcrt_quit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include <raleigh/w/button.h>
|
#include <raleigh/w/button.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
button::button(widget &inner, void (*on_click)(button_tag_t), button_tag_t tag,
|
button::button(widget &inner, void (*on_click)(button &),
|
||||||
_pixel_t border_color, _pixel_t bg_color, _pixel_t pressed_color)
|
_pixel_t border_color, _pixel_t bg_color, _pixel_t pressed_color)
|
||||||
: inner(inner), on_click(on_click), tag(tag), border_color(border_color),
|
: inner(inner), on_click(on_click), border_color(border_color),
|
||||||
bg_color(bg_color), pressed_color(pressed_color), is_pressed(false) {
|
bg_color(bg_color), pressed_color(pressed_color), is_pressed(false) {
|
||||||
size = coord(inner.size.x + 2, inner.size.y + 2);
|
size = coord(inner.size.x + 2, inner.size.y + 2);
|
||||||
closest_opaque = this;
|
closest_opaque = this;
|
||||||
|
@ -18,8 +18,10 @@ namespace raleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
void button::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
void button::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
||||||
if (next_paint_full) {
|
for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y)
|
||||||
next_paint_full = false;
|
for (uint32_t x = window_offset.x + 1; x < window_offset.x + size.x - 1; ++x)
|
||||||
|
pixbuf[y * pitch + x] = is_pressed ? pressed_color : bg_color;
|
||||||
|
inner.paint(pixbuf, pitch);
|
||||||
for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) {
|
for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) {
|
||||||
pixbuf[window_offset.y * pitch + x] = border_color;
|
pixbuf[window_offset.y * pitch + x] = border_color;
|
||||||
pixbuf[(window_offset.y + size.y - 1) * pitch + x] = border_color;
|
pixbuf[(window_offset.y + size.y - 1) * pitch + x] = border_color;
|
||||||
|
@ -29,12 +31,6 @@ namespace raleigh {
|
||||||
pixbuf[y * pitch + window_offset.x + size.x - 1] = border_color;
|
pixbuf[y * pitch + window_offset.x + size.x - 1] = border_color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y)
|
|
||||||
for (uint32_t x = window_offset.x + 1; x < window_offset.x + size.x - 1; ++x)
|
|
||||||
pixbuf[y * pitch + x] = is_pressed ? pressed_color : bg_color;
|
|
||||||
inner.next_paint_full = true;
|
|
||||||
inner.paint(pixbuf, pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void button::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
void button::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
||||||
if (click_type != mouse_packet::LEFT)
|
if (click_type != mouse_packet::LEFT)
|
||||||
|
@ -44,7 +40,7 @@ namespace raleigh {
|
||||||
inner.window_offset = coord(window_offset.x + 1, window_offset.y + 1);
|
inner.window_offset = coord(window_offset.x + 1, window_offset.y + 1);
|
||||||
inner.notify_window_change();
|
inner.notify_window_change();
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
on_click(tag);
|
on_click(*this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
is_pressed = true;
|
is_pressed = true;
|
||||||
|
@ -59,4 +55,12 @@ namespace raleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
void button::notify_has_opaque_parent(widget *parent) {}
|
void button::notify_has_opaque_parent(widget *parent) {}
|
||||||
|
|
||||||
|
void button::on_mouse_move(coord window_coords) {
|
||||||
|
if ((window_coords.x >= inner.window_offset.x) &&
|
||||||
|
(window_coords.y >= inner.window_offset.y) &&
|
||||||
|
(window_coords.x < inner.window_offset.x + inner.size.x) &&
|
||||||
|
(window_coords.y < inner.window_offset.y + inner.size.y))
|
||||||
|
inner.on_mouse_move(window_coords);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
colorpicker::colorpicker(_pixel_t default_color, uint8_t resolution)
|
colorpicker::colorpicker(_pixel_t default_color, uint8_t resolution)
|
||||||
: picked_color(default_color), resolution(resolution),
|
: picked_color(default_color), resolution(resolution),
|
||||||
inv_res(256 / resolution) {
|
inv_res(256 / resolution), selected(NO) {
|
||||||
size = coord(inv_res * 2, inv_res * 2);
|
size = coord(inv_res * 2, inv_res * 2);
|
||||||
closest_opaque = this;
|
closest_opaque = this;
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,13 @@ namespace raleigh {
|
||||||
pb_ptr[y * pitch + x] = picked_color;
|
pb_ptr[y * pitch + x] = picked_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorpicker::set_picked_color(_pixel_t c) {
|
|
||||||
picked_color = c;
|
|
||||||
if (w)
|
|
||||||
w->notify_needs_paint(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void colorpicker::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
void colorpicker::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
||||||
if (up || (click_type != mouse_packet::LEFT))
|
if (click_type != mouse_packet::LEFT)
|
||||||
return;
|
return;
|
||||||
|
if (up) {
|
||||||
|
selected = NO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
window_coords.x -= window_offset.x;
|
window_coords.x -= window_offset.x;
|
||||||
window_coords.y -= window_offset.y;
|
window_coords.y -= window_offset.y;
|
||||||
if ((window_coords.x < inv_res) && (window_coords.y < inv_res)) {
|
if ((window_coords.x < inv_res) && (window_coords.y < inv_res)) {
|
||||||
|
@ -59,48 +57,37 @@ namespace raleigh {
|
||||||
picked_color.g = (window_coords.y - inv_res) * resolution;
|
picked_color.g = (window_coords.y - inv_res) * resolution;
|
||||||
}
|
}
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
w->notify_wants_movements(*this, mouse_packet::LEFT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void colorpicker::notify_has_opaque_parent(widget *parent) {}
|
void colorpicker::notify_has_opaque_parent(widget *parent) {}
|
||||||
|
|
||||||
void colorpicker::on_mouse_move(coord window_coords) {
|
void colorpicker::on_mouse_move(coord window_coords) {
|
||||||
int32_t x = window_coords.x - window_offset.x;
|
uint32_t x = window_coords.x - window_offset.x;
|
||||||
int32_t y = window_coords.y - window_offset.y;
|
uint32_t y = window_coords.y - window_offset.y;
|
||||||
switch (selected) {
|
switch (selected) {
|
||||||
|
case NO:
|
||||||
|
return;
|
||||||
case R:
|
case R:
|
||||||
if (x >= inv_res)
|
if (x >= inv_res)
|
||||||
x = inv_res - 1;
|
x = inv_res - 1;
|
||||||
if (x < 0)
|
|
||||||
x = 0;
|
|
||||||
if (y >= inv_res)
|
if (y >= inv_res)
|
||||||
y = inv_res - 1;
|
y = inv_res - 1;
|
||||||
if (y < 0)
|
|
||||||
y = 0;
|
|
||||||
picked_color.g = x * resolution;
|
picked_color.g = x * resolution;
|
||||||
picked_color.b = y * resolution;
|
picked_color.b = y * resolution;
|
||||||
break;
|
break;
|
||||||
case G:
|
case G:
|
||||||
if (x < inv_res)
|
if (x < inv_res)
|
||||||
x = inv_res;
|
x = inv_res;
|
||||||
if (x >= inv_res * 2)
|
|
||||||
x = inv_res * 2 - 1;
|
|
||||||
if (y >= inv_res)
|
if (y >= inv_res)
|
||||||
y = inv_res - 1;
|
y = inv_res - 1;
|
||||||
if (y < 0)
|
|
||||||
y = 0;
|
|
||||||
picked_color.b = x * resolution;
|
picked_color.b = x * resolution;
|
||||||
picked_color.r = y * resolution;
|
picked_color.r = y * resolution;
|
||||||
break;
|
break;
|
||||||
case B:
|
case B:
|
||||||
if (x >= inv_res)
|
if (x >= inv_res)
|
||||||
x = inv_res - 1;
|
x = inv_res - 1;
|
||||||
if (x < 0)
|
|
||||||
x = 0;
|
|
||||||
if (y < inv_res)
|
if (y < inv_res)
|
||||||
y = inv_res;
|
y = inv_res;
|
||||||
if (y >= inv_res * 2)
|
|
||||||
y = inv_res * 2 - 1;
|
|
||||||
picked_color.r = x * resolution;
|
picked_color.r = x * resolution;
|
||||||
picked_color.g = y * resolution;
|
picked_color.g = y * resolution;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,210 +1,263 @@
|
||||||
#include <raleigh/s/text_flower.h>
|
|
||||||
#include <raleigh/w/entry.h>
|
#include <raleigh/w/entry.h>
|
||||||
|
#include <knob/format.h>
|
||||||
|
#include <knob/block.h>
|
||||||
|
#include <knob/heap.h>
|
||||||
|
#include <knob/key.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
entry::entry(uint32_t rows, uint32_t cols, const char *default_text,
|
entry::entry(uint32_t rows, uint32_t cols, const char *default_text,
|
||||||
const struct font_info *fi, _pixel_t bg, _pixel_t fg,
|
const char *font, _pixel_t bg, _pixel_t fg, _pixel_t border_color)
|
||||||
_pixel_t border_color)
|
: rows(rows), cols(cols), bg(bg), fg(fg), border_color(border_color),
|
||||||
: fi(fi), border_color(border_color), fg(fg), bg(bg), rows(rows),
|
fi(get_font(font)), data(new char[rows * cols]),
|
||||||
cols(cols), text_back(default_text, strlen(default_text) + 1),
|
line_indices(new uint32_t[rows + 1]), first_paint(true),
|
||||||
flower(text_back.buf, cols, rows) {
|
has_focus(false) {
|
||||||
size = coord(fi->space_width * (cols - 1) + fi->char_width + 6,
|
size = coord(fi->space_width * (cols - 1) + fi->char_width + 6,
|
||||||
fi->space_height * (rows - 1) + fi->char_height + 6);\
|
fi->space_height * (rows - 1) + fi->char_height + 6);
|
||||||
closest_opaque = this;
|
closest_opaque = this;
|
||||||
|
|
||||||
|
const uint32_t l = strlen(default_text);
|
||||||
|
const uint32_t cl = l > rows * cols - 1 ? rows * cols - 1 : l;
|
||||||
|
blockcpy(data, default_text, cl);
|
||||||
|
data[cl] = '\0';
|
||||||
|
|
||||||
|
line_indices[0] = 0;
|
||||||
|
get_indices(0, 0, 0);
|
||||||
|
cur_x = end_x;
|
||||||
|
cur_y = end_y;
|
||||||
|
cur_d = end_d;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__ ((pure))
|
void entry::get_indices(uint32_t from_y, uint32_t from_x, uint32_t from_d) {
|
||||||
const char *entry::get_contents() {
|
while (1) {
|
||||||
return text_back.buf;
|
const uint32_t ln = str_find_any(data + from_d, " \n");
|
||||||
|
bool quit_after = !data[from_d + ln];
|
||||||
|
if ((from_x + ln <= cols) || (ln >= cols)) {
|
||||||
|
from_x += ln;
|
||||||
|
from_d += ln;
|
||||||
|
if (data[from_d] == '\n') {
|
||||||
|
++from_y;
|
||||||
|
from_x = 0;
|
||||||
|
line_indices[from_y] = from_d + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++from_x;
|
||||||
|
++from_d;
|
||||||
|
if (from_x >= cols) {
|
||||||
|
++from_y;
|
||||||
|
from_x = 0;
|
||||||
|
line_indices[from_y] = from_d;
|
||||||
|
}
|
||||||
|
if (quit_after)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++from_y;
|
||||||
|
from_x = 0;
|
||||||
|
line_indices[from_y] = from_d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line_indices[from_y + 1] = from_d;
|
||||||
|
end_y = from_y;
|
||||||
|
end_x = from_x;
|
||||||
|
end_d = from_d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::set_contents(const char *s) {
|
void entry::notify_window_change() {}
|
||||||
text_back.copy_from(s, strlen(s) + 1);
|
|
||||||
on_text_change();
|
void entry::paint_text(_pixel_t *pixbuf, uint32_t pitch) {
|
||||||
|
for (uint32_t y = 0; y <= end_y; ++y) {
|
||||||
|
const char *const line = data + line_indices[y];
|
||||||
|
const uint32_t len = line_indices[y + 1] - line_indices[y] >= cols ? cols : line_indices[y + 1] - line_indices[y];
|
||||||
|
for (uint32_t x = 0; x < len; ++x)
|
||||||
|
if ((line[x] != '\n') && line[x])
|
||||||
|
put_char_no_bg(fi, line[x], pixbuf + (window_offset.y + 3 + y * fi->space_height) * pitch + (window_offset.x + 3 + x * fi->space_width), pitch, fg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
void entry::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
||||||
if (next_paint_full) {
|
_pixel_t *const cur_ptr = pixbuf + (window_offset.y + 3 + cur_y * fi->space_height) * pitch + (window_offset.x + 3 + cur_x * fi->space_width);
|
||||||
for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) {
|
_pixel_t *const old_cur_ptr = pixbuf + (window_offset.y + 3 + cur_y_last_paint * fi->space_height) * pitch + (window_offset.x + 3 + cur_x_last_paint * fi->space_width);
|
||||||
pixbuf[window_offset.y * pitch + x] = border_color;
|
|
||||||
pixbuf[(window_offset.y + size.y - 1) * pitch + x] = border_color;
|
if (first_paint) {
|
||||||
|
for (uint32_t x = 0; x < size.x; ++x) {
|
||||||
|
pixbuf[(window_offset.y) * pitch + window_offset.x + x] = border_color;
|
||||||
|
pixbuf[(window_offset.y + size.y - 1) * pitch + window_offset.x + x] = border_color;
|
||||||
}
|
}
|
||||||
for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y) {
|
for (uint32_t y = 1; y < size.y - 1; ++y) {
|
||||||
pixbuf[y * pitch + window_offset.x] = border_color;
|
pixbuf[(window_offset.y + y) * pitch + window_offset.x] = border_color;
|
||||||
pixbuf[y * pitch + window_offset.x + size.x - 1] = border_color;
|
pixbuf[(window_offset.y + y) * pitch + window_offset.x + size.x - 1] = border_color;
|
||||||
}
|
|
||||||
for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y)
|
|
||||||
for (uint32_t x = window_offset.x + 1; x < window_offset.x + size.x - 1; ++x)
|
|
||||||
pixbuf[y * pitch + x] = bg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_paint_full || text_change) {
|
for (uint32_t y = 1; y < size.y - 1; ++y)
|
||||||
for (uint32_t y = window_offset.y + 3; y < window_offset.y + size.y - 3; ++y)
|
for (uint32_t x = 1; x < size.x - 1; ++x)
|
||||||
for (uint32_t x = window_offset.x + 3; x < window_offset.x + size.x - 3; ++x)
|
pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg;
|
||||||
pixbuf[y * pitch + x] = bg;
|
|
||||||
flower.draw_text(pixbuf + (window_offset.y + 3) * pitch + window_offset.x + 3, pitch, fi, fg);
|
paint_text(pixbuf, pitch);
|
||||||
|
first_paint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((cursor_change || !is_cur) && was_cur_before) {
|
else if (text_changed_since_last_paint) {
|
||||||
const uint32_t y_start = window_offset.y + 3 + fi->space_height * old_cur_y;
|
for (uint32_t y = 3; y < size.y - 3; ++y)
|
||||||
const uint32_t x_start = window_offset.x + 3 + fi->space_width * old_cur_x;
|
for (uint32_t x = 3; x < size.x - 3; ++x)
|
||||||
if (old_cur_x == cols)
|
pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg;
|
||||||
for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) {
|
paint_text(pixbuf, pitch);
|
||||||
pixbuf[y * pitch + x_start] = bg;
|
text_changed_since_last_paint = false;
|
||||||
pixbuf[y * pitch + x_start + 1] = bg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
put_char(fi, flower.get_nth_line(old_cur_y)[old_cur_x],
|
|
||||||
pixbuf + y_start * pitch + x_start, pitch, bg, fg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_cur) {
|
else if (had_focus_last_paint) {
|
||||||
const uint32_t y_start = window_offset.y + 3 + fi->space_height * cur_y;
|
for (uint32_t y = 0; y < fi->char_height; ++y) {
|
||||||
const uint32_t x_start = window_offset.x + 3 + fi->space_width * cur_x;
|
old_cur_ptr[y * pitch] = bg;
|
||||||
if (old_cur_x == cols)
|
old_cur_ptr[y * pitch + 1] = bg;
|
||||||
for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) {
|
|
||||||
pixbuf[y * pitch + x_start] = fg;
|
|
||||||
pixbuf[y * pitch + x_start + 1] = fg;
|
|
||||||
}
|
}
|
||||||
|
if (data[cur_d_last_paint] && (data[cur_d_last_paint] != '\n') && (cur_d_last_paint < line_indices[cur_y_last_paint + 1]))
|
||||||
|
put_char_no_bg(fi, data[cur_d_last_paint], old_cur_ptr, pitch, fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
next_paint_full = false;
|
if (has_focus)
|
||||||
text_change = false;
|
for (uint32_t y = 0; y < fi->char_height; ++y) {
|
||||||
cursor_change = false;
|
cur_ptr[y * pitch] = fg;
|
||||||
|
cur_ptr[y * pitch + 1] = fg;
|
||||||
was_cur_before = is_cur;
|
|
||||||
old_cur_x = cur_x;
|
|
||||||
old_cur_y = cur_y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::notify_has_opaque_parent(widget *parent) {}
|
cur_y_last_paint = cur_y;
|
||||||
|
cur_x_last_paint = cur_x;
|
||||||
|
cur_d_last_paint = cur_d;
|
||||||
|
had_focus_last_paint = has_focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entry::ensure_cursor_in_line() {
|
||||||
|
cur_d = line_indices[cur_y] + cur_x;
|
||||||
|
if (cur_d >= line_indices[cur_y + 1]) {
|
||||||
|
cur_d = line_indices[cur_y + 1] - 1;
|
||||||
|
if (data[cur_d] && (data[cur_d] != '\n'))
|
||||||
|
++cur_d;
|
||||||
|
cur_x = cur_d - line_indices[cur_y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void entry::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
void entry::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
||||||
if (up || (click_type != mouse_packet::LEFT))
|
if (up || (click_type != mouse_packet::LEFT))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (window_coords.x < window_offset.x)
|
if (window_coords.x - window_offset.x < 3)
|
||||||
window_coords.x = window_offset.x;
|
window_coords.x = 3 + window_offset.x;
|
||||||
if (window_coords.y < window_offset.y)
|
else if (window_coords.x - window_offset.x > size.x - 4)
|
||||||
window_coords.y = window_offset.y;
|
window_coords.x = size.x - 4 + window_offset.x;
|
||||||
|
if (window_coords.y - window_offset.y < 3)
|
||||||
|
window_coords.y = 3 + window_offset.y;
|
||||||
|
else if (window_coords.y - window_offset.y > size.y - 4)
|
||||||
|
window_coords.y = size.y - 4 + window_offset.y;
|
||||||
|
|
||||||
cur_x = (window_coords.x - window_offset.x) / fi->space_width;
|
cur_y = (window_coords.y - window_offset.y - 3) / fi->space_height;
|
||||||
cur_y = (window_coords.y - window_offset.y) / fi->space_height;
|
cur_x = (window_coords.x - window_offset.x - 3) / fi->space_width;
|
||||||
|
if (cur_y > end_y) {
|
||||||
check_y();
|
cur_y = end_y;
|
||||||
check_x();
|
cur_x = end_x;
|
||||||
on_cursor_change();
|
|
||||||
}
|
}
|
||||||
|
ensure_cursor_in_line();
|
||||||
|
|
||||||
void entry::check_y() {
|
if (has_focus)
|
||||||
if (cur_y >= flower.get_n_lines())
|
|
||||||
cur_y = flower.get_n_lines() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry::check_x() {
|
|
||||||
if (cur_x > strlen(flower.get_nth_line(cur_y)))
|
|
||||||
cur_x = strlen(flower.get_nth_line(cur_y));
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry::on_text_change() {
|
|
||||||
flower.s = text_back.buf;
|
|
||||||
flower.flow_text();
|
|
||||||
text_change = true;
|
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
|
else
|
||||||
|
w->focus(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::on_cursor_change() {
|
void entry::notify_has_opaque_parent(widget *parent) {}
|
||||||
cursor_change = true;
|
|
||||||
w->notify_needs_paint(*this);
|
bool entry::cursor_left() {
|
||||||
|
if (cur_x) {
|
||||||
|
--cur_x;
|
||||||
|
--cur_d;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!cur_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
--cur_y;
|
||||||
|
cur_x = line_indices[cur_y + 1] - line_indices[cur_y] - 1;
|
||||||
|
if (cur_x == cols)
|
||||||
|
--cur_x;
|
||||||
|
cur_d = line_indices[cur_y] + cur_x;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entry::cursor_right() {
|
||||||
|
if (cur_d >= (end_d - 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++cur_d;
|
||||||
|
++cur_x;
|
||||||
|
|
||||||
|
if (cur_d >= line_indices[cur_y + 1]) {
|
||||||
|
cur_x = 0;
|
||||||
|
++cur_y;
|
||||||
|
cur_d = line_indices[cur_y];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entry::cursor_up() {
|
||||||
|
if (!cur_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
--cur_y;
|
||||||
|
ensure_cursor_in_line();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool entry::cursor_down() {
|
||||||
|
if (cur_y == end_y)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
++cur_y;
|
||||||
|
ensure_cursor_in_line();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::handle_key(struct key_packet kp) {
|
void entry::handle_key(struct key_packet kp) {
|
||||||
const uint32_t pos = flower.get_line_offset(cur_y) + cur_x;
|
switch (kp.key_id) {
|
||||||
const char ch = key_to_char(kp);
|
case kp.KEY_LEFT_ARROW:
|
||||||
|
if (cursor_left() && has_focus)
|
||||||
if (kp.key_id == kp.KEY_BSPACE) {
|
w->notify_needs_paint(*this);
|
||||||
if (pos) {
|
break;
|
||||||
text_back.remove(pos - 1);
|
case kp.KEY_RIGHT_ARROW:
|
||||||
left();
|
if (cursor_right() && has_focus)
|
||||||
on_text_change();
|
w->notify_needs_paint(*this);
|
||||||
}
|
break;
|
||||||
}
|
case kp.KEY_DOWN_ARROW:
|
||||||
|
if (cursor_down() && has_focus)
|
||||||
else if (kp.key_id == kp.KEY_DELETE) {
|
w->notify_needs_paint(*this);
|
||||||
if (pos != text_back.n_entries - 1) {
|
break;
|
||||||
text_back.remove(pos);
|
case kp.KEY_UP_ARROW:
|
||||||
on_text_change();
|
if (cursor_up() && has_focus)
|
||||||
}
|
w->notify_needs_paint(*this);
|
||||||
}
|
break;
|
||||||
|
case kp.KEY_HOME:
|
||||||
else if (kp.key_id == kp.KEY_LEFT_ARROW)
|
if (cur_x) {
|
||||||
left();
|
|
||||||
else if (kp.key_id == kp.KEY_RIGHT_ARROW)
|
|
||||||
right();
|
|
||||||
else if (kp.key_id == kp.KEY_UP_ARROW)
|
|
||||||
up();
|
|
||||||
else if (kp.key_id == kp.KEY_DOWN_ARROW)
|
|
||||||
down();
|
|
||||||
|
|
||||||
else if (ch) {
|
|
||||||
text_back.insert(pos, ch);
|
|
||||||
on_text_change();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry::left() {
|
|
||||||
if (cur_x)
|
|
||||||
--cur_x;
|
|
||||||
else if (cur_y) {
|
|
||||||
--cur_y;
|
|
||||||
check_x();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
on_cursor_change();
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry::right() {
|
|
||||||
if (++cur_x <= strlen(flower.get_nth_line(cur_y)))
|
|
||||||
on_cursor_change();
|
|
||||||
else if (cur_y != flower.get_n_lines()) {
|
|
||||||
++cur_y;
|
|
||||||
cur_x = 0;
|
cur_x = 0;
|
||||||
on_cursor_change();
|
if (has_focus)
|
||||||
|
w->notify_needs_paint(*this);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
case kp.KEY_END:
|
||||||
void entry::up() {
|
cur_x = cols;
|
||||||
if (cur_y) {
|
ensure_cursor_in_line();
|
||||||
--cur_y;
|
if (has_focus)
|
||||||
check_x();
|
w->notify_needs_paint(*this);
|
||||||
on_cursor_change();
|
break;
|
||||||
}
|
default:
|
||||||
else if (!cur_x) {
|
break;
|
||||||
cur_x = 0;
|
|
||||||
on_cursor_change();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry::down() {
|
|
||||||
if (cur_y != flower.get_n_lines()) {
|
|
||||||
++cur_y;
|
|
||||||
check_x();
|
|
||||||
on_cursor_change();
|
|
||||||
}
|
|
||||||
else if (cur_x < strlen(flower.get_nth_line(cur_y))) {
|
|
||||||
cur_x = strlen(flower.get_nth_line(cur_y));
|
|
||||||
on_cursor_change();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::on_focus() {
|
void entry::on_focus() {
|
||||||
is_cur = true;
|
has_focus = true;
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void entry::on_unfocus() {
|
void entry::on_unfocus() {
|
||||||
is_cur = false;
|
has_focus = false;
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
#include <raleigh/w/hbox.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
hbox::hbox(dllist<widget &> widgets)
|
|
||||||
: multicontainer(widgets) {
|
|
||||||
size = determine_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
coord hbox::determine_size() {
|
|
||||||
uint32_t w = 0, h = 0;
|
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
|
||||||
n->d.parent = this;
|
|
||||||
w += n->d.size.x;
|
|
||||||
if (n->d.size.y > h)
|
|
||||||
h = n->d.size.y;
|
|
||||||
}
|
|
||||||
return coord(w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hbox::set_child_offsets() {
|
|
||||||
uint32_t x = window_offset.x;
|
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
|
||||||
n->d.w = w;
|
|
||||||
n->d.window_offset = coord(x, window_offset.y + size.y / 2 - n->d.size.y / 2);
|
|
||||||
n->d.notify_window_change();
|
|
||||||
x += n->d.size.x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,36 +3,26 @@
|
||||||
#include <knob/block.h>
|
#include <knob/block.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
coord label::determine_size() {
|
label::label(const char *value, const char *font, bool bg_transparent, _pixel_t fg, _pixel_t bg)
|
||||||
uint32_t longest = 0;
|
: fi(get_font(font)), bg_transparent(bg_transparent), fg(fg), bg(bg) {
|
||||||
|
|
||||||
for (uint32_t i = 0; i < tf.get_n_lines(); ++i)
|
v_size = strlen(value) + 1;
|
||||||
if (strlen(tf.get_nth_line(i)) > longest)
|
this->value = new char[v_size];
|
||||||
longest = strlen(tf.get_nth_line(i));
|
blockcpy(this->value, value, v_size);
|
||||||
|
size = coord(fi->space_width * (v_size - 2) + fi->char_width, fi->char_height);
|
||||||
|
|
||||||
const int32_t width = fi->space_width * (longest - 1) + fi->char_width;
|
closest_opaque = 0;
|
||||||
const int32_t height = fi->space_height * (tf.get_n_lines() - 1) + fi->char_height;
|
|
||||||
return coord(width < 0 ? 0 : width, height < 0 ? 0 : height);
|
|
||||||
}
|
|
||||||
|
|
||||||
label::label(const char *value, const char *font, uint32_t cols,
|
|
||||||
bool bg_transparent, _pixel_t fg, _pixel_t bg)
|
|
||||||
: fi(get_font(font)), cols(cols), bg_transparent(bg_transparent),
|
|
||||||
fg(fg), bg(bg), tf(strdup(value), cols) {
|
|
||||||
|
|
||||||
size = determine_size();
|
|
||||||
closest_opaque = bg_transparent ? 0 : this;
|
|
||||||
}
|
|
||||||
|
|
||||||
label::~label() {
|
|
||||||
free_block(tf.s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void label::change_value(const char *new_value) {
|
void label::change_value(const char *new_value) {
|
||||||
free_block(tf.s);
|
delete[] value;
|
||||||
tf.s = strdup(new_value);
|
const uint32_t ns = strlen(new_value) + 1;
|
||||||
tf.flow_text();
|
if (ns != v_size) {
|
||||||
set_size(determine_size());
|
v_size = ns;
|
||||||
|
value = new char[ns];
|
||||||
|
set_size(coord(fi->space_width * (ns - 2) + fi->char_width, fi->char_height));
|
||||||
|
}
|
||||||
|
blockcpy(value, new_value, ns);
|
||||||
w->notify_needs_paint(*this);
|
w->notify_needs_paint(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +31,14 @@ namespace raleigh {
|
||||||
for (uint32_t y = window_offset.y; y < window_offset.y + size.y; ++y)
|
for (uint32_t y = window_offset.y; y < window_offset.y + size.y; ++y)
|
||||||
for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x)
|
for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x)
|
||||||
pixbuf[y * pitch + x] = bg;
|
pixbuf[y * pitch + x] = bg;
|
||||||
tf.draw_text(pixbuf + window_offset.y * pitch + window_offset.x, pitch, fi, fg);
|
_pixel_t *ptr = pixbuf + window_offset.y * pitch + window_offset.x;
|
||||||
|
for (const char *c = value; *c; ++c) {
|
||||||
|
put_char_no_bg(fi, *c, ptr, pitch, fg);
|
||||||
|
ptr += fi->space_width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void label::notify_has_opaque_parent(widget *parent) {
|
void label::notify_has_opaque_parent(widget *parent) {
|
||||||
if (bg_transparent)
|
|
||||||
closest_opaque = parent;
|
closest_opaque = parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
|
|
||||||
namespace raleigh {
|
|
||||||
multicontainer::multicontainer(dllist<widget &> widgets)
|
|
||||||
: widgets(widgets) {
|
|
||||||
closest_opaque = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::notify_window_change() {
|
|
||||||
set_child_offsets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
|
||||||
if (next_paint_full)
|
|
||||||
n->d.next_paint_full = true;
|
|
||||||
n->d.paint(pixbuf, pitch);
|
|
||||||
}
|
|
||||||
if (next_paint_full)
|
|
||||||
next_paint_full = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next)
|
|
||||||
if ((window_coords.x >= n->d.window_offset.x) &&
|
|
||||||
(window_coords.y >= n->d.window_offset.y) &&
|
|
||||||
(window_coords.x < n->d.window_offset.x + n->d.size.x) &&
|
|
||||||
(window_coords.y < n->d.window_offset.y + n->d.size.y))
|
|
||||||
n->d.handle_click(window_coords, click_type, up);
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::notify_has_opaque_parent(widget *parent) {
|
|
||||||
closest_opaque = parent;
|
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next)
|
|
||||||
n->d.notify_has_opaque_parent(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::notify_child_size_change(widget &from, coord old_size) {
|
|
||||||
set_size(determine_size());
|
|
||||||
set_child_offsets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::add_end(widget &n) {
|
|
||||||
widgets.add_back(n);
|
|
||||||
set_size(determine_size());
|
|
||||||
set_child_offsets();
|
|
||||||
if (w)
|
|
||||||
w->notify_needs_paint(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void multicontainer::add_start(widget &n) {
|
|
||||||
widgets.add_front(n);
|
|
||||||
set_size(determine_size());
|
|
||||||
set_child_offsets();
|
|
||||||
if (w)
|
|
||||||
w->notify_needs_paint(*this);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,10 +15,6 @@ namespace raleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
void padding::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
void padding::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
||||||
if (next_paint_full) {
|
|
||||||
next_paint_full = false;
|
|
||||||
inner.next_paint_full = true;
|
|
||||||
}
|
|
||||||
inner.paint(pixbuf, pitch);
|
inner.paint(pixbuf, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,4 +34,12 @@ namespace raleigh {
|
||||||
void padding::notify_child_size_change(widget &child, coord old_size) {
|
void padding::notify_child_size_change(widget &child, coord old_size) {
|
||||||
set_size(coord(inner.size.x + pad_by * 2, inner.size.y + pad_by * 2));
|
set_size(coord(inner.size.x + pad_by * 2, inner.size.y + pad_by * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void padding::on_mouse_move(coord window_coords) {
|
||||||
|
if ((window_coords.x >= inner.window_offset.x) &&
|
||||||
|
(window_coords.y >= inner.window_offset.y) &&
|
||||||
|
(window_coords.x < inner.window_offset.x + inner.size.x) &&
|
||||||
|
(window_coords.y < inner.window_offset.y + inner.size.y))
|
||||||
|
inner.on_mouse_move(window_coords);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,7 @@
|
||||||
#include <raleigh/w/vbox.h>
|
#include <raleigh/w/vbox.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
vbox::vbox(dllist<widget &> widgets)
|
vbox::vbox(dllist<widget &> widgets) : widgets(widgets) {
|
||||||
: multicontainer(widgets) {
|
|
||||||
size = determine_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
coord vbox::determine_size() {
|
|
||||||
uint32_t w = 0, h = 0;
|
uint32_t w = 0, h = 0;
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
||||||
n->d.parent = this;
|
n->d.parent = this;
|
||||||
|
@ -14,10 +9,11 @@ namespace raleigh {
|
||||||
if (n->d.size.x > w)
|
if (n->d.size.x > w)
|
||||||
w = n->d.size.x;
|
w = n->d.size.x;
|
||||||
}
|
}
|
||||||
return coord(w, h);
|
size = coord(w, h);
|
||||||
|
closest_opaque = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vbox::set_child_offsets() {
|
void vbox::notify_window_change() {
|
||||||
uint32_t h = window_offset.y;
|
uint32_t h = window_offset.y;
|
||||||
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
||||||
n->d.w = w;
|
n->d.w = w;
|
||||||
|
@ -26,4 +22,56 @@ namespace raleigh {
|
||||||
h += n->d.size.y;
|
h += n->d.size.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vbox::paint(_pixel_t *pixbuf, uint32_t pitch) {
|
||||||
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next)
|
||||||
|
n->d.paint(pixbuf, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vbox::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {
|
||||||
|
uint32_t h = window_offset.y;
|
||||||
|
dllist<widget &>::node *n = widgets.first;
|
||||||
|
while (h + n->d.size.y <= window_coords.y) {
|
||||||
|
h += n->d.size.y;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
if ((window_coords.x >= n->d.window_offset.x) &&
|
||||||
|
(window_coords.x < n->d.window_offset.x + n->d.size.x))
|
||||||
|
n->d.handle_click(window_coords, click_type, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vbox::notify_has_opaque_parent(widget *parent) {
|
||||||
|
closest_opaque = parent;
|
||||||
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next)
|
||||||
|
n->d.notify_has_opaque_parent(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vbox::notify_child_size_change(widget &from, coord old_size) {
|
||||||
|
if ((old_size.y == from.size.y) && (from.size.x <= size.x)) {
|
||||||
|
from.window_offset.x = window_offset.x + size.x / 2 - from.size.x / 2;
|
||||||
|
from.notify_window_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {//lazy, less efficient approach
|
||||||
|
uint32_t h = 0, w = 0;
|
||||||
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next) {
|
||||||
|
h += n->d.size.y;
|
||||||
|
if (n->d.size.x > w)
|
||||||
|
w = n->d.size.x;
|
||||||
|
}
|
||||||
|
set_size(coord(w, h));
|
||||||
|
notify_window_change();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vbox::on_mouse_move(coord window_coords) {
|
||||||
|
for (dllist<widget &>::node *n = widgets.first; n; n = n->next)
|
||||||
|
if ((window_coords.x >= n->d.window_offset.x) &&
|
||||||
|
(window_coords.y >= n->d.window_offset.y) &&
|
||||||
|
(window_coords.x < n->d.window_offset.x + n->d.size.x) &&
|
||||||
|
(window_coords.y < n->d.window_offset.y + n->d.size.y)) {
|
||||||
|
n->d.on_mouse_move(window_coords);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
widget::widget()
|
widget::widget()
|
||||||
: parent(0), w(0), next_paint_full(true) {}
|
: parent(0) {}
|
||||||
|
|
||||||
void widget::notify_window_change() {}
|
void widget::notify_window_change() {}
|
||||||
void widget::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {}
|
void widget::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {}
|
||||||
|
|
|
@ -5,26 +5,25 @@
|
||||||
#include <knob/format.h>
|
#include <knob/format.h>
|
||||||
|
|
||||||
namespace raleigh {
|
namespace raleigh {
|
||||||
window::window(widget &root, _pixel_t bg_color, bool (*on_close)(window_tag_t), window_tag_t tag)
|
window::window(widget &root, _pixel_t bg_color, bool (*on_close)(window &))
|
||||||
: root(root), handle(0), pixbuf(0), size(root.size), focussed(&root),
|
: handle(0), size(root.size), root(root), focussed(&root),
|
||||||
drag_reciever(0), bg_color(bg_color), on_close(on_close), tag(tag) {
|
bg_color(bg_color), on_close(on_close) {
|
||||||
root.w = this;
|
root.w = this;
|
||||||
root.window_offset = coord(0, 0);
|
root.window_offset = coord(0, 0);
|
||||||
root.notify_window_change();
|
root.notify_window_change();
|
||||||
|
|
||||||
if (size.x && size.y) {
|
|
||||||
pixbuf = new _pixel_t[size.x * size.y];
|
pixbuf = new _pixel_t[size.x * size.y];
|
||||||
if (!pixbuf)
|
if (!pixbuf)
|
||||||
show_error_and_quitf("Failed to create %d byte pixel buffer\nfor requested %dx%d pixel window.", size.x * size.y * sizeof(_pixel_t), size.x, size.y);
|
show_error_and_quitf("Failed to create %d byte pixel buffer\nfor requested %dx%d pixel window.", size.x * size.y * sizeof(_pixel_t), size.x, size.y);
|
||||||
}
|
|
||||||
|
|
||||||
paint_full();
|
paint_full();
|
||||||
root.on_focus();
|
root.on_focus();
|
||||||
needs_repaint = false;
|
needs_repaint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void window::consume_actions() {
|
window::try_actions_return_t window::try_actions() {
|
||||||
struct window_action wa;
|
struct window_action wa;
|
||||||
|
window::try_actions_return_t got = NONE;
|
||||||
while (1) {
|
while (1) {
|
||||||
_get_win_action(handle, &wa);
|
_get_win_action(handle, &wa);
|
||||||
if (!wa.action_type) {
|
if (!wa.action_type) {
|
||||||
|
@ -32,36 +31,34 @@ namespace raleigh {
|
||||||
needs_repaint = false;
|
needs_repaint = false;
|
||||||
_paint_window(handle);
|
_paint_window(handle);
|
||||||
}
|
}
|
||||||
return;
|
return got;
|
||||||
}
|
}
|
||||||
if ((wa.action_type == wa.KEY_DOWN) &&
|
if ((wa.action_type == wa.KEY_DOWN) &&
|
||||||
(wa.as_key.modifiers & wa.as_key.ALTS) &&
|
(wa.as_key.modifiers & wa.as_key.ALTS) &&
|
||||||
(wa.as_key.key_id == wa.as_key.KEY_F4)) {
|
(wa.as_key.key_id == wa.as_key.KEY_F4))
|
||||||
if (!on_close || on_close(tag)) {
|
if (!on_close || on_close(*this))
|
||||||
to_be_deleted.add_back(*this);
|
return DELETE;
|
||||||
return;
|
got = GOOD;
|
||||||
}
|
if (wa.action_type == wa.MOUSE_DOWN)
|
||||||
}
|
|
||||||
else if (wa.action_type == wa.MOUSE_DOWN)
|
|
||||||
root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, false);
|
root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, false);
|
||||||
else if (wa.action_type == wa.MOUSE_UP) {
|
else if (wa.action_type == wa.MOUSE_UP)
|
||||||
if (drag_reciever && (wa.as_mouse.which == drag_until))
|
|
||||||
drag_reciever = 0;
|
|
||||||
root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, true);
|
root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, true);
|
||||||
}
|
|
||||||
else if (wa.action_type == wa.KEY_DOWN) {
|
else if (wa.action_type == wa.KEY_DOWN) {
|
||||||
void (*const f)(window_tag_t) = keybinds.transform(wa.as_key);
|
for (dllist<duple<struct key_packet, void (*)(window &)>>::node *n = keybinds.first; n; n = n->next)
|
||||||
if (f)
|
if (match_side_agnostic(wa.as_key, n->d.a)) {
|
||||||
f(tag);
|
n->d.b(*this);
|
||||||
else
|
goto next_loop;
|
||||||
|
}
|
||||||
focussed->handle_key(wa.as_key);
|
focussed->handle_key(wa.as_key);
|
||||||
|
next_loop:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
else if (wa.action_type == wa.FOCUS_ENTER)
|
else if (wa.action_type == wa.FOCUS_ENTER)
|
||||||
focussed->on_focus();
|
focussed->on_focus();
|
||||||
else if (wa.action_type == wa.FOCUS_LEAVE)
|
else if (wa.action_type == wa.FOCUS_LEAVE)
|
||||||
focussed->on_unfocus();
|
focussed->on_unfocus();
|
||||||
else if (drag_reciever && (wa.action_type == wa.MOUSE_MOVE))
|
else if (wa.action_type == wa.MOUSE_MOVE)
|
||||||
drag_reciever->on_mouse_move(coord(wa.moved_to.x, wa.moved_to.y));
|
root.on_mouse_move(coord(wa.moved_to.x, wa.moved_to.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,15 +71,8 @@ namespace raleigh {
|
||||||
}
|
}
|
||||||
|
|
||||||
void window::paint_full() {
|
void window::paint_full() {
|
||||||
//syslogf("paint_full called with");
|
for (uint32_t i = 0; i < size.x * size.y; ++i)
|
||||||
//syslogf(" pixbuf = 0x%x", pixbuf);
|
|
||||||
//syslogf(" size.x = %u", size.x);
|
|
||||||
//syslogf(" size.y = %u", size.y);
|
|
||||||
|
|
||||||
const uint32_t n = size.x * size.y;
|
|
||||||
for (uint32_t i = 0; i < n; ++i)
|
|
||||||
pixbuf[i] = bg_color;
|
pixbuf[i] = bg_color;
|
||||||
root.next_paint_full = true;
|
|
||||||
root.paint(pixbuf, size.x);
|
root.paint(pixbuf, size.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +99,6 @@ namespace raleigh {
|
||||||
from.parent->notify_child_size_change(from, old_size);
|
from.parent->notify_child_size_change(from, old_size);
|
||||||
else {
|
else {
|
||||||
size = root.size;
|
size = root.size;
|
||||||
if (pixbuf)
|
|
||||||
delete[] pixbuf;
|
delete[] pixbuf;
|
||||||
pixbuf = new _pixel_t[size.x * size.y];
|
pixbuf = new _pixel_t[size.x * size.y];
|
||||||
if (!pixbuf)
|
if (!pixbuf)
|
||||||
|
@ -119,12 +108,7 @@ namespace raleigh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void window::add_keybind(struct key_packet kp, void (*handler)(window_tag_t)) {
|
void window::add_keybind(struct key_packet kp, void (*handler)(window &)) {
|
||||||
keybinds.add_pair(kp, handler);
|
keybinds.add_front(duple<struct key_packet, void (*)(window &)>(kp, handler));
|
||||||
}
|
|
||||||
|
|
||||||
void window::notify_wants_movements(widget &from, enum mouse_packet::mouse_button while_down) {
|
|
||||||
drag_reciever = &from;
|
|
||||||
drag_until = while_down;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
59
src/user/rhello/main.cpp
Normal file
59
src/user/rhello/main.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include <raleigh/w/colorpicker.h>
|
||||||
|
#include <raleigh/w/padding.h>
|
||||||
|
#include <raleigh/w/button.h>
|
||||||
|
#include <raleigh/w/label.h>
|
||||||
|
#include <raleigh/w/entry.h>
|
||||||
|
#include <raleigh/w/vbox.h>
|
||||||
|
|
||||||
|
#include <raleigh/runtime.h>
|
||||||
|
#include <raleigh/window.h>
|
||||||
|
|
||||||
|
#include <knob/format.h>
|
||||||
|
#include <pland/pcrt.h>
|
||||||
|
|
||||||
|
using namespace raleigh;
|
||||||
|
|
||||||
|
colorpicker *cp;
|
||||||
|
label *p_l;
|
||||||
|
window *p_w;
|
||||||
|
|
||||||
|
void onclick(button &from) {
|
||||||
|
const _pixel_t pc = cp->get_picked_color();
|
||||||
|
char *const text = format("Selected color is #%2x%2x%2x", pc.r, pc.g, pc.b);
|
||||||
|
p_l->change_value(text);
|
||||||
|
free_block(text);
|
||||||
|
p_w->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
label l("Hello, world! Close me with Alt+F4.");
|
||||||
|
padding pl(l, 2);
|
||||||
|
|
||||||
|
label bl("Click me!");
|
||||||
|
padding pbl(bl, 4);
|
||||||
|
button b(pbl, &onclick);
|
||||||
|
padding pb(b, 2);
|
||||||
|
|
||||||
|
entry e(8, 31, "This window is made with the Raleigh widget toolkit for Portland OS.\n\nI am a text entry widget. My cursor can be used, but editing is not yet implemented.");
|
||||||
|
padding pe(e, 2);
|
||||||
|
|
||||||
|
cp = new colorpicker();
|
||||||
|
padding pcp(*cp, 2);
|
||||||
|
|
||||||
|
dllist<widget &> wl;
|
||||||
|
wl.add_front(pb);
|
||||||
|
wl.add_front(pcp);
|
||||||
|
wl.add_front(pe);
|
||||||
|
wl.add_front(pl);
|
||||||
|
vbox vb(wl);
|
||||||
|
padding pvb(vb, 2);
|
||||||
|
|
||||||
|
window w(pvb, RGB(bf, bf, bf), (bool (*)(window &))&__pcrt_quit);
|
||||||
|
|
||||||
|
p_l = new label("");
|
||||||
|
padding p_pl(*p_l, 4);
|
||||||
|
p_w = new window(p_pl);
|
||||||
|
|
||||||
|
w.show();
|
||||||
|
start_runtime();
|
||||||
|
}
|
|
@ -9,6 +9,3 @@ _ZdlPvj = free_block;
|
||||||
|
|
||||||
/* void operator delete[](void *) */
|
/* void operator delete[](void *) */
|
||||||
_ZdaPv = free_block;
|
_ZdaPv = free_block;
|
||||||
|
|
||||||
/* void operator delete[](void *, size_t) */
|
|
||||||
_ZdaPvj = free_block;
|
|
|
@ -1,36 +0,0 @@
|
||||||
#include "color_kind.h"
|
|
||||||
|
|
||||||
#include <raleigh/w/colorpicker.h>
|
|
||||||
|
|
||||||
void write_color_main(uint32_t &data_offset, file *f, const backing_t backing) {
|
|
||||||
_pixel_t main[2];
|
|
||||||
main[0] = *(const _pixel_t *)backing;
|
|
||||||
write_to_file(f, 8, main);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_color_data(file *f, const backing_t backing) {}
|
|
||||||
|
|
||||||
backing_t read_color_backing(file *f, uint32_t data_start) {
|
|
||||||
_pixel_t *p = new _pixel_t[1];
|
|
||||||
read_from_file(f, 3, p);
|
|
||||||
return (backing_t)p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_into_picker(raleigh::colorpicker &e, _pixel_t *s) {
|
|
||||||
e.set_picked_color(*s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_from_picker(raleigh::colorpicker &e, _pixel_t *&s) {
|
|
||||||
*s = e.get_picked_color();
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_color_editor(setting &s) {
|
|
||||||
do_common_editor<_pixel_t *, raleigh::colorpicker, &load_into_picker, &save_from_picker>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
const setting_kind_info color_kind = {
|
|
||||||
&write_color_main,
|
|
||||||
&write_color_data,
|
|
||||||
&read_color_backing,
|
|
||||||
&open_color_editor
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef COLOR_KIND_H
|
|
||||||
#define COLOR_KIND_H
|
|
||||||
|
|
||||||
#include "model.h"
|
|
||||||
|
|
||||||
extern const setting_kind_info color_kind;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,35 +0,0 @@
|
||||||
#include "model.h"
|
|
||||||
|
|
||||||
#include <raleigh/w/button.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
|
|
||||||
#define SETTINGS_FILE "/sys/settings.pls"
|
|
||||||
|
|
||||||
using namespace raleigh;
|
|
||||||
|
|
||||||
void on_button(button_tag_t tag) {
|
|
||||||
setting *s = (setting *)tag;
|
|
||||||
s->kind->open_editor(*s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
settings_model sm(SETTINGS_FILE);
|
|
||||||
|
|
||||||
label instructions("Click a button below to edit that setting.");
|
|
||||||
|
|
||||||
dllist<widget &> box_widgets;
|
|
||||||
box_widgets.add_back(instructions);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sm.settings.n_entries; ++i) {
|
|
||||||
label *l = new label(sm.settings.buf[i].name);
|
|
||||||
button *b = new button(*l, &on_button, (button_tag_t)&sm.settings.buf[i]);
|
|
||||||
box_widgets.add_back(*b);
|
|
||||||
}
|
|
||||||
|
|
||||||
vbox box(box_widgets);
|
|
||||||
window w(box);
|
|
||||||
w.show();
|
|
||||||
|
|
||||||
start_runtime();
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
#include <raleigh/util.h>
|
|
||||||
|
|
||||||
#include "string_kind.h"
|
|
||||||
#include "color_kind.h"
|
|
||||||
|
|
||||||
#define N_SETTING_KINDS 2
|
|
||||||
const setting_kind_info *setting_kinds[] = {
|
|
||||||
&string_kind,
|
|
||||||
&color_kind
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_head {
|
|
||||||
uint32_t main_start;
|
|
||||||
uint32_t count;
|
|
||||||
uint32_t names_start;
|
|
||||||
uint32_t data_start;
|
|
||||||
} __attribute__ ((__packed__));
|
|
||||||
|
|
||||||
struct setting_head {
|
|
||||||
uint32_t name_offset;
|
|
||||||
uint8_t name_length;
|
|
||||||
uint8_t type;
|
|
||||||
} __attribute__ ((__packed__));
|
|
||||||
|
|
||||||
settings_model::settings_model(const char *from_file)
|
|
||||||
: settings() {
|
|
||||||
file *f = open_file(from_file);
|
|
||||||
|
|
||||||
file_head header;
|
|
||||||
read_from_file(f, 16, &header);
|
|
||||||
settings.expand_to(header.count);
|
|
||||||
settings.n_entries = header.count;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < header.count; ++i) {
|
|
||||||
setting_head shead;
|
|
||||||
seek_file_to(f, header.main_start + i * 16);
|
|
||||||
read_from_file(f, sizeof(setting_head), &shead);
|
|
||||||
|
|
||||||
char *name = new char[shead.name_length + 1];
|
|
||||||
seek_file_to(f, header.names_start + shead.name_offset);
|
|
||||||
read_from_file(f, shead.name_length, name);
|
|
||||||
name[shead.name_length] = '\0';
|
|
||||||
|
|
||||||
if (shead.type >= N_SETTING_KINDS)
|
|
||||||
raleigh::show_error_popup_and_quitf("setting \"%s\" has unkown type 0x%2x.", name, shead.type);
|
|
||||||
|
|
||||||
setting ns;
|
|
||||||
ns.name = name;
|
|
||||||
ns.kind = setting_kinds[shead.type];
|
|
||||||
|
|
||||||
seek_file_to(f, header.main_start + i * 16 + 8);
|
|
||||||
ns.backing = ns.kind->read_backing(f, header.data_start);
|
|
||||||
|
|
||||||
settings.buf[i] = ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
close_file(f);
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef MODEL_H
|
|
||||||
#define MODEL_H
|
|
||||||
|
|
||||||
#include <raleigh/d/dialog.h>
|
|
||||||
#include <raleigh/w/button.h>
|
|
||||||
#include <raleigh/w/label.h>
|
|
||||||
#include <raleigh/w/vbox.h>
|
|
||||||
#include <raleigh/window.h>
|
|
||||||
#include <structs/map.h>
|
|
||||||
#include <knob/file.h>
|
|
||||||
|
|
||||||
typedef void *backing_t;
|
|
||||||
|
|
||||||
struct setting;
|
|
||||||
|
|
||||||
struct setting_kind_info {
|
|
||||||
void (*write_main)(uint32_t &data_offset, file *f, const backing_t backing);
|
|
||||||
void (*write_data)(file *f, const backing_t backing);
|
|
||||||
backing_t (*read_backing)(file *f, uint32_t data_start);
|
|
||||||
void (*open_editor)(setting &s);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct setting {
|
|
||||||
const char *name;
|
|
||||||
const setting_kind_info *kind;
|
|
||||||
void *backing;
|
|
||||||
};
|
|
||||||
|
|
||||||
class settings_model {
|
|
||||||
public:
|
|
||||||
settings_model(const char *from_file);
|
|
||||||
|
|
||||||
void write_to_file(const char *to_file);
|
|
||||||
|
|
||||||
alist<setting> settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
using namespace raleigh;
|
|
||||||
|
|
||||||
template<class backing_type, class editing_widget, void (*load_into_widget)(editing_widget &ew, backing_type s), void (*save_from_widget)(editing_widget &ew, backing_type &s)>
|
|
||||||
void do_common_editor(setting &s) {
|
|
||||||
dllist<widget &> widgets;
|
|
||||||
|
|
||||||
label l(s.name);
|
|
||||||
widgets.add_back(l);
|
|
||||||
|
|
||||||
editing_widget ew;
|
|
||||||
load_into_widget(ew, (backing_type)s.backing);
|
|
||||||
widgets.add_back(ew);
|
|
||||||
|
|
||||||
vbox box(widgets);
|
|
||||||
|
|
||||||
dialog d(box, okay_cancel);
|
|
||||||
d.show_modal();
|
|
||||||
|
|
||||||
if (d.result == OKAY)
|
|
||||||
save_from_widget(ew, (backing_type &)s.backing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,52 +0,0 @@
|
||||||
#include "string_kind.h"
|
|
||||||
|
|
||||||
#include <raleigh/w/entry.h>
|
|
||||||
|
|
||||||
void write_string_main(uint32_t &data_offset, file *f, const backing_t backing) {
|
|
||||||
const uint32_t len = strlen((const char *)backing);
|
|
||||||
|
|
||||||
uint32_t main[2];
|
|
||||||
main[0] = data_offset;
|
|
||||||
main[1] = len;
|
|
||||||
|
|
||||||
data_offset += len;
|
|
||||||
|
|
||||||
write_to_file(f, 8, main);
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_string_data(file *f, const backing_t backing) {
|
|
||||||
const char *b = (const char *)backing;
|
|
||||||
write_to_file(f, strlen(b), b);
|
|
||||||
}
|
|
||||||
|
|
||||||
backing_t read_string_backing(file *f, uint32_t data_start) {
|
|
||||||
uint32_t main[2];
|
|
||||||
read_from_file(f, 8, main);
|
|
||||||
|
|
||||||
seek_file_to(f, data_start + main[0]);
|
|
||||||
|
|
||||||
char *buf = new char[main[1] + 1];
|
|
||||||
read_from_file(f, main[1], buf);
|
|
||||||
buf[main[1]] = '\0';
|
|
||||||
|
|
||||||
return (backing_t)buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_into_entry(raleigh::entry &e, const char *s) {
|
|
||||||
e.set_contents(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_from_entry(raleigh::entry &e, const char *&s) {
|
|
||||||
s = e.get_contents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_string_editor(setting &s) {
|
|
||||||
do_common_editor<const char *, raleigh::entry, &load_into_entry, &save_from_entry>(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
const setting_kind_info string_kind = {
|
|
||||||
&write_string_main,
|
|
||||||
&write_string_data,
|
|
||||||
&read_string_backing,
|
|
||||||
&open_string_editor
|
|
||||||
};
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef STRING_KIND_H
|
|
||||||
#define STRING_KIND_H
|
|
||||||
|
|
||||||
#include "model.h"
|
|
||||||
|
|
||||||
extern const setting_kind_info string_kind;
|
|
||||||
|
|
||||||
#endif
|
|
271
src/user/ttt/main.c
Normal file
271
src/user/ttt/main.c
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
#include <pland/syscall.h>
|
||||||
|
#include <popups/info.h>
|
||||||
|
#include <knob/rand.h>
|
||||||
|
|
||||||
|
#define SPACE_SIZE 20
|
||||||
|
#define BORDER_SIZE 4
|
||||||
|
#define WIDTH (SPACE_SIZE * 3 + BORDER_SIZE * 4)
|
||||||
|
|
||||||
|
#define BG ((_pixel_t){.r = 0xd6, .g = 0xd6, .b = 0xd6})
|
||||||
|
#define FG ((_pixel_t){.r = 0x33, .g = 0x33, .b = 0x33})
|
||||||
|
#define XC ((_pixel_t){.r = 0x60, .g = 0x06, .b = 0x43})
|
||||||
|
#define OC ((_pixel_t){.r = 0x2c, .g = 0x77, .b = 0x30})
|
||||||
|
#define SL ((_pixel_t){.r = 0x9d, .g = 0x99, .b = 0xc2})
|
||||||
|
|
||||||
|
static const bool x_pic[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,
|
||||||
|
0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,
|
||||||
|
0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,
|
||||||
|
0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,
|
||||||
|
0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,
|
||||||
|
0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,
|
||||||
|
0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const bool o_pic[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||||
|
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,
|
||||||
|
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||||
|
0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const bool b_pic[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {B, X, O} trit;
|
||||||
|
|
||||||
|
static const bool *pics[] = {b_pic, x_pic, o_pic};
|
||||||
|
static const _pixel_t colors[] = {FG, XC, OC};
|
||||||
|
|
||||||
|
static _window_handle_t w;
|
||||||
|
static _pixel_t pbuf[WIDTH * WIDTH];
|
||||||
|
static trit board_state[9];
|
||||||
|
static uint8_t cursor;
|
||||||
|
static trit playing_as;
|
||||||
|
static uint8_t filled_squares;
|
||||||
|
|
||||||
|
__attribute__ ((__pure__))
|
||||||
|
static bool is_win(uint8_t hint) {
|
||||||
|
const uint8_t c = hint % 3;
|
||||||
|
if ((board_state[c] == board_state[c + 3]) && (board_state[c] == board_state[c + 6]))
|
||||||
|
return true;
|
||||||
|
const uint8_t r = hint - c;
|
||||||
|
if ((board_state[r] == board_state[r + 1]) && (board_state[r] == board_state[r + 2]))
|
||||||
|
return true;
|
||||||
|
return board_state[4] && (
|
||||||
|
((board_state[0] == board_state[4]) && (board_state[0] == board_state[8])) ||
|
||||||
|
((board_state[2] == board_state[4]) && (board_state[2] == board_state[6]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_rect(uint8_t y, uint8_t x, uint8_t h, uint8_t w, _pixel_t color) {
|
||||||
|
for (uint8_t yy = y; yy < y + h; ++yy)
|
||||||
|
for (uint8_t xx = x; xx < x + w; ++xx)
|
||||||
|
pbuf[yy * WIDTH + xx] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_spot(uint8_t n) {
|
||||||
|
const _pixel_t bg_c = n == cursor ? SL : BG;
|
||||||
|
const _pixel_t fg_c = colors[board_state[n]];
|
||||||
|
const bool *const pic = pics[board_state[n]];
|
||||||
|
|
||||||
|
const uint8_t ys = BORDER_SIZE + (n / 3) * (BORDER_SIZE + SPACE_SIZE);
|
||||||
|
const uint8_t xs = BORDER_SIZE + (n % 3) * (BORDER_SIZE + SPACE_SIZE);
|
||||||
|
for (uint8_t y = 0; y < SPACE_SIZE; ++y)
|
||||||
|
for (uint8_t x = 0; x < SPACE_SIZE; ++x)
|
||||||
|
pbuf[(ys + y) * WIDTH + xs + x] = pic[y * SPACE_SIZE + x] ? fg_c : bg_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ai_turn();
|
||||||
|
|
||||||
|
static void reset_board() {
|
||||||
|
cursor = 4;
|
||||||
|
playing_as = gen_rand() % 2 + 1;
|
||||||
|
filled_squares = 0;
|
||||||
|
for (uint8_t i = 0; i < 9; ++i) {
|
||||||
|
board_state[i] = B;
|
||||||
|
draw_spot(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gen_rand() % 2)
|
||||||
|
ai_turn();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t start_time;
|
||||||
|
|
||||||
|
static void on_win() {
|
||||||
|
struct popup p;
|
||||||
|
info_popupf(&p, "You win! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time);
|
||||||
|
make_modal(&p);
|
||||||
|
reset_board();
|
||||||
|
_paint_window(w);
|
||||||
|
start_time = _get_timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_tie() {
|
||||||
|
struct popup p;
|
||||||
|
info_popupf(&p, "Tie! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time);
|
||||||
|
make_modal(&p);
|
||||||
|
reset_board();
|
||||||
|
_paint_window(w);
|
||||||
|
start_time = _get_timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ai_turn() {
|
||||||
|
//super easy mode
|
||||||
|
uint8_t n;
|
||||||
|
do
|
||||||
|
n = gen_rand() % 9;
|
||||||
|
while (board_state[n]);
|
||||||
|
board_state[n] = playing_as == O ? X : O;
|
||||||
|
draw_spot(n);
|
||||||
|
_paint_window(w);
|
||||||
|
if (is_win(n)) {
|
||||||
|
struct popup p;
|
||||||
|
info_popupf(&p, "You lose. Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time);
|
||||||
|
make_modal(&p);
|
||||||
|
reset_board();
|
||||||
|
_paint_window(w);
|
||||||
|
start_time = _get_timestamp();
|
||||||
|
}
|
||||||
|
else if (++filled_squares == 9)
|
||||||
|
on_tie();
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
struct popup controls;
|
||||||
|
info_popup(&controls,
|
||||||
|
"Tic-Tac-Toe Controls:\n\n"
|
||||||
|
"Arrow keys: move selection\n"
|
||||||
|
"Spacebar: confirm selection\n"
|
||||||
|
"Escape: quit\n\n"
|
||||||
|
"Press escape to start.", FG, BG);
|
||||||
|
make_modal(&controls);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < WIDTH * WIDTH; ++i)
|
||||||
|
pbuf[i] = BG;
|
||||||
|
|
||||||
|
draw_rect(SPACE_SIZE + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG);
|
||||||
|
draw_rect(BORDER_SIZE, SPACE_SIZE + BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG);
|
||||||
|
draw_rect(SPACE_SIZE * 2 + BORDER_SIZE * 2, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG);
|
||||||
|
draw_rect(BORDER_SIZE, SPACE_SIZE * 2 + BORDER_SIZE * 2, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG);
|
||||||
|
|
||||||
|
reset_board();
|
||||||
|
|
||||||
|
w = _new_window(WIDTH, WIDTH, pbuf);
|
||||||
|
start_time = _get_timestamp();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct window_action wa;
|
||||||
|
_get_win_action(w, &wa);
|
||||||
|
if (!wa.action_type) {
|
||||||
|
_wait_for_action();
|
||||||
|
_yield_task();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wa.action_type != KEY_DOWN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (wa.as_key.key_id) {
|
||||||
|
case KEY_UP_ARROW:
|
||||||
|
if (cursor >= 3) {
|
||||||
|
cursor -= 3;
|
||||||
|
draw_spot(cursor + 3);
|
||||||
|
draw_spot(cursor);
|
||||||
|
_paint_window(w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_DOWN_ARROW:
|
||||||
|
if (cursor < 6) {
|
||||||
|
cursor += 3;
|
||||||
|
draw_spot(cursor - 3);
|
||||||
|
draw_spot(cursor);
|
||||||
|
_paint_window(w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_LEFT_ARROW:
|
||||||
|
if (cursor % 3) {
|
||||||
|
--cursor;
|
||||||
|
draw_spot(cursor + 1);
|
||||||
|
draw_spot(cursor);
|
||||||
|
_paint_window(w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_RIGHT_ARROW:
|
||||||
|
if (cursor % 3 != 2) {
|
||||||
|
++cursor;
|
||||||
|
draw_spot(cursor - 1);
|
||||||
|
draw_spot(cursor);
|
||||||
|
_paint_window(w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KEY_ESCAPE:
|
||||||
|
return;
|
||||||
|
case KEY_SPACE:
|
||||||
|
if (!board_state[cursor]) {
|
||||||
|
board_state[cursor] = playing_as;
|
||||||
|
draw_spot(cursor);
|
||||||
|
_paint_window(w);
|
||||||
|
if (is_win(cursor))
|
||||||
|
on_win();
|
||||||
|
else if (++filled_squares == 9)
|
||||||
|
on_tie();
|
||||||
|
else
|
||||||
|
ai_turn();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue