window borders
This commit is contained in:
		
							parent
							
								
									e6c3a80b01
								
							
						
					
					
						commit
						c34b9191f2
					
				
					 20 changed files with 212 additions and 35 deletions
				
			
		|  | @ -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) | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
|   } | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
							
								
								
									
										78
									
								
								applications/goldman/source/window.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								applications/goldman/source/window.cpp
									
										
									
									
									
										Normal 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); | ||||
| 
 | ||||
| } | ||||
|  | @ -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); | ||||
|   } | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; } | ||||
| 
 | ||||
|   }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -4,6 +4,14 @@ | |||
| 
 | ||||
| namespace pake { | ||||
| 
 | ||||
|   enum class halign { | ||||
|     left, center, right | ||||
|   }; | ||||
| 
 | ||||
|   enum class valign { | ||||
|     top, center, bottom | ||||
|   }; | ||||
| 
 | ||||
|   class widget { | ||||
| 
 | ||||
|   public: | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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). | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								skeleton/assets/terminus/6x12.psf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								skeleton/assets/terminus/6x12.psf
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										3
									
								
								skeleton/assets/terminus/readme.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								skeleton/assets/terminus/readme.txt
									
										
									
									
									
										Normal 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). | ||||
		Reference in a new issue