f9b938f706
controls.cpp Abbassati legermente i checkbox mask.cpp Corretto controllo sulle maschere multipagina non a tutto schermo maskfld.cpp Corretto passaggio al campo successivo doppo un tasto F9 msksheet.cpp Corretta gestione del messaggio di inizializzazione in modo da cercare di andare sempre sulla prima riga progind.cpp Corretto calcolo della percentuale (arrotondato e non troncato) relapp.h Reso pubblico il metoto TRelation_application::lnflag() const git-svn-id: svn://10.65.10.50/trunk@3573 c028cbd2-c16b-5b4b-a496-9718f37d4682
2098 lines
55 KiB
C++
Executable File
2098 lines
55 KiB
C++
Executable File
#if XVT_OS == XVT_OS_WIN
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include <colors.h>
|
|
#include <config.h>
|
|
#include <controls.h>
|
|
#include <mask.h>
|
|
#include <urldefid.h>
|
|
#include <window.h>
|
|
|
|
COLOR MASK_BACK_COLOR = COLOR_DKCYAN;
|
|
COLOR MASK_LIGHT_COLOR = COLOR_CYAN;
|
|
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_LTGRAY;
|
|
COLOR DISABLED_COLOR = COLOR_GRAY;
|
|
COLOR DISABLED_BACK_COLOR = MASK_BACK_COLOR;
|
|
COLOR FOCUS_COLOR = NORMAL_COLOR;
|
|
COLOR FOCUS_BACK_COLOR = COLOR_CYAN;
|
|
BOOLEAN CAMPI_SCAVATI = FALSE;
|
|
BOOLEAN AUTOSELECT = FALSE;
|
|
|
|
#ifndef STX_DATA
|
|
// Very deep hacking
|
|
typedef struct _stx_data
|
|
{
|
|
int cid;
|
|
WINDOW win;
|
|
RCT rct;
|
|
unsigned long attrib;
|
|
} STX_DATA;
|
|
|
|
#endif
|
|
|
|
HIDDEN bool _button_blocked = FALSE;
|
|
|
|
short get_focus_id(WINDOW win)
|
|
{
|
|
XI_OBJ * itf = xi_get_itf(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;
|
|
}
|
|
|
|
|
|
// #define CAMPI_SCAVATI FALSE
|
|
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)
|
|
{
|
|
KEY key = xiev->v.chr.ch;
|
|
if (key < K_INS || key > K_HELP)
|
|
{
|
|
if (xiev->v.chr.shift && (key < ' ' || key >= K_UP)) key += K_SHIFT;
|
|
if (xiev->v.chr.control && key >= ' ') key += K_CTRL;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
|
|
// @doc INTERNAL
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TPicture_array
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TPicture_array : public TArray
|
|
{
|
|
public:
|
|
TImage& add(short id);
|
|
|
|
const TImage& image(short id) const { return (const TImage&)operator[](id); }
|
|
bool exist(short id) const { return objptr(id) != NULL; }
|
|
void reload();
|
|
|
|
TPicture_array() : TArray(128) {}
|
|
virtual ~TPicture_array() {}
|
|
};
|
|
|
|
TImage& TPicture_array::add(short id)
|
|
{
|
|
TImage* i = (TImage*)objptr(id);
|
|
|
|
if (i == NULL)
|
|
{
|
|
i = new TImage(id);
|
|
i->convert_transparent_color(BTN_BACK_COLOR);
|
|
TArray::add(i, id);
|
|
}
|
|
|
|
return *i;
|
|
}
|
|
|
|
void TPicture_array::reload()
|
|
{
|
|
for (int id = last(); id >= 0; id--)
|
|
{
|
|
TImage* i = (TImage*)objptr(id);
|
|
if (i)
|
|
{
|
|
i->load(id);
|
|
i->convert_transparent_color(BTN_BACK_COLOR);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Utility functions
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN TPicture_array* _picture = NULL;
|
|
HIDDEN XVT_FNTID DEF_FONT = NULL;
|
|
HIDDEN XVT_FNTID FAT_FONT = NULL;
|
|
|
|
XVT_FNTID xvt_default_font(bool bold)
|
|
{
|
|
if (DEF_FONT == NULL)
|
|
{
|
|
DEF_FONT = xvt_dwin_get_font(TASK_WIN);
|
|
|
|
TConfig font(CONFIG_USER, "Font");
|
|
TString font_ser_desc(font.get("FontDesc"));
|
|
if (font_ser_desc.empty())
|
|
font_ser_desc << "01\\Courier\\0\\10\\WIN01/-13/0/0/0/400/0/0/0/0/1/2/1/49/Courier";
|
|
xvt_font_deserialize(DEF_FONT, (char *)(const char *) 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");
|
|
// Get true text size
|
|
#if XVT_OS == XVT_OS_WIN
|
|
TEXTMETRIC tm;
|
|
HDC hdc = (HDC)xvt_vobj_get_attr(TASK_WIN, ATTR_NATIVE_GRAPHIC_CONTEXT);
|
|
GetTextMetrics(hdc, &tm);
|
|
|
|
const int COLX = GetSystemMetrics(SM_CXSCREEN) / 80;
|
|
CHARX = tm.tmAveCharWidth+1;
|
|
if (CHARX > COLX) CHARX = COLX;
|
|
|
|
CHARY = tm.tmHeight;
|
|
BASEY = tm.tmAscent;
|
|
if (CHARY > ROWY-2) CHARY = ROWY-2;
|
|
#endif
|
|
}
|
|
|
|
return bold ? FAT_FONT : DEF_FONT;
|
|
}
|
|
|
|
XVT_FNTID xvt_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;
|
|
}
|
|
|
|
X_FU_MULTIPLE = Y_FU_MULTIPLE = 0;
|
|
|
|
return xvt_default_font(FALSE);
|
|
}
|
|
|
|
static byte event_map[XIE_POST_NAVIGATION+1];
|
|
enum event_action { a_ignore, a_xvt, a_xvt_post, a_obj, a_child, a_update, a_select, a_post, a_debug };
|
|
|
|
HIDDEN void set_default_palette(WINDOW win)
|
|
{
|
|
COLOR colori[12] = { MASK_BACK_COLOR, MASK_LIGHT_COLOR, MASK_DARK_COLOR,
|
|
NORMAL_COLOR, NORMAL_BACK_COLOR,
|
|
FOCUS_COLOR, FOCUS_BACK_COLOR,
|
|
DISABLED_COLOR, DISABLED_BACK_COLOR,
|
|
BTN_BACK_COLOR, BTN_LIGHT_COLOR, BTN_DARK_COLOR };
|
|
|
|
XVT_PALETTE wp = xvt_vobj_get_palet(win);
|
|
if (wp != NULL)
|
|
{
|
|
XVT_PALETTE up = xvt_palet_create(XVT_PALETTE_USER, NULL);
|
|
if (up != NULL)
|
|
{
|
|
xvt_palet_set_tolerance(up, xvt_palet_get_tolerance(wp));
|
|
|
|
const int MAXCOL = 256;
|
|
COLOR colors[MAXCOL];
|
|
const int num = xvt_palet_get_colors(wp, colors, MAXCOL);
|
|
xvt_palet_add_colors(up, colors, num);
|
|
const int add = xvt_palet_add_colors(up, colori, 12);
|
|
if (add > 0)
|
|
{
|
|
xvt_vobj_set_palet(win, up);
|
|
xvt_palet_destroy(wp);
|
|
}
|
|
else
|
|
xvt_palet_destroy(up);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// @func Permette di cambiare 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_USER, "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);
|
|
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, (bool)CAMPI_SCAVATI);
|
|
AUTOSELECT = colors.get_bool("AutoSelect", NULL, -1, (bool)AUTOSELECT);
|
|
|
|
xi_set_pref(XI_PREF_NATIVE_CTRLS, FALSE);
|
|
xi_set_pref(XI_PREF_3D_LOOK, TRUE);
|
|
|
|
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_LIGHT, BTN_LIGHT_COLOR);
|
|
|
|
BTN_LIGHT_COLOR = colors.get_color("ButtonLight", NULL, -1, BTN_LIGHT_COLOR);
|
|
aga_set_pref(AGA_PREF_BTN_COLOR_CTRL, BTN_BACK_COLOR);
|
|
|
|
BTN_DARK_COLOR = colors.get_color("ButtonDark", NULL, -1, BTN_DARK_COLOR);
|
|
aga_set_pref(AGA_PREF_BTN_COLOR_DARK, BTN_DARK_COLOR);
|
|
|
|
set_default_palette(TASK_WIN);
|
|
|
|
if (_picture)
|
|
_picture->reload();
|
|
}
|
|
|
|
void init_controls()
|
|
{
|
|
xi_set_font_id(xvt_load_default_font());
|
|
|
|
xi_set_pref(XI_PREF_CARET_WIDTH, 2);
|
|
|
|
xi_init();
|
|
|
|
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_ignore;
|
|
event_map[XIE_COL_SIZE] = a_ignore;
|
|
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;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Interface creation
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN void xi_event_handler(XI_OBJ *itf, XI_EVENT *xiev);
|
|
|
|
#define MASK_RECT_ID -883
|
|
|
|
WINDOW create_interface(WINDOW parent, short x, short y, short dx, short dy,
|
|
const char* caption, TWindow* msk, bool tag)
|
|
{
|
|
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; xvt_vobj_get_client_rect(parent, &max);
|
|
if (parent == TASK_WIN)
|
|
max.bottom -= 26; // Non contare la status bar
|
|
|
|
if (dy <= 0)
|
|
height = max.bottom - top + dy * ROWY;
|
|
|
|
if (dx <= 0)
|
|
{
|
|
width = max.right - left + dx * CHARX;
|
|
if (!tag && dx == 0 && y > 0) // Aggiusta toolbar
|
|
top++;
|
|
}
|
|
|
|
if (x < 0) left = (max.right - width) >> 1;
|
|
if (y < 0) top = (max.bottom - height) >> 1;
|
|
}
|
|
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, (char*)caption, NULL, parent, wsf,
|
|
EM_ALL, (EVENT_HANDLER)xi_event, (long)msk);
|
|
CHECK(win, "Can't create an XVT window for an interface");
|
|
set_default_palette(win);
|
|
|
|
XI_OBJ_DEF* def = xi_create_itf_def(ITF_CID, xi_event_handler, &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 = xvt_default_font(FALSE);
|
|
def->v.itf->tab_on_enter = TRUE;
|
|
def->v.itf->win = win;
|
|
|
|
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)
|
|
{
|
|
RCT max; xvt_vobj_get_client_rect(TASK_WIN, &max);
|
|
xi_pu_to_fu(itf, (PNT*)&max, 2);
|
|
X_FU_MULTIPLE = max.right / 80;
|
|
Y_FU_MULTIPLE = max.bottom / 25;
|
|
}
|
|
|
|
if (dx > 0)
|
|
{
|
|
xi_pu_to_fu(itf, (PNT*)&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, (PNT*)&r, 2);
|
|
xvt_vobj_move(win, &r);
|
|
}
|
|
|
|
if (tag)
|
|
{
|
|
XI_RCT rct; xi_get_xi_rct(itf, &rct);
|
|
rct.top += Y_FU_MULTIPLE; // Lascia lo spazio per i Bottoni di cambio pagina
|
|
|
|
def = xi_add_rect_def(NULL, MASK_RECT_ID, &rct, XI_ATR_VISIBLE, 0, 0);
|
|
XI_OBJ* obj = xi_create(itf, def);
|
|
CHECK(obj, "Can't create page rectangle");
|
|
|
|
// Fa coincidere esattamente il rettangolo con la finestra che lo contiene
|
|
RCT& rect = obj->v.rect->rct;
|
|
const int oldy = rect.top;
|
|
xvt_vobj_get_client_rect(win, &rect);
|
|
rect.top = oldy;
|
|
|
|
xi_dequeue();
|
|
xi_tree_free(def);
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
void attach_interface(WINDOW win, COLOR back)
|
|
{
|
|
xvt_win_set_handler(win, (EVENT_HANDLER)xi_event);
|
|
RCT rc; xvt_vobj_get_client_rect(win, &rc);
|
|
WINDOW wp = xvt_vobj_get_parent(win);
|
|
xvt_vobj_translate_points(win, wp, (PNT*)&rc, 2);
|
|
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, &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 = 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:
|
|
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, &b->v.btn->rct, &xiev->v.xvte.v.update.rct))
|
|
{
|
|
TPushbutton_control* p = (TPushbutton_control*)b->app_data;
|
|
p->update();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case a_select:
|
|
if (xiev->v.xi_obj->type == XIT_LIST)
|
|
ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj);
|
|
else
|
|
ctl = (TControl*)xi_get_app_data(xiev->v.xi_obj->parent);
|
|
break;
|
|
case a_xvt:
|
|
switch (xiev->v.xvte.type)
|
|
{
|
|
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);
|
|
#ifdef DBG
|
|
if (xiev->v.xvte.v.chr.ch == K_DOWN || xiev->v.xvte.v.chr.ch == K_UP)
|
|
break;
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case a_xvt_post:
|
|
if (notify_xvt)
|
|
{
|
|
TWindow* w = (TWindow*)xi_get_app_data(itf);
|
|
CHECK(w, "Can't send XVT event to a null window");
|
|
w->handler(w->win(), &xiev->v.xvte);
|
|
|
|
if (xiev->v.xvte.type == E_MOUSE_UP)
|
|
_button_blocked = FALSE;
|
|
}
|
|
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)
|
|
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(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* first = find_operable(_obj->itf, TRUE, TRUE);
|
|
XI_OBJ* last = find_operable(_obj->itf, FALSE, TRUE);
|
|
int num;
|
|
XI_OBJ** child = xi_get_member_list(_obj, &num);
|
|
set_tab_cid(child[num-1], first->cid);
|
|
set_tab_cid(last, child[0]->cid);
|
|
} else
|
|
if (_obj->parent != _obj->itf)
|
|
{
|
|
XI_OBJ* first = find_operable(_obj->itf, TRUE, FALSE);
|
|
XI_OBJ* last = find_operable(_obj->itf, FALSE, FALSE);
|
|
set_tab_cid(_obj->parent, first->cid);
|
|
set_tab_cid(last, _obj->parent->cid);
|
|
}
|
|
}
|
|
|
|
void TControl::coord2rct(WINDOW win, short x, short y, short dx, short dy, XI_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);
|
|
|
|
// 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; xvt_vobj_get_client_rect(win, &max);
|
|
xi_pu_to_fu(itf, (PNT*)&max, 2);
|
|
const int& MAXX = max.right;
|
|
const int& MAXY = max.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;
|
|
}
|
|
|
|
RCT& TControl::get_rect(RCT& r) const
|
|
{
|
|
xi_get_rect(_obj, &r);
|
|
return r;
|
|
}
|
|
|
|
void TControl::set_rect(const RCT&)
|
|
{
|
|
CHECK(0, "Can't set_rect to generic TControl");
|
|
}
|
|
|
|
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 'R': attrib |= XI_ATR_RJUST; break;
|
|
default : break;
|
|
}
|
|
}
|
|
return attrib;
|
|
}
|
|
|
|
const char* TControl::parse_caption(const char* cap, bool& bold, COLOR& color) const
|
|
{
|
|
bold = FALSE;
|
|
color = NORMAL_COLOR;
|
|
for (const char* t = cap; *t == '@' || *t == '$'; t++)
|
|
{
|
|
if (*t == '@')
|
|
{
|
|
const char code = toupper(*(t+1));
|
|
if (code == 'B')
|
|
{
|
|
bold = TRUE;
|
|
t++;
|
|
}
|
|
else
|
|
{
|
|
NFCHECK(0, "Bad character after @ in prompt");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (*(t+1) == '[')
|
|
{
|
|
t += 2; // Skip [
|
|
if (isalpha(*t))
|
|
color = trans_color(*t);
|
|
else
|
|
{
|
|
int r = 0, g = 0, b = 0;
|
|
sscanf(t, "%d,%d,%d", &r, &g, &b);
|
|
if (r == 0 && g == 0 && b == 0)
|
|
color = COLOR_BLACK;
|
|
else
|
|
color = 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 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)
|
|
{
|
|
bool ok = TRUE;
|
|
return ok;
|
|
}
|
|
|
|
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
|
|
{
|
|
// Se la finestra e' chiusa e il campo e un bottone o e' editabile allora cambia l'attributo
|
|
// senza ridisegnare il campo, il che provocherebbe problemi di funzionamento degli sheet
|
|
if (_obj->type == XIT_BTN || _obj->type == XIT_FIELD)
|
|
{
|
|
const TWindow* w = (const TWindow*)_obj->itf->app_data;
|
|
if (!w->is_open())
|
|
{
|
|
if (_obj->type == XIT_FIELD)
|
|
((STX_DATA*)_obj->v.field->stx)->attrib = attr;
|
|
else
|
|
_obj->v.btn->attrib = attr;
|
|
return;
|
|
}
|
|
}
|
|
// Usa tranquillamente il metodo ortodosso
|
|
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);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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;
|
|
COLOR color;
|
|
TString t = parse_caption(text, bold, color);
|
|
t.rtrim();
|
|
if (width <= 0)
|
|
width = t.len();
|
|
|
|
XI_RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
rct.right += bold ? (width*XI_FU_MULTIPLE/4) : XI_FU_MULTIPLE;
|
|
|
|
const unsigned long attrib = flags2attr(flags);
|
|
XI_OBJ_DEF* def = xi_add_text_def(NULL, cid, &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)
|
|
def->v.text->font_id = xvt_default_font(TRUE);
|
|
_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;
|
|
COLOR color;
|
|
const char* c = parse_caption(text, bold, color);
|
|
xi_set_text(_obj, (char*)c);
|
|
_obj->v.text->fore_color = color;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 = _obj->v.text->rct;
|
|
tr.top--; tr.bottom--;
|
|
|
|
XI_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, &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);
|
|
|
|
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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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);
|
|
}
|
|
|
|
void TField_control::create(WINDOW win, short cid,
|
|
short left, short top, short width, short height, short maxlen,
|
|
const char* flags, const char* text, bool button)
|
|
{
|
|
in_create = TRUE;
|
|
|
|
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;
|
|
|
|
XI_RCT rct; coord2rct(win, left, top, width, height, rct);
|
|
rct.right += XI_FU_MULTIPLE/4;
|
|
|
|
unsigned long attrib = flags2attr(flags);
|
|
if (AUTOSELECT)
|
|
attrib |= XI_ATR_AUTOSELECT;
|
|
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;
|
|
f->well = CAMPI_SCAVATI;
|
|
f->auto_tab = TRUE;
|
|
f->active_back_color = FOCUS_BACK_COLOR;
|
|
if (button)
|
|
{
|
|
f->button = TRUE;
|
|
f->pixel_button_distance = 1;
|
|
}
|
|
if (height != 1) // E' un multiline, quindi setto il rettangolo
|
|
f->xi_rct = rct;
|
|
|
|
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);
|
|
|
|
// Aggiusta il rettangolo del bottone in modo da allinearlo al testo
|
|
RCT& br = _obj->v.field->btn_rct;
|
|
const int offset = stx->rct.right - br.left - 1;
|
|
br.left += offset;
|
|
br.right += offset;
|
|
|
|
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;
|
|
if (f->button != on)
|
|
{
|
|
f->button = on;
|
|
xi_invalidate_rect(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:
|
|
notify_key(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();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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 bold;
|
|
COLOR color;
|
|
TString txt(text); txt.strip("&~");
|
|
const char* t = parse_caption(txt, bold, 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, &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; break;
|
|
case WC_CHECKBOX : def->v.btn->type = XIBT_CHECKBOX; break;
|
|
case WC_RADIOBUTTON: def->v.btn->type = XIBT_RADIOBTN; break;
|
|
default : def->v.btn->type = XIBT_TABBTN; break;
|
|
}
|
|
|
|
if (container == NULL)
|
|
container = get_interface(win);
|
|
_obj = xi_create(container, def);
|
|
CHECKD(_obj, "Can't create TButton_control ", cid);
|
|
|
|
// Aggiusta bottoni con icona a sinistra
|
|
if (wc == WC_CHECKBOX || wc == WC_RADIOBUTTON)
|
|
{
|
|
RCT& r = _obj->v.btn->rct;
|
|
r.top++; r.bottom-=2;
|
|
r.right += XI_FU_MULTIPLE / 2;
|
|
}
|
|
|
|
xi_dequeue();
|
|
xi_tree_free(def);
|
|
|
|
update_tab_cid();
|
|
}
|
|
|
|
XI_BTN_TYPE 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;
|
|
}
|
|
|
|
void TButton_control::set_rect(const RCT& r)
|
|
{
|
|
_obj->v.btn->rct = r;
|
|
}
|
|
|
|
bool TButton_control::event_handler(XI_OBJ* itf, XI_EVENT* xiev)
|
|
{
|
|
bool ok = TRUE;
|
|
|
|
if (xiev->type == XIE_BUTTON)
|
|
{
|
|
if (xi_move_focus(_obj))
|
|
{
|
|
switch (_obj->v.btn->type)
|
|
{
|
|
case XIBT_CHECKBOX:
|
|
case XIBT_BUTTON_CHECKBOX:
|
|
toggle();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ok = notify_key(K_SPACE);
|
|
}
|
|
else
|
|
ok = FALSE;
|
|
}
|
|
else
|
|
if (xiev->type == XIE_POST_NAVIGATION)
|
|
ok == notify_key(K_CTRL + K_TAB);
|
|
else
|
|
ok = TControl::event_handler(itf, xiev);
|
|
|
|
return ok;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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)
|
|
|
|
{
|
|
bool bold;
|
|
COLOR color;
|
|
_caption = parse_caption(text, bold, color);
|
|
|
|
_underscore = _caption.find('~');
|
|
if (_underscore < 0)
|
|
_underscore = _caption.find('&');
|
|
if (_underscore >= 0)
|
|
_caption.strip("~&");
|
|
|
|
create(win, cid, left, top, width, height, flags, text, WC_PUSHBUTTON, NULL);
|
|
_obj->v.btn->drawable = TRUE;
|
|
*_obj->v.btn->text = '\0';
|
|
|
|
set_bmp(bmp_up, bmp_dn);
|
|
}
|
|
|
|
void TPushbutton_control::set_bmp(short bmp_up, short bmp_dn)
|
|
{
|
|
if (bmp_up > 0)
|
|
{
|
|
_picture->add(_bmp_up = bmp_up);
|
|
if (bmp_dn > 0)
|
|
_picture->add(_bmp_dn = bmp_dn);
|
|
else
|
|
_bmp_dn = _bmp_up;
|
|
}
|
|
else
|
|
{
|
|
_bmp_up = _bmp_dn = 0;
|
|
}
|
|
}
|
|
|
|
void TPushbutton_control::update()
|
|
{
|
|
const long attrib = xi_get_attrib(_obj);
|
|
const WINDOW win = parent();
|
|
|
|
if (attrib & XI_ATR_VISIBLE)
|
|
{
|
|
const short bmp = (_bmp_dn > 0 && _obj->v.btn->down) ? _bmp_dn : _bmp_up;
|
|
if (bmp > 0)
|
|
{
|
|
const TImage& i = _picture->image(bmp);
|
|
const RCT& rct = _obj->v.btn->rct;
|
|
int x = rct.left + (rct.right - rct.left - i.width()) / 2;
|
|
int y = rct.top + (rct.bottom - rct.top - i.height()) / 2;
|
|
if (_obj->v.btn->down)
|
|
{
|
|
x += 2;
|
|
y += 2;
|
|
}
|
|
|
|
i.draw(win, x, y);
|
|
if (!(attrib & XI_ATR_ENABLED))
|
|
{
|
|
CPEN pen;
|
|
pen.width = 1;
|
|
pen.pat = PAT_SOLID;
|
|
pen.style = P_SOLID;
|
|
pen.color = BTN_BACK_COLOR;
|
|
xvt_dwin_set_cpen(win, &pen);
|
|
for (int py = y + i.height(); py >= y; py -= 2)
|
|
{
|
|
PNT p; p.v = py; p.h = x;
|
|
xvt_dwin_draw_set_pos(win, p);
|
|
p.h += i.width();
|
|
xvt_dwin_draw_line(win, p);
|
|
}
|
|
for (int px = x + i.width(); px >= x; px -= 2)
|
|
{
|
|
PNT p; p.v = y; p.h = px;
|
|
xvt_dwin_draw_set_pos(win, p);
|
|
p.v += i.height();
|
|
xvt_dwin_draw_line(win, p);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RCT& r = _obj->v.btn->rct;
|
|
xvt_dwin_set_font(win, xvt_default_font());
|
|
|
|
int ascent, descent;
|
|
xvt_dwin_get_font_metrics(win, NULL, &ascent, &descent);
|
|
const int w = xvt_dwin_get_text_width(win, (char*)(const char*)_caption, -1);
|
|
|
|
int x = r.left + (r.right - r.left - w) / 2;
|
|
int y = r.top + (r.bottom - r.top + ascent - (descent+1)) / 2;
|
|
|
|
if (_obj->v.btn->down)
|
|
{
|
|
x += 2;
|
|
y += 2;
|
|
}
|
|
|
|
DRAW_CTOOLS ct;
|
|
xvt_dwin_get_draw_ctools(win, &ct);
|
|
ct.opaque_text = FALSE;
|
|
ct.fore_color = (attrib & XI_ATR_ENABLED) ? _obj->v.btn->fore_color : DISABLED_COLOR;
|
|
xvt_dwin_set_draw_ctools(win, &ct);
|
|
|
|
xvt_dwin_draw_text(win, x, y, (char*)(const char*)_caption, -1);
|
|
|
|
if (_underscore >= 0)
|
|
{
|
|
TString80 cap = _caption;
|
|
cap[_underscore] = '_';
|
|
xvt_dwin_draw_text(win, x, y, (char*)(const char*)cap, _underscore+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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, NULL); }
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// 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_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, &rct, orient, cid);
|
|
def->app_data = (long)this;
|
|
|
|
const unsigned long attrib = flags2attr(flags);
|
|
for (int b = 1; b <= tot; b++)
|
|
{
|
|
bool bold;
|
|
COLOR color;
|
|
const char* t = parse_caption(testo.get(), bold, 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);
|
|
for (int 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);
|
|
CHECKD(c < children, "This radio is rather old, it doesn't have button ", c);
|
|
if (!xi_is_checked(child[c]))
|
|
xi_check(child[c], TRUE);
|
|
}
|
|
|
|
void TRadiobutton_control::show_button(byte c, bool on)
|
|
{
|
|
int children;
|
|
XI_OBJ** child = xi_get_member_list(_obj, &children);
|
|
CHECKD(c < children, "This radio is rather old, it doesn't have button ", c);
|
|
change_attrib(XI_ATR_VISIBLE, on, child[c]);
|
|
}
|
|
|
|
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)) // 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);
|
|
for (int 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;
|
|
COLOR color;
|
|
const char* t = parse_caption(titolo.get(), bold, 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;
|
|
}
|
|
|
|
_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);
|
|
const char* row = NULL;
|
|
long rec = 0l;
|
|
|
|
if (!ddl->is_open()) return;
|
|
|
|
switch(xiev->type)
|
|
{
|
|
case XIE_CELL_REQUEST:
|
|
rec = xiev->v.cell_request.rec;
|
|
row = ddl->item((int)rec);
|
|
strncpy(xiev->v.cell_request.s, (char *)row, xiev->v.cell_request.len);
|
|
xiev->v.cell_request.s[xiev->v.cell_request.len - 1] = '\0';
|
|
break;
|
|
case XIE_GET_FIRST:
|
|
if (ddl->items() == 0)
|
|
xiev->refused = TRUE;
|
|
else
|
|
{
|
|
xiev->v.rec_request.data_rec = ddl->items() * xiev->v.rec_request.percent/100;
|
|
ddl->update_selection(xiev);
|
|
}
|
|
break;
|
|
case XIE_GET_LAST:
|
|
xiev->v.rec_request.data_rec = ddl->items() - 1;
|
|
ddl->update_selection(xiev);
|
|
break;
|
|
case XIE_GET_NEXT:
|
|
if (xiev->v.rec_request.spec_rec >= ddl->items()-1)
|
|
xiev->refused = TRUE;
|
|
else
|
|
{
|
|
xiev->v.rec_request.data_rec = xiev->v.rec_request.spec_rec + 1;
|
|
ddl->update_selection(xiev);
|
|
}
|
|
break;
|
|
case XIE_GET_PREV:
|
|
if (xiev->v.rec_request.spec_rec == 0)
|
|
xiev->refused = TRUE;
|
|
else
|
|
{
|
|
xiev->v.rec_request.data_rec = xiev->v.rec_request.spec_rec - 1;
|
|
ddl->update_selection(xiev);
|
|
}
|
|
break;
|
|
case XIE_GET_PERCENT:
|
|
if (ddl->items() > 1)
|
|
xiev->v.get_percent.percent = int((xiev->v.get_percent.record * 100L)/(ddl->items()-1));
|
|
break;
|
|
case XIE_DBL_CELL:
|
|
ddl->select((int)(ddl->row2rec(xiev->v.xi_obj->v.cell.row)));
|
|
ddl->close();
|
|
break;
|
|
case XIE_ON_ROW:
|
|
/* Guy: Per ora ignora sto evento, prova con XIE_SELECT */
|
|
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:
|
|
if ((xiev->v.xvte.type == E_FOCUS && xiev->v.xvte.v.active == FALSE) ||
|
|
xiev->v.xvte.type == E_MOUSE_UP)
|
|
{
|
|
ddl->close();
|
|
if (xiev->v.xvte.type == E_FOCUS)
|
|
_button_blocked = TRUE;
|
|
}
|
|
else if (xiev->v.xvte.type == 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(k);
|
|
}
|
|
}
|
|
break;
|
|
case XIE_CHAR_CELL: // TBI: questa e' copiata da edit
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TDropDownList::close()
|
|
{
|
|
if (_open)
|
|
{
|
|
_open = _displayed = FALSE;
|
|
xvt_vobj_destroy(xi_get_window(_xi_lst->itf));
|
|
xvt_dwin_update (xi_get_window(_obj->itf));
|
|
}
|
|
}
|
|
|
|
bool TDropDownList::select(int i, bool force)
|
|
{
|
|
if (force || i != _selected)
|
|
{
|
|
_selected = i;
|
|
|
|
if (_obj->type == XIT_FIELD)
|
|
{
|
|
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 && is_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;
|
|
}
|
|
|
|
TDropDownList::TDropDownList(XI_OBJ* o, const char* codes, const char* values)
|
|
: _obj(o), _codes(codes), _values(values),
|
|
_open(FALSE), _xi_lst(NULL), _displayed(FALSE), _selected(0)
|
|
{
|
|
if (o->type == XIT_CELL)
|
|
{
|
|
const char* val = xi_get_text(o, NULL, -1);
|
|
_selected = _codes.get_pos(val);
|
|
if (_selected < 0)
|
|
_selected = 0;
|
|
}
|
|
}
|
|
|
|
void TDropDownList::set_values(const char* c, const char* v)
|
|
{
|
|
_codes = c;
|
|
_values = v;
|
|
}
|
|
|
|
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 * XI_FU_MULTIPLE;
|
|
}
|
|
|
|
void TDropDownList::open()
|
|
{
|
|
if (_open) return;
|
|
|
|
XI_OBJ_DEF* itfdef = xi_create_itf_def(ITF_CID, (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(6,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);
|
|
|
|
lstdef->v.list->active_back_color = FOCUS_BACK_COLOR;
|
|
lstdef->v.list->scroll_bar = items() > 6;
|
|
lstdef->v.list->no_heading = TRUE;
|
|
lstdef->v.list->no_horz_lines = TRUE;
|
|
// lstdef->v.list->no_vert_lines = TRUE;
|
|
lstdef->v.list->resize_with_window = TRUE;
|
|
lstdef->v.list->single_select = TRUE;
|
|
|
|
// compute size in pixel of field (with button enclosed)
|
|
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;
|
|
}
|
|
// 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_OBJ_DEF* coldef = xi_add_column_def(lstdef, _obj->cid+2000,
|
|
XI_ATR_VISIBLE|XI_ATR_ENABLED|XI_ATR_READONLY|XI_ATR_SELECTABLE,
|
|
0, len, 80, "");
|
|
|
|
RCT l; xi_get_def_rect(lstdef, &l);
|
|
PNT p; p.h = r.left;
|
|
WINDOW pwin = 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, &l);
|
|
wr.right = r.right; // wr.left + (l.right - l.left) -1;
|
|
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 = win;
|
|
itfdef->v.itf->rctp = ≀
|
|
XI_OBJ* itfobj = xi_create(NULL, itfdef);
|
|
xi_tree_free(itfdef);
|
|
|
|
CHECK(itfobj != NULL, "Oggetto del cazzo!");
|
|
|
|
_xi_lst = xi_get_obj(itfobj, _obj->cid+1000);
|
|
|
|
CHECK(_xi_lst != NULL, "Lista del cazzo!");
|
|
|
|
_open = TRUE;
|
|
xi_cell_request(_xi_lst);
|
|
xvt_scr_set_focus_vobj(win);
|
|
xvt_vobj_raise(win);
|
|
_displayed = TRUE;
|
|
|
|
select(_selected, TRUE);
|
|
|
|
xi_dequeue();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
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->is_open() && !_button_blocked)
|
|
_ddl->open();
|
|
break;
|
|
case XIE_CHAR_FIELD:
|
|
{
|
|
const KEY k = xiev_to_key(xiev);
|
|
if (k >= ' ' && k <= 'z')
|
|
_ddl->select_by_initial(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);
|
|
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)
|
|
{
|
|
_ddl->set_values(cod, val);
|
|
if (selected() >= items())
|
|
_ddl->select(0, TRUE);
|
|
else
|
|
_ddl->select(selected(), TRUE);
|
|
}
|
|
|
|
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;
|
|
}
|