#include "ba0103.h" #include #include #include #include #include #include #include /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// static int draw_text(WINDOW win, const char* txt, RCT& rct, char halign='L', char valign='T') { const int max_row_width = xvt_rect_get_width(&rct); int lines = 0; if (xvt_dwin_get_text_width(win, txt, -1) < max_row_width) { advanced_draw_text_line(win, txt,rct, halign, valign); lines = 1; } else { TString_array para; TToken_string p(txt, '\n'); para.destroy(); FOR_EACH_TOKEN(p, line) para.add(line); for (int i = 0; i < para.items(); i++) { TString& row = para.row(i); int pix = xvt_dwin_get_text_width(win, row, -1); if (pix > max_row_width) { int good_len = 0; const int first_space = row.find(' '); if (first_space >= 0) { // Linea con almeno uno spazio for (int i = first_space; row[i]; i++) if (row[i] == ' ') { pix = xvt_dwin_get_text_width(win, row, i); if (pix <= max_row_width) good_len = i; else break; } } if (good_len == 0) // Puo' succedere per linee senza spazi o con parole lunghissime { for (good_len = row.len(); good_len > 0; good_len--) { const int pix = xvt_dwin_get_text_width(win, row, good_len); if (pix < max_row_width) break; } } TString next_row = row.mid(good_len); next_row.ltrim(); para.insert(next_row, i+1); row.cut(good_len); } } advanced_draw_paragraph(win, para, rct, halign, valign, CHARY); lines = para.items(); } return lines; } /////////////////////////////////////////////////////////// // TMetro_menu /////////////////////////////////////////////////////////// static TOutlook_mask* _main_mask = NULL; class TMetro_item : public TSortable { RCT _rct; protected: virtual int compare(const TSortable& s) const { const TMetro_item& mi = (const TMetro_item&)s; return mi.score() - score(); } virtual COLOR back() const { return REQUIRED_BACK_COLOR; } virtual COLOR fore() const { return NORMAL_COLOR; } virtual int icon() const { return 0; } virtual const TString& caption() const pure { return EMPTY_STRING; } virtual const TMetro_item& item(int) const { return *this; } public: virtual void sort() { } virtual int score() const { return 0; } virtual const TString& code() const pure { return EMPTY_STRING; } virtual PNT size_min() const { PNT p = { 32+2*CHARY, 16*CHARX }; return p; } virtual void draw(WINDOW win, const RCT& rct); virtual bool on_click(const PNT& pnt) { return xvt_rect_has_point(&_rct, pnt) != 0; } const RCT& rect() const { return _rct; } TMetro_item() { memset(&_rct, 0, sizeof(_rct)); } }; void TMetro_item::draw(WINDOW win, const RCT& rct) { _rct = rct; // store for hit test xvt_dwin_set_std_cpen(win, TL_PEN_HOLLOW); CBRUSH brush; brush.color = back(); brush.pat = PAT_SOLID; xvt_dwin_set_cbrush(win, &brush); xvt_dwin_draw_rect(win, &rct); if (caption().full()) { xvt_dwin_set_back_color(win, back()); xvt_dwin_set_fore_color(win, fore()); } } class TMetro_cell : public TMetro_item { const TMenuitem* _mi; int _count; // usage count TDate _last; // last run protected: virtual int score() const { return _count; } virtual int compare(const TSortable& s) const; virtual const TDate& last_run() const { return _last; } virtual const TString& code() const { return _mi->action(); } virtual const TString& caption() const { return _mi->caption(); } virtual const TString& message() const { return EMPTY_STRING; } virtual int icon() const { return _mi->icon(); } virtual bool on_click(const PNT& pnt); virtual void draw(WINDOW win, const RCT& rct); public: TMetro_cell(const TMenuitem& mi, int cnt, const TDate& last) : _mi(&mi), _count(cnt), _last(last) {} }; int TMetro_cell::compare(const TSortable& s) const { const TMetro_cell& mi = (const TMetro_cell&)s; int cmp = TMetro_item::compare(mi); if (cmp == 0) cmp = mi._last - _last; return cmp; } void TMetro_cell::draw(WINDOW win, const RCT& rct) { TMetro_item::draw(win, rct); // store for hit test const int margin = 2; RCT area = rct; xvt_rect_deflate(&area, margin, margin); if (caption().full()) { draw_text(win, caption(), area, 'L', 'B'); area.bottom -= CHARY; if (xvt_rect_get_height(&area) > 32) { int ico = icon(); if (ico <= 0) ico = ICON_RSRC; xvt_dwin_draw_icon(win, area.left, area.top, ico); area.top += 32+margin; } } if (xvt_rect_get_height(&area) >= CHARY) draw_text(win, message(), area, 'C', 'C'); } bool TMetro_cell::on_click(const PNT& pnt) { bool go = TMetro_item::on_click(pnt); if (go && _main_mask) { go = _main_mask->run_child(*_mi); if (go) { _count++; _last = TODAY; } } return go; } /////////////////////////////////////////////////////////// // TMetro_setup_cell /////////////////////////////////////////////////////////// class TMetro_setup_cell : public TMetro_cell { int _updates; protected: virtual COLOR back() const { return _updates > 0 ? FOCUS_BACK_COLOR : TMetro_cell::back(); } virtual const TString& message() const; public: TMetro_setup_cell(const TMenuitem& mi, int cnt, const TDate& last); }; const TString& TMetro_setup_cell::message() const { TString& tmp = get_tmp_string(); tmp.format(FR("%d aggiornamenti disponibili"), _updates); return tmp; } TMetro_setup_cell::TMetro_setup_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last), _updates(0) { const TDongle& don = dongle(); if (don.administrator() && ini_get_int(CONFIG_INSTALL, "Main", "Type") != 2 && xvt_net_get_status()>=2) { int y,r,t,p; main_app().get_version_info(y, r, t, p); TString dir; dir.format("/release%02d0/*a.ini", r); TString_array patches; http_dir("http://93.146.247.172", dir, patches); TArray modules; FOR_EACH_ARRAY_ROW(patches, i, row) { const TString& mod = row->left(2); const word aut = don.module_name2code(mod); if (don.active(aut)) { TToken_string* p = (TToken_string*)modules.objptr(aut); if (p == NULL) { p = new TToken_string; p->add(ini_get_int(CONFIG_GENERAL, mod, "Patch")); modules.add(p); } if (p->items() == 1) { const int local_patch = p->get_int(0); const int remote_patch = atoi(row->mid(2)); if (remote_patch > local_patch) { p->add(remote_patch, 1); _updates++; } } } } } } /////////////////////////////////////////////////////////// // TMetro_dbase_cell /////////////////////////////////////////////////////////// class TMetro_dbase_cell : public TMetro_cell { clock_t _next_update; int _users; protected: int users() const; virtual COLOR back() const { return users() > 1 ? FOCUS_BACK_COLOR : TMetro_cell::back(); } virtual const TString& message() const; public: TMetro_dbase_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last), _users(0) {} }; int TMetro_dbase_cell::users() const { const clock_t now = clock(); if (_users <= 0 || now > _next_update) { TRelation users(LF_USER); TCursor connections(&users, "CONNECTED=\"X\""); (int&)_users = max(1, connections.items()); (clock_t&)_next_update = clock() + 15*CLOCKS_PER_SEC; } return _users; } const TString& TMetro_dbase_cell::message() const { TString& tmp = get_tmp_string(); const int u = users(); if (u > 1) tmp.format(FR("%d utenti connessi"), u); else tmp.format(FR("Un utente connesso")); return tmp; } /////////////////////////////////////////////////////////// // TMetro_backup_cell /////////////////////////////////////////////////////////// class TMetro_backup_cell : public TMetro_cell { long days() const { return TDate(TODAY) - last_run(); } protected: virtual COLOR back() const { return days() > 7 ? FOCUS_BACK_COLOR : TMetro_cell::back(); } virtual const TString& message() const; public: TMetro_backup_cell(const TMenuitem& mi, int cnt, const TDate& last) : TMetro_cell(mi, cnt, last) {} }; const TString& TMetro_backup_cell::message() const { TString& tmp = get_tmp_string(); const int d = days(); if (d > 0) tmp.format(FR("%d giorni dall'ultimo backup"), d); return tmp; } /////////////////////////////////////////////////////////// // TMetro_panel /////////////////////////////////////////////////////////// class TMetro_panel : public TMetro_item { TString _name; int _icon; TArray _child; protected: virtual int score() const; virtual const TString& code() const { return _name; } virtual const TString& caption() const { return _name; } virtual int icon() const { return _icon; } virtual COLOR fore() const { return PROMPT_COLOR; } virtual COLOR back() const { return _name.full() ? MASK_BACK_COLOR : NORMAL_BACK_COLOR; } virtual PNT size_min() const { PNT p = TMetro_item::size_min(); p.v = p.v * 2 + 32; p.h *= 3; return p; } virtual const TMetro_item& item(int i) const { return (const TMetro_item&)_child[i]; } public: virtual void sort(); virtual void draw(WINDOW win, const RCT& rct); virtual bool on_click(const PNT& pnt); TMetro_cell* add_item(const TMenuitem& item, int cnt, const TDate& last); TMetro_panel* add_panel(const TString& name, int icon); bool is_empty() const { return _child.empty(); } TMetro_panel(const TString& name, int icon) : _name(name), _icon(icon) {} }; #define FOR_EACH_CHILD(i) TMetro_item* i; for (int _r##i = 0; (i = (TMetro_item*)_child.objptr(_r##i)) != NULL; _r##i++) int TMetro_panel::score() const { int max_score = 0; FOR_EACH_CHILD(i) { const int s = i->score(); if (s > max_score) max_score = s; } return max_score; } void TMetro_panel::sort() { _child.sort(); FOR_EACH_CHILD(i) i->sort(); } TMetro_cell* TMetro_panel::add_item(const TMenuitem& mi, int cnt, const TDate& last) { // check for duplicates FOR_EACH_CHILD(i) if (mi.action() == i->code()) return (TMetro_cell*)i; TMetro_cell* mir = NULL; if (mi.action() == "ba1 -0") mir = new TMetro_dbase_cell(mi, cnt, last); else if (mi.action() == "ba1 -6") mir = new TMetro_setup_cell(mi, cnt, last); else if (mi.action() == "ba2 -1") mir = new TMetro_backup_cell(mi, cnt, last); else mir = new TMetro_cell(mi, cnt, last); _child.add(mir); return mir; } TMetro_panel* TMetro_panel::add_panel(const TString& name, int icon) { // check for duplicates FOR_EACH_CHILD(i) if (i->code() == name) return (TMetro_panel*)i; TMetro_panel* mp = new TMetro_panel(name, icon); _child.add(mp); return mp; } void TMetro_panel::draw(WINDOW win, const RCT& rct) { TMetro_item::draw(win, rct); const int tot = _child.items(); const int margin = 4; RCT area = rct; area.left += margin; area.top += margin; if (caption().full()) { RCT txt = area; txt.bottom = area.top + 36; if (icon()) { xvt_dwin_draw_icon(win, txt.left, txt.top, icon()); txt.left += 36; } advanced_draw_text_line(win, caption(), txt, 'L', 'C'); area.top = txt.bottom; } const TMetro_item& mi = item(0); const int width = xvt_rect_get_width(&area); const int height = xvt_rect_get_height(&area); const int cols = width / mi.size_min().h; const int rows = height / mi.size_min().v; const int drawables = rows * cols; for (int i = 0; i < tot && i < drawables; i++) { const int x = i % cols, y = i / cols; RCT r; r.left = area.left + width * x / cols; r.right = area.left + width * (x+1) / cols - margin; r.top = area.top + height * y / rows; r.bottom = area.top + height * (y+1) / rows - margin; TMetro_item& mi = *(TMetro_item*)_child.objptr(i); mi.draw(win, r); } } bool TMetro_panel::on_click(const PNT& pnt) { const bool go = TMetro_item::on_click(pnt); if (go) { FOR_EACH_CHILD(i) if (i->on_click(pnt)) { sort(); break; } } return go; } /////////////////////////////////////////////////////////// // TMetro_menu /////////////////////////////////////////////////////////// class TMetro_menu : public TMetro_panel { TWindow* _book; TImage* _logo; protected: int find_icon(const TMenuitem& mi, const TSubmenu& node, TAssoc_array& visited) const; bool add_item(const TMenuitem& mi, int cnt, const TDate& d); void find_actions(const TSubmenu& sm, const TArray& actions) const; virtual void draw(WINDOW win, RCT& rct); static long handler(WINDOW win, EVENT* ep); public: void create(TWindow* book_win, const TMenu& menu); TWindow* book() const { return _book; } TMetro_menu() : TMetro_panel(EMPTY_STRING, 0), _book(NULL), _logo(NULL) {} }; static TMetro_menu _metro_menu; void TMetro_menu::draw(WINDOW win, RCT& rct) { TMetro_panel::draw(win,rct); if (_logo == NULL) _logo = new TImage(get_logo()); if (_logo->ok()) { RCT child = item(0).rect(); const int dx = rct.right - child.right; const int dy = rct.bottom - child.bottom; xvt_rect_offset(&child, dx, dy); xvt_dwin_set_std_cbrush(win, TL_BRUSH_WHITE); xvt_dwin_draw_rect(win, &child); _logo->draw(win, child, 'C', 'C', '*'); } } long TMetro_menu::handler(WINDOW win, EVENT* ep) { if (ep->type == E_UPDATE) { if (xvt_win_get_children_count(win) == 0) // Visibility test { RCT rct; xvt_vobj_get_client_rect(win, &rct); rct.bottom = ep->v.update.rct.bottom; _metro_menu.draw(win, rct); } return 0; } if (ep->type == E_MOUSE_DOWN) { if (_metro_menu.on_click(ep->v.mouse.where)) return 0; } return _metro_menu.book()->handler(win, ep); } // 0 = not found; -1 = no icon; >0 = icon int TMetro_menu::find_icon(const TMenuitem& mi, const TSubmenu& node, TAssoc_array& visited) const { int ico = 0; for (int i = 0; ico == 0 && i < node.items(); i++) { const TMenuitem& sm = node.item(i); if (sm.is_program()) { if (mi.action() == sm.action()) { ico = -1; break; } } else if (sm.is_submenu()) { const TSubmenu* sub = sm.child_submenu(); if (sub && !visited.is_key(sub->name())) { visited.add(sub->name()); ico = find_icon(mi, *sub, visited); if (ico < 0 && sm.icon() > 0) ico = sm.icon(); } } } return ico; } bool TMetro_menu::add_item(const TMenuitem& mi, int cnt, const TDate& last) { const TString& action = mi.action(); TString4 mod = action.left(2); TString desc; int ico = 0; if ((mod == "ba" && action[2]<='2') || action.find("iewer")>= 0) { if (!dongle().administrator()) return false; mod = "sy"; ico = 10210; desc = TR("Sistema"); } else { const word idx = dongle().module_name2code(mod); desc = dongle().module_code2desc(idx); TMenu& menu = mi.menu(); const TSubmenu* root = menu.find("MENU_000"); if (root) { TAssoc_array visited; visited.add(root->name()); visited.add("MENU_PREFERITI)"); ico = find_icon(mi, *root, visited); } if (ico <= 0) ico = ICON_RSRC; } TMetro_panel* a = add_panel(desc, ico); return a ? (a->add_item(mi, cnt, last) != NULL) : false; } struct TFreq_info : public TString { const TMenuitem* _mi; int _freq; TDate _last; double _score; TFreq_info(const TString& cmd, int f, const TDate& last) : TString(cmd), _mi(NULL), _freq(f), _last(last), _score(0.8) {} }; void TMetro_menu::find_actions(const TSubmenu& sm, const TArray& actions) const { if (sm.enabled() && sm.name() != "MENU_PREFERITI") { for (int i = 0; i < sm.items(); i++) { const TMenuitem& mi = sm[i]; if (mi.enabled() && mi.is_program()) { FOR_EACH_ARRAY_ITEM(actions, a, itm) { TFreq_info& fi = *(TFreq_info*)itm; if (fi._score < 1.0) { const double score = xvt_str_fuzzy_compare_ignoring_case(fi, mi.action()); if (score > fi._score) { fi._score = score; fi._mi = &mi; } } } } } } } void TMetro_menu::create(TWindow* book, const TMenu& menu) { const int def_cnt = 999999; const TDate def_dat(TODAY); /* const TSubmenu* pref = menu.find("MENU_PREFERITI"); if (pref) { for (int i = 0; i < pref->items(); i++) add_item(pref->item(i), def_cnt, def_dat); } */ TArray freq; TConfig gui(CONFIG_GUI, "Counters"); TAssoc_array& cmds = gui.list_variables(); TToken_string pair; FOR_EACH_ASSOC_OBJECT(cmds, obj, cmd, cnt) { pair = *(TString*)cnt; freq.add(new TFreq_info(cmd, pair.get_int(0), TDate(pair.get_long(1)))); } if (dongle().administrator()) { const char* cmd[] = { "ba1 -0", "ba1 -6", "ba2 -1", "setup/TeamviewerQS_it.exe", NULL }; for (int i = 0; cmd[i]; i++) { TFreq_info* fi = new TFreq_info(cmd[i], def_cnt-i, def_dat); freq.add(fi); } } TAssoc_array& am = (TAssoc_array&)menu; // cheating :-) FOR_EACH_ASSOC_OBJECT(am, obj, name, sub) find_actions(*(const TSubmenu*)sub, freq); FOR_EACH_ARRAY_ITEM(freq, i, itm) { const TFreq_info& fi = *(const TFreq_info*)itm; if (fi._mi != NULL) add_item(*fi._mi, fi._freq, fi._last); } sort(); _book = book; xvt_win_set_handler(book->win(), handler); // Nasty code injection } /////////////////////////////////////////////////////////// // TMetro_mask /////////////////////////////////////////////////////////// TMetro_mask::TMetro_mask(TMenu& menu) : TOutlook_mask(menu, true) { TWindow& bw = ((TWindowed_field&)book_field()).win(); _metro_menu.create(&bw, menu); _main_mask = this; } TMetro_mask::~TMetro_mask() { _main_mask = NULL; }