#define XI_INTERNAL #include #ifndef STX_DATA extern "C" { #include #include #include } #endif #include #include #include #include #include #include #include #include #include COLOR MASK_BACK_COLOR = XVT_MAKE_COLOR(201,194,188); // COLOR_LTGRAY; COLOR MASK_LIGHT_COLOR = COLOR_WHITE; COLOR MASK_DARK_COLOR = COLOR_GRAY; COLOR BTN_BACK_COLOR = COLOR_LTGRAY; COLOR BTN_LIGHT_COLOR = COLOR_WHITE; COLOR BTN_DARK_COLOR = COLOR_GRAY; COLOR NORMAL_COLOR = COLOR_BLACK; COLOR NORMAL_BACK_COLOR = COLOR_WHITE; COLOR PROMPT_COLOR = NORMAL_COLOR; COLOR DISABLED_COLOR = COLOR_DKGRAY; COLOR DISABLED_BACK_COLOR = MASK_BACK_COLOR; COLOR FOCUS_COLOR = NORMAL_COLOR; COLOR FOCUS_BACK_COLOR = COLOR_YELLOW; COLOR REQUIRED_BACK_COLOR = XVT_MAKE_COLOR(255,255,156); COLOR EASY_RIDER_COLOR = XVT_MAKE_COLOR(228,225,221); bool CAMPI_SCAVATI = true; bool AUTOSELECT = false; bool ADVANCED_GRAPHICS = true; bool AUTOZOOM = false; bool AUTOEND = false; bool NATIVE_CONTROLS = false; int TOOL_SIZE = 24; bool TOOL_TEXT = true; bool EASY_RIDER = true; bool ENTER_AS_TAB = false; int INTERLINE = 0; bool ANIMATED_BOXES = false; HIDDEN bool _ddl_shown = false; HIDDEN int _last_mouse_button = 0; HIDDEN const int ITF_CID = 30000; short low_get_focus_id(WINDOW win) { XI_OBJ * itf = xi_get_itf((XinWindow)win); XI_OBJ * obj = xi_get_focus(itf); if (obj == NULL || obj->type == XIT_ITF) return -1; if (obj->type == XIT_CELL || (obj->type == XIT_BTN && obj->parent != obj->itf)) obj = obj->parent; return obj->cid; } void low_set_focus_id(WINDOW win, short id) { XI_OBJ * itf = xi_get_itf((XinWindow)win); if (id > 0) { // TO BE IMPLEMENTED } else xi_set_focus(itf); } KEY TControl::xiev_to_key(const XI_EVENT* xiev) { const int k = xiev->v.chr.ch; KEY key = k; if (key < K_INS || key > K_HELP) { if (xiev->v.chr.shift && (k < ' ' || k >= K_UP)) key += K_SHIFT; //if (xiev->v.chr.control && k >= ' ') key += K_CTRL; // Correzione per gestire i tasti AltGr sulle tastiere non U.S.A. if (xiev->v.chr.control && (k > K_SHIFT || (k >= K_F1 && k <= K_F12) || xvt_chr_is_alnum(k) || strchr("\r+-*/",k) != NULL)) key += K_CTRL; } return key; } // @doc INTERNAL /////////////////////////////////////////////////////////// // TPicture_array /////////////////////////////////////////////////////////// class TPicture_array { TArray _enabled, _disabled; public: bool add(int id); int add(const char* n); int add_icon(int id); const TImage& image(int id) const { return (const TImage&)_enabled[id]; } const TImage& disabled_image(int id) const { return (const TImage&)_disabled[id]; } bool exist(int id) const { return _enabled.objptr(id) != NULL; } void reload(); TPicture_array() {} virtual ~TPicture_array() {} }; int TPicture_array::add(const char* n) { int id; // calcola il prossimo identificatore di immagine libero for (id = 30000; _enabled.objptr(id) != NULL; id++); TImage* i = new TImage(n); _enabled.add(i, id); TImage* d = new TImage(*i); d->fade_to_gray(true); _disabled.add(d, id); return id; } int TPicture_array::add_icon(int id) { const int rid = 50000+id; TImage* i = (TImage*)_enabled.objptr(rid); if (i == NULL) { TImage* i = new TImage(id, true); // id is an icon identifier! _enabled.add(i, rid); TImage* d = new TImage(*i); d->fade_to_gray(true); _disabled.add(d, rid); } return rid; } bool TPicture_array::add(int id) { TImage* i = (TImage*)_enabled.objptr(id); if (i == NULL) { i = new TImage(id); if (i->ok()) { i->convert_transparent_color(BTN_BACK_COLOR); _enabled.add(i, id); TImage* d = new TImage(*i); d->fade_to_gray(true); _disabled.add(d, id); } else { delete i; i = NULL; } } return i != NULL; } void TPicture_array::reload() { _disabled.destroy(); for (int id = _enabled.last(); id > 0; id = _enabled.pred(id)) { _enabled.destroy(id); add(id); } } /////////////////////////////////////////////////////////// // Utility functions /////////////////////////////////////////////////////////// HIDDEN TPicture_array* _picture = NULL; HIDDEN XVT_FNTID DEF_FONT = NULL; HIDDEN XVT_FNTID FAT_FONT = NULL; HIDDEN XVT_FNTID BIG_FONT = NULL; HIDDEN XVT_FNTID BIGFAT_FONT = NULL; bool is_xvt_font(const char * nome_font) { const int max_fonts = 1024; char * fonts[max_fonts]; const int num_fonts = xvt_fmap_get_families(NULL, fonts, max_fonts); bool found = false; for (int i = num_fonts-1; i >= 0; i--) { if (!found && xvt_str_compare_ignoring_case(fonts[i], nome_font) == 0) found = true; xvt_mem_free(fonts[i]); } return found; } XVT_FNTID xvtil_default_font(bool bold, bool big) { if (DEF_FONT == NULL) { DEF_FONT = xvt_dwin_get_font(TASK_WIN); TConfig font(CONFIG_GUI, "Colors"); TString font_ser_desc = font.get("FontDesc"); // Modernamente e' nel paragrafo Colors INTERLINE = font.get_int("InterLine", NULL, -1, -1); if (font_ser_desc.empty()) { const char* name = "Verdana"; font_ser_desc.format("01\\%s\\0\\8\\WIN01/8/0/0/0/400/0/0/0/0/1/2/1/49/%s", name, name); font.set("FontDesc", font_ser_desc, "Colors", true); // Salva definitivamente il font } xvt_font_deserialize(DEF_FONT, font_ser_desc); xvt_font_map_using_default(DEF_FONT); CHECK(xvt_font_is_mapped(DEF_FONT), "Can't map native font"); xvt_dwin_set_font(TASK_WIN, DEF_FONT); xi_set_font_id(DEF_FONT); xi_init_sysvals(); // Ricalcola i FU units CHARX = xi_get_fu_width(NULL); CHARY = xi_get_fu_height(NULL); // Compute suitable text size if (xvt_sys_is_pda()) // Schermo piccolo da terminalino { ROWY = CHARY; } else { //calcolo interlinea se non specificata dall'utente if (INTERLINE < 0) //interlinea automatica { const PNT pnt = xvtil_taskwin_size(); ROWY = max(CHARY, pnt.v/MAX_MASK_ROWS); } else ROWY = CHARY + INTERLINE; } XI_PNT fu = { ROWY, CHARX }; xi_pu_to_fu(NULL, &fu, 1); xi_fu_to_pu(NULL, &fu, 1); CHARX = fu.h; ROWY = fu.v; xvt_menu_set_font_sel(TASK_WIN, DEF_FONT); FAT_FONT = xvt_font_create(); xvt_font_copy(FAT_FONT, DEF_FONT, XVT_FA_ALL); xvt_font_set_style(FAT_FONT, XVT_FS_BOLD); xvt_font_map_using_default(FAT_FONT); CHECK(xvt_font_is_mapped(FAT_FONT), "Can't map native font"); BIG_FONT = xvt_font_create(); xvt_font_copy(BIG_FONT, DEF_FONT, XVT_FA_ALL); xvt_font_set_size(BIG_FONT, xvt_font_get_size(DEF_FONT) * 2); xvt_font_map_using_default(BIG_FONT); CHECK(xvt_font_is_mapped(BIG_FONT), "Can't map native font"); BIGFAT_FONT = xvt_font_create(); xvt_font_copy(BIGFAT_FONT, FAT_FONT, XVT_FA_ALL); xvt_font_set_size(BIGFAT_FONT, xvt_font_get_size(FAT_FONT) * 2); xvt_font_map_using_default(BIGFAT_FONT); CHECK(xvt_font_is_mapped(BIGFAT_FONT), "Can't map native font"); } XVT_FNTID f = NULL; if (bold) f = big ? BIGFAT_FONT : FAT_FONT; else f = big ? BIG_FONT : DEF_FONT; return f; } XVT_FNTID xvtil_load_default_font() { if (DEF_FONT) { xvt_font_destroy(DEF_FONT); DEF_FONT = NULL; } if (FAT_FONT) { xvt_font_destroy(FAT_FONT); FAT_FONT = NULL; } if (BIG_FONT) { xvt_font_destroy(BIG_FONT); BIG_FONT = NULL; } if (BIGFAT_FONT) { xvt_font_destroy(BIGFAT_FONT); BIGFAT_FONT = NULL; } XVT_FNTID font = xvtil_default_font(); statbar_set_fontid(TASK_WIN, font); return font; } #define XI_INVALID_BITMAP ((XI_BITMAP*)-1) HIDDEN XI_BITMAP* get_background_bitmap(bool reload) { static XI_BITMAP* bmp = XI_INVALID_BITMAP; if (reload || bmp == XI_INVALID_BITMAP) { if (bmp != NULL && bmp != XI_INVALID_BITMAP) xi_bitmap_destroy(bmp); bmp = NULL; if (ADVANCED_GRAPHICS && !xi_get_pref(XI_PREF_NATIVE_CTRLS)) { TFilename back = ini_get_string(CONFIG_GUI, "Colors", "Tile"); if (back.custom_path()) { bmp = xi_bitmap_create(back.get_buffer(), XI_BITMAP_TILE); if (bmp != NULL) { XVT_IMAGE img = (XVT_IMAGE)bmp->xin_bitmap->x; short w, h; xvt_image_get_dimensions(img, &w, &h); unsigned long r=0, g=0, b=0; const short k = min(w,h); for (short xy = 0; xy < k; xy++) { const COLOR col = xvt_image_get_pixel(img, xy, xy); r += XVT_COLOR_GET_RED(col); g += XVT_COLOR_GET_GREEN(col); b += XVT_COLOR_GET_BLUE(col); } r = (r+k/2)/k; g = (g+k/2)/k; b = (b+k/2)/k; MASK_BACK_COLOR = XVT_MAKE_COLOR(r, g, b); // Mean texture color MASK_LIGHT_COLOR = modulate_color(MASK_BACK_COLOR, +0.2); MASK_DARK_COLOR = modulate_color(MASK_BACK_COLOR, -0.2); DISABLED_BACK_COLOR = MASK_BACK_COLOR; if (w > 512 || h > 512) { bmp->mode = XI_BITMAP_NORMAL; bmp->hcenter = bmp->vcenter = TRUE; bmp->background = MASK_BACK_COLOR; } } } } } return bmp; } XVT_IMAGE get_background_texture() { XVT_IMAGE img = NULL; XI_BITMAP* bmp = get_background_bitmap(false); if (bmp != NULL) img = (XVT_IMAGE)bmp->xin_bitmap->x; return img; } static byte event_map[XIE_LAST_EVENT]; enum event_action { a_ignore, a_xvt, a_xvt_post, a_obj, a_child, a_update, a_select, a_post, a_debug }; // @func Permette di aggiornare i colori attivi del programma void customize_colors() // @comm Legge dal file di configurazione i colori scelti dall'utente e // ne setta le variabili in modo da poter personalizzare i colori // // @xref { TConfig colors(CONFIG_GUI, "Colors"); MASK_BACK_COLOR = colors.get_color("MaskBack", NULL, -1, MASK_BACK_COLOR); MASK_LIGHT_COLOR = colors.get_color("MaskLight", NULL, -1, MASK_LIGHT_COLOR); MASK_DARK_COLOR = colors.get_color("MaskDark", NULL, -1, MASK_DARK_COLOR); NORMAL_COLOR = colors.get_color("Normal", NULL, -1, NORMAL_COLOR); NORMAL_BACK_COLOR = colors.get_color("NormalBack", NULL, -1, NORMAL_BACK_COLOR); PROMPT_COLOR = colors.get_color("Prompt", NULL, -1, PROMPT_COLOR); REQUIRED_BACK_COLOR = colors.get_color("RequiredBack", NULL, -1, REQUIRED_BACK_COLOR); DISABLED_COLOR = colors.get_color("Disabled", NULL, -1, DISABLED_COLOR); DISABLED_BACK_COLOR = colors.get_color("DisabledBack", NULL, -1, DISABLED_BACK_COLOR); FOCUS_COLOR = colors.get_color("Focus", NULL, -1, FOCUS_COLOR); FOCUS_BACK_COLOR = colors.get_color("FocusBack", NULL, -1, FOCUS_BACK_COLOR); CAMPI_SCAVATI = colors.get_bool("Campi3D", NULL, -1, CAMPI_SCAVATI); AUTOSELECT = colors.get_bool("AutoSelect", NULL, -1, AUTOSELECT); AUTOZOOM = colors.get_bool("AutoZoom", NULL, -1, AUTOZOOM); ADVANCED_GRAPHICS = colors.get_bool("AdvancedGraphics", NULL, -1, ADVANCED_GRAPHICS); EASY_RIDER = colors.get_bool("EasyRider", NULL, -1, EASY_RIDER); EASY_RIDER_COLOR = blend_colors(NORMAL_BACK_COLOR, DISABLED_BACK_COLOR, 0.5); NATIVE_CONTROLS = colors.get_bool("NativeControls", NULL, -1, NATIVE_CONTROLS); xi_set_pref(XI_PREF_NATIVE_CTRLS, ADVANCED_GRAPHICS && NATIVE_CONTROLS); ENTER_AS_TAB = colors.get_bool("EnterAsTab", NULL, -1, ENTER_AS_TAB); ANIMATED_BOXES = is_power_reseller() && colors.get_bool("AnimatedBoxes", NULL, -1, ANIMATED_BOXES); TOOL_SIZE = colors.get_int("ToolSize", NULL, -1, TOOL_SIZE); TOOL_TEXT = colors.get_bool("ToolText", NULL, -1, TOOL_TEXT); get_background_bitmap(true); // Reload background bitmap const int SPEECH_MODE = is_power_reseller() ? colors.get_int("SpeechMode", NULL, -1, 0) : 0; xvt_vobj_set_attr(NULL_WIN, ATTR_SPEECH_MODE, SPEECH_MODE); xi_set_pref(XI_PREF_COLOR_LIGHT, MASK_LIGHT_COLOR); xi_set_pref(XI_PREF_COLOR_CTRL, MASK_BACK_COLOR); xi_set_pref(XI_PREF_COLOR_DARK, MASK_DARK_COLOR); xi_set_pref(XI_PREF_COLOR_DISABLED, DISABLED_COLOR); XVT_COLOR_COMPONENT xcc[8]; memset(xcc, 0, sizeof(xcc)); xcc[0].type = XVT_COLOR_BACKGROUND; xcc[0].color = NORMAL_BACK_COLOR; xcc[1].type = XVT_COLOR_FOREGROUND; xcc[1].color = NORMAL_COLOR; xcc[2].type = XVT_COLOR_HIGHLIGHT; xcc[2].color = FOCUS_COLOR; xcc[3].type = XVT_COLOR_SELECT; xcc[3].color = FOCUS_BACK_COLOR; xvt_vobj_set_attr(TASK_WIN, ATTR_APP_CTL_COLORS, (long)xcc); BTN_BACK_COLOR = colors.get_color("ButtonBack", NULL, -1, BTN_BACK_COLOR); aga_set_pref(AGA_PREF_BTN_COLOR_CTRL, BTN_BACK_COLOR); BTN_LIGHT_COLOR = colors.get_color("ButtonLight", NULL, -1, BTN_LIGHT_COLOR); aga_set_pref(AGA_PREF_BTN_COLOR_LIGHT, BTN_LIGHT_COLOR); BTN_DARK_COLOR = colors.get_color("ButtonDark", NULL, -1, BTN_DARK_COLOR); aga_set_pref(AGA_PREF_BTN_COLOR_DARK, BTN_DARK_COLOR); aga_set_pref(AGA_PREF_BTN_COLOR_TEXT, PROMPT_COLOR); if (_picture) _picture->reload(); xvtil_load_default_font(); // Aggiorna anche il font! } static bool campi_scavati() { return CAMPI_SCAVATI && ADVANCED_GRAPHICS; } void init_controls() { xi_set_font_id(xvtil_load_default_font()); xi_set_pref(XI_PREF_NATIVE_CTRLS, NATIVE_CONTROLS && ADVANCED_GRAPHICS); xi_set_pref(XI_PREF_3D_LOOK, campi_scavati()); xi_set_pref(XI_PREF_CARET_WIDTH, 2); xi_set_pref(XI_PREF_COMBO_ICON, ICO_COMBO); xi_set_pref(XI_PREF_OPTIMIZE_CELL_REQUESTS, TRUE); xi_init(); memset(event_map, a_ignore, sizeof(event_map)); event_map[XIE_CHAR_FIELD] = a_obj; event_map[XIE_DBL_FIELD] = a_obj; event_map[XIE_CHG_FIELD] = a_obj; event_map[XIE_OFF_FIELD] = a_obj; event_map[XIE_ON_FIELD] = a_obj; event_map[XIE_OFF_GROUP] = a_ignore; event_map[XIE_ON_GROUP] = a_ignore; event_map[XIE_OFF_FORM] = a_ignore; event_map[XIE_ON_FORM] = a_ignore; event_map[XIE_VIR_PAN] = a_ignore; event_map[XIE_XVT_EVENT] = a_xvt; event_map[XIE_XVT_POST_EVENT] = a_xvt_post; event_map[XIE_INIT] = a_ignore; event_map[XIE_BUTTON] = a_obj; event_map[XIE_CHAR_CELL] = a_child; event_map[XIE_CLEANUP] = a_ignore; event_map[XIE_CLOSE] = a_ignore; event_map[XIE_COMMAND] = a_ignore; event_map[XIE_DBL_CELL] = a_child; event_map[XIE_GET_FIRST] = a_obj; event_map[XIE_GET_LAST] = a_obj; event_map[XIE_GET_NEXT] = a_obj; event_map[XIE_GET_PERCENT] = a_obj; event_map[XIE_GET_PREV] = a_obj; event_map[XIE_CELL_REQUEST] = a_obj; event_map[XIE_CHG_CELL] = a_child; event_map[XIE_OFF_CELL] = a_child; event_map[XIE_ON_CELL] = a_child; event_map[XIE_OFF_ROW] = a_child; event_map[XIE_ON_ROW] = a_child; event_map[XIE_OFF_COLUMN] = a_ignore; event_map[XIE_ON_COLUMN] = a_ignore; event_map[XIE_OFF_LIST] = a_obj; event_map[XIE_ON_LIST] = a_obj; event_map[XIE_REC_ALLOCATE] = a_ignore; event_map[XIE_REC_FREE] = a_ignore; event_map[XIE_ROW_SIZE] = a_ignore; event_map[XIE_SELECT] = a_select; event_map[XIE_UPDATE] = a_update; event_map[XIE_COL_DELETE] = a_ignore; event_map[XIE_COL_MOVE] = a_obj; event_map[XIE_COL_SIZE] = a_obj; event_map[XIE_POST_NAVIGATION]= a_post; if (_picture == NULL) _picture = new TPicture_array; } void free_controls() { if (_picture) { delete _picture; _picture = NULL; } if (DEF_FONT) { xvt_font_destroy(DEF_FONT); DEF_FONT = NULL; } if (FAT_FONT) { xvt_font_destroy(FAT_FONT); FAT_FONT = NULL; } if (BIG_FONT) { xvt_font_destroy(BIG_FONT); BIG_FONT = NULL; } } bool has_virtual_keyboard() { static bool hvk = ini_get_bool(CONFIG_INSTALL, "Main", "VirtualKeyboard"); return hvk; } /////////////////////////////////////////////////////////// // Interface creation /////////////////////////////////////////////////////////// HIDDEN void xi_event_handler(XI_OBJ *itf, XI_EVENT *xiev); WINDOW create_interface(WINDOW parent, short x, short y, short dx, short dy, const char* caption, TWindow* msk) { if (parent == NULL_WIN) parent = TASK_WIN; short left = x * CHARX; short top = y * ROWY; short width = dx * CHARX + (dx > 0 ? CHARX : 0); short height = dy * ROWY + (dy > 0 ? ROWY : 0); if (x <= 0 || y <= 0 || dx <= 0 || dy <= 0) { RCT max_rct; xvt_vobj_get_client_rect(parent, &max_rct); if (dy <= 0) { // Gestisce centrature e caso particolare di bottombar di una riga if (y < -1 || (y == -1 && (dy == 0 || dy == 1))) { height = -top; top += max_rct.bottom; y = (max_rct.bottom-height)/ROWY; // MAX_MASK_ROWS - height/ROWY; } else height = max_rct.bottom - top + dy * ROWY; } if (dx <= 0) { width = max_rct.right + dx * CHARX; if (left > 0) width -= left; } if (x < 0 && dx != 0) left = (max_rct.right - width) / 2; if (y < 0 && dy != 0) top = (max_rct.bottom - height) / 2; } RCT r; xvt_rect_set(&r, left, top, left+width, top+height); const WIN_TYPE wt = (dx == 0) ? W_PLAIN : W_DOC; long wsf = WSF_INVISIBLE | WSF_NO_MENUBAR; WINDOW win = xvt_win_create(wt, &r, caption, 0L, parent, wsf, EM_ALL, (EVENT_HANDLER)xi_event, (long)msk); CHECK(win, "Can't create an XVT window for an interface"); xvtil_set_font(win, NULL, 0, 0); XI_RCT xrct; xrct = (XI_RCT&)r; xi_pu_to_fu(NULL, (XI_PNT*)&xrct, 2); XI_OBJ_DEF* def = xi_create_itf_def(ITF_CID, xi_event_handler, &xrct, (char*)caption, (long)msk); CHECK(def, "Can't define an interface"); def->v.itf->automatic_back_color = false; def->v.itf->back_color = MASK_BACK_COLOR; def->v.itf->font_id = xvtil_default_font(); def->v.itf->tab_on_enter = true; def->v.itf->win = (XinWindow)win; def->v.itf->edit_menu = true; // Update edit menu items def->v.itf->menu_win = (XinWindow)TASK_WIN; // Window that owns the menu XI_BITMAP* bmpback = get_background_bitmap(false); if (bmpback != NULL) { def->v.itf->back_color = 0; def->v.itf->bitmap = bmpback; } XI_OBJ* itf = xi_create(NULL, def); CHECK(itf, "Can't create an interface"); xi_dequeue(); xi_tree_free(def); if (dx > 0 && dy > 0) { xi_pu_to_fu(itf, (XI_PNT*)&r, 2); r.right = r.left + (dx+1) * XI_FU_MULTIPLE; r.bottom = r.top + (dy+1) * XI_FU_MULTIPLE; xi_fu_to_pu(itf, (XI_PNT*)&r, 2); xvt_vobj_move(win, &r); // Forza dimensioni corrette client area } return win; } void attach_interface(WINDOW win, COLOR back) { xvt_win_set_handler(win, (EVENT_HANDLER)xi_event); RCT rc; xvt_vobj_get_outer_rect(win, &rc); char caption[128]; xvt_vobj_get_title(win, caption, 128); TWindow* parent = (TWindow*)xvt_vobj_get_data(win); XI_OBJ_DEF* def = xi_create_itf_def(ITF_CID, xi_event_handler, (XI_RCT*)&rc, caption, (long)parent); CHECK(def, "Can't define an interface"); def->v.itf->automatic_back_color = (back == 0); if (back) def->v.itf->back_color = back; def->v.itf->tab_on_enter = true; def->v.itf->win = (XinWindow)win; if (ADVANCED_GRAPHICS && same_color(back, MASK_BACK_COLOR)) { XI_BITMAP* bmpback = get_background_bitmap(false); if (bmpback != NULL) { def->v.itf->automatic_back_color = false; def->v.itf->back_color = 0; def->v.itf->bitmap = bmpback; } } XI_OBJ* itf = xi_create(NULL, def); CHECK(itf, "Can't create an interface"); xi_dequeue(); xi_tree_free(def); } HIDDEN void xi_event_handler(XI_OBJ* itf, XI_EVENT* xiev) { static bool notify_xvt = true; TControl* ctl = NULL; switch (event_map[xiev->type]) { case a_obj: if (xiev->v.xi_obj) ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj); break; case a_child: ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj->parent); break; case a_update: { int num; XI_OBJ** button = xi_get_member_list(itf, &num); for (int i = num-1; i >= 0; i--) { XI_OBJ* b = button[i]; if (b->type == XIT_BTN && b->v.btn->drawable) { if (xvt_rect_intersect(NULL, (RCT*)&b->v.btn->rct, &xiev->v.xvte.v.update.rct)) { TPushbutton_control* p = (TPushbutton_control*)b->app_data; p->update(); } } } } break; case a_select: switch(xiev->v.xi_obj->type) { case XIT_LIST: ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj); break; case XIT_ROW : case XIT_CELL: ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj->parent); break; default : break; } break; case a_xvt: switch (xiev->v.xvte.type) { case E_MOUSE_DOWN: _last_mouse_button = xiev->v.xvte.v.mouse.button; break; case E_CHAR: { XI_OBJ* fo = xi_get_focus(itf); if (fo != NULL && fo->type == XIT_CELL) ctl = (TControl*)xi_get_app_data(fo->parent); } break; default: break; } break; case a_xvt_post: if (notify_xvt && xiev->v.xvte.type != 0) { TWindow* w = (TWindow*)xi_get_app_data(itf); WINDOW win = NULL_WIN; if (w != NULL) { if (w->is_kind_of(CLASS_MASK)) win = ((TMask*)w)->curr_win(); else win = w->win(); } if (win != NULL_WIN) { switch (xiev->v.xvte.type) { case E_CONTROL: switch (xiev->v.xvte.v.ctl.ci.type) { case WC_PUSHBUTTON: case WC_RADIOBUTTON: case WC_CHECKBOX: break; // Ignora i bottoni altrimenti li preme due volte se nativi default: w->handler(win, &xiev->v.xvte); break; } break; default: w->handler(win, &xiev->v.xvte); break; } } } else notify_xvt = true; break; case a_post: { XI_OBJ * obj = xi_get_focus(itf); if ((obj != NULL && obj->type != XIT_ITF)) { if ((obj->type == XIT_CELL || (obj->type == XIT_BTN && obj->v.btn->type == XIBT_RADIOBTN))) obj = obj->parent; CHECK(obj != NULL, "Unexpected null obj"); ctl = (TControl*)xi_get_app_data(obj); } } break; case a_debug: break; // Put your breakpoint here default: break; } if (ctl != NULL) { const bool ok = ctl->event_handler(itf, xiev); if (!ok) { xiev->refused = true; if (xiev->type == XIE_CHAR_FIELD || xiev->type == XIE_CHAR_CELL || xiev->type == XIE_XVT_EVENT || xiev->type == XIE_BUTTON) notify_xvt = false; } } } /////////////////////////////////////////////////////////// // TControl /////////////////////////////////////////////////////////// TControl::TControl() : _obj(NULL), _fld(NULL) {} // Virtual destructor needed to make derived descrutors live! TControl::~TControl() {} XI_OBJ* TControl::get_interface(WINDOW win) const { XI_OBJ* itf; if (win == NULL_WIN) { CHECK(_obj, "Can't get the interface from NULL XI object"); itf = _obj->itf; } else { itf = xi_get_itf((XinWindow)win); CHECK(itf, "Can't get the interface from a window"); } return itf; } void TControl::set_tab_cid(XI_OBJ* obj, short cid) const { CHECK(obj, "Can't set tab cid to null control"); switch(obj->type) { case XIT_BTN: obj->v.btn->tab_cid = cid; break; case XIT_CONTAINER: obj->v.container->tab_cid = cid; break; case XIT_FIELD: obj->v.field->tab_cid = cid; break; case XIT_FORM: obj->v.form->tab_cid = cid; break; case XIT_LIST: obj->v.list->tab_cid = cid; break; case XIT_COLUMN: obj->parent->v.list->tab_cid = cid; break; default: NFCHECK(0, "Can't set tab_cid to a static control: ", _obj->cid); break; } } HIDDEN bool is_container(const XI_OBJ* obj) { return obj->type == XIT_CONTAINER || obj->type == XIT_FORM || obj->type == XIT_GROUP; } XI_OBJ* TControl::find_operable(XI_OBJ* container, bool forward, bool normal) const { int num; XI_OBJ** child = xi_get_member_list(container, &num); CHECK(num > 0, "Container too empty"); const int first = forward ? 0 : num-2; const int last = forward ? num-1 : -1; const int delta = forward ? +1 : -1; XI_OBJ* found = NULL; for (int c = first; c != last && found == NULL; c += delta) { XI_OBJ* obj = child[c]; switch (obj->type) { case XIT_BTN: if (obj->v.btn->type == XIBT_BUTTON_CHECKBOX) break; case XIT_LIST: case XIT_FIELD: if (normal && obj->cid > 0) found = obj; break; case XIT_CONTAINER: case XIT_FORM: case XIT_GROUP: if (obj->cid > 0) { if (normal) { int num; XI_OBJ** child = xi_get_member_list(obj, &num); found = forward ? child[0] : child[num-1]; } else found = obj; } break; default: break; } } if (found == NULL) { found = child[num-1]; if (is_container(found) && normal) { int num; XI_OBJ** child = xi_get_member_list(found, &num); found = forward ? child[0] : child[num-1]; } } return found; } void TControl::update_tab_cid() { const bool is_cont = is_container(_obj); XI_OBJ *first = find_operable(_obj->itf, true, !is_cont); set_tab_cid(_obj, first->cid); XI_OBJ *last = find_operable(_obj->itf, false, !is_cont); set_tab_cid(last, _obj->cid); if (is_cont) { XI_OBJ* fi = find_operable(_obj->itf, true, true); XI_OBJ* la = find_operable(_obj->itf, false, true); int num; XI_OBJ** child = xi_get_member_list(_obj, &num); set_tab_cid(child[num-1], fi->cid); set_tab_cid(la, child[0]->cid); } else if (_obj->parent != _obj->itf) { XI_OBJ* fi = find_operable(_obj->itf, true, false); XI_OBJ* la = find_operable(_obj->itf, false, false); set_tab_cid(_obj->parent, fi->cid); set_tab_cid(la, _obj->parent->cid); } } XI_RCT TControl::coord2rct(XI_OBJ* itf, short x, short y, short dx, short dy) const { // Spazio da lasciare prima di toccare i bordi const int X_DELTA = CHARX / 4; const int Y_DELTA = CHARY / 8; XI_RCT rct; RCT max_rct; xvt_vobj_get_client_rect((WINDOW)xi_get_window(itf), &max_rct); const short MAXX = max_rct.right; const short MAXY = max_rct.bottom; int width = CHARX; if (dx > 0) width = dx * CHARX; int height = CHARY; if (dy > 1) height += (dy-1) * ROWY; if (x < 0) { x = -x; if (x > 10) { const int num = x / 10 -1; const int tot = x % 10; const int spc = (MAXX - tot*width) / (tot+1); rct.left = spc + num * (spc+width); } else rct.left = MAXX - width - x * CHARX - X_DELTA; } else { rct.left = x * CHARX + X_DELTA; if (dx > 0 && MAXX > 80 * CHARX) rct.left += (MAXX - 80 * CHARX) / 2; } if (y < 0) { y = -y; if (y > 10) { const int num = y / 10 -1; const int tot = y % 10; const int spc = (MAXY - tot*height) / (tot+1); rct.top = spc + num * (spc+height); } else rct.top = MAXY - height - (y-1) * ROWY - Y_DELTA; } else rct.top = y * ROWY + Y_DELTA; if (dx > 0) rct.right = rct.left + width; else rct.right = MAXX + (dx-1) * CHARX - X_DELTA; if (dy > 0) rct.bottom = rct.top + height; else rct.bottom = MAXY + dy * ROWY - Y_DELTA; xi_pu_to_fu(itf, (XI_PNT*)&rct, 2); return rct; } short TControl::id() const { return _obj->cid; } int TControl::type() const { return _obj->type; } RCT& TControl::get_rect(RCT& r) const { xi_get_rect(_obj, (XI_RCT*) &r); return r; } void TControl::set_rect(const RCT& r) { xi_set_rect(_obj, (XI_RCT*)&r, false); if ( _obj->type == XIT_BTN ) { // Dovevano pensarci quelli di XI, ma sono morti! if (xi_get_native_controls(_obj)) xvt_vobj_move((WINDOW)_obj->v.btn->btnctl, &r); } } void TControl::set_rect(short cx, short cy, short cwidth, short cheight, short clen) { XI_RCT rct = coord2rct(_obj->itf, cx, cy, cwidth + 1, cheight); xi_fu_to_pu(_obj->itf, (XI_PNT*)&rct, 2); set_rect((const RCT &)rct); if ( _obj->type == XIT_FIELD) { if (_obj->v.field->button) { const short delta = _obj->v.field->btn_rct.left - (_obj->v.field->rct.right + CAMPI_SCAVATI); _obj->v.field->btn_rct.left -= delta; _obj->v.field->btn_rct.right -= delta; } if (clen > 0) (( STX_DATA * ) _obj->v.field->stx)->text_size = clen + 1; } } unsigned long TControl::flags2attr(const char* flags) const { unsigned long attrib = XI_ATR_VISIBLE | XI_ATR_ENABLED; for (const char* f = flags; *f; f++) { switch(toupper(*f)) { case '*': attrib |= XI_ATR_PASSWORD; break; case 'C': attrib |= XI_ATR_HCENTER; break; case 'D': attrib &= ~XI_ATR_ENABLED; break; case 'H': attrib &= ~XI_ATR_VISIBLE; break; case 'L': attrib |= XI_ATR_READONLY; break; case 'R': attrib |= XI_ATR_RJUST; break; default : break; } } return attrib; } const char* TControl::parse_caption(const char* cap, bool& bold, bool& big, COLOR& color) const { bold = false; big = false; color = PROMPT_COLOR; const char* t; for (t = cap; *t == '@' || *t == '$'; t++) { if (*t == '@') { const char code = toupper(*(t+1)); if (code == 'B') { bold = true; t++; } else if (code == 'G') { big = true; t++; } else { NFCHECK("Bad character (%c) after @ in %s", code, cap); break; } } else { if (*(t+1) == '[') { t += 2; // Skip [ if (isalpha(*t)) color = trans_color(*t); else { int r = 0, g = 0, b = 0; if (sscanf(t, "%d,%d,%d", &r, &g, &b) == 3) color = XVT_MAKE_COLOR(r, g, b); } while (*t && *t != ']') t++; } else { NFCHECK(0, "Bad character after $ in prompt"); break; } } } return t; } WINDOW TControl::parent() const { return (WINDOW)xi_get_window(_obj->itf); } void TControl::set_focus() const { xi_set_focus(_obj); } bool TControl::notify_key(KEY k) { bool ok = true; if (_fld == NULL) { TWindow* msk = (TWindow*)xi_get_app_data(get_interface()); CHECK(msk, "Can't get TMask from XI interface"); if (msk->is_kind_of(CLASS_MASK)) { const TMask& m = (TMask&)*msk; const int pos = m.id2pos(id()); if (pos >= 0) _fld = &m.fld(pos); } } if (_fld) ok = _fld->on_key(k); return ok; } bool TControl::is_edit_key(KEY k) const { return k >= ' ' && k < 255 && k != K_DEL; } bool TControl::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { return true; } void TControl::change_attrib(unsigned long mask, bool on, XI_OBJ* obj) { if (obj == NULL) obj = _obj; const unsigned long old_attr = xi_get_attrib(obj); unsigned long attr = old_attr; if (on) attr |= mask; else attr &= ~mask; if (attr != old_attr) // C'e' un vero cambiamento d'attributo xi_set_attrib(obj, attr); } // @doc INTERNAL // @mfunc Mostra/Nasconde il controllo void TControl::show( bool on) // @parm Operazione da svolgere sul controllo: // @flag true | Il controllo viene mostrato // @flag false | Il controllo viene nascosto { change_attrib(XI_ATR_VISIBLE, on); } // @doc INTERNAL // @mfunc Abilita/disabilita il controllo void TControl::enable( bool on) // @parm Operazione da svolgere sul controllo: // @flag true | Il controllo viene abilitato // @flag false | Il controllo viene disabilitato { change_attrib(XI_ATR_ENABLED, on); } // @mfunc Abilita/disabilita l'autoselezione del testo void TControl::autoselect(bool on) { change_attrib(XI_ATR_AUTOSELECT, on); } // @mfunc Allineamento a destra del testo void TControl::set_rjust(bool on) { change_attrib(XI_ATR_RJUST, on); } // @doc INTERNAL // @mfunc Flag di sola lettura bool TControl::read_only() const { return (xi_get_attrib(_obj) & XI_ATR_READONLY) != 0; } // @mfunc Flag di sola lettura void TControl::set_read_only(bool on) { change_attrib(XI_ATR_READONLY, on); } void TControl::set_caret_pos(int pos) { xi_lowlevel_focus(_obj, TRUE); if (pos >= 0) xi_aga_field_set_caret_pos(_obj, pos); } const char* TControl::caption() const { const char* c = xi_get_text(_obj, NULL, 512); return c; } void TControl::set_caption(const char* c) { xi_set_text(_obj, (char*)c); } void TControl::destroy() { if (_obj != NULL) { xi_delete(_obj); _obj = NULL; } } /////////////////////////////////////////////////////////// // TText /////////////////////////////////////////////////////////// TText_control::TText_control(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text) { bool bold, big; COLOR color; TString t = parse_caption(text, bold, big, color); t.rtrim(); if (width <= 0) width = t.len(); XI_OBJ* itf = get_interface(win); XI_RCT rct = coord2rct(itf, left, top, width, height); rct.right += bold ? (width*XI_FU_MULTIPLE/4) : XI_FU_MULTIPLE; if (big) { rct.right += (rct.right - rct.left); rct.bottom += short(xvt_font_get_size(BIG_FONT) - xvt_font_get_size(DEF_FONT)); } const unsigned long attrib = flags2attr(flags); XI_OBJ_DEF* def = xi_add_text_def(NULL, cid, &rct, attrib, t.get_buffer()); CHECKS(def, "Can't create the definition of TText_control:", text); def->v.text->fore_color = color; if (bold || big) def->v.text->font_id = xvtil_default_font(bold, big); _obj = xi_create(itf, def); CHECKS(_obj, "Can't create TText_control ", text); xi_dequeue(); xi_tree_free(def); } void TText_control::set_caption(const char* text) { bool bold, big; COLOR color; const char* c = parse_caption(text, bold, big, color); xi_set_text(_obj, (char*)c); _obj->v.text->fore_color = color; xi_set_obj_font_id(_obj, xvtil_default_font(bold, big)); } /////////////////////////////////////////////////////////// // TGroupbox_control /////////////////////////////////////////////////////////// TGroupbox_control::TGroupbox_control(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text) : TText_control(win, cid, left, top, width, 1, flags, text) { XI_OBJ* itf = get_interface(win); XI_RCT rct = coord2rct(itf, left, top, width, height); rct.top = _obj->v.text->xi_rct.bottom - 2; rct.bottom -= XI_FU_MULTIPLE / 2; XI_OBJ_DEF* def = xi_add_rect_def(NULL, cid, &rct, XI_ATR_VISIBLE, 0, 0); // Ignore colors CHECKS(def, "Can't create the definition of TGroupbox_control ", text); def->v.rect->hilight_color = MASK_LIGHT_COLOR; def->v.rect->back_color = MASK_BACK_COLOR; def->v.rect->shadow_color = MASK_DARK_COLOR; def->v.rect->bitmap = get_background_bitmap(false); const bool erre = strchr(flags, 'R') != NULL; if (erre) change_attrib(XI_ATR_RJUST, false, _obj); // Toglie l'erroneo allineamento a destra del titolo if (campi_scavati()) def->v.rect->well = erre; // Mette eventualmente in rilievo il rettangolo else def->v.rect->ridge = true; // Angoli arrotondati in caso di stile piatto _rct = xi_create(itf, def); CHECKD(_rct, "Can't create Groupbox_control ", cid); XI_RCT& rt = _obj->v.text->rct; rt.top--; rt.bottom--; xi_dequeue(); xi_tree_free(def); } void TGroupbox_control::show(bool on) { TText_control::show(on); change_attrib(XI_ATR_VISIBLE, on, _rct); } RCT& TGroupbox_control::get_rect(RCT& r) const { xi_get_rect(_rct, (XI_RCT*)&r); return r; } /////////////////////////////////////////////////////////// // TField /////////////////////////////////////////////////////////// static bool in_create = false; TField_control::TField_control(WINDOW win, short cid, short left, short top, short width, short maxlen, const char* flags, const char* text) { const bool button = strchr(flags, 'B') != NULL; create(win, cid, left, top, width, 1, maxlen, flags, text, button ? 2 : 0); } void TField_control::create(WINDOW win, short cid, short left, short top, short width, short height, short maxlen, const char* flags, const char* text, int button) { CHECK(!in_create, "Nested control creation"); in_create = true; bool big = false; bool bold = false; const short fcid = cid > 0 ? cid + 2000 : cid - 2000; XI_OBJ_DEF* frm_def = xi_add_form_def(NULL, fcid, fcid); frm_def->app_data = (long)this; for (const char* s = flags; *s; s++) { if (*s == '{') big = true; else if (*s == '}') bold = true; } XI_OBJ* itf = get_interface(win); XI_RCT rct = coord2rct(itf, left, top, width, height); rct.right += bold ? (width*XI_FU_MULTIPLE/4) : XI_FU_MULTIPLE/4; if (big) { rct.right += (rct.right - rct.left); rct.bottom += short(xvt_font_get_size(BIG_FONT) - xvt_font_get_size(DEF_FONT)); } unsigned long attrib = flags2attr(flags) | XI_ATR_EDITMENU; if (AUTOSELECT) attrib |= XI_ATR_AUTOSELECT; if (AUTOEND) attrib |= XI_AGA_ATR_AUTOEND; if (!campi_scavati()) attrib |= XI_ATR_BORDER; if (maxlen > width) attrib |= XI_ATR_AUTOSCROLL; XI_OBJ_DEF* def = xi_add_field_def(frm_def, cid, rct.top, rct.left, rct.right - rct.left, attrib, cid, maxlen+1, NORMAL_COLOR, NORMAL_BACK_COLOR, NORMAL_COLOR, DISABLED_BACK_COLOR, FOCUS_COLOR); def->app_data = (long)this; XI_FIELD_DEF* f = def->v.field; if (big || bold) f->font_id = xvtil_default_font(bold, big); f->well = campi_scavati(); f->active_back_color = FOCUS_BACK_COLOR; if (height == 1) { f->auto_tab = true; if (button != 0) { f->button = true; switch (button) { case 2: f->icon_rid = ICO_SEARCH; break; // Bottone per ricerche default: break; // Bottone standard ICO_COMBO } f->pixel_button_distance = 1; } } else // E' un multiline, quindi setto il rettangolo { f->xi_rct.top = rct.top; f->xi_rct.bottom = rct.bottom; f->xi_rct.right = rct.right; f->xi_rct.left = rct.left; f->cr_ok = true; f->var_len_text = true; } XI_OBJ* form = xi_create(itf, frm_def); CHECKD(form, "Can't create the form for field ", cid); _obj = xi_get_obj(form, cid); CHECKD(_obj, "Can't create field ", cid); STX_DATA* stx = (STX_DATA*)_obj->v.field->stx; CHECKD(stx, "NULL stx for field ", cid); if (_obj->v.field->button) { // Aggiusta il rettangolo del bottone in modo da allinearlo al testo XI_RCT& br = (XI_RCT&)_obj->v.field->btn_rct; const int offset = stx->rct.right - br.left - 1; br.left += offset; br.right += offset; br.top = stx->rct.top + (campi_scavati() ? 1 : 0); br.bottom = stx->rct.bottom; } update_tab_cid(); xi_dequeue(); xi_tree_free(frm_def); in_create = false; } void TField_control::show_button(bool on) { XI_FIELD_DATA* f = _obj->v.field; const bool has_button = f->button != 0; if (has_button != on) { f->button = on; xi_invalidate_rect((XinWindow)parent(), &f->btn_rct); } } bool TField_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { if (in_create) return false; bool ok = true; switch(xiev->type) { case XIE_OFF_FIELD: ok = notify_key(K_TAB); break; case XIE_ON_FIELD: notify_key(K_CTRL+K_TAB); break; case XIE_DBL_FIELD: if (!read_only()) notify_key(has_virtual_keyboard() ? K_F12 : K_F9); break; case XIE_CHAR_FIELD: { KEY k = xiev_to_key(xiev); if (k == K_PREV || k == K_NEXT || k > K_CTRL) { k = K_TAB; xiev->refused = true; } if (k == K_TAB || is_edit_key(k) || (k > K_F1 && k < K_F12)) ok = notify_key(k); } break; case XIE_CHG_FIELD: notify_key(K_CTRL+K_SPACE); break; case XIE_BUTTON: notify_key(K_F9); break; default: ok = TControl::event_handler(itf, xiev); break; } return ok; } void TField_control::set_focus() const { TControl::set_focus(); } void TField_control::set_back_color(COLOR col) { xi_set_color(_obj, XIC_BACK, col); } /////////////////////////////////////////////////////////// // TMultiline_control /////////////////////////////////////////////////////////// TMultiline_control::TMultiline_control(WINDOW win, short cid, short left, short top, short width, short height, short maxlen, const char* flags, const char* text) { create(win, cid, left, top, width, height, maxlen, flags, text, false); } /////////////////////////////////////////////////////////// // TButton_control /////////////////////////////////////////////////////////// void TButton_control::create(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text, WIN_TYPE wc, XI_OBJ* container, bool drawable) { bool bold, big; COLOR color; TString txt(text); txt.trim(); char mnemonic = '\0'; int underscore = -1; if (wc == WC_PUSHBUTTON || wc == WC_CHECKBUTTON) { underscore = txt.find('~'); if (underscore < 0) underscore = txt.find('&'); if (underscore >= 0) mnemonic = txt[underscore+1]; txt.strip("&~"); } const char* t = parse_caption(txt, bold, big, color); if (width <= 0) width = strlen(t)+3; XI_RCT rct = coord2rct(get_interface(win), left, top, width, height); const unsigned long attrib = flags2attr(flags); XI_OBJ_DEF* def = xi_add_button_def(NULL, cid, &rct, attrib, (char*)t, cid); CHECKD(def, "Can't create the interface of TButton_control ", cid); def->v.btn->fore_color = color; def->app_data = (long)this; switch (wc) { case WC_PUSHBUTTON : def->v.btn->type = XIBT_BUTTON; if (bold) def->v.btn->font = (XinFont *)BIG_FONT; if (drawable) def->v.btn->text = ""; // Nasceranno icone successivamente break; case WC_CHECKBOX : def->v.btn->type = XIBT_CHECKBOX; break; case WC_RADIOBUTTON: def->v.btn->type = XIBT_RADIOBTN; break; case WC_CHECKBUTTON: def->v.btn->type = XIBT_BUTTON_CHECKBOX; break; default : def->v.btn->type = XIBT_TABBTN; break; } if (mnemonic) { int mnemonic_instance = 1; for (int c = underscore-1; c >= 0; c--) if (t[c] == mnemonic) mnemonic_instance++; def->v.btn->mnemonic = mnemonic; def->v.btn->mnemonic_instance = mnemonic_instance; } if (container == NULL) container = get_interface(win); _obj = xi_create(container, def); CHECKD(_obj, "Can't create TButton_control ", cid); // Aggiusta bottoni switch (wc) { case WC_PUSHBUTTON: if (height == 1) { XI_RCT& r = _obj->v.btn->rct; // r.top--; Commentata di recente } break; case WC_CHECKBUTTON: if (height == 1) { XI_RCT& r = _obj->v.btn->rct; r.top -= 2; r.bottom++; } break; case WC_CHECKBOX: case WC_RADIOBUTTON: { XI_RCT& r = _obj->v.btn->rct; r.top++; r.bottom -= 2; r.right += XI_FU_MULTIPLE / 2; } break; default: break; } xi_dequeue(); xi_tree_free(def); if (wc != WC_CHECKBUTTON) // Annullo fastidiosa gestione tab per i checkbutton update_tab_cid(); } int TButton_control::button_type() const { return _obj->v.btn->type; } XI_OBJ* TButton_control::container() const { return _obj->parent; } void TButton_control::check(bool on) { xi_check(_obj, on); } bool TButton_control::checked() const { return xi_is_checked(_obj) ? true : false; } bool TButton_control::toggle() { const bool on = !checked(); check(on); return on; } bool TButton_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { bool ok = true; if (xiev->type == XIE_BUTTON) { if (_last_mouse_button == 0) { if (id() != DLG_CANCEL && id() != DLG_QUIT) ok = xi_move_focus(_obj) ? true : false; if (ok) { switch (_obj->v.btn->type) { case XIBT_CHECKBOX: case XIBT_BUTTON_CHECKBOX: toggle(); break; default: break; } ok = notify_key(K_SPACE); } } } else { if (xiev->type == XIE_POST_NAVIGATION) ok = notify_key(K_CTRL + K_TAB); else ok = TControl::event_handler(itf, xiev); } return ok; } void TButton_control::set_icon(unsigned int icon_up, unsigned int icon_dn) { if (icon_dn <= 0) icon_dn = icon_up; xi_set_icon(_obj, icon_up, icon_dn); _obj->v.btn->drawable = false; const XI_RCT& rct = _obj->v.btn->rct; _obj->v.btn->icon_x = short(rct.right - rct.left - xvt_vobj_get_attr(NULL_WIN, ATTR_ICON_WIDTH)) / 2 - 5; _obj->v.btn->icon_y = short(rct.bottom - rct.top - xvt_vobj_get_attr(NULL_WIN, ATTR_ICON_HEIGHT)) / 2 - 5; } /////////////////////////////////////////////////////////// // TPushbutton_control /////////////////////////////////////////////////////////// TPushbutton_control::TPushbutton_control(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text, int bmp_up, int bmp_dn) : _bmp_up(bmp_up), _bmp_dn(bmp_dn) { const bool drawable = bmp_up > 0; create(win, cid, left, top, width, height, flags, text, WC_PUSHBUTTON, NULL, drawable); set_bmp(bmp_up, bmp_dn); } TPushbutton_control::~TPushbutton_control() { } char TPushbutton_control::mnemonic() const { return _obj->v.btn->mnemonic; } void TPushbutton_control::set_caption(const char* c) { bool bold, big; COLOR color; const char* cap = parse_caption(c, bold, big, color); if (*cap) { TControl::set_caption(cap); set_icon(0); set_bmp(0, 0); _obj->v.btn->drawable = false; _obj->v.btn->fore_color = color; xi_set_obj_font_id(_obj, xvtil_default_font(bold, big)); } } void TPushbutton_control::set_bmp(int bmp_up, int bmp_dn) { if (bmp_up > 0) { set_icon(0); _bmp_up = (bmp_up > 0 && _picture->add(bmp_up)) ? bmp_up : 0; _bmp_dn = (bmp_dn > 0 && _picture->add(bmp_dn)) ? bmp_dn : _bmp_up; } else _bmp_up = _bmp_dn = 0; if (xi_get_native_controls(_obj)) { _obj->v.btn->drawable = FALSE; // Non disegnarci a mano e lascia fare ad XVT! XVT_IMAGE img_up = NULL, img_dn = NULL; if (bmp_up > 0) img_up = _picture->image(_bmp_up).xvt_image(); if (bmp_dn > 0) img_dn = _picture->image(_bmp_dn).xvt_image(); xvt_btn_set_images((WINDOW)_obj->v.btn->btnctl, img_up, img_dn); } else _obj->v.btn->drawable = _bmp_up > 0; } void TPushbutton_control::set_icon(int icon_up, int icon_dn) { if (xi_get_native_controls(_obj)) { TButton_control::set_icon(0, 0); if (icon_up > 0) { const int bmp_up = _picture->add_icon(icon_up); const int bmp_dn = _picture->add_icon(icon_dn > 0 ? icon_dn : icon_up); set_bmp(bmp_up, bmp_dn); } } else TButton_control::set_icon(icon_up, icon_dn); } void TPushbutton_control::set_bmp(const char* bmp_up, const char* bmp_dn) { if (bmp_up && *bmp_up) { set_icon(0); _bmp_up = _picture->add(bmp_up); if (bmp_dn && *bmp_dn) _bmp_dn = _picture->add(bmp_dn); else _bmp_dn = _bmp_up; } else _bmp_up = _bmp_dn = 0; // Chiamo qui la gestione di basso livello per gestire i native controls set_bmp(_bmp_up, _bmp_dn); } void TPushbutton_control::update() { // Dovrebbe passare di qui solo per i controlli NON nativi, ma non si sa mai if (!xi_get_native_controls(_obj)) { const long attrib = xi_get_attrib(_obj); if (attrib & XI_ATR_VISIBLE) { XinWindow win = xi_get_window(_obj); XI_RCT rct; xi_get_rect(_obj, &rct); // = _obj->v.btn->rct; xi_inflate_rect(&rct, -3); xi_set_clip(win, &rct); /*if (CAMPI_SCAVATI) xi_draw_shaded_rect(win, &rct, _obj->v.btn->down, 2, BTN_LIGHT_COLOR, BTN_BACK_COLOR, BTN_DARK_COLOR); else*/ xi_draw_3d_rect(win, &rct, _obj->v.btn->down, 2, BTN_LIGHT_COLOR, BTN_BACK_COLOR, BTN_DARK_COLOR); const int bmp = (_bmp_dn > 0 && _obj->v.btn->down) ? _bmp_dn : _bmp_up; if (bmp > 0) { const TImage& i = attrib & XI_ATR_ENABLED ? _picture->image(bmp) : _picture->disabled_image(bmp); RCT& dst = xvtil_align_rect(i.rect(), (RCT&)rct, 'C', 'C', '-'); if (_obj->v.btn->down) xvt_rect_offset(&dst, 2, 2); i.draw((WINDOW)win, dst); } xi_set_clip(win, NULL); } } } bool TPushbutton_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { bool ok = TButton_control::event_handler(itf, xiev); switch (xiev->type) { case XIE_BUTTON: { TWindow* w = (TWindow*)xi_get_app_data(get_interface()); w->on_button(id()); } break; default: break; } return ok; } /////////////////////////////////////////////////////////// // TCheckbox_control /////////////////////////////////////////////////////////// TCheckbox_control::TCheckbox_control(WINDOW win, short cid, short left, short top, short width, const char* flags, const char* text) { create(win, cid, left, top, width, 1, flags, text, WC_CHECKBOX); } /////////////////////////////////////////////////////////// // TCheckbutton_control /////////////////////////////////////////////////////////// void TCheckbutton_control::check(bool on) { TButton_control::check(on); if (xi_get_native_controls(_obj)) { XVT_IMAGE img_up = _picture->image(on ? _pic_dn : _pic_up).xvt_image(); XVT_IMAGE img_dn = _picture->image(on ? _pic_up : _pic_dn).xvt_image(); xvt_btn_set_images((WINDOW)_obj->v.btn->btnctl, img_up, img_dn); } } void TCheckbutton_control::set_icon(int icon_up, int icon_dn) { if (xi_get_native_controls(_obj)) { TButton_control::set_icon(0, 0); if (icon_up > 0) { _pic_up = _picture->add_icon(icon_up); _pic_dn = _picture->add_icon(icon_dn > 0 ? icon_dn : icon_up); XVT_IMAGE img_up = _pic_up > 0 ? _picture->image(_pic_up).xvt_image() : NULL; XVT_IMAGE img_dn = _pic_dn > 0 ? _picture->image(_pic_dn).xvt_image() : NULL; xvt_btn_set_images((WINDOW)_obj->v.btn->btnctl, img_up, img_dn); } } else TButton_control::set_icon(icon_up, icon_dn); } TCheckbutton_control::TCheckbutton_control(WINDOW win, short cid, short left, short top, short width, int height, const char* flags, const char* text, int icon_up, int icon_dn) { create(win, cid, left, top, width, height, flags, text, WC_CHECKBUTTON, NULL); set_icon(icon_up, icon_dn); } /////////////////////////////////////////////////////////// // TRadiobutton_control /////////////////////////////////////////////////////////// TRadiobutton_control::TRadiobutton_control(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text) { TToken_string testo(text); testo.strip("&~"); const int tot = testo.items(); const XI_CONTAINER_ORIENTATION orient = height == 1 ? XI_STACK_HORIZONTAL : XI_STACK_VERTICAL; XI_OBJ* itf = get_interface(win); XI_RCT rct = coord2rct(itf, left, top, width, height); XI_OBJ_DEF* def = xi_add_container_def(NULL, cid, &rct, orient, cid); def->app_data = (long)this; const unsigned long attrib = flags2attr(flags); for (int b = 1; b <= tot; b++) { bool bold, big; COLOR color; const char* t = parse_caption(testo.get(), bold, big, color); const int next = cid + (b+1)*1000; XI_OBJ_DEF* btn_def = xi_add_button_def(def, cid + b*1000, NULL, attrib, (char*)t, next); CHECKD(btn_def, "Can't create definition for radio-button ", cid); btn_def->app_data = (long)this; XI_BTN_DEF* btn = btn_def->v.btn; btn->type = XIBT_RADIOBTN; btn->fore_color = color; btn->checked = b == 1; } _obj = xi_create(itf, def); CHECKD(_obj, "Can't create radio-button container ", cid); if (height > 1 && tot > 1) { xi_get_rect(_obj, &rct); int children; XI_OBJ** child = xi_get_member_list(_obj, &children); XI_RCT brct; xi_get_rect(child[0], &brct); const int bheight = brct.bottom-brct.top; const int delta = rct.bottom-rct.top - children*bheight; for (int c = 0; c < children; c++) { XI_RCT& brct = child[c]->v.btn->rct; brct.top = rct.top + delta*c/(tot-1) + bheight*c; brct.bottom = brct.top + bheight; } } update_tab_cid(); xi_dequeue(); xi_tree_free(def); } void TRadiobutton_control::show(bool on) { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); for (int c = children-1; c >= 0; c--) change_attrib(XI_ATR_VISIBLE, on, child[c]); } void TRadiobutton_control::enable(bool on) { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); for (int c = children-1; c >= 0; c--) change_attrib(XI_ATR_ENABLED, on, child[c]); } byte TRadiobutton_control::get_checked() const { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); int c; for (c = children-1; c > 0; c--) if (xi_is_checked(child[c])) break; return (byte)c; } void TRadiobutton_control::check_button(byte c) { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); if (child != NULL && c < children) xi_check(child[c], true); else NFCHECK("This radio is rather old, it doesn't have a button"); } void TRadiobutton_control::show_button(byte c, bool on) { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); if (child != NULL && c < children) change_attrib(XI_ATR_VISIBLE, on, child[c]); else NFCHECK("This radio is rather old, it doesn't have a button"); } bool TRadiobutton_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { bool ok = true; if (xiev->type == XIE_BUTTON) { XI_OBJ* obj = xiev->v.xi_obj; // Elemento del gruppo di radio buttons da premere if (xi_move_focus(obj)) // Tenta di dargli il focus { if (!xi_is_checked(obj) || xi_get_native_controls(obj)) { // Se non e' gia' premuto ... xi_check(obj, true); // ... allora premilo e ... ok = notify_key(K_SPACE); // ... avverti il mask_field proprietario } } else ok = false; } else ok = TButton_control::event_handler(itf, xiev); return ok; } void TRadiobutton_control::set_focus() const { int children; XI_OBJ** child = xi_get_member_list(_obj, &children); int c; for (c = children-1; c > 0; c--) if (xi_is_checked(child[c])) break; xi_set_focus(child[c]); } /////////////////////////////////////////////////////////// // TTagbutton_control /////////////////////////////////////////////////////////// TTagbutton_control::TTagbutton_control(WINDOW win, short cid, short left, short top, short width, short height, const char* flags, const char* text, int tag) { XI_OBJ* itf = get_interface(win); XI_RCT rct; xi_get_xi_rct(itf, &rct); rct.bottom = rct.top + XI_FU_MULTIPLE; XI_OBJ_DEF* cnt_def = xi_add_container_def(NULL, cid, &rct, XI_STACK_HORIZONTAL, cid); cnt_def->app_data = (long)this; const unsigned long attrib = flags2attr(flags); TToken_string titolo(text); const int tot = titolo.items(); for (int b = 1; b <= tot; b++) { bool bold, big; COLOR color; const char* t = parse_caption(titolo.get(), bold, big, color); const int next_bid = b == tot ? cid+1 : cid+b+1; XI_OBJ_DEF* btn_def = xi_add_button_def(cnt_def, cid+b, NULL, attrib, (char*)t, next_bid); btn_def->v.btn->type = XIBT_TABBTN; btn_def->v.btn->fore_color = color; btn_def->v.btn->checked = tag == b-1; btn_def->app_data = (long)this; btn_def->v.btn->draw_as = XIBT_EMULATED; // Disegna le orecchie a mano! } _obj = xi_create(itf, cnt_def); CHECKD(_obj, "Can't create tab-button container ", cid); update_tab_cid(); xi_dequeue(); xi_tree_free(cnt_def); } bool TTagbutton_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { bool ok = true; if (xiev->type == XIE_BUTTON) { XI_OBJ* obj = xiev->v.xi_obj; // Elemento del gruppo di radio buttons da premere if (!xi_is_checked(obj)) // Se e' gia' selezionato ignoralo completamente { if (xi_move_focus(itf)) // Controlla se si puo' cambiare pagina { TWindow* w = (TWindow*)xi_get_app_data(itf); const KEY k = K_CTRL + K_F1 + xiev->v.xi_obj->cid - id() - 1; w->on_key(k); } } } else ok = TRadiobutton_control::event_handler(itf, xiev); return ok; } void TTagbutton_control::set_caption(const char* text) { TToken_string cap = text; int num; XI_OBJ** tag = xi_get_member_list(_obj, &num); for (int i = 0; i < num; i++) { text = cap.get(); if (text == NULL) text = cap.get(0); xi_set_text(tag[i], (char*)text); } } /////////////////////////////////////////////////////////// // TListbox_control /////////////////////////////////////////////////////////// const char* xvtil_get_cell_selection(XI_OBJ* field_or_cell, int sel, const char* cod, const char* val) { if (sel < 0) sel = 0; TToken_string values(val); if (field_or_cell->type != XIT_FIELD) { XI_RCT ownrct; xi_get_rect(field_or_cell, &ownrct); const int max_width = (ownrct.right-ownrct.left) - 20; // Larghezza cella stimata senza bottone WINDOW parent = (WINDOW)xi_get_window(field_or_cell); const char* txt = values.get(sel); int text_width = xvt_dwin_get_text_width(parent, txt, -1); if (text_width <= max_width) { int maxlen = strlen(txt); FOR_EACH_TOKEN(values, tok) { const int len = strlen(tok); if (len > maxlen) { maxlen = len; text_width = xvt_dwin_get_text_width(parent, tok, -1); } } } if (text_width > max_width) { TToken_string codes(cod); return codes.get(sel); } } return values.get(sel); } int xvtil_drop_down_list(XI_OBJ* field_or_cell, const char* codes, const char* values) { if (_ddl_shown) return -1; _ddl_shown = true; TToken_string val(values); int sel = -1; if (!val.empty_items()) { const int TAGDDL = 1000; // Tag della prima voce della lista TString current; // Carico l'eventuale testo corrente xi_get_text(field_or_cell, current.get_buffer(), current.size()); const int maxi = val.items()+1; // Alloco sempre un item in piu' che fa da fine lista MENU_ITEM* menu = new MENU_ITEM[maxi]; memset(menu, 0, sizeof(MENU_ITEM)*maxi); int items = 0; FOR_EACH_TOKEN(val, tok) { MENU_ITEM& mi = menu[items]; mi.text = xvt_str_duplicate(tok); mi.tag = TAGDDL+items; mi.enabled = true; if (sel < 0 && current == tok) sel = items; items++; } if (items > 0) { WINDOW parent = (WINDOW)xi_get_window(field_or_cell); XVT_COLOR_COMPONENT xcc[8]; memset(&xcc, 0, sizeof(xcc)); xcc[0].type = XVT_COLOR_BACKGROUND; xcc[0].color = NORMAL_BACK_COLOR; xcc[1].type = XVT_COLOR_FOREGROUND; xcc[1].color = NORMAL_COLOR; xcc[2].type = XVT_COLOR_HIGHLIGHT; xcc[2].color = FOCUS_COLOR; xcc[3].type = XVT_COLOR_SELECT; xcc[3].color = FOCUS_BACK_COLOR; xvt_dwin_set_font(parent, xvtil_default_font()); // Prepara il font da copiare nel popup RCT ownrct; xi_get_rect(field_or_cell, (XI_RCT*)&ownrct); const MENU_TAG tag = xvt_list_popup(parent, &ownrct, menu, xcc, sel >= 0 ? TAGDDL+sel : -1); if (tag >= TAGDDL) { sel = tag-TAGDDL; const char* txt = xvtil_get_cell_selection(field_or_cell, sel, codes, values); xi_set_text(field_or_cell, (char*)txt); } } // Free menu data for (int i = items-1; i >= 0; i--) xvt_mem_free(menu[i].text); delete menu; } _ddl_shown = false; return sel; } /////////////////////////////////////////////////////////// // TListbox_control /////////////////////////////////////////////////////////// bool TListbox_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev) { bool ok = true; switch (xiev->type) { case XIE_DBL_FIELD: case XIE_BUTTON: if (!_ddl_shown && !read_only()) { const int sel = xvtil_drop_down_list(_obj, _codes, _values); if (sel >= 0) { select(sel); notify_key(K_SPACE); } } break; case XIE_CHAR_FIELD: { const KEY k = xiev_to_key(xiev); if (!read_only()) { if (k >= ' ' && k <= 'z') select_by_initial(char(k)); else if (k == K_F9) { const int sel = xvtil_drop_down_list(_obj, _codes, _values); if (sel >= 0) { select(sel); notify_key(K_SPACE); } } else if (k == K_RIGHT) // poor man's substitute for down arrow select_by_ofs(1); else if (k == K_LEFT) // poor man's substitute for up arrow select_by_ofs(-1); else if (k == K_F2 || k == K_F11 || k == K_F12) notify_key(k); } else if (k == K_F11 || k == K_F12) notify_key(k); xiev->refused = true; } break; case XIE_CHG_FIELD: // Ignore changes: they are notified by the drop-down list break; default: ok = TField_control::event_handler(itf, xiev); break; } return ok; } void TListbox_control::set_values(const char* cod, const char* val) { _codes = cod; _values = val; if (_current >= items()) _current = 0; if (_values.full()) xi_set_text(_obj, (char*)_values.get(_current)); else xi_set_text(_obj, ""); } int TListbox_control::items() const { return _codes.items(); } bool TListbox_control::select(int i) { const bool ok = i >= 0 && i < items(); if (ok) { if (_current != i) { _current = i; xi_set_text(_obj, ""); // Senno' a volte disegna male xi_set_text(_obj, (char*)_values.get(i)); } } return ok; } bool TListbox_control::select_by_initial(char c) { int i = _current; const int tot = items(); for (i = (i+1)%tot; i != _current; i = (i+1)%tot) { if (toupper(_values.get_char(i)) == toupper(c)) break; } const bool changed = i != _current; if (changed) { select(i); notify_key(K_SPACE); } return changed; } bool TListbox_control::select_by_ofs(int i) { const int last = items()-1; i += _current; if (i < 0) i = last; else if (i > last) i = last; const bool changed = i != _current; if (changed) { select(i); notify_key(K_SPACE); } return changed; } int TListbox_control::selected() const { return _current; } TListbox_control::TListbox_control(WINDOW win, short cid, short left, short top, short width, const char* flags, const char* text, const char* codes, const char* values) : _codes(codes), _values(values), _current(-1) { create(win, cid, left, top, width , 1, width, flags, text, true); } TListbox_control::~TListbox_control() { }