window borders

This commit is contained in:
Benji Dial 2024-07-29 21:26:17 -04:00
parent e6c3a80b01
commit c34b9191f2
20 changed files with 212 additions and 35 deletions
applications
euler/include/std
libraries
daguerre/include/daguerre
pake
include/pake
source/widgets
readme.txt
skeleton/assets

View file

@ -1,5 +1,5 @@
SOURCES = \
main.cpp renderer.cpp input.cpp socket.cpp
main.cpp renderer.cpp input.cpp socket.cpp window.cpp
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)

View file

@ -52,9 +52,11 @@ void renderer::do_render() {
for (auto it = windows.begin(); it != windows.end(); ++it)
double_buffer.copy_from(
(*it)->contents, (*it)->x, (*it)->y, 0, 0,
std::min((*it)->contents.width, double_buffer.width - (*it)->x),
std::min((*it)->contents.height, double_buffer.height - (*it)->y));
(*it)->contents_with_decorations, (*it)->x, (*it)->y, 0, 0,
std::min((*it)->contents_with_decorations.width,
double_buffer.width - (*it)->x),
std::min((*it)->contents_with_decorations.height,
double_buffer.height - (*it)->y));
double_buffer.convert_from(
cursor_background, cursor, cursor_x, cursor_y, 0, 0,
@ -93,10 +95,15 @@ void renderer::bump_cursor(int x_offset, int y_offset) {
}
void renderer::add_window(const window *w) {
void renderer::add_window(window *w) {
if (windows.size() != 0)
windows.back()->draw_decorations(false);
w->draw_decorations(true);
windows.push_back(w);
}
void renderer::remove_window(const window *w) {
void renderer::remove_window(window *w) {
windows.remove(w);
if (windows.size() != 0)
windows.back()->draw_decorations(true);
}

View file

@ -18,7 +18,7 @@ class renderer {
int cursor_y;
//bottom to top
std::list<const window *> windows;
std::list<window *> windows;
std::mutex mut;
@ -55,7 +55,11 @@ public:
void bump_cursor(int x_offset, int y_offset);
void add_window(const window *w);
void remove_window(const window *w);
void add_window(window *w);
void remove_window(window *w);
inline bool is_top(window *w) {
return windows.size() != 0 && w == windows.back();
}
};

View file

@ -43,12 +43,13 @@ struct socket_state {
euler::syscall::stream_result::success)
return false;
if (packet.width > __INT_MAX__ || packet.height > __INT_MAX__)
if (packet. width > __INT_MAX__ - window::decorations_extra_width ||
packet.height > __INT_MAX__ - window::decorations_extra_height)
return false;
r->lock();
w->contents = daguerre::image<daguerre::hilbert_color>(
packet.width, packet.height);
w->set_size(packet.width, packet.height);
w->draw_decorations(r->is_top(w));
r->unlock();
return true;
@ -69,6 +70,7 @@ struct socket_state {
r->lock();
w->title = std::move(title);
w->draw_decorations(r->is_top(w));
r->unlock();
r->dispatch_render();
return true;

View file

@ -0,0 +1,78 @@
#include <daguerre/psf.hpp>
#include "renderer.hpp"
#include "window.hpp"
#include <cassert>
//TODO: make these statically intialized once that is implemented
bool have_initialized_decoration_stuff;
daguerre::fixed_font<bool> *title_font;
daguerre::hilbert_color border_color_top;
daguerre::hilbert_color border_color_not_top;
daguerre::hilbert_color title_color;
void window::set_size(int width, int height) {
contents_with_decorations =
daguerre::image<daguerre::hilbert_color>(width + 4, height + 18);
contents = daguerre::image<daguerre::hilbert_color>(
width, height,
&contents_with_decorations.at(2, 16),
contents_with_decorations.buffer_pitch, false);
}
void title_converter(
daguerre::hilbert_color &out, const bool &in, const bool &top) {
out = in ? title_color : top ? border_color_top : border_color_not_top;
}
void window::draw_decorations(bool top) {
//TODO: handle error loading font.
//see also comment on title_font declaration.
if (!have_initialized_decoration_stuff) {
title_font = new daguerre::fixed_font<bool>(
*daguerre::try_load_psf("/assets/terminus/6x12.psf"));
assert(title_font->glyph_height == 12);
border_color_top = euler::syscall::encode_color(0x00, 0x3f, 0xff);
border_color_not_top = euler::syscall::encode_color(0x22, 0x22, 0x22);
title_color = euler::syscall::encode_color(0xff, 0xff, 0xff);
have_initialized_decoration_stuff = true;
}
static_assert( decorations_extra_width == 4);
static_assert(decorations_extra_height == 18);
auto border_color = top ? border_color_top : border_color_not_top;
contents_with_decorations.fill(border_color, 0, 0,
contents_with_decorations.width, 16);
contents_with_decorations.fill(
border_color, 0, contents_with_decorations.height - 2,
contents_with_decorations.width, 2);
contents_with_decorations.fill(border_color, 0, 16,
2, contents_with_decorations.height - 18);
contents_with_decorations.fill(border_color,
contents_with_decorations.width - 2, 16,
2, contents_with_decorations.height - 18);
//TODO: make UTF-8--safe
unsigned max_title_length =
contents_with_decorations.width / title_font->glyph_width;
std::string *title_to_draw;
std::string shortened_title;
if (title.size() > max_title_length) {
shortened_title.resize(max_title_length - 3);
memcpy(shortened_title.data(), title.data(), max_title_length - 3);
shortened_title[max_title_length - 3] = '.';
shortened_title[max_title_length - 2] = '.';
shortened_title[max_title_length - 1] = '.';
title_to_draw = &shortened_title;
}
else
title_to_draw = &title;
contents_with_decorations.render_text(*title_font, top,
contents_with_decorations.width / 2 -
(title_to_draw->size() * title_font->glyph_width) / 2,
2, title_to_draw->data(), title_converter);
}

View file

@ -4,6 +4,10 @@
struct window {
static constexpr int decorations_extra_width = 4;
static constexpr int decorations_extra_height = 18;
daguerre::image<daguerre::hilbert_color> contents_with_decorations;
daguerre::image<daguerre::hilbert_color> contents;
int x;
@ -13,6 +17,12 @@ struct window {
std::string title;
window() : x(0), y(0), is_shown(false) {}
void set_size(int width, int height);
void draw_decorations(bool top);
inline window() : x(0), y(0), is_shown(false) {
set_size(0, 0);
draw_decorations(false);
}
};

View file

@ -7,18 +7,30 @@ daguerre::fixed_font<bool> *font;
int main(int, char **) {
font = new daguerre::fixed_font<bool>(
daguerre::try_load_psf("/assets/terminus-bold-18x10.psf").value());
daguerre::try_load_psf("/assets/terminus/10x18-bold.psf").value());
pake::widgets::fixed_text *text =
new pake::widgets::fixed_text("Hello, world!", font,
euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
euler::syscall::encode_color(0x00, 0x00, 0x00));
euler::syscall::encode_color(0x00, 0x00, 0x00),
pake::halign::center, pake::valign::center);
pake::window w(300, 200, "Hello");
w.set_root(std::unique_ptr<pake::widget>(text));
w.render_and_send_to_compositor();
w.show();
pake::widgets::fixed_text *text2 =
new pake::widgets::fixed_text("H!", font,
euler::syscall::encode_color(0xaa, 0xaa, 0xaa),
euler::syscall::encode_color(0x00, 0x00, 0x00),
pake::halign::center, pake::valign::center);
pake::window w2(100, 50, "Hello 2");
w2.set_root(std::unique_ptr<pake::widget>(text2));
w2.render_and_send_to_compositor();
w2.show();
//TODO: call event loop
euler::syscall::stream_handle h1, h2;

View file

@ -155,6 +155,11 @@ namespace std {
return *this;
}
T &back() { return last_node->value; }
const T &back() const { return last_node->value; }
size_t size() const noexcept { return count; }
};
}

View file

@ -110,6 +110,13 @@ namespace daguerre {
param_converter_t<color_t, font_color_t, param_t> *conversion =
&default_conversion);
//does not check bounds or wrap text
template <class font_color_t>
void render_text(
const fixed_font<font_color_t> &font, int x, int y, const char *text,
converter_t<color_t, font_color_t> *conversion =
&default_conversion);
};
template <class color_t>

View file

@ -35,6 +35,7 @@ namespace daguerre {
glyphs[i] = std::move(other.glyphs[i]);
other.glyph_width = 0;
other.glyph_height = 0;
return *this;
}
template <class color_t>

View file

@ -107,7 +107,7 @@ namespace daguerre {
void image<color_t>::fill(
const color_t &color, int start_x, int start_y, int width, int height) {
for (int y = start_y; y < start_y + height; ++y)
for (int x = 0; x < start_x + width; ++x)
for (int x = start_x; x < start_x + width; ++x)
buffer[y * buffer_pitch + x] = color;
}
@ -170,7 +170,7 @@ namespace daguerre {
void image<color_t>::convert_from(
const image<other_color_t> &other, int to_x, int to_y,
converter_t<color_t, other_color_t> *conversion) {
convert_from(other, to_x, to_y, 0, 0, other.width, other.y, conversion);
convert_from(other, to_x, to_y, 0, 0, other.width, other.height, conversion);
}
template <class color_t>
@ -213,6 +213,22 @@ namespace daguerre {
}
template <class color_t>
template <class font_color_t>
void image<color_t>::render_text(
const fixed_font<font_color_t> &font, int x, int y, const char *text,
converter_t<color_t, font_color_t> *conversion) {
while (*text) {
int ch = *text;
if (ch >= 0 && ch < 128)
convert_from(font.glyphs[ch], x, y, conversion);
++text;
x += font.glyph_width;
}
}
template <class color_t>
void swap(image<color_t> &a, image<color_t> &b) {
std::swap(a.delete_buffer_on_destruct, b.delete_buffer_on_destruct);

View file

@ -4,6 +4,14 @@
namespace pake {
enum class halign {
left, center, right
};
enum class valign {
top, center, bottom
};
class widget {
public:

View file

@ -12,6 +12,8 @@ namespace pake::widgets {
std::string text;
int width, height;
halign ha;
valign va;
public:
//TODO: look up font in some kind of catalogue
@ -19,7 +21,8 @@ namespace pake::widgets {
std::string &&text,
const daguerre::fixed_font<bool> *font,
daguerre::hilbert_color bg,
daguerre::hilbert_color fg);
daguerre::hilbert_color fg,
halign ha, valign va);
virtual void render(
dirtiable_image &onto, int x_off, int y_off, bool force) override;

View file

@ -12,24 +12,48 @@ namespace pake::widgets {
std::string &&text,
const daguerre::fixed_font<bool> *font,
daguerre::hilbert_color bg,
daguerre::hilbert_color fg)
: font(font), bg(bg), fg(fg), text(std::move(text)) {}
daguerre::hilbert_color fg,
halign ha, valign va)
: font(font), bg(bg), fg(fg),
text(std::move(text)), ha(ha), va(va) {}
void fixed_text::render(
dirtiable_image &onto, int x_off, int y_off, bool force) {
if (force) {
onto.image.fill( bg, x_off, y_off, width, height);
onto.dirty.fill(true, x_off, y_off, width, height);
//TODO: have options for alignment
//TODO: check overflow
onto.dirty.fill(true, x_off, y_off, width, height);
onto.image.fill( bg, x_off, y_off, width, height);
switch (ha) {
case halign::left:
break;
case halign::center:
x_off = width / 2 - text.size() * font->glyph_width / 2;
break;
case halign::right:
x_off = width - text.size() * font->glyph_width;
break;
}
switch (va) {
case valign::top:
break;
case valign::center:
y_off = height / 2 - font->glyph_height / 2;
break;
case valign::bottom:
y_off = height - font->glyph_width;
break;
}
onto.image.render_text(
*font, fg, x_off, y_off,
text.data(), draw_if_true);
onto.dirty.fill(
true, x_off, y_off,
font->glyph_width * text.size(),
font->glyph_height);
}
}

View file

@ -5,7 +5,8 @@ makefile target builds a disk image at build/disk.iso that can be booted on a
64-bit bios system. you can use command [2] to build that. finally, use
command [3] to run the disk in qemu with gdb attached.
[1] apt install bison flex g++ gdb git libgmp-dev libmpfr-dev libmpc-dev make nasm qemu-system-x86 texinfo xorriso
[1] apt install bison flex g++ gdb git libgmp-dev libmpfr-dev
libmpc-dev make nasm qemu-system-x86 texinfo xorriso
[2] make -j$(nproc)
[3] make run
@ -44,7 +45,7 @@ acknowledgements (any under "dependencies" are downloaded during build):
license: https://unsplash.com/license
source: https://unsplash.com/photos/selective-focus-photography-snowflakes-9yhy1FXlKwI
- skeleton/assets/terminus-bold-18x10.psf (terminus font, bold, 18x10)
- skeleton/assets/terminus/*.psf (terminus font)
copyright 2020 dimitar toshkov zhekov
license: skeleton/assets/terminus-ofl.txt (sil open font license v1.1)
homepage: https://terminus-font.sourceforge.net/
@ -87,8 +88,8 @@ project structure:
- libraries/daguerre:
an image loading / rendering library.
- libraries/goldman:
a library for interfacing with the goldman compositor
- libraries/pake:
a widget library for windowed applications
- patches:
a couple patches that are applied to dependencies

View file

@ -5,7 +5,3 @@ its license can be found online at https://unsplash.com/license.
the icon in pointer.ppm is released under the cc0 1.0 universal public
domain dedication (https://creativecommons.org/publicdomain/zero/1.0/).
the font in terminus-bold-18x10.psf is the "terminus" font, in bold weight, at
18x10. it can be found only at https://terminus-font.sourceforge.net/ and is
under the license in terminus-ofl.txt (the sil open font license v1.1).

Binary file not shown.

View file

@ -0,0 +1,3 @@
this directory contains the "terminus" font, at a couple weights and sizes.
terminus can be found only at https://terminus-font.sourceforge.net/ and is
under the license in terminus-ofl.txt (the sil open font license v1.1).