Files correlati : ba1.exe Ricompilazione Demo : [ ] Commento : 0001036: installazione cd patch 180 Installando ex novo ed indicando una società esistente di dati su una cartella diversa viene segnalato l'errore ba1.exe in fase di conversione archivi, richiamando da manutenzione archivi la conversione vengono generati gli errori allegati. Nell'area ftp di Aga, cartella Ilaria allego l'area dati SIDA per il test. git-svn-id: svn://10.65.10.50/trunk@17971 c028cbd2-c16b-5b4b-a496-9718f37d4682
2602 lines
67 KiB
C++
Executable File
2602 lines
67 KiB
C++
Executable File
#define XI_INTERNAL
|
|
#include <xinclude.h>
|
|
|
|
#ifndef STX_DATA
|
|
extern "C"
|
|
{
|
|
#include <xitext.h>
|
|
#include <xistx.h>
|
|
#include <xiutils.h>
|
|
}
|
|
#endif
|
|
|
|
#include <colors.h>
|
|
#include <config.h>
|
|
#include <controls.h>
|
|
#include <image.h>
|
|
#include <mask.h>
|
|
#include <urldefid.h>
|
|
|
|
#include <statbar.h>
|
|
|
|
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 TOOL_BACK_COLOR = COLOR_GRAY;
|
|
COLOR NORMAL_COLOR = COLOR_BLACK;
|
|
COLOR NORMAL_BACK_COLOR = COLOR_WHITE;
|
|
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 = false;
|
|
bool EASY_RIDER = true;
|
|
bool ENTER_AS_TAB = false;
|
|
|
|
HIDDEN bool _button_blocked = false;
|
|
HIDDEN int _last_mouse_button = 0;
|
|
HIDDEN TDropDownList* _cur_ddl = NULL;
|
|
|
|
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;
|
|
}
|
|
|
|
HIDDEN int X_FU_MULTIPLE = 0;
|
|
HIDDEN int Y_FU_MULTIPLE = 0;
|
|
HIDDEN const int ITF_CID = 30000;
|
|
|
|
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)
|
|
{
|
|
TConfig ini("res/resource.ini", "Icons");
|
|
TString8 strid; strid << id;
|
|
TFilename n; n << "res/" << ini.get(strid);
|
|
TImage* i = new TImage(n);
|
|
_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)
|
|
{
|
|
RCT pc; xvt_vobj_get_client_rect(TASK_WIN, &pc);
|
|
|
|
DEF_FONT = xvt_dwin_get_font(TASK_WIN);
|
|
|
|
TConfig font(CONFIG_GUI, "Font");
|
|
TString font_ser_desc = font.get("FontDesc");
|
|
if (font_ser_desc.empty())
|
|
{
|
|
const char* name = "Courier New";
|
|
// Tenta di usare il Verdana se possibile
|
|
if (pc.right > 800 && is_xvt_font("Verdana"))
|
|
name = "Verdana";
|
|
|
|
font_ser_desc.format("01\\%s\\0\\10\\WIN01/-13/0/0/0/400/0/0/0/0/1/2/1/49/%s", name, name);
|
|
|
|
font.set("FontDesc", font_ser_desc); // 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);
|
|
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");
|
|
|
|
// Compute true text size
|
|
ROWY = (pc.bottom - pc.top) / 25;
|
|
const int COLX = (pc.right - pc.left) / 80;
|
|
|
|
TString str(80, 'M');
|
|
CHARX = xvt_dwin_get_text_width(TASK_WIN, str.get_buffer(), str.size()) / str.size();
|
|
|
|
int leading, ascent, descent;
|
|
xvt_dwin_get_font_metrics(TASK_WIN, &leading, &ascent, &descent);
|
|
CHARY = ascent + descent + 1;
|
|
BASEY = ascent;
|
|
|
|
if (CHARX > COLX)
|
|
CHARX = COLX;
|
|
|
|
if (CHARY > ROWY-2)
|
|
CHARY = ROWY-2;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
X_FU_MULTIPLE = Y_FU_MULTIPLE = 0;
|
|
XVT_FNTID font = xvtil_default_font();
|
|
xi_set_font_id(font);
|
|
xi_init_sysvals(); // Ricalcola i FU units
|
|
|
|
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 && !NATIVE_CONTROLS)
|
|
{
|
|
TConfig ini(CONFIG_GUI, "Colors");
|
|
TFilename back = ini.get("Tile");
|
|
if (back.custom_path())
|
|
bmp = xi_bitmap_create(back.get_buffer(), XI_BITMAP_TILE);
|
|
}
|
|
}
|
|
return bmp;
|
|
}
|
|
|
|
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 <c TConfig>
|
|
|
|
{
|
|
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);
|
|
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);
|
|
TOOL_BACK_COLOR = colors.get_color("ToolBack", NULL, -1, MASK_DARK_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 = ADVANCED_GRAPHICS && colors.get_bool("NativeControls", NULL, -1, NATIVE_CONTROLS);
|
|
xi_set_pref(XI_PREF_NATIVE_CTRLS, NATIVE_CONTROLS);
|
|
ENTER_AS_TAB = colors.get_bool("EnterAsTab", NULL, -1, ENTER_AS_TAB);
|
|
|
|
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 = colors.get_int("SpeechMode", NULL, -1, 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);
|
|
|
|
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);
|
|
|
|
if (_picture)
|
|
_picture->reload();
|
|
|
|
xvtil_load_default_font(); // Aggiorna anche il font!
|
|
}
|
|
|
|
void init_controls()
|
|
{
|
|
xi_set_font_id(xvtil_load_default_font());
|
|
|
|
xi_set_pref(XI_PREF_NATIVE_CTRLS, NATIVE_CONTROLS);
|
|
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 int maybe = -1;
|
|
if (maybe < 0)
|
|
{
|
|
TConfig ini(CONFIG_INSTALL, "Main");
|
|
maybe = ini.get_bool("VirtualKeyboard") ? 1 : 0;
|
|
}
|
|
return maybe != 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Interface creation
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN void xi_event_handler(XI_OBJ *itf, XI_EVENT *xiev);
|
|
|
|
HIDDEN void init_fu_multiple(XI_OBJ* itf)
|
|
{
|
|
RCT max_rct; xvt_vobj_get_client_rect(TASK_WIN, &max_rct);
|
|
xi_pu_to_fu(itf, (XinPoint *) &max_rct, 2);
|
|
X_FU_MULTIPLE = max_rct.right / 80;
|
|
Y_FU_MULTIPLE = max_rct.bottom / 25;
|
|
}
|
|
|
|
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;
|
|
short height = dy * ROWY;
|
|
|
|
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; // 22 - 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_OBJ_DEF* def = xi_create_itf_def(ITF_CID, xi_event_handler, (XinRect *) &r, (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 (Y_FU_MULTIPLE == 0)
|
|
init_fu_multiple(itf);
|
|
|
|
if (dx > 0)
|
|
{
|
|
xi_pu_to_fu(itf, (XinPoint *) &r, 2);
|
|
r.right = r.left + (dx+1) * XI_FU_MULTIPLE;
|
|
r.bottom = r.top + (dy+1) * Y_FU_MULTIPLE;
|
|
xi_fu_to_pu(itf, (XinPoint *) &r, 2);
|
|
xvt_vobj_move(win, &r);
|
|
}
|
|
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[80]; xvt_vobj_get_title(win, caption, 80);
|
|
TWindow* parent = (TWindow*)xvt_vobj_get_data(win);
|
|
XI_OBJ_DEF* def = xi_create_itf_def(ITF_CID, xi_event_handler, (XinRect *) &rc, caption, (long)parent);
|
|
CHECK(def, "Can't define an interface");
|
|
|
|
def->v.itf->automatic_back_color = false;
|
|
def->v.itf->back_color = back;
|
|
def->v.itf->tab_on_enter = true;
|
|
def->v.itf->win = (XinWindow)win;
|
|
|
|
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;
|
|
if (_cur_ddl != NULL)
|
|
_cur_ddl->on_mouse_down(xiev->v.xvte.v.mouse.where);
|
|
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;
|
|
case E_MOUSE_UP:
|
|
_button_blocked = false;
|
|
// fall down
|
|
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_LIST:
|
|
case XIT_BTN:
|
|
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);
|
|
}
|
|
}
|
|
|
|
void TControl::coord2rct(WINDOW win, short x, short y, short dx, short dy, RCT & rct) const
|
|
{
|
|
// Spazio da lasciare prima di toccare i bordi
|
|
const int X_FU_DELTA = XI_FU_MULTIPLE / 4;
|
|
const int Y_FU_DELTA = XI_FU_MULTIPLE / 8;
|
|
|
|
XI_OBJ* itf = get_interface(win);
|
|
|
|
if (Y_FU_MULTIPLE == 0) // Puo' succedere che non sia ancora inizializzato
|
|
init_fu_multiple(itf);
|
|
|
|
/* OBSOLETE
|
|
// Se ci sono i tab controls sulla pagina salta una riga
|
|
if (y >= 0)
|
|
{
|
|
int num;
|
|
XI_OBJ** child = xi_get_member_list(itf, &num);
|
|
if (num > 0 && child[0]->cid == MASK_RECT_ID)
|
|
y++;
|
|
}
|
|
*/
|
|
|
|
RCT max_rct; xvt_vobj_get_client_rect(win, &max_rct);
|
|
xi_pu_to_fu(itf, (XinPoint *)&max_rct, 2);
|
|
const int MAXX = max_rct.right;
|
|
const int MAXY = max_rct.bottom;
|
|
|
|
int width = XI_FU_MULTIPLE;
|
|
if (dx > 0)
|
|
width = dx * XI_FU_MULTIPLE;
|
|
|
|
int height = XI_FU_MULTIPLE;
|
|
if (dy > 1)
|
|
height += (dy-1) * Y_FU_MULTIPLE;
|
|
|
|
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 * XI_FU_MULTIPLE;
|
|
}
|
|
else
|
|
{
|
|
rct.left = x * XI_FU_MULTIPLE + X_FU_DELTA;
|
|
|
|
if (dx > 0 && MAXX > 80 * XI_FU_MULTIPLE)
|
|
rct.left += (MAXX - 80 * XI_FU_MULTIPLE) / 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) * Y_FU_MULTIPLE - Y_FU_DELTA;
|
|
}
|
|
else
|
|
rct.top = y * Y_FU_MULTIPLE + Y_FU_DELTA;
|
|
|
|
if (dx > 0)
|
|
rct.right = rct.left + width;
|
|
else
|
|
rct.right = MAXX + (dx-1) * XI_FU_MULTIPLE - X_FU_DELTA;
|
|
|
|
if (dy > 0)
|
|
rct.bottom = rct.top + height;
|
|
else
|
|
rct.bottom = MAXY + dy * Y_FU_MULTIPLE - X_FU_DELTA;
|
|
}
|
|
|
|
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, (XinRect *) &r);
|
|
return r;
|
|
}
|
|
|
|
void TControl::set_rect(const RCT& r)
|
|
{
|
|
xi_set_rect(_obj, (XinRect*)&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);
|
|
}
|
|
}
|
|
|
|
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 = NORMAL_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();
|
|
|
|
RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
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, (XinRect *) &rct, attrib, (char*)(const char*)t);
|
|
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(get_interface(win), 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)
|
|
{
|
|
// Alza di un pixel il rettangolo per non coprire il rettangolo
|
|
RCT& tr = (RCT &) _obj->v.text->rct;
|
|
tr.top--; tr.bottom--;
|
|
|
|
RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
rct.top += XI_FU_MULTIPLE - 2;
|
|
rct.bottom -= Y_FU_MULTIPLE / 2;
|
|
|
|
XI_OBJ_DEF* def = xi_add_rect_def(NULL, cid, (XI_RCT*) &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;
|
|
|
|
const bool erre = strchr(flags, 'R') != NULL;
|
|
if (erre)
|
|
{
|
|
def->v.rect->well = true; // Mette in rilievo il rettangolo
|
|
change_attrib(XI_ATR_RJUST, false, _obj); // Toglie l'erroneo allineamento a destra del titolo
|
|
}
|
|
_rct = xi_create(get_interface(win), 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;
|
|
}
|
|
|
|
RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
|
|
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* itf = get_interface(win);
|
|
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
|
|
XinRect& br = (XinRect&)_obj->v.field->btn_rct;
|
|
const int offset = stx->rct.right - br.left - 1;
|
|
br.left += offset;
|
|
br.right += offset;
|
|
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;
|
|
|
|
RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
|
|
const unsigned long attrib = flags2attr(flags);
|
|
XI_OBJ_DEF* def = xi_add_button_def(NULL, cid, (XinRect*)&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--;
|
|
}
|
|
break;
|
|
case WC_CHECKBUTTON:
|
|
if (height == 1)
|
|
{
|
|
XI_RCT& r = _obj->v.btn->rct;
|
|
r.bottom+=2;
|
|
}
|
|
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);
|
|
|
|
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 = (rct.right - rct.left - 32) / 2 - 5;
|
|
_obj->v.btn->icon_y = (rct.bottom - rct.top - 32) / 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,
|
|
short bmp_up, short 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(short(0), short(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)
|
|
{
|
|
WINDOW win = parent();
|
|
XI_RCT rct = _obj->v.btn->rct;
|
|
rct.left += 5; rct.top += 5; rct.right -= 5; rct.bottom -= 5;
|
|
xi_set_clip((XinWindow)win, &rct);
|
|
|
|
// Cancello il testo sottostante
|
|
CBRUSH brush = { PAT_SOLID, BTN_BACK_COLOR };
|
|
xvt_dwin_set_cbrush(win, &brush);
|
|
xvt_dwin_set_std_cpen(win, TL_PEN_HOLLOW);
|
|
xi_draw_rect((XinWindow)win, &rct);
|
|
|
|
const short 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);
|
|
int x = (rct.right + rct.left - i.width()) / 2;
|
|
int y = (rct.bottom + rct.top - i.height()) / 2;
|
|
if (_obj->v.btn->down)
|
|
{
|
|
x += 2;
|
|
y += 2;
|
|
}
|
|
i.draw(win, x, y);
|
|
}
|
|
xi_set_clip((XinWindow)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;
|
|
RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
|
|
if (height > 1)
|
|
{
|
|
// Aggiusta rettangolo in modo da centrare i bottoni
|
|
const int extra = rct.bottom - rct.top - tot * XI_FU_MULTIPLE;
|
|
if (extra > 0)
|
|
rct.top += extra / 2;
|
|
else
|
|
if (extra < 0)
|
|
rct.bottom -= extra;
|
|
rct.left -= XI_FU_MULTIPLE / 4;
|
|
rct.right += XI_FU_MULTIPLE / 4;
|
|
}
|
|
XI_OBJ_DEF* def = xi_add_container_def(NULL, cid, (XinRect *) &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;
|
|
}
|
|
|
|
XI_OBJ* itf = get_interface(win);
|
|
_obj = xi_create(itf, def);
|
|
CHECKD(_obj, "Can't create radio-button container ", cid);
|
|
|
|
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 + Y_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
|
|
///////////////////////////////////////////////////////////
|
|
|
|
long TDropDownList::row2rec(int row) const
|
|
{
|
|
int rows;
|
|
const long* handle = xi_get_list_info(_xi_lst, &rows);
|
|
|
|
if (row < 0) row = 0;
|
|
else
|
|
if (row >= rows)
|
|
row = rows-1;
|
|
const long r = handle[row];
|
|
CHECKD(r >= 0 && r < items(), "Sheet line out of range: ", row);
|
|
|
|
return r;
|
|
}
|
|
|
|
int TDropDownList::rec2row(long rec) const
|
|
{
|
|
int rows;
|
|
const long* handle = xi_get_list_info(_xi_lst, &rows);
|
|
|
|
int r = int(rec - handle[0]);
|
|
if (r < 0 || r >= rows)
|
|
r = -1;
|
|
|
|
return r;
|
|
}
|
|
|
|
void TDropDownList::update_selection(XI_EVENT* xiev) const
|
|
{
|
|
if (xiev->v.rec_request.data_rec == selected())
|
|
xiev->v.rec_request.attrib |= XI_ATR_SELECTED;
|
|
else
|
|
xiev->v.rec_request.attrib &= ~XI_ATR_SELECTED;
|
|
}
|
|
|
|
void TDropDownList::ddl_str_eh(XI_OBJ* itf, XI_EVENT* xiev)
|
|
{
|
|
TDropDownList* ddl = (TDropDownList*)xi_get_app_data(itf);
|
|
if (!ddl->is_open())
|
|
return;
|
|
|
|
switch(xiev->type)
|
|
{
|
|
case XIE_GET_FIRST:
|
|
if (ddl->items() > 0)
|
|
{
|
|
// GUY
|
|
// xiev->v.rec_request.data_rec = ddl->items() * xiev->v.rec_request.percent/100;
|
|
// ddl->update_selection(xiev);
|
|
long n = ddl->items() * (long)xiev->v.rec_request.percent / 100L;
|
|
if (n < 0L) n = 0L;
|
|
xiev->v.rec_request.data_rec = n;
|
|
}
|
|
else
|
|
xiev->refused = true;
|
|
break;
|
|
case XIE_GET_LAST:
|
|
xiev->v.rec_request.data_rec = ddl->items() - 1;
|
|
// GUY ddl->update_selection(xiev);
|
|
break;
|
|
case XIE_GET_PREV:
|
|
case XIE_GET_NEXT:
|
|
{
|
|
const long n = xiev->v.rec_request.spec_rec + (xiev->type == XIE_GET_NEXT ? +1 : -1) ;
|
|
if (n >= 0 && n < ddl->items())
|
|
xiev->v.rec_request.data_rec = n;
|
|
else
|
|
xiev->refused = true;
|
|
}
|
|
break;
|
|
case XIE_CELL_REQUEST:
|
|
{
|
|
const long rec = xiev->v.cell_request.rec;
|
|
if (rec >= 0 && rec < ddl->items())
|
|
{
|
|
const char* row = ddl->item(xiev->v.cell_request.rec);
|
|
const int len = xiev->v.cell_request.len;
|
|
strncpy(xiev->v.cell_request.s, (char*)row, len);
|
|
xiev->v.cell_request.s[len - 1] = '\0';
|
|
}
|
|
}
|
|
break;
|
|
case XIE_GET_PERCENT:
|
|
{
|
|
const long rec = xiev->v.get_percent.record;
|
|
long n = ddl->items(); if (n <= 0) n = 1;
|
|
xiev->v.get_percent.percent = int(rec * 100L / n);
|
|
}
|
|
break;
|
|
case XIE_DBL_CELL:
|
|
ddl->select((int)(ddl->row2rec(xiev->v.xi_obj->v.cell.row)));
|
|
ddl->close();
|
|
break;
|
|
case XIE_SELECT:
|
|
if (xiev->v.xi_obj->type == XIT_ROW)
|
|
{
|
|
const long rec = ddl->row2rec(xiev->v.xi_obj->v.row);
|
|
ddl->select(int(rec));
|
|
}
|
|
break;
|
|
case XIE_XVT_EVENT:
|
|
switch (xiev->v.xvte.type)
|
|
{
|
|
case E_CHAR:
|
|
{
|
|
const KEY k = xiev->v.xvte.v.chr.ch;
|
|
if (k == K_ENTER || k == K_ESC)
|
|
ddl->close();
|
|
else
|
|
{
|
|
if (k >= ' ' && k <= 'z')
|
|
ddl->select_by_initial(char(k));
|
|
}
|
|
}
|
|
break;
|
|
case E_MOUSE_DBL:
|
|
ddl->close();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TDropDownList::close()
|
|
{
|
|
if (_open)
|
|
{
|
|
_open = false;
|
|
if (_xi_lst != NULL)
|
|
xvt_vobj_set_visible((WINDOW)xi_get_window(_xi_lst->itf), false);
|
|
_cur_ddl = NULL;
|
|
}
|
|
}
|
|
|
|
void TDropDownList::destroy()
|
|
{
|
|
close();
|
|
if (_xi_lst != NULL)
|
|
{
|
|
xvt_vobj_destroy((WINDOW)xi_get_window(_xi_lst->itf));
|
|
_xi_lst = NULL;
|
|
}
|
|
}
|
|
|
|
bool TDropDownList::select(int i, bool force)
|
|
{
|
|
if (force || i != _selected)
|
|
{
|
|
_selected = i;
|
|
|
|
if (_obj->type == XIT_FIELD)
|
|
{
|
|
if (_open) xi_set_text(_obj, ""); // Altrimenti a volte ridisegna male!
|
|
xi_set_text(_obj, (char*)_values.get(i));
|
|
TListbox_control* listbox = (TListbox_control*)xi_get_app_data(_obj);
|
|
listbox->notify_key(K_SPACE);
|
|
}
|
|
else
|
|
xi_set_text(_obj, (char*)_codes.get(i));
|
|
|
|
if (force && _open)
|
|
xi_scroll_rec(_xi_lst, i, FOCUS_COLOR, XI_ATR_ENABLED | XI_ATR_SELECTED, 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TDropDownList::select_by_initial(char c)
|
|
{
|
|
const int tot = _values.items();
|
|
int i = _selected;
|
|
c = toupper(c);
|
|
while(true)
|
|
{
|
|
i++;
|
|
if (i >= tot)
|
|
i = 0;
|
|
if (i == _selected)
|
|
break;
|
|
const char p = toupper(*(_values.get(i)));
|
|
if (p == c)
|
|
break;
|
|
}
|
|
|
|
bool ok = false;
|
|
if (i != selected())
|
|
{
|
|
if (is_open())
|
|
{
|
|
const int oldsel = selected();
|
|
|
|
// Scrolla alla selezione corrente
|
|
xi_scroll_rec(_xi_lst, i, FOCUS_COLOR, XI_ATR_SELECTED | XI_ATR_ENABLED, 0);
|
|
|
|
const int r = rec2row(oldsel);
|
|
if (r >= 0)
|
|
{
|
|
XI_OBJ riga; XI_MAKE_ROW(&riga, _xi_lst, r);
|
|
long attr = xi_get_attrib(&riga);
|
|
attr &= ~XI_ATR_SELECTED;
|
|
xi_set_attrib(&riga, attr);
|
|
xi_dequeue();
|
|
}
|
|
|
|
}
|
|
ok = select(i);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool TDropDownList::select_by_ofs(int i)
|
|
{
|
|
i += _selected;
|
|
if (i >= 0 && i < _values.items())
|
|
return select(i);
|
|
return false;
|
|
}
|
|
|
|
void TDropDownList::set_values(const char* c, const char* v)
|
|
{
|
|
const int old_items = _codes.items();
|
|
|
|
_codes = c;
|
|
_values = v;
|
|
|
|
const int new_items = _codes.items();
|
|
if (new_items != old_items && _xi_lst != NULL)
|
|
destroy();
|
|
}
|
|
|
|
int TDropDownList::calc_min_width()
|
|
{
|
|
int len = 1;
|
|
for (const char* v = _values.get(0); v; v = _values.get())
|
|
{
|
|
const int l = strlen(v);
|
|
if (l > len) len = l;
|
|
}
|
|
|
|
return (len+2) * XI_FU_MULTIPLE;
|
|
}
|
|
|
|
void TDropDownList::create()
|
|
{
|
|
if (_xi_lst != NULL)
|
|
return;
|
|
|
|
XI_OBJ_DEF* itfdef = xi_create_itf_def(ITF_CID+1, (XI_EVENT_HANDLER)ddl_str_eh, NULL, "",
|
|
(long)this);
|
|
itfdef->v.itf->automatic_back_color = true;
|
|
|
|
const int hei = items() <= 1 ? 2*XI_FU_MULTIPLE + 1 : (min(8,items()) * XI_FU_MULTIPLE) + 1;
|
|
XI_OBJ_DEF* lstdef = xi_add_list_def(itfdef, _obj->cid+1000, 0, 0, hei,
|
|
XI_ATR_ENABLED|XI_ATR_VISIBLE,
|
|
FOCUS_COLOR, FOCUS_BACK_COLOR,
|
|
DISABLED_COLOR, DISABLED_BACK_COLOR,
|
|
FOCUS_COLOR, 0);
|
|
XI_LIST_DEF* ld = lstdef->v.list;
|
|
ld->active_back_color = FOCUS_BACK_COLOR;
|
|
ld->scroll_bar = items() > 8;
|
|
ld->no_heading = true;
|
|
ld->no_horz_lines = true;
|
|
ld->no_vert_lines = true;
|
|
ld->resize_with_window = true;
|
|
ld->single_select = true;
|
|
#ifdef LINUX
|
|
ld->scroll_on_thumb_track = true;
|
|
#endif
|
|
|
|
// compute size in pixel of field (with button enclosed)
|
|
XI_RCT r; xi_get_rect(_obj, &r);
|
|
|
|
// Larghezza in pixel dell'edit field
|
|
int len = r.right - r.left;
|
|
if (lstdef->v.list->scroll_bar)
|
|
{
|
|
// Larghezza in pixel del bottone
|
|
const int bw = int(_obj->itf->v.itf->fu_height * XI_FU_MULTIPLE / _obj->itf->v.itf->fu_width);
|
|
len -= bw;
|
|
len -= 2; // Don't ask me why
|
|
}
|
|
else
|
|
len -= 6; // Don't ask me why
|
|
|
|
// Larghezza in form units dell'edit field
|
|
len = len * XI_FU_MULTIPLE / _obj->itf->v.itf->fu_width - 2;
|
|
|
|
if (_obj->type == XIT_CELL)
|
|
{
|
|
const int m = calc_min_width();
|
|
if (len < m)
|
|
{
|
|
len = m;
|
|
r.right = r.left + m * _obj->itf->v.itf->fu_width / XI_FU_MULTIPLE;
|
|
}
|
|
}
|
|
|
|
xi_add_column_def(lstdef, _obj->cid+2000,
|
|
XI_ATR_VISIBLE|XI_ATR_ENABLED|XI_ATR_READONLY|XI_ATR_SELECTABLE,
|
|
0, len, 80, "");
|
|
|
|
XI_RCT l; xi_get_def_rect(lstdef, &l);
|
|
PNT p; p.h = r.left;
|
|
WINDOW pwin = (WINDOW)xi_get_window(_obj->itf);
|
|
RCT w; xvt_vobj_get_client_rect(pwin, &w);
|
|
// place rectangle
|
|
if (r.bottom + l.bottom - l.top <= w.bottom)
|
|
p.v = r.bottom;
|
|
else
|
|
{
|
|
p.v = r.top - l.bottom - l.top;
|
|
if (p.v < w.top) p.v = w.top;
|
|
}
|
|
RCT wr;
|
|
wr.left = p.h; wr.top = p.v;
|
|
// xi_get_def_rect(lstdef, (XinRect *) &l);
|
|
wr.right = r.right;
|
|
wr.bottom = wr.top + l.bottom - l.top;
|
|
const int delta_x = _obj->itf->v.itf->delta_x;
|
|
const int delta_y = _obj->itf->v.itf->delta_y;
|
|
wr.left -= delta_x;
|
|
wr.right -= delta_x;
|
|
wr.top -= delta_y;
|
|
wr.bottom -= delta_y;
|
|
|
|
WINDOW win = xvt_win_create(W_PLAIN, &wr, "", 0, pwin, WSF_NO_MENUBAR, EM_ALL,
|
|
(EVENT_HANDLER)xi_event, 0L);
|
|
itfdef->v.itf->win = (XinWindow)win;
|
|
itfdef->v.itf->rctp = (XinRect *) ≀
|
|
XI_OBJ* itfobj = xi_create(NULL, itfdef);
|
|
CHECK(itfobj, "Can't create listbox");
|
|
|
|
xi_dequeue();
|
|
xi_tree_free(itfdef);
|
|
|
|
_xi_lst = xi_get_obj(itfobj, _obj->cid+1000);
|
|
CHECK(_xi_lst, "Can't create listbox");
|
|
}
|
|
|
|
void TDropDownList::open()
|
|
{
|
|
if (_open)
|
|
return;
|
|
|
|
if (_xi_lst != NULL)
|
|
xvt_vobj_set_visible((WINDOW)xi_get_window(_xi_lst->itf), true);
|
|
else
|
|
create();
|
|
|
|
_open = true;
|
|
xi_cell_request(_xi_lst);
|
|
|
|
WINDOW win = (WINDOW)xi_get_window(_xi_lst->itf);
|
|
xvt_scr_set_focus_vobj(win);
|
|
xvt_vobj_raise(win);
|
|
|
|
select(_selected, true);
|
|
|
|
xi_dequeue();
|
|
_cur_ddl = this;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
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 (!_button_blocked && !read_only())
|
|
{
|
|
if (_ddl->is_open())
|
|
_ddl->close();
|
|
else
|
|
_ddl->open();
|
|
}
|
|
break;
|
|
case XIE_CHAR_FIELD:
|
|
{
|
|
const KEY k = xiev_to_key(xiev);
|
|
|
|
if (!read_only())
|
|
{
|
|
if (k >= ' ' && k <= 'z')
|
|
_ddl->select_by_initial(char(k));
|
|
else
|
|
if (k == K_F9)
|
|
_ddl->open();
|
|
else
|
|
if (k == K_RIGHT) // poor man's substitute for down arrow
|
|
_ddl->select_by_ofs(1);
|
|
else
|
|
if (k == K_LEFT) // poor man's substitute for up arrow
|
|
_ddl->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 TDropDownList::on_mouse_down(const PNT& pt)
|
|
{
|
|
if (_open)
|
|
{
|
|
RCT rct;
|
|
xi_get_rect(_obj, (XinRect*)&rct);
|
|
if (xvt_rect_has_point(&rct, pt))
|
|
return; // E' nel campo di testo proprietario della lista
|
|
|
|
xvt_vobj_get_outer_rect((WINDOW)xi_get_window(_xi_lst->itf), &rct);
|
|
if (!xvt_rect_has_point(&rct, pt)) // Fuori dalla lista
|
|
close();
|
|
}
|
|
}
|
|
|
|
TDropDownList::TDropDownList(XI_OBJ* o, const char* codes, const char* values)
|
|
: _obj(o), _xi_lst(NULL), _codes(codes),
|
|
_values(values), _selected(0), _open(false)
|
|
{
|
|
if (o->type == XIT_CELL)
|
|
{
|
|
const char* val = xi_get_text(o, NULL, -1);
|
|
_selected = _codes.get_pos(val);
|
|
if (_selected < 0)
|
|
_selected = 0;
|
|
}
|
|
}
|
|
|
|
TDropDownList::~TDropDownList()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TListbox_control
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void TListbox_control::set_values(const char* cod, const char* val)
|
|
{
|
|
_ddl->set_values(cod, val);
|
|
if (selected() >= items())
|
|
_ddl->select(0, true);
|
|
else
|
|
_ddl->select(selected(), true);
|
|
}
|
|
|
|
int TListbox_control::items() const
|
|
{
|
|
return _ddl->items();
|
|
}
|
|
|
|
bool TListbox_control::select(int i)
|
|
{
|
|
return _ddl->select(i);
|
|
}
|
|
|
|
bool TListbox_control::select_by_initial(char c)
|
|
{
|
|
return _ddl->select_by_initial(c);
|
|
}
|
|
|
|
bool TListbox_control::select_by_ofs(int i)
|
|
{
|
|
return _ddl->select_by_ofs(i);
|
|
}
|
|
|
|
int TListbox_control::selected() const
|
|
{
|
|
return _ddl->selected();
|
|
}
|
|
|
|
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)
|
|
{
|
|
create(win, cid, left, top, width , 1, width, flags, text, true);
|
|
_ddl = new TDropDownList(_obj, codes, values);
|
|
_ddl->select(0, true);
|
|
}
|
|
|
|
TListbox_control::~TListbox_control()
|
|
{
|
|
delete _ddl; _ddl = NULL;
|
|
}
|