/
trilirium
/
Archived_BLC
Обзор
Документация
Войти
/
trilirium
/
Archived_BLC
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
widgets.cpp
772 строки
17 KB
Trilirium
repo created OK
22 янв 2026, 16:43
22 янв 2026, 16:43
f05d14b
Код
Авторство
О чём код?
/* + === - === - === - === - === - === - === - === | | widgets.cpp | | Core widgets implemented | + === - === - === - === - === - === - === - === */ #include "mem_mgr.h" #include "canvas.h" #include "widgets.h" #include <unistd.h> // // Widget_List implementation // // Relocate widgets list bool Widget_List::reloc (Point &delta) { bool result = true; area_total.shift (delta); for (W_Node *list = start; list; list = list->next) { list->area.shift (delta); result = (list->node) ? list->node->reloc (delta) && result : false; } return result; } // Widget_List::reloc // Relocate widgets vector bool Widget_Vector::resize (Area &area) { bool vert = flags & (WV_Ver | WV_Hor); unsigned align = flags & WV_Align; W_Node *entry; // (calculate metrics) unsigned count = 0, a_height = 0, a_width = 0; for (entry = start; entry; entry = entry->next) { Point &_extent = entry->area.Extent; if (entry->node) { Area _area (0, 0, 0, 0); entry->node->resize (_area); if (entry->node->getarea (entry->area)) { if (vert) { a_height += _extent.Y; if (_extent.X > a_width) a_width = _extent.X; } else { a_width += _extent.X; if (_extent.Y > a_height) a_height = _extent.Y; } } else entry->area.clear (); ++ count; } // if (node) } // for (entry) // (place elements at proper locations) Point origin = area_total.Origin; area.Origin = origin; if (flags & WV_Before) { if (vert) origin.Y += inspace; else origin.X += inspace; ++ count; } for (entry = start; entry; entry = entry->next) { Point &_origin = entry->area.Origin; Point &_extent = entry->area.Extent; if (entry->node) { unsigned offset; switch (align) { case WV_Top: // == WV_Left: offset = 0; break; case WV_Bottom: // == WV_Right: if (vert) origin.X += (offset = a_width - _extent.X); else origin.Y += (offset = a_height - _extent.Y); break; default: // WV_Center: if (vert) origin.X += (offset = (a_width - _extent.X) >> 1); else origin.Y += (offset = (a_height - _extent.Y) >> 1); break; } // switch (align) Point delta (origin.X - _origin.X, origin.Y - _origin.Y); entry->node->reloc (delta); // (relocate widget) if (vert) { origin.X -= offset; origin.Y += _extent.Y + inspace; } else { origin.Y -= offset; origin.X += _extent.X + inspace; } } // if (node) } // for (entry) // (final area calculation:) if (! (flags & WV_After)) -- count; if (vert) { area.Extent.X = a_width; area.Extent.Y = a_height + count * inspace; } else { area.Extent.Y = a_height; area.Extent.X = a_width + count * inspace; } area_total = area; return true; } // Widget_Vector::resize // Resize widgets list bool Widget_List::resize (Area &area) { bool result = true; // if no arrange manager present... Area _area (0, 0, 0, 0); W_Node *list; for (list = start; list; list = list->next) { result = (list->node) ? list->node->resize (resize_mode ? area : _area) && result : false; } // for (list) // calculate extent area Rect r_extent, r_area; unsigned count = 0; for (list = start; list; list = list->next) { if (list->node) { if (list->node->getarea (list->area)) { r_area.copy (list->area); if (count ++) r_extent.unite (r_area); else r_extent = r_area; } } } // for (list) if (count) area_total.copy (r_extent); else area_total.clear (); return result; } // Widget_List::resize // Redraw widgets list bool Widget_List::redraw (A_Canvas &canvas) { bool result = true; for (W_Node *list = start; list; list = list->next) result = (list->node) ? list->node->redraw (canvas) && result : false; return result; } // Widget_List::redraw // Dump widget list void Widget_List::dump (A_Console &console) { unsigned count = 0; console. out_tab (). out_ch ('{'). out_nl (); for (W_Node *list = start; list; list = list->next) { if (list->node) { console. out_ch ('['). out_dec (++ count). out_ch (']'). out_tab (); list->node->dump (console); } else console.out_ch ('~'); console. out_nl (); } // for (list) console. out_tab (). out_ch ('}'). out_nl (); } // Widget_List::dump // Dump widget vector void Widget_Vector::dump (A_Console &console) { console. out_ch ('['). out_dec (flags). out_ch ('#'). out_dec (inspace). out_ch (']'); Widget_List::dump (console); } // Widget_Vector::dump // Init widgets list bool Widget_List::init (A_Canvas &canvas) { bool result = true; for (W_Node *list = start; list; list = list->next) result = (list->node) ? list->node->init (canvas) && result : false; return result; } // Widget_List::init // Terminate widgets list bool Widget_List::term (A_Canvas &canvas) { bool result = true; for (W_Node *list = start; list; list = list->next) result = (list->node) ? list->node->term (canvas) && result : false; return result; } // Widget_List::term // (List of widgets coercion) Widget_List *Widget_List::is_list () { return this; } // Count all widgets in list unsigned Widget_List::count_all () { unsigned total = 0; for (W_Node *entry = start; entry; entry = entry->next) ++ total; return total; } // Widget_List::count_all // (Add widget to list) void Widget_List::add_widget (A_Widget *widget) { if (widget) start = new ("<widget:node>") W_Node (widget, start); } // Widget_List::add_widget // (Remove widget from list) A_Widget *Widget_List::remove_widget () { W_Node *node = start; if (node) { A_Widget *widget = node->node; start = node->next; delete node; return widget; } return 0; // (nothing to remove...) } // Widget_List::remove_widget // (Reverse widgets list) void Widget_List::reverse_widgets () { W_Node *list = 0; while (start) { W_Node *next = start->next; start->next = list; list = start; start = next; } start = list; } // Widget_List::reverse_widgets // (Accelerator dispatch to widget list) bool Widget_List::accel (RootWindow &root, unsigned accel) { for (W_Node *list = start; list; list = list->next) if (list->node && list->node->accel (root, accel)) return true; return false; } // Widget_List::accel // (Command dispatch to widget list) bool Widget_List::command (RootWindow &root, unsigned arg_0, unsigned arg_1) { for (W_Node *list = start; list; list = list->next) if (list->node && list->node->command (root, arg_0, arg_1)) return true; return false; } // Widget_List::command // (Notification dispatch to widgets) bool Widget_List::notify (RootWindow &root, struct A_Notify ¬e) { for (W_Node *list = start; list; list = list->next) if (list->node && list->node->notify (root, note)) return true; return false; } // Widget_List::notify // (Dispatch mouse action to widgets) bool Widget_List::mouse_click (RootWindow &root, unsigned act_state, unsigned button_state, unsigned mouse_action, unsigned X, unsigned Y) { for (W_Node *list = start; list; list = list->next) if (list->node && list->node->mouse_click (root, act_state, button_state, mouse_action, X, Y)) return true; return false; } // Widget_List::mouse_click // (Release all widgets in list) void Widget_List::release (M_Collect &collector) { W_Node *list = start; while (list) { W_Node *next = list->next; if (list->node) { list->node->release (collector); delete list->node; } delete list; list = next; } // while (list) start = 0; } // Widget_List::release // // Align root window // (according to 'type') // void RootWindow::align (Point &extent, WIN_align type) { if (type != Align_N && widgets) { Area &int_area = widgets->area_total; Point delta (0, 0); unsigned _type = type & Align_HV; // [ vertical alignment ] switch (_type) { case Align_LT: // left / top case Align_CT: // center / top case Align_RT: // right / top // (align top) delta.Y = 0; break; case Align_LC: // left / center case Align_CC: // center / center case Align_RC: // right / center // (align center) delta.Y = (extent.Y - int_area.Extent.Y) >> 1; break; case Align_LB: // left / bottom case Align_CB: // center / bottom case Align_RB: // right / bottom // (align bottom) delta.Y = extent.Y - int_area.Extent.Y; break; } // (vertical) delta.Y -= int_area.Origin.Y; // [ horizontal alignment ] switch (_type) { case Align_LT: // left / top case Align_LC: // left / center case Align_LB: // left / bottom // (align left) delta.X = 0; break; case Align_CT: // center / top case Align_CC: // center / center case Align_CB: // center / bottom // (align center) delta.X = (extent.X - int_area.Extent.X) >> 1; break; case Align_RT: // right / top case Align_RC: // right / center case Align_RB: // right / bottom // (align right) delta.X = extent.X - int_area.Extent.X; break; } // (horizontal) delta.X -= int_area.Origin.X; // (finally: move all widgets in list) if (delta.X || delta.Y) widgets->reloc (delta); } // (do alignment) } // RootWindow::align // Dump window void RootWindow::dump (A_Console &console) { console. out_ch('#'). out_dec(index). out_ch('\t'); if (title) console. out_qstr (title, '<', '>'); if (area.not_empty ()) console. out_pfx('@'). out_rect(area); if (background) console. out_pfx('$'). out_color(background); if (widgets) widgets->dump (console); MenuItem::menu_dump (console, winmenu); console.out_nl (); } // RootWindow::dump // (Add widget to list) void RootWindow::add_widget (A_Widget *widget) { if (! widgets) widgets = new ("<widgets:root>") Widget_List (); widgets->add_widget (widget); } // RootWindow::add_widget // (Change window resize logic) void RootWindow::change_resize (bool mode) { if (widgets) widgets->resize_mode = mode; } // RootWindow::change_resize // (Open nested list) void RootWindow::open_list (Widget_List *list) { list->add_widget (widgets); widgets = list; } // RootWindow::open_list // (Close nested list) void RootWindow::close_list () { // (last entry must be first entry!) widgets->reverse_widgets (); A_Widget *old_widgets = widgets->remove_widget (); Widget_List *old_list = old_widgets ? old_widgets->is_list () : 0; if (old_list) { // (- exchange -) old_list->add_widget (widgets); widgets = old_list; } } // RootWindow::close_list // (Reload window) void RootWindow::window_reload () { if (on_reload) (* on_reload) (this); } // RootWindow::window_reload // (Apply border to final item) void RootWindow::apply_border (Color bgcolor, Def_Frame *frame) { A_Widget *entry = widgets->remove_widget (); if (entry) widgets->add_widget (new ("Border") A_Border (bgcolor, frame, entry)); } // RootWindow::apply_border // (Apply sort key to final item) void RootWindow::apply_sortkey (A_Order *sort_key, Key_Entry * &key_chain) { if (sort_key) { A_Widget *entry = widgets->remove_widget (); if (entry) { Key_Entry *key_entry = new ("SortEntry") Key_Entry (entry, sort_key); // ... insert into key chain ... key_entry->follow = key_chain; key_chain = key_entry; widgets->add_widget (key_entry); } // (existing entry) } // (sort key) } // RootWindow::apply_sortkey // Dump widget list void dump_sort_keys (A_Console &logger, Key_Entry * key_chain) { Key_Entry *node; for (node = key_chain; node; node = node->follow) { logger.out_tab (); node->key_val->dump (logger); logger.out_nl (); } // for (node) logger.out_nl (); } // dump_sort_keys // Sort widgets in key chain void RootWindow::sort_widgets (Key_Entry * key_chain, bool order) { if (key_chain) { // (sort list tail) sort_widgets (key_chain->follow, order); A_Order *_keyval = key_chain->key_val; A_Widget *_content = key_chain->content; Key_Entry *key_next; int _compared; // (move list head in place) while (key_next = key_chain->follow) { // (compare entries) if (_compared = _keyval->compare (key_next->key_val), order ? (_compared >= 0) : (_compared <= 0) ) { break; // (sorting complete!) } // (move content closer to head) key_chain->content = key_next->content; key_chain->key_val = key_next->key_val; // (advance) key_chain = key_next; } // (while) // (when done:) key_chain->content = _content; key_chain->key_val = _keyval; } // (key_chain) } // RootWindow::sort_widgets // Locate widget (by 'target') A_Widget *RootWindow::locate_widget (Key_Entry * key_chain, A_Order *target) { if (target) { while (key_chain) { if (target->compare (key_chain->key_val) == 0) // (found widget!) return key_chain->content; key_chain = key_chain->follow; } // while (key_chain) } return 0; } // RootWindow::locate_widget // Replace widget (by 'target') with 'replace' A_Widget *RootWindow::replace_widget (Key_Entry * key_chain, A_Order *target, A_Widget *replace) { if (target) { while (key_chain) { if (target->compare (key_chain->key_val) == 0) { // (found widget!) A_Widget *previous = key_chain->content; key_chain->content = replace; return previous; } key_chain = key_chain->follow; } // while (key_chain) } return 0; } // RootWindow::replace_widget // Reverse widgets void RootWindow::reverse () { if (widgets) widgets->reverse_widgets (); } // RootWindow::reverse // (Accelerator dispatch) bool RootWindow::accel (unsigned accel) { if (widgets) return widgets->accel (*this, accel); return false; } // RootWindow::accel // (Command dispatch) bool RootWindow::command (unsigned arg_0, unsigned arg_1) { if (widgets) return widgets->command (*this, arg_0, arg_1); return false; } // RootWindow::command // (Release all, using 'collector') void RootWindow::release (M_Collect &collector) { if (widgets) { widgets->release (collector); delete widgets; widgets = 0; } // (free menu) MenuItem::release_all (winmenu, collector); // (free window title, if any) collector.text_free (title); } // RootWindow::release // (dispatch notification) bool RootWindow::notify (A_Notify ¬e) { if (widgets) return widgets->notify (*this, note); return false; } // RootWindow::notify // (first/root node, when present) A_Widget *RootWindow::root_elem () { return widgets->start ? widgets->start->node : 0; } // // Dynamic Reshaping // #define checkEvent(Type, Event) (dynamic_cast <Type *> (&Event)) // (Reshape notification) struct Widget_Reshape : A_Notify { A_Widget *widget; Widget_Reshape (A_Widget *widget) { this->widget = widget; } void dump (A_Console &console) { console.out_cstr ("Reshape"); } }; // Widget_Reshape // (notify any reshape widget...) bool A_ReshapeWidget::notify (RootWindow &root, struct A_Notify ¬e) { Widget_Reshape *eventReshape; if (eventReshape = checkEvent (Widget_Reshape, note)) { if (eventReshape->widget == this) // (reshaped this one!) return true; } return false; } // A_ReshapeWidget::notify static bool reshape_entry (Widget_Vector &widget, RootWindow &root, Widget_Reshape &eventReshape) { for (Widget_Vector::W_Node *entry = widget.start; entry; entry = entry->next) { if (entry->node->notify (root, eventReshape)) { // (adjust all!) Area _area (0, 0, 0, 0); widget.resize (_area); return true; } } // (not found) return false; } // reshape_entry // (Notification dispatch to widgets) bool Widget_Vector::notify (RootWindow &root, struct A_Notify ¬e) { Widget_Reshape *eventReshape; if (eventReshape = checkEvent (Widget_Reshape, note)) // (special treatment for reshape event) return reshape_entry (*this, root, *eventReshape); // (all default notifications) return Widget_List::notify (root, note); } // Widget_Vector::notify // Reshape widget bool RootWindow::reshape_widget (A_Widget *target) { if (target) { bool result; Widget_Reshape ReshapeEvent (target); // (redraw all window when OK...) result = notify (ReshapeEvent); if (result) refresh (0); return result; } // (target) return false; } // RootWindow::reshape_widget // // Root window finalization: // static struct InFinale { char const *_tag; void (* action) (A_Console &logger); InFinale *next; } *_finale = 0; // (add finalizer to registry) void RootWindow::add_finalizer (char const *_tag, void (* action) (A_Console &logger)) { if (action) { InFinale *entry = new (_tag) InFinale; entry->_tag = _tag; entry->action = action; entry->next = _finale; _finale = entry; } } // RootWindow::add_finalizer // on closing windows system (global) void RootWindow::final_action (A_Console &logger) { InFinale *entry; while (entry = _finale) { _finale = entry->next; entry->action (logger); delete entry; // (free entry ...) } // while (entry) } // RootWindow::final_action // // Menu debug output // void MenuItem::menu_dump (A_Console &console, MenuItem *menu, unsigned depth) { if (menu) { if (! depth) console. out_label ("MENU ->"). out_nl (); while (menu) { MenuPopup *popup = dynamic_cast <MenuPopup *> (menu); for (int i = 0; i != depth; ++ i) console.out_cstr (" | "); menu->dump (console); console.out_nl (); if (popup) menu_dump (console, popup->submenu, depth + 1); menu = menu->next; } // while (menu) if (! depth) console. out_ch ('.'). out_nl (); } } // MenuItem::menu_dump