/
trilirium
/
Archived_BLC
Обзор
Документация
Войти
/
trilirium
/
Archived_BLC
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
textform.cpp
2 379 строк
54 KB
Trilirium
repo created OK
22 янв 2026, 16:43
22 янв 2026, 16:43
f05d14b
Код
Авторство
О чём код?
/* + === - === - === - === - === - === - === - === | | textform.cpp | | Text content formatting engine | + === - === - === - === - === - === - === - === */ #include "mem_mgr.h" #include "canvas.h" #include "widgets.h" #include "textform.h" // // Null console interface // struct Null_Console : A_Console { void _put_text (char const *text, unsigned count) {} }; // Null_Console static Null_Console _null_console; // // Conditional output // // (if check) A_Console &A_Console::check_if (bool cond) { return cond ? *this : _null_console; } // A_Console::check_if // (unless check) A_Console &A_Console::check_unless (bool cond) { return cond ? _null_console : *this; } // A_Console::check_unless // (conditional end) A_Console &A_Console::check_end (A_Console &console) { return console; } // A_Console::check_end // // Check string value (compare) // bool A_Console::expect_eq (char const *message, char const *expected, char const *obtained) { if (strcmp (expected, obtained)) { out_label ("Unexpected:"); out_cstr (message); out_cstr (" ["); out_cstr (expected); out_cstr (" : "); out_cstr (obtained); out_cstr (" ]"); out_nl (); return false; } return true; } // A_Console::expect_eq // Convert number (by radix) static void digits_unsigned (unsigned value, char *_buffer, short radix, short digits) { if (value == 0) { while (digits --) *_buffer ++ = '0'; *_buffer = '\0'; } else { unsigned count = 0, dig; do { for (int i = count; i; -- i) _buffer [i] = _buffer [i - 1]; count ++; dig = value % radix; *_buffer = dig < 10 ? '0' + dig : 'A' + dig - 10; } while (value /= radix); // (padding) if (count < digits) { unsigned shift = digits - count; while (count --) _buffer [count + shift] = _buffer [count]; while (shift --) _buffer [shift] = '0'; _buffer [digits] = '\0'; } else _buffer [count] = '\0'; } } // digits_unsigned // Put decimal number void A_Console::print_decimal (unsigned value, short digits) { char _buffer [10 + 1]; digits_unsigned (value, _buffer, 10, digits); print_cstr (_buffer); } // A_Console::print_decimal // Put octal number void A_Console::print_octal (unsigned value, short digits) { char _buffer [11 + 1]; digits_unsigned (value, _buffer, 8, digits); print_cstr (_buffer); } // A_Console::print_octal // Put hex number void A_Console::print_hex (unsigned value, short digits) { char _buffer [8 + 1]; digits_unsigned (value, _buffer, 16, digits); print_cstr (_buffer); } // A_Console::print_hex // Print text (in quotes) void A_Console::print_text (char const *text, unsigned len) { print_char ('"'); _put_text (text, len); print_char ('"'); } // A_Console::print_text // Print hex text (in brockets) void A_Console::print_hex_text (char const *text, unsigned len) { print_char ('<'); for (int i = 0; i != len; ++ i) { if (i) print_char (' '); print_hex (text [i] & 0xFF); } print_char ('>'); } // A_Console::print_hex_text // Print wide text (in brockets) void A_Console::print_w_text (wchar_t const *w_text, unsigned len) { print_char ('<'); for (int i = 0; i != len; ++ i) { if (i) print_char (' '); print_hex (w_text [i]); } print_char ('>'); } // A_Console::print_w_text // // Common canvas attributes // // Get plot color Color A_Canvas::get_plot_color (){ Color _color = plot_color (0); // (restore back) plot_color (_color); return _color; } // A_Canvas::get_plot_color // Get fill color Color A_Canvas::get_fill_color () { Color _color = fill_color (0); // (restore back) fill_color (_color); return _color; } // A_Canvas::get_fill_color // Get font face char const *A_Canvas::get_fontface () { enum { MaxFontName = 64 }; char _font_face [MaxFontName + 1]; if (style_fontface ("", _font_face, MaxFontName)) { // (restore back) style_fontface (_font_face, 0, MaxFontName); unsigned font_len = strlen (_font_face); char *font_face = new ("<font_face>") char [font_len + 1]; memcpy (font_face, _font_face, font_len); font_face [font_len] = '\0'; return font_face; } return 0; // (failed) } // A_Canvas::get_fontface // Get font size unsigned A_Canvas::get_fontsize () { unsigned font_size = style_fontsize (1); // (restore back) style_fontsize (font_size); return font_size; } // A_Canvas::get_fontsize // Get font color Color A_Canvas::get_fontcolor () { Color font_color = style_fontcolor (0); // (restore back) style_fontcolor (font_color); return font_color; } // A_Canvas::get_fontcolor // Get font background color Color A_Canvas::get_backcolor () { Color back_color = style_backcolor (0); // (restore back) style_backcolor (back_color); return back_color; } // A_Canvas::get_backcolor // Get font bold style bool A_Canvas::is_bold () { bool flag = style_bold (false); style_bold (flag); return flag; } // A_Canvas::is_bold // Get font italic style bool A_Canvas::is_italic () { bool flag = style_italic (false); style_italic (flag); return flag; } // A_Canvas::is_italic // Get font underline style bool A_Canvas::is_underline () { bool flag = style_underline (false); style_underline (flag); return flag; } // A_Canvas::is_underline // Get font overstrike style bool A_Canvas::is_overstrike () { bool flag = style_overstrike (false); style_overstrike (flag); return flag; } // A_Canvas::is_overstrike // // Text term constructors // TFE_Text_C::TFE_Text_C (unsigned Len, char const *_Text) : TFE_Text (Len, 0) { char *__Text = new ("[Text_C]") char [Len]; memcpy (__Text, _Text, Len); Text = __Text; } // TFE_Text_C::TFE_Text_C TFE_Text_C::~TFE_Text_C () { delete [] Text; } TFE_W_Text_C::TFE_W_Text_C (unsigned Len, wchar_t const *_W_Text) : TFE_W_Text (Len, 0) { wchar_t * __W_Text = new ("[W_Text_C]") wchar_t [Len]; memcpy (__W_Text, _W_Text, Len * sizeof (wchar_t)); W_Text = __W_Text; } // TFE_W_Text_C::TFE_W_Text_C TFE_W_Text_C::~TFE_W_Text_C () { delete [] W_Text; } // // Metrics implementation // // (constructor) A_Metrix::A_Metrix () : paragraph (0, 0) { elem_count = 0; elem_vector = 0; action_list = 0; style_count = 0; style_list = 0; span_list = 0; } // A_Metrix::A_Metrix // Prepare metrix // (before actual use) void A_Metrix::prepare () { unsigned _count = elem_count; Elem_Metrix *_ptr = elem_vector = new ("Metrix[]") Elem_Metrix [_count]; // (clean vector up...) while (_count --) { _ptr->orig.clear (); _ptr->size.clear (); _ptr->flags = 0; ++ _ptr; } // while (count) GfxExtent.clear (); } // A_Metrix::prepare // Unprepare metrix // (after actual use) void A_Metrix::unprepare () { if (elem_vector) delete [] elem_vector; elem_vector = 0; } // A_Metrix::unprepare // expand with area: [Start -> End] void A_Metrix::expand (Point &Start, Point &End) { Rect &extent = GfxExtent; bool empty = ! extent.not_empty (); // // horizontal expand // if (Start.X < End.X) { if (empty) { extent.LeftTop.X = Start.X; extent.RightBottom.X = End.X; } else { if (Start.X < extent.LeftTop.X) extent.LeftTop.X = Start.X; if (End.X > extent.RightBottom.X) extent.RightBottom.X = End.X; } } else if (Start.X > End.X) { if (empty) { extent.LeftTop.X = End.X; extent.RightBottom.X = Start.X; } else { if (End.X < extent.LeftTop.X) extent.LeftTop.X = End.X; if (Start.X > extent.RightBottom.X) extent.RightBottom.X = Start.X; } } else { // (Start.X == End.X) if (empty) extent.LeftTop.X = extent.RightBottom.X = Start.X; else { if (Start.X < extent.LeftTop.X) extent.LeftTop.X = Start.X; else if (Start.X > extent.RightBottom.X) extent.RightBottom.X = Start.X; } } // // vertical expand // if (Start.Y < End.Y) { if (empty) { extent.LeftTop.Y = Start.Y; extent.RightBottom.Y = End.Y; } else { if (Start.Y < extent.LeftTop.Y) extent.LeftTop.Y = Start.Y; if (End.Y > extent.RightBottom.Y) extent.RightBottom.Y = End.Y; } } else if (Start.Y > End.Y) { if (empty) { extent.LeftTop.Y = End.Y; extent.RightBottom.Y = Start.Y; } else { if (End.Y < extent.LeftTop.Y) extent.LeftTop.Y = End.Y; if (Start.Y > extent.RightBottom.Y) extent.RightBottom.Y = Start.Y; } } else { // (Start.Y == End.Y) if (empty) extent.LeftTop.Y = extent.RightBottom.Y = Start.Y; else { if (Start.Y < extent.LeftTop.Y) extent.LeftTop.Y = Start.Y; else if (Start.Y > extent.RightBottom.Y) extent.RightBottom.Y = Start.Y; } } } // A_Metrix::expand // Count elements (with actual metrix) unsigned A_Metrix::count_list (TFE_Term *node) { TFE_Attr *attr; unsigned count = 0; for ( ; node; node = node->next) if (attr = node->as_Attr ()) // (...recurse...) count += count_list (attr->list); else ++ count; return count; } // A_Metrix::count_list // // Attributes (TFE_A_ ...) implemented // // Apply Bold bool TFE_A_Bold::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { bool _state = canvas.style_bold (state); bool result = (this->*process_all) (canvas, metrix); canvas.style_bold (_state); return result; } // apply void TFE_A_Bold::dump (A_Console &console) { console.out_label ("Bold"). out_bool (state); } // Apply Italic bool TFE_A_Italic::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { bool _state = canvas.style_italic (state); bool result = (this->*process_all) (canvas, metrix); canvas.style_italic (_state); return result; } // apply void TFE_A_Italic::dump (A_Console &console) { console.out_label ("Italic"). out_bool (state); } // Apply Underline bool TFE_A_ULine::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { bool _state = canvas.style_underline (state); bool result = (this->*process_all) (canvas, metrix); canvas.style_underline (_state); return result; } // TFE_A_ULine::apply void TFE_A_ULine::dump (A_Console &console) { console.out_label ("Underline"). out_bool (state); } // Apply Overstrike bool TFE_A_OStrike::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { bool _state = canvas.style_overstrike (state); bool result = (this->*process_all) (canvas, metrix); canvas.style_overstrike (_state); return result; } // TFE_A_OStrike::apply void TFE_A_OStrike::dump (A_Console &console) { console.out_label ("Overstrike"). out_bool (state); } // Apply Font Face bool TFE_A_FontFace::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { enum { MaxFontName = 64 }; char _font_face [MaxFontName + 1]; if (canvas.style_fontface (font_face, _font_face, MaxFontName)) { bool result = (this->*process_all) (canvas, metrix); canvas.style_fontface (_font_face, 0, MaxFontName); return result; } else return false; } // TFE_A_FontFace::apply void TFE_A_FontFace::dump (A_Console &console) { console.out_label ("FontFace"). out_qstr (font_face, '[', ']'); } // Apply Font Size bool TFE_A_FontSize::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { unsigned _font_size = canvas.style_fontsize (font_size); bool result = (this->*process_all) (canvas, metrix); canvas.style_fontsize (_font_size); return result; } // TFE_A_FontSize::apply void TFE_A_FontSize::dump (A_Console &console) { console.out_label ("FontSize"). out_dec (font_size); } // Apply Font Width bool TFE_A_FontWidth::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { unsigned _font_width = canvas.style_fontwidth (font_width); bool result = (this->*process_all) (canvas, metrix); canvas.style_fontwidth (_font_width); return result; } // TFE_A_FontWidth::apply void TFE_A_FontWidth::dump (A_Console &console) { console.out_label ("FontWidth"). out_dec (font_width); } // Apply Font Color bool TFE_A_FontColor::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { unsigned _font_color = canvas.style_fontcolor (font_color); bool result = (this->*process_all) (canvas, metrix); canvas.style_fontcolor (_font_color); return result; } // TFE_A_FontColor::apply void TFE_A_FontColor::dump (A_Console &console) { console.out_label ("FontColor"). out_color (font_color); } // Apply Back Color bool TFE_A_BackColor::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { unsigned _back_color = canvas.style_backcolor (back_color); bool result = (this->*process_all) (canvas, metrix); canvas.style_backcolor (_back_color); return result; } // TFE_A_BackColor::apply void TFE_A_BackColor::dump (A_Console &console) { console.out_label ("BackColor"). out_color (back_color); } // Apply Font effect bool TFE_A_FontEffect::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { bool result = (this->*process_all) (canvas, metrix); return result; } // TFE_A_FontEffect::apply void TFE_A_FontEffect::dump (A_Console &console) { console.out_label ("FontEffect"); } // // Text formatting implemented // // (initialize) void TFE_A_Form::init (A_Metrix &metrix) { elem_beg = metrix.elem_count; TFE_Attr::init (metrix); elem_end = metrix.elem_count; } // TFE_A_Form::init // (dump) void TFE_A_Form::dump (A_Console &console) { console.out_label ("Form"). out_dec (H_Space); } // (reformatting fragment) bool TFE_A_Form::reform (A_Metrix &metrix, Point &origin, Point &extent) { unsigned count = metrix.elem_count; unsigned height = 0, left = origin.X; for (unsigned i = elem_beg; i != elem_end; ++ i) { Elem_Metrix &element = metrix.elem_vector[i]; element.orig = origin; origin.X += element.size.X + H_Space; if (element.size.Y > height) height = element.size.Y; } // for (i) origin.Y = extent.Y = height; extent.X = origin.X - left; return true; } // TFE_A_Form::reform // (init paragraph) void TFE_A_Para::init (A_Metrix &metrix) { elem_beg = metrix.elem_count; TFE_Attr::init (metrix); elem_end = metrix.elem_count; } // TFE_A_Para::init // (shape paragraph) bool TFE_A_Para::shape (A_Canvas &canvas, A_Metrix &metrix) { bool result = TFE_Attr::shape (canvas, metrix); if (elem_beg < elem_end && elem_end <= metrix.elem_count) { metrix.elem_vector [elem_beg].flags |= MF_ParaS; metrix.elem_vector [elem_end - 1].flags |= MF_ParaE; } return result; } // TFE_A_Para::shape // (dump) void TFE_A_Para::dump (A_Console &console) { console.out_label ('*'); } // (reformatting fragment) bool TFE_A_Para::reform (A_Metrix &metrix, Point &origin, Point &extent) { return metrix.para_reform (elem_beg, elem_end, origin, extent); } // (dump) void TFE_A_ParaLines::dump (A_Console &console) { console.out_label ("ParaLines"); } // // Word joiners // void TFE_WordGlue::init (A_Metrix &metrix) { ordinal = metrix.elem_count; } bool TFE_WordGlue::shape (A_Canvas &canvas, A_Metrix &metrix) { // (glue two elements together:) if (ordinal && ordinal < metrix.elem_count) { metrix.elem_vector [ordinal - 1].flags |= MF_GlueA; metrix.elem_vector [ordinal].flags |= MF_GlueB; return true; } return false; } // TFE_WordGlue::shape void TFE_WordGlue::dump (A_Console &console) { console.out_label ("<+>"); } void TFE_WordNail::init (A_Metrix &metrix) { ordinal = metrix.elem_count; } bool TFE_WordNail::shape (A_Canvas &canvas, A_Metrix &metrix) { // (nail two elements together:) if (ordinal && ordinal < metrix.elem_count) { metrix.elem_vector [ordinal - 1].flags |= MF_NailA; metrix.elem_vector [ordinal].flags |= MF_NailB; return true; } return false; } // TFE_WordNail::shape void TFE_WordNail::dump (A_Console &console) { console.out_label ("<~>"); } // // Text paragraph break // void TFE_ParaBreak::init (A_Metrix &metrix) { ordinal = metrix.elem_count; } bool TFE_ParaBreak::shape (A_Canvas &canvas, A_Metrix &metrix) { if (ordinal < metrix.elem_count) metrix.elem_vector [ordinal].flags |= MF_Break; return true; } // TFE_ParaBreak::shape void TFE_ParaBreak::dump (A_Console &console) { console.out_label ("<|>"); } // // Paragraph metrics // // (reformatting fragment) bool TFE_A_ParaMeter::reform (A_Metrix &metrix, Point &origin, Point &extent) { unsigned short ¶_value = metrix.paragraph.*refval; unsigned short _value = para_value; para_value = setval; bool result = TFE_Attr::reform (metrix, origin, extent); para_value = _value; return result; } // TFE_A_ParaMeter::reform void TFE_A_ParaMeter::dump (A_Console &console) { console. out_label (label). out_dec (setval); } // (reformatting fragment) bool TFE_A_ParaAlign::reform (A_Metrix &metrix, Point &origin, Point &extent) { signed char ¶_align = metrix.paragraph.*refval; signed char _align = para_align; para_align = setval; bool result = TFE_Attr::reform (metrix, origin, extent); para_align = _align; return result; } // TFE_A_ParaAlign::reform void TFE_A_ParaAlign::dump (A_Console &console) { char align_ch = setval < 0 ? '-' : setval == 0 ? '=' : setval > 1 ? '*' : '+'; console.out_label (label). out_ch (align_ch); } // TFE_A_ParaAlign::dump // // 'TFE_A_DefStyle' / 'TFE_A_WithStyle' : // implemented // // (constructor) TFE_A_DefStyle::TFE_A_DefStyle (char const *style_id, TFE_Attr *style_def) { this->style_id = style_id; this->style_def = style_def; style_ord = 0; style_link = 0; ref_node = 0; } // TFE_A_DefStyle::TFE_A_DefStyle // (init style def) void TFE_A_DefStyle::init (A_Metrix &metrix) { style_ord = ++ metrix.style_count; // (add to chain) style_link = metrix.style_list; metrix.style_list = this; for (TFE_Attr *style = style_def; style; style = style->list ? style->list->as_Attr () : 0) ref_node = &style->list; } // TFE_A_DefStyle::init void TFE_A_DefStyle::set_refer () { for (TFE_Attr *style = style_def; style; style = style->list ? style->list->as_Attr () : 0) ref_node = &style->list; } // TFE_A_DefStyle::set_refer // (dump style def) void TFE_A_DefStyle::dump (A_Console &console) { console. out_label ('%'). out_cstr (style_id). out_cstr (" : "); if (style_ord) console. out_ch ('['). out_dec (style_ord). out_ch (']'); for (TFE_Attr *style = style_def; style; style = style = style->list ? style->list->as_Attr () : 0) { style->dump (console); console.out_cstr (" -> "); } console.out_ch ('%'); } // TFE_A_DefStyle::dump // (apply style def) bool TFE_A_DefStyle::apply_style (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix), TFE_Term *elem_list) { if (ref_node) { bool result; TFE_Term *saved = *ref_node; *ref_node = elem_list; result = style_def->apply (canvas, metrix, process_all); *ref_node = saved; return result; } // (ref_node) return false; } // TFE_A_DefStyle::apply_style // (reformat with style) bool TFE_A_DefStyle::reform_style (A_Metrix &metrix, Point &origin, Point &extent, TFE_Term *elem_list) { if (ref_node) { bool result; TFE_Term *saved = *ref_node; *ref_node = elem_list; result = style_def->reform (metrix, origin, extent); *ref_node = saved; return result; } // (ref_node) return false; } // TFE_A_DefStyle::reform_style // (term style def) void TFE_A_DefStyle::term (A_Metrix &metrix) { } // TFE_A_DefStyle::term // (virtual destructor) TFE_A_DefStyle::~TFE_A_DefStyle () { TFE_Term *_list = style_def; release_list (_list); style_def = 0; } // TFE_A_DefStyle::~TFE_A_DefStyle // (constructor) TFE_A_WithStyle::TFE_A_WithStyle (char const *style_id) { this->style_id = style_id; style_ord = 0; style_def = 0; } // TFE_A_WithStyle::TFE_A_WithStyle // (init: bind to style def) void TFE_A_WithStyle::init (A_Metrix &metrix) { // (locate style in list) for (TFE_A_DefStyle *style = metrix.style_list; style; style = style->style_link) if (strcmp (style->style_id, style_id) == 0) { // (found style!) style_def = style; style_ord = style->style_ord; break; } // (super init) TFE_Attr::init (metrix); } // TFE_A_WithStyle::init // (apply attribute) bool TFE_A_WithStyle::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { if (style_def) return style_def->apply_style (canvas, metrix, process_all, list); return false; } // TFE_A_WithStyle::apply // (reformat attribute) bool TFE_A_WithStyle::reform (A_Metrix &metrix, Point &origin, Point &extent) { if (style_def) return style_def->reform_style (metrix, origin, extent, list); return false; } // TFE_A_WithStyle::reform // (dump) void TFE_A_WithStyle::dump (A_Console &console) { console. out_label ("$"). out_cstr (style_id); if (style_ord) console. out_ch ('['). out_dec (style_ord). out_ch (']'); } // TFE_A_WithStyle::dump void TFE_A_WithStyle::term (A_Metrix &metrix) { // (super term) TFE_Attr::term (metrix); } // TFE_A_WithStyle::term // // TFE_A_Error : implementation // // (constructor) TFE_A_Error::TFE_A_Error (char const *attr_name, unsigned name_len, char const *attr_arg, unsigned arg_len) { if (name_len) { error_name = new char [name_len + 1]; memcpy (error_name, attr_name, name_len); error_name[name_len] = '\0'; } else error_name = 0; if (arg_len) { error_arg = new char [arg_len + 1]; memcpy (error_arg, attr_arg, arg_len); error_arg[arg_len] = '\0'; } else error_arg = 0; } // TFE_A_Error::TFE_A_Error // (dump) void TFE_A_Error::dump (A_Console &console) { console.out_label ("Error"). out_ch ('['). out_cstr (error_name). out_ch (':'). out_cstr (error_arg). out_ch (']'); } // TFE_A_Error::dump // (destructor) TFE_A_Error::~TFE_A_Error () { if (error_name) delete [] error_name; if (error_arg) delete [] error_arg; } // TFE_A_Error::~TFE_A_Error // // IRL + URL implemented // // // URL action // TFE_Action_URL::TFE_Action_URL (Color linkback, char const *URL) { content_URL = URL; background = linkback; } TFE_Action_URL::~TFE_Action_URL () { delete [] content_URL; } void TFE_Action_URL::dump (A_Console &console) { console. out_label ("Action_URL:"). out_qstr (content_URL, '[', ']'); } // TFE_Action_URL::dump bool TFE_Action_URL::handle (RootWindow &root, A_Console &console, W_TextBox &textbox, unsigned type) { console. out_label ("URL activated:"). out_cstr (content_URL). out_nl (); if (content_URL) return root.URL_Launch (content_URL); return false; } // TFE_Action_URL::handle // // IRL action // TFE_Action_IRL::TFE_Action_IRL (Color linkback, char const *IRL) { content_IRL = IRL; background = linkback; } TFE_Action_IRL::~TFE_Action_IRL () { delete [] content_IRL; } void TFE_Action_IRL::dump (A_Console &console) { console. out_label ("Action_IRL"). out_cstr (content_IRL); } bool TFE_Action_IRL::handle (RootWindow &root, A_Console &console, W_TextBox &textbox, unsigned type) { console. out_label ("IRL activated:"). out_cstr (content_IRL). out_nl (); if (content_IRL) return root.IRL_Launch (content_IRL); return true; } // TFE_Action_IRL::handle // // Toggle span action // TFE_Action_Toggle::TFE_Action_Toggle (bool collapse, Color linkback, char const *spanID) { this->span_ID = spanID; // (span to toggle) this->collapse = collapse; } // TFE_Action_Toggle::TFE_Action_Toggle TFE_Action_Toggle::~TFE_Action_Toggle () { delete span_ID; } void TFE_Action_Toggle::dump (A_Console &console) { console. out_label ("Action_toggle:"). out_cstr (span_ID); } bool TFE_Action_Toggle::handle (RootWindow &root, A_Console &console, W_TextBox &textbox, unsigned type) { unsigned count = 0; A_Metrix &metrix = *textbox.metrix; for (TFE_TextSpan *span = metrix.span_list; span; span = span->next) { if (strcmp (span_ID, span->name) == 0) { // (found!) span->toggle (collapse, metrix); ++ count; } } // for (span) if (count) { console. out_label ("Toggle activated:"). out_cstr (span_ID). out_pfx ('{'). out_ch (collapse ? '*' : ' '). out_ch ('}'). out_nl (); return root.reshape_widget (&textbox); } console.out_label ("Undefined span:"). out_qstr (span_ID, '"', '"'). out_ch ('!'). out_nl (); } // TFE_Action_Toggle::handle // // Define text span // // (constructor) TFE_TextSpan::TFE_TextSpan (char const *_name, bool _state) { name = _name; state = _state; collapse = false; ord_beg = ord_end = 0; next = 0; contain = depth = 0; } // TFE_TextSpan::TFE_TextSpan // (init span) void TFE_TextSpan::init (A_Metrix &metrix) { ord_beg = metrix.elem_count; TFE_Attr::init (metrix); ord_end = metrix.elem_count; if (metrix.span_list) { // (next span in chain) next = metrix.span_list; metrix.span_list = this; } else { // (first span in chain) metrix.span_list = this; next = 0; } } // TFE_TextSpan::init // (shape span) bool TFE_TextSpan::shape (A_Canvas &canvas, A_Metrix &metrix) { bool result = TFE_Attr::shape (canvas, metrix); return result; } // TFE_TextSpan::shape // (span update) bool TFE_TextSpan::update (A_Metrix &metrix, unsigned flag) { if (ord_beg > ord_end) return false; Elem_Metrix *elem = metrix.elem_vector + ord_beg; unsigned count = ord_end - ord_beg; if (state) { // (show all elements:) flag = ~flag; while (count --) (elem ++)->flags &= flag; } else { // (hide all elements:) while (count --) (elem ++)->flags |= flag; } return true; } // TFE_TextSpan::update // (span toggle) bool TFE_TextSpan::toggle (bool collapse, A_Metrix &metrix) { state = ! state; update (metrix, MF_Hide | MF_OCol | MF_ICol); if (contain) { TFE_TextSpan *span = next; unsigned count = contain; while (count --) { span->update (metrix, MF_Hide | MF_ICol); span = span->next; } // while (...) } return state; } // TFE_TextSpan::toggle // (reform span) bool TFE_TextSpan::reform (A_Metrix &metrix, Point &origin, Point &extent) { return TFE_Attr::reform (metrix, origin, extent); } // TFE_TextSpan::reform // (draw span) bool TFE_TextSpan::draw (A_Canvas &canvas, A_Metrix &metrix) { if (state) return TFE_Attr::draw (canvas, metrix); else // (hidden) return true; } // TFE_TextSpan::draw // (dump self) void TFE_TextSpan::dump (A_Console &console) { console.out_label ("TextSpan"). out_cstr (name). out_tab (). out_bool (state); } // TFE_TextSpan::dump // (term span) void TFE_TextSpan::term (A_Metrix &metrix) { TFE_Attr::term (metrix); } // TFE_TextSpan::term // (destructor) TFE_TextSpan::~TFE_TextSpan () { if (name) { delete name; name = 0; } } // TFE_TextSpan::~TFE_TextSpan // Prepare actions in 'span_list' for work bool A_Metrix::prepare_spans (A_Canvas &canvas) { for (TFE_TextSpan *span_0 = span_list; span_0; span_0 = span_0->next) { unsigned count = 0; TFE_TextSpan *span_1 = span_0; while (span_1 = span_1->next) { if (span_0->ord_beg <= span_1->ord_beg && span_1->ord_end <= span_0->ord_end) { ++ count; ++ span_1->depth; } else break; } // while (span_1) span_0->contain = count; // (# spans inside) } // while (span_0) return true; } // A_Metrix::prepare_spans // // Graphic primitives // void TFE_Vertex::dump (A_Console &console) { console. out_ch ('^'). out_point (where); } // (get next VERTEX in chain) Point *TFE_G_Primary::fetch_vertex () { TFE_Term *elem = draw_list; TFE_Vertex *vertex = dynamic_cast <TFE_Vertex *> (elem); if (vertex) { draw_list = elem->next; return &vertex->where; } return 0; // (end of chain) } // TFE_G_Primary::fetch_vertex // (get next TEXT element in sequence) TFE_Elem *TFE_G_Primary::fetch_text () { TFE_Term *elem = draw_list; TFE_Elem *text_elem; if (elem && (text_elem = elem->as_Elem ())) { draw_list = elem->next; return text_elem; } return 0; // (end of chain) } // TFE_G_Primary::fetch_text // (dump terms list) void TFE_G_Primary::dump_list (A_Console &console, unsigned columns) { unsigned count = 0; Point *point; TFE_Term *_draw_list = draw_list; while (point = fetch_vertex ()) { if (count % columns == 0) console.out_nl (); console.out_tab (); console.out_point (*point); } draw_list = _draw_list; console.out_nl (); } // TFE_G_Primary::dump_list // === Points: // (shape points) bool TFE_G_Points::reshape (A_Metrix &metrix) { Point *At; while (At = fetch_vertex ()) metrix.expand (*At, *At); return true; } // TFE_G_Points::reshape // (draw points) bool TFE_G_Points::redraw (A_Canvas &canvas) { Point *At; while (At = fetch_vertex ()) { if (! canvas.plot (*At)) return false; } return true; } // TFE_G_Points::redraw // (dump points) void TFE_G_Points::dump (A_Console &console) { console.out_label ("Points"); dump_list (console, 1); } // TFE_G_Points::dump // === Lines: // (shape lines) bool TFE_G_Lines::reshape (A_Metrix &metrix) { Point *From, *To; while ( (From = fetch_vertex ()) && (To = fetch_vertex ()) ) metrix.expand (*From, *To); return true; } // TFE_G_Lines::reshape // (draw lines) bool TFE_G_Lines::redraw (A_Canvas &canvas) { Point *From, *To; while ( (From = fetch_vertex ()) && (To = fetch_vertex ()) ) if (! canvas.line (*From, *To)) return false; return true; } // TFE_G_Lines::redraw // (dump lines) void TFE_G_Lines::dump (A_Console &console) { console.out_label ("Lines"); dump_list (console, 2); } // TFE_G_Lines::dump // === PolyLines: // (shape connected lines) bool TFE_G_PolyLine::reshape (A_Metrix &metrix) { Point *From, *To; if (From = fetch_vertex ()) { while (To = fetch_vertex ()) { metrix.expand (*From, *To); From = To; } // while } return true; } // TFE_G_PolyLine::reshape // (draw connected lines) bool TFE_G_PolyLine::redraw (A_Canvas &canvas) { Point *From, *To; if (From = fetch_vertex ()) { while (To = fetch_vertex ()) { if (! canvas.line (*From, *To)) return false; From = To; } // while return true; } return false; } // TFE_G_PolyLine::redraw // (dump connected lines) void TFE_G_PolyLine::dump (A_Console &console) { console.out_label ("PolyLine"); dump_list (console, 1); } // TFE_G_PolyLine::dump // === Rectangles: // (shape rectangles) bool TFE_G_Rects::reshape (A_Metrix &metrix) { Point *Start, *End; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) ) metrix.expand (*Start, *End); return true; } // TFE_G_Rects::reshape // (draw rectangles) bool TFE_G_Rects::redraw (A_Canvas &canvas) { Point *Start, *End; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) ) if (! canvas.rectangle (*Start, *End)) return false; return true; } // TFE_G_Rects::redraw // (dump rectangles) void TFE_G_Rects::dump (A_Console &console) { console.out_label ("Rects"); dump_list (console, 2); } // TFE_G_Rects::dump // === Ovals: // (shape ovals) bool TFE_G_Ovals::reshape (A_Metrix &metrix) { Point *Start, *End; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) ) metrix.expand (*Start, *End); return true; } // TFE_G_Ovals::reshape // (draw ovals) bool TFE_G_Ovals::redraw (A_Canvas &canvas) { Point *Start, *End; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) ) if (! canvas.ellipse (*Start, *End)) return false; return true; } // TFE_G_Ovals::redraw // (dump ovals) void TFE_G_Ovals::dump (A_Console &console) { console.out_label ("Ovals"); dump_list (console, 2); } // TFE_G_Ovals::dump // === RoundRects: // (shape rounded rectangles) bool TFE_G_RoundRects::reshape (A_Metrix &metrix) { Point *Start, *End, *Angle; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) && (Angle = fetch_vertex ()) ) metrix.expand (*Start, *End); return true; } // TFE_G_RoundRects::reshape // (draw rounded rectangles) bool TFE_G_RoundRects::redraw (A_Canvas &canvas) { Point *Start, *End, *Angle; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) && (Angle = fetch_vertex ()) ) if (! canvas.round_rect (*Start, *End, *Angle)) return false; return true; } // TFE_G_RoundRects::redraw void TFE_G_RoundRects::dump (A_Console &console) { console.out_label ("RoundRects"); dump_list (console, 3); } // TFE_G_RoundRects::dump // === Arcs / Chords / Wedges: // ID => string static char const * Arc_Type (A_Canvas::ArcType arc_type) { switch (arc_type) { case A_Canvas::ArcPlain: return "Arcs"; case A_Canvas::ArcChord: return "Chords"; case A_Canvas::ArcWedge: return "Wedges"; } // switch return ""; // ??? unknown } // Arc_Type // (shape arcs/wedges/chords) bool TFE_G_Arcs::reshape (A_Metrix &metrix) { Point *Start, *End; Point *StartRay, *EndRay; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) && (StartRay = fetch_vertex ()) && (EndRay = fetch_vertex ()) ) metrix.expand (*Start, *End); return true; } // TFE_G_Arcs::reshape // (draw arcs/wedges/chords) bool TFE_G_Arcs::redraw (A_Canvas &canvas) { Point *Start, *End; Point *StartRay, *EndRay; while ( (Start = fetch_vertex ()) && (End = fetch_vertex ()) && (StartRay = fetch_vertex ()) && (EndRay = fetch_vertex ()) ) if (! canvas.arc_chord_wedge (arc_type, *Start, *End, *StartRay, *EndRay)) return false; return true; } // TFE_G_Arcs::redraw // (dump arcs/wedges/chords) void TFE_G_Arcs::dump (A_Console &console) { console. out_label (Arc_Type (arc_type)); dump_list (console, 4); } // TFE_G_Arcs::dump // === Trigons: // (shape trigons) bool TFE_G_Trigons::reshape (A_Metrix &metrix) { Point *V_A, *V_B, *V_C; while ( (V_A = fetch_vertex ()) && (V_B = fetch_vertex ()) && (V_C = fetch_vertex ()) ) { metrix.expand (*V_A, *V_B); metrix.expand (*V_B, *V_C); } return true; } // TFE_G_Trigons::reshape // (draw trigons) bool TFE_G_Trigons::redraw (A_Canvas &canvas) { Point *V_A, *V_B, *V_C; while ( (V_A = fetch_vertex ()) && (V_B = fetch_vertex ()) && (V_C = fetch_vertex ()) ) if (! canvas.trigon (*V_A, *V_B, *V_C)) return false; return true; } // TFE_G_Trigons::redraw void TFE_G_Trigons::dump (A_Console &console) { console.out_label ("Trigons"); dump_list (console, 3); } // TFE_G_Trigons::dump // === Text elements: // (shape text) bool TFE_G_Text::shape (A_Canvas &canvas, A_Metrix &metrix) { draw_list = list; // to be done!!!! return true; } // TFE_G_Text::shape // (draw text) bool TFE_G_Text::draw (A_Canvas &canvas, A_Metrix &metrix) { Point *Org; TFE_Elem *Text; draw_list = list; while ( (Org = fetch_vertex ()) && (Text = fetch_text ()) ) { metrix.elem_vector [Text->ordinal].orig = *Org; if (! Text->draw (canvas, metrix)) return false; } // while return true; } // TFE_G_Text::draw void TFE_G_Text::dump (A_Console &console) { console.out_label ("G_Text"); // correct dump TBD! } // TFE_G_Text::dump // Graphic attributes bool TFE_A_PlotColor::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { Color _plot_color = canvas.plot_color (plot_color); bool result = (this->*process_all) (canvas, metrix); canvas.plot_color (_plot_color); return result; } // apply void TFE_A_PlotColor::dump (A_Console &console) { console.out_label ("PlotColor"). out_color (plot_color); } bool TFE_A_FillColor::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { Color _fill_color = canvas.fill_color (fill_color); bool result = (this->*process_all) (canvas, metrix); canvas.fill_color (_fill_color); return result; } // TFE_A_FillColor::apply void TFE_A_FillColor::dump (A_Console &console) { console.out_label ("FillColor"). out_color (fill_color); } bool TFE_A_PlotFillColor::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { Color _plot_color = canvas.plot_color (color); Color _fill_color = canvas.fill_color (color); bool result = (this->*process_all) (canvas, metrix); canvas.plot_color (_plot_color); canvas.fill_color (_fill_color); return result; } // TFE_A_PlotFillColor::apply void TFE_A_PlotFillColor::dump (A_Console &console) { console.out_label ("PlotFillColor"). out_color (color); } // // Canvas object // void TFE_Canvas::init (A_Metrix &metrix) { ordinal = metrix.elem_count ++; } bool TFE_Canvas::shape (A_Canvas &canvas, A_Metrix &metrix) { metrix.elem_vector [ordinal].size = extent; return TFE_Attr::shape (canvas, metrix); } // TFE_Canvas::shape bool TFE_Canvas::draw (A_Canvas &canvas, A_Metrix &metrix) { canvas.fill_area_color (back, metrix.elem_vector [ordinal].orig, extent); return TFE_Attr::draw (canvas, metrix); } // TFE_Canvas::draw void TFE_Canvas::dump (A_Console &console) { console. out_label ("Canvas"). out_point (extent). out_tab (). out_color (back); } // // Implementing: text box // // (hyperlink color) Color linkColor (Color source, unsigned shift) { #if 0 return (((source & 0xFF0000) << shift) & 0xFF0000) | (((source & 0x00FF00) << shift) & 0x00FF00) | (((source & 0x0000FF) << shift) & 0x0000FF); #else return source ^ 0x3F3F3F; #endif } // linkColor // (Init text box) bool W_TextBox::init (A_Canvas &canvas) { metrix = new ("Metrix") A_Metrix; metrix->init_list (content); metrix->prepare (); if (0) metrix->count_list (content); metrix->prepare_actions (canvas, linkColor (color, 2), flags & WTB_ActJoin ? true : false); metrix->prepare_spans (canvas); if (metrix->shape_list (content, canvas)) { Area _area (0, 0, 0, 0); resize (_area); return true; } return false; } // W_TextBox::init // (Get text box area) bool W_TextBox::getarea (Area &area) { area.Origin = origin; area.Extent = extent; return true; } // W_TextBox::getarea // (Relocate text box) bool W_TextBox::reloc (Point &delta) { origin.shift (delta); return true; } // W_TextBox::reloc // (Resize text box) bool W_TextBox::resize (Area &area) { Point _origin = origin; Point _extent = extent; Point origin_0 (0, 0); // TODO: check for zero area (???) bool result = metrix->reform_list (content, origin_0, _extent); if (flags & WTB_ActJoin) // (join nodes for actions) for (TFE_A_Action *action = metrix->action_list; action; action = action->next) action->reflow_nodes (*metrix); extent.X = _extent.X; extent.Y = origin_0.Y; // (extent adjust) Rect &G_extent = metrix->GfxExtent; if (G_extent.not_empty ()) { // (horizontal?) if (G_extent.right () > extent.X) extent.X = G_extent.right (); // (vertical?) if (G_extent.bottom () > extent.Y) extent.Y = G_extent.bottom (); } return result; } // W_TextBox::resize // (Check clipping) bool W_TextBox::clip_check (Rect *rect_clip) { if (rect_clip) { // (horizontal bounds check) if (rect_clip->RightBottom.X <= origin.X) return false; if (rect_clip->LeftTop.X >= origin.X + extent.X) return false; // (vertical bounds check) if (rect_clip->RightBottom.Y <= origin.Y) return false; if (rect_clip->LeftTop.Y >= origin.Y + extent.Y) return false; } // (rect_clip) // no clipping / intersection: return true; } // W_TextBox::clip_check // (Redraw text box) bool W_TextBox::redraw (A_Canvas &canvas) { if (clip_check (canvas.area_clip)) { bool result; Point old_org; Area old_clip; Area new_clip; new_clip.Origin = origin; new_clip.Extent = extent; canvas.fill_area_color (color, origin, extent); canvas.text_offset (origin, old_org); if (0) canvas.clip_area (new_clip, old_clip); result = metrix->draw_list (content, canvas); if (result) metrix->draw_actions (canvas, origin, C_Invert (color)); canvas.text_offset (old_org, origin); return result; } return true; } // W_TextBox::redraw // (Term text box) bool W_TextBox::term (A_Canvas &canvas) { metrix->unprepare (); metrix->term_list (content); delete metrix; return true; } // W_TextBox::term // (Release text box) void W_TextBox::release (M_Collect &collector) { TFE_Term::release_list (content); } // W_TextBox::release // (Dump text box) void W_TextBox::dump (A_Console &console) { console.out_cstr ("TextBox"). check_if (origin.not_zero ()). out_pfx('@'). out_point(origin). check_end (console). check_if (extent.not_zero ()). out_pfx('#'). out_point(extent). check_end (console). check_if (color). out_pfx('$'). out_color(color). check_end (console); if (0) // (dump actions in list!) for (TFE_A_Action *action = metrix->action_list; action; action = action->next) { console.out_tab (); action->dump (console); console.out_nl (); } // for (action) } // W_TextBox::dump // // Parse source code for TextBox // #include "parser.h" static W_TextBox::ParserError *global_error_info = 0; static void parse_error_fn (char const *message, unsigned offset, unsigned length) { if (global_error_info) { global_error_info->message = message; global_error_info->end = (global_error_info->start = offset) + length; } } // parse_error_fn unsigned W_TextBox::verify_source (A_Console &console, char const *source, ParserError *error_info) { bool word_mode = (flags & WTB_Split) != 0; ::set_error_handler (parse_error_fn); global_error_info = error_info; bool result = ::verify_source (console, source, word_mode, decoder_fn); ::set_error_handler (0); global_error_info = 0; return result; } // W_TextBox::verify_source TFE_Term *W_TextBox::parse_source (A_Console &console, char const *source, ParserError *error_info) { bool dump_mode = (flags & WTB_Dump) != 0; bool wrap_mode = (flags & WTB_Wrap) != 0; bool word_mode = (flags & WTB_Split) != 0; ::set_error_handler (parse_error_fn); global_error_info = error_info; TFE_Term *result = ::parse_source (console, source, word_mode, wrap_mode, dump_mode, decoder_fn); ::set_error_handler (0); global_error_info = 0; return result; } // W_TextBox::parse_source // // Actions // // (init action) void TFE_A_Action::init (A_Metrix &metrix) { ord_beg = metrix.elem_count; TFE_Attr::init (metrix); ord_end = metrix.elem_count; if (metrix.action_list) { // (next action in chain) next = metrix.action_list; metrix.action_list = this; // (next index) index = next->index + 1; } else { // (first action in chain) metrix.action_list = this; index = 0; next = 0; } } // TFE_A_Action::init // (apply action) bool TFE_A_Action::apply (A_Canvas &canvas, A_Metrix &metrix, bool (TFE_Attr::* process_all) (A_Canvas &canvas, A_Metrix &metrix)) { if (~background) { unsigned _background = canvas.style_backcolor (background); bool result = (this->*process_all) (canvas, metrix); canvas.style_backcolor (_background); return result; } else return (this->*process_all) (canvas, metrix); } // TFE_A_Action::apply // (dump self) void TFE_A_Action::dump (A_Console &console) { console.out_label ("Action #"). out_dec (index). out_ch (' '). out_ch ('['). out_dec (ord_beg). out_cstr (".."). out_dec (ord_end). out_ch (']'); } // TFE_A_Action::dump // (check nodes alignment) static bool line_aligned (Elem_Metrix &left, Elem_Metrix &right) { return left.orig.Y == right.orig.Y && left.size.Y == right.size.Y; } // line_aligned // (default action handler:) bool TFE_A_Action::handle (RootWindow &root, A_Console &console, W_TextBox &textbox, unsigned type) { dump (console); console.out_nl (); } // TFE_A_Action::handle // (Reflow action nodes) void TFE_A_Action::reflow_nodes (A_Metrix &metrix) { if (join_vec) { Elem_Metrix *elems = metrix.elem_vector; // // length of [join_vec] == (ord_end - ord_beg) // unsigned offset = ord_beg; unsigned total = ord_end - offset; if (total) { unsigned i = 0, j = 0; join_vec [j] = 1; // (initial node) while (-- total) { if (line_aligned (elems [offset + i], elems [offset + (++j)])) { join_vec [j] = 0; // (filler...) ++ join_vec [i]; } else join_vec [i = j] = 1; } } // (total) } // (join_vec) } // TFE_A_Action::reflow_nodes // (term action) void TFE_A_Action::term (A_Metrix &metrix) { if (join_vec) { delete join_vec; join_vec = 0; } TFE_Attr::term (metrix); } // TFE_A_Action::term // (Handle click of mouse) bool W_TextBox::mouse_click (RootWindow &root, unsigned act_state, unsigned button_state, unsigned mouse_action, unsigned X, unsigned Y) { // (boundaries check:) if ((int) X >= origin.X && (X -= origin.X) < extent.X && (int) Y >= origin.Y && (Y -= origin.Y) < extent.Y) { A_Console &logger = *root.logger; if (flags & WTB_Mouse) { logger.out_label ("= Clicked:"); dump (logger); logger.out_cstr (" -> "). /* dump format: {X,Y}+|-Buttons:Action */ out_ch ('{'). out_dec (X). out_ch (','). out_dec (Y). out_ch ('}'). out_ch (act_state ? '+' : '-'). out_hex (button_state). out_ch (':'). out_hex (mouse_action). out_nl (); } // (WTB_Mouse) if (act_state) { Point where (X, Y); unsigned offset = metrix->track_point (where, button_state); if (offset) { // (something found!) for (TFE_A_Action *action = metrix->action_list; action; action = action->next) { if (offset == action->index + 1) action->handle (root, logger, *this, button_state); } } } return true; } // (bounds check) return false; // (out of text box!) } // W_TextBox::mouse_click // Area to rectangle void Rect::copy (Area &area) { LeftTop = area.Origin; RightBottom = area.Extent; RightBottom.shift (LeftTop); } // Rect::copy // Rectangle to area void Area::copy (Rect &rect) { Origin = rect.LeftTop; Extent.X = rect.RightBottom.X - Origin.X; Extent.Y = rect.RightBottom.Y - Origin.Y; } // Area::copy // Check for clipping bool Area::clip_check (Rect *rect_clip) { if (rect_clip) { // (horizontal bounds check) if (rect_clip->RightBottom.X <= Origin.X) return false; if (rect_clip->LeftTop.X >= Origin.X + Extent.X) return false; // (vertical bounds check) if (rect_clip->RightBottom.Y <= Origin.Y) return false; if (rect_clip->LeftTop.Y >= Origin.Y + Extent.Y) return false; } // (rect_clip) // no clipping / intersection: return true; } // Area::clip_check // // Dumping colors / points / rectangles / areas // A_Console &A_Console::out_color (Color color) { print_char ('#'); print_hex (color & 0xFF, 2); print_hex ((color >> 8) & 0xFF, 2); print_hex ((color >> 16) & 0xFF, 2); return *this; } // A_Console::out_color A_Console &A_Console::out_point (Point &point) { point.dump (*this); return *this; } // A_Console::out_point A_Console &A_Console::out_rect (Rect &rect) { rect.dump (*this); return *this; } // A_Console::out_rect A_Console &A_Console::out_area (Area &area) { area.dump (*this); return *this; } // A_Console::out_area // // Dumping TFE tree // unsigned A_Console::dump_TFE_Tree (TFE_Term *root, unsigned indent) { unsigned counter = 0; while (root) { for (int i = 0; i != indent; ++ i) print_cstr ("| "); root->dump (*this); ++ counter; TFE_Attr *attr = dynamic_cast <TFE_Attr *> (root); if (attr) { print_cstr (" {"); out_nl (); counter += dump_TFE_Tree (attr->list, 1 + indent); for (int i = 0; i != indent; ++ i) print_cstr ("+---"); print_char ('}'); } // (attr) root = root->next; out_nl (); } // while (root) return counter; } // A_Console::dump_TFE_Tree // // Paragraph formatting // // Reformatting elements [from -> to] horizontally static void align_items_hor (int hor_align, Elem_Metrix *from, Elem_Metrix *to, int remain, unsigned sp_count) { // (horizontal shift) if (hor_align > 1) { if (remain > 0) if (sp_count == to - from) { switch (to - from) { case 0: case 1: break; // (nothing to do) case 2: // (2 elements -- move last) (++ from)->orig.X += remain; break; case 3: // (3 elements -- move middle & last) (++ from)->orig.X += remain >> 1; (++ from)->orig.X += remain; break; default: { // (4 or more elements ...) unsigned count = to - from - 1; unsigned accum = 0, offset = 0; do { accum += remain; offset += accum / count; accum %= count; (++ from)->orig.X += offset; } while (from < to); } } // switch (to - from) } else { unsigned count = sp_count - 1; unsigned accum = 0, offset = 0; if (! count) { // // throw "Zero division!"; // return; } do { if (! (((++ from)->flags) & (MF_GlueB|MF_NailB))) { accum += remain; offset += accum / count; accum %= count; } from->orig.X += offset; } while (from < to); } } else { // (no justify) if (hor_align < 0) remain = 0; // (align left) else if (! hor_align) remain >>= 1; // (center) // (else: align right) // (move all elements) while (from < to) { (from ++)->orig.X += remain; } } } // align_items_hor // Reformatting elements [from -> to] vertically static void align_items_ver (int ver_align, Elem_Metrix *from, Elem_Metrix *to, unsigned height) { // (move all elements) while (from < to) { unsigned _height = from->size.Y; if (_height < height) { unsigned shift = ver_align < 0 ? 0 : ver_align > 0 ? height - _height : (height - _height) >> 1; from->orig.Y += shift; } ++ from; } } // align_items_ver // Content width adjustment for formatted line void adjust_width (Elem_Metrix *start, Elem_Metrix *end, unsigned &max_width) { if (start < end --) { unsigned lastX = end->orig.X + end->size.X; if (lastX > max_width) max_width = lastX; } } // adjust_width // Actually, reformat paragraph! bool Para_Def::reform (Elem_Metrix *element, unsigned count, Point &origin, Point &extent) { if (count) { unsigned save_X = origin.X; unsigned width = extent.X; unsigned H_Space = hor_space; unsigned left = origin.X; unsigned height = 0, max_width = width; int remain; if (margin_first + margin_right < width) { remain = width - margin_first - margin_right; origin.X += margin_first; } else remain = 0; if (margin_left + margin_right < width) { width -= margin_left + margin_right; left += margin_left; } else width = 0; origin.Y += skip_above; remain += H_Space; width += H_Space; // (reserve) Elem_Metrix *start = element; unsigned sp_count = 0; // (spaces between elements) unsigned inter = skip_inter; while (count --) { unsigned e_flags = element->flags; int e_width = element->size.X, e_height = element->size.Y; // (hidden???) if (e_flags & (MF_OCol | MF_ICol)) { ++ element; continue; } if (! (e_flags & (MF_GlueA|MF_NailA))) { ++ sp_count; e_width += H_Space; } if ((e_width > remain || (e_flags & MF_Break)) && ! (e_flags & MF_NailB)) { // (finalize formed line:) align_items_hor (hor_align, start, element, remain, sp_count); align_items_ver (ver_align, start, element, height); adjust_width (start, element, max_width); // (get ready for next line:) start = element; remain = width; origin.X = left; origin.Y += height + inter; height = 0; sp_count = 0; } (element ++)->orig = origin; // (next element) remain -= e_width; origin.X += e_width; if (e_height > height) height = e_height; } // while (count) // (finalize final line) align_items_hor (hor_align > 1 ? -1 : hor_align, start, element, remain, 0); align_items_ver (ver_align, start, element, height); adjust_width (start, element, max_width); origin.Y += height + skip_below; origin.X = save_X; extent.X = max_width; } // (count) return true; } // Para_Def::reform // // Tracking point actions // // Prepare actions for draw bool A_Metrix::prepare_actions (A_Canvas &canvas, Color color, bool joinable) { if (elem_vector) { for (TFE_A_Action *action = action_list; action; action = action->next) { action->background = color; if (joinable) { unsigned count = action->ord_end - action->ord_beg; if (count > 1 && count < 256) // (allocate vector!) action->join_vec = new ("action_nodes") unsigned char [count]; } } // for (action) } // (elem_vector) } // A_Metrix::prepare_actions // (Track point to widget) unsigned A_Metrix::track_point (Point &location, unsigned type) { if (elem_vector) { int locX = location.X, locY = location.Y; for (TFE_A_Action *action = action_list; action; action = action->next) { unsigned index_beg = action->ord_beg, index_end = action->ord_end; if (index_beg < index_end && index_end <= elem_count) { unsigned count = index_end - index_beg; Elem_Metrix *_ptr = elem_vector + index_beg; if (action->join_vec) { unsigned char *join_vec = action->join_vec; unsigned index = 0; while (count) { unsigned join_count = join_vec [index]; if (join_count) { Elem_Metrix *_left = _ptr + index; Elem_Metrix *_right = _left + join_count - 1; Point &_orig = _left->orig; if (_orig.X <= locX && locX < _right->orig.X + _right->size.X && _orig.Y <= locY && locY - _orig.Y < _left->size.Y) // (found!) return action->index + 1; } // (join_count) index += join_count; count -= join_count; } // while (count) } else while (count --) { Point &_orig = _ptr->orig; Point &_size = _ptr->size; if (_orig.X <= locX && locX - _orig.X < _size.X && _orig.Y <= locY && locY - _orig.Y < _size.Y) // (found!) return action->index + 1; ++ _ptr; } // while (cnt) } } // for (action) } // (elem vector OK) return 0; // (action not found) } // A_Metrix::track_point // Mark action region static bool mark_action (A_Canvas &canvas, Point &offset, Point &orig, Point &size) { int _L_ = offset.X + orig.X, _T_ = offset.Y + orig.Y; int _R_ = _L_ + size.X, _B_ = _T_ + size.Y; Rect area (_L_ - 1, _T_ - 1, _R_ + 1, _B_ + 1); return /* canvas.invert_rect (area) && */ canvas.marker_rect (area); #if 0 Point _LT_ (_L_, _T_), _RT_ (_R_, _T_), _LB_ (_L_, _B_), _RB_ (_R_, _B_); return canvas.line (_LT_, _RT_) && canvas.line (_RT_, _RB_) && canvas.line (_RB_, _LB_) && canvas.line (_LB_, _LT_); #endif } // mark_action // (Draw action markers) bool A_Metrix::draw_actions (A_Canvas &canvas, Point offset, Color color) { if (elem_vector) { Color _old_plot = canvas.plot_color (color); for (TFE_A_Action *action = action_list; action; action = action->next) { unsigned index_beg = action->ord_beg, index_end = action->ord_end; unsigned count = index_end - index_beg; if (index_beg < index_end && index_end <= elem_count) { if (action->join_vec) { unsigned char *join_vec = action->join_vec; unsigned index = 0; while (count) { unsigned join_count = join_vec [index]; if (join_count) { Elem_Metrix *_left = elem_vector + index_beg + index; Elem_Metrix *_right = _left + join_count - 1; Point _extent (_right->orig.X + _right->size.X - _left->orig.X, _left->size.Y); mark_action (canvas, offset, _left->orig, _extent); } // (join_count) index += join_count; count -= join_count; } } // (join vector) else { Elem_Metrix *_ptr = elem_vector + index_beg; while (count --) { mark_action (canvas, offset, _ptr->orig, _ptr->size); ++ _ptr; } // while (cnt) } } } // for (action) canvas.plot_color (_old_plot); } // (elem vector OK) return true; } // A_Metrix::draw_actions