golem.cpp Migliorata gestione degli hook agli handler di finestra msksheet.cpp Eliminati molti sfarfallamenti duante cambio focus relapp.cpp Corretta gestione messaggio ED sheet.cpp Corretto posizionamento iniziale su righe disabilitate xvtility.cpp Migliorata gestione dell'event hook. git-svn-id: svn://10.65.10.50/trunk@3328 c028cbd2-c16b-5b4b-a496-9718f37d4682
1139 lines
28 KiB
C++
Executable File
1139 lines
28 KiB
C++
Executable File
#include <applicat.h>
|
|
#include <colors.h>
|
|
#include <config.h>
|
|
#include <date.h>
|
|
#include <urldefid.h>
|
|
#include <utility.h>
|
|
#include <mask.h>
|
|
|
|
#if XVT_OS == XVT_OS_WIN
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#pragma hdrstop
|
|
#include "prochook.h"
|
|
#define MAX_PATH 260 // This really should be in WINDOWS.H, but is
|
|
// inexplicably hard-coded into the data structures
|
|
int MungeModuleHeader( HINSTANCE hInstance, BOOL fMunge );
|
|
#endif
|
|
|
|
#if XVT_OS == XVT_OS_SCOUNIX
|
|
extern "C" { long nap(long period); }
|
|
#endif
|
|
|
|
// ERROR HOOK che intercetta errori XVT
|
|
// put breakpoint here
|
|
|
|
BOOLEAN error_hook(XVT_ERRMSG err, DATA_PTR)
|
|
{
|
|
const XVT_ERRSEV sev = xvt_errmsg_get_sev_id(err);
|
|
#ifdef DBG
|
|
return FALSE;
|
|
#else
|
|
return sev < SEV_ERROR;
|
|
#endif
|
|
}
|
|
|
|
#if XVT_OS == XVT_OS_WIN
|
|
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#include <ctl3d.h>
|
|
|
|
extern "C" {
|
|
WINDOW xvtwi_hwnd_to_window(HWND);
|
|
#include <statbar.h>
|
|
}
|
|
#include <controls.h>
|
|
|
|
short CHARX = 8;
|
|
short ROWY = GetSystemMetrics(SM_CYSCREEN) / 25;
|
|
short CHARY = 14;
|
|
short BASEY = 12;
|
|
|
|
const word WM_WAKEUP = RegisterWindowMessage("WAKEUP");
|
|
|
|
// By Matt Pietrek
|
|
//########################################################################
|
|
// Code that does the real work
|
|
//########################################################################
|
|
|
|
//
|
|
// Central function that modifies a module table to trick the loader
|
|
// into letting a second instance of a multiple data segment program run.
|
|
//
|
|
int MungeModuleHeader( HINSTANCE hInstance, BOOL fMunge )
|
|
{
|
|
HMODULE hModuleSel;
|
|
LPSTR lpszModName, lpszFileName;
|
|
BYTE cbModuleName;
|
|
static BOOL fResidentNamesMunged = FALSE;
|
|
|
|
hModuleSel = SELECTOROF( // Convert the HINSTANCE to an HMODULE
|
|
GlobalLock(GetModuleHandle((LPSTR)MAKELP(0,hInstance))));
|
|
|
|
if ( hModuleSel == 0 ) // Make sure we succeeded.
|
|
return 0;
|
|
|
|
//
|
|
// First, we'll take care of the resident names table
|
|
//
|
|
if ( FALSE == fResidentNamesMunged )
|
|
{
|
|
// Make pointers to the module name in the resident names table
|
|
lpszModName = (LPSTR)MAKELP(hModuleSel,
|
|
*(WORD FAR *)MAKELP(hModuleSel, 0x26) );
|
|
|
|
// Get the module name length, and advance to the actual string
|
|
cbModuleName = *lpszModName++; // First byte is a length byte
|
|
|
|
// Convert the first uppercase letter of the modulename to lowercase
|
|
while ( cbModuleName )
|
|
{
|
|
if ( isupper(*lpszModName) )
|
|
{
|
|
*lpszModName = tolower(*lpszModName); break;
|
|
}
|
|
cbModuleName--; lpszModName++;
|
|
}
|
|
|
|
if ( cbModuleName == 0 ) // Make sure we succeeded
|
|
return 0;
|
|
|
|
// Remember that we've done this, so that we don't bother doing
|
|
// it in the future.
|
|
fResidentNamesMunged = TRUE;
|
|
}
|
|
|
|
//
|
|
// Now, we'll turn our attention to the module file name in the OFSTRUCT
|
|
//
|
|
lpszFileName = (LPSTR)MAKELP(hModuleSel,
|
|
*(WORD FAR *)MAKELP(hModuleSel, 0x0A));
|
|
|
|
// Position to the end of the filename. First byte is a length byte
|
|
lpszFileName += *lpszFileName - 1;
|
|
|
|
// If we're munging, added 0x30 to the last character value, otherwise
|
|
// subtract 0x30. 0x30 is chosen completely at random.
|
|
if ( fMunge )
|
|
*lpszFileName += 0x30;
|
|
else
|
|
*lpszFileName -= 0x30;
|
|
return 1;
|
|
}
|
|
|
|
//########################################################################
|
|
// This section watches calls to LoadModule and munges the EXE's module
|
|
// database as needed.
|
|
//########################################################################
|
|
|
|
HIDDEN NPHOOKCHILD npHookLoadModule = 0;
|
|
HIDDEN char szOurFileName[MAX_PATH];
|
|
HIDDEN HINSTANCE HInstance;
|
|
|
|
HINSTANCE
|
|
WINAPI
|
|
__export MultInst95LoadModule( LPCSTR lpszModuleName,
|
|
LPVOID lpvParameterBlock )
|
|
{
|
|
HINSTANCE retValue;
|
|
|
|
// Uppercase the name of the module name that was passed to LoadModule
|
|
char szNewFileName[MAX_PATH];
|
|
lstrcpy( szNewFileName, lpszModuleName );
|
|
strupr( szNewFileName );
|
|
|
|
// Compare the incoming filename to our EXE's module name. If they
|
|
// don't match, we don't need to bother munging the module database
|
|
BOOL fSecondInstance = strstr(szOurFileName, szNewFileName) ? TRUE:FALSE;
|
|
|
|
// Unhook our LoadModule hook so that we can call the real LoadModule
|
|
ProcUnhook( npHookLoadModule );
|
|
|
|
// Munge module database if needed
|
|
if ( fSecondInstance )
|
|
MungeModuleHeader( HInstance, TRUE );
|
|
|
|
// Call the original LoadModule code
|
|
retValue = LoadModule( lpszModuleName, lpvParameterBlock );
|
|
|
|
// Unmunge module database if needed
|
|
if ( fSecondInstance )
|
|
MungeModuleHeader( HInstance, FALSE );
|
|
|
|
// Reinstall our LoadModule hook so that we see future loads
|
|
ProcHook( npHookLoadModule );
|
|
|
|
return retValue;
|
|
}
|
|
|
|
BOOL deny_another_instance()
|
|
{
|
|
if ( !npHookLoadModule )
|
|
return FALSE;
|
|
|
|
SetProcRelease( npHookLoadModule );
|
|
npHookLoadModule = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL allow_another_instance()
|
|
{
|
|
#ifdef __NOMUNGE__
|
|
return FALSE;
|
|
#endif
|
|
|
|
if ( npHookLoadModule )
|
|
return TRUE;
|
|
|
|
// Get the EXE's filename into a global string variable and uppercase it
|
|
GetModuleFileName( HInstance, szOurFileName, sizeof(szOurFileName) );
|
|
strupr( szOurFileName );
|
|
|
|
// Create a MakeProcInstance thunk so that our callback function
|
|
// will always be using the correct DS selector
|
|
FARPROC lpfnMPI
|
|
= MakeProcInstance( (FARPROC)MultInst95LoadModule, HInstance );
|
|
|
|
if ( !lpfnMPI )
|
|
return FALSE;
|
|
|
|
// Call PROCHOOK.DLL to hook calls to LoadModule
|
|
npHookLoadModule = SetProcAddress( (FARPROC)LoadModule,
|
|
lpfnMPI, FALSE );
|
|
|
|
return (BOOL)npHookLoadModule;
|
|
}
|
|
|
|
static BOOLEAN event_hook(HWND hwnd,
|
|
UINT msg,
|
|
UINT wparam,
|
|
ULONG lparam,
|
|
long* ret)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_SYSCOLORCHANGE:
|
|
Ctl3dColorChange();
|
|
break;
|
|
case WM_MENUCHAR:
|
|
if (wparam > ' ' && wparam <= 'z')
|
|
{
|
|
WINDOW win = cur_win();
|
|
if (win != NULL_WIN)
|
|
{
|
|
// TWindow* w = (TWindow*)xvt_vobj_get_data(win);
|
|
const KEY key = toupper(wparam)+K_CTRL;
|
|
// w->on_key(key);
|
|
dispatch_e_char(win, key);
|
|
*ret = 2 << 8;
|
|
}
|
|
}
|
|
break;
|
|
case WM_KEYDOWN:
|
|
if (wparam == VK_F1)
|
|
{
|
|
if ((lparam & (1<<29)) == 0) // Il tasto alt non e' premuto
|
|
{
|
|
KEY k = K_F1;
|
|
int sc = GetAsyncKeyState(VK_CONTROL); // Stato del tasto control
|
|
if (sc & 1) k += K_CTRL;
|
|
|
|
int ss = GetAsyncKeyState(VK_SHIFT); // Stato del tasto shift
|
|
if (ss & 1) k += K_SHIFT;
|
|
|
|
WINDOW win = cur_win();
|
|
if (win != NULL_WIN)
|
|
dispatch_e_char(win, k);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (msg == WM_WAKEUP && wparam == main_app().waiting())
|
|
main_app().wake_up();
|
|
break;
|
|
}
|
|
|
|
return TRUE; // Continua col processo normale
|
|
}
|
|
|
|
#endif
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Calcola dimensioni e posizione di un controllo contenuto nella finestra
|
|
//
|
|
// @rdesc Ritorna il rettangolo
|
|
RCT& resize_rect(
|
|
short x, // @parm Coordinata x del controllo (espresso in caratteri)
|
|
short y, // @parm Coordinata y del controllo (espresso in caratteri)
|
|
short dx, // @parm Larghezza del controllo (espresso in caratteri)
|
|
short dy, // @parm Altezza del controllo (espresso in caratteri)
|
|
WIN_TYPE wt, // @parm Tipo di controllo da creare
|
|
WINDOW parent) // @parm Identificatore della finestra padre
|
|
{
|
|
static RCT r;
|
|
|
|
if (parent != TASK_WIN)
|
|
{
|
|
if (xvt_vobj_get_type(parent) == W_PLAIN) // Mask with Toolbar
|
|
{
|
|
if (y >= 0)
|
|
{
|
|
const TMask* m = (const TMask*)xvt_vobj_get_data(parent);
|
|
if (parent != m->toolwin())
|
|
y++;
|
|
}
|
|
if (x > 0 || (wt != WO_TE && x == 0))
|
|
{
|
|
RCT pc; xvt_vobj_get_client_rect(parent, &pc); // Get parent window size
|
|
const int width = pc.right;
|
|
const int tot = 80*CHARX;
|
|
if (width > tot) x += (width-tot) / (CHARX<<1);
|
|
}
|
|
}
|
|
wt = WC_EDIT;
|
|
}
|
|
|
|
switch (wt)
|
|
{
|
|
case WC_EDIT :
|
|
r.left = (x+1)*CHARX;
|
|
r.top = y*ROWY;
|
|
r.right = dx*CHARX;
|
|
r.bottom = (CHARY << 1) - BASEY;
|
|
if (dy > 1)
|
|
r.bottom += ROWY*(dy-1);
|
|
break;
|
|
case W_DOC:
|
|
r.left = x * CHARX;
|
|
r.top = y * ROWY;
|
|
r.right = dx * CHARX;
|
|
r.bottom = dy * CHARY;
|
|
break;
|
|
default:
|
|
r.left = x * CHARX;
|
|
r.top = y * ROWY;
|
|
r.right = (dx+2)*CHARX;
|
|
r.bottom = dy*ROWY-1;
|
|
break;
|
|
}
|
|
|
|
if (x < 0 || y < 0 || dx <= 0 || dy <= 0)
|
|
{
|
|
RCT pc;
|
|
if (parent == NULL_WIN) parent = TASK_WIN;
|
|
xvt_vobj_get_client_rect(parent, &pc); // Get parent window size
|
|
const short MAXX = pc.right;
|
|
const short MAXY = pc.bottom;
|
|
|
|
if (x < 0)
|
|
{
|
|
x = -x;
|
|
if (wt != WC_EDIT && x == 1) x = 11;
|
|
if (x > 10)
|
|
{
|
|
const int num = x/10 -1;
|
|
const int tot = x%10;
|
|
const int spc = (MAXX - tot*r.right) / (tot+1);
|
|
r.left = spc + num*(spc+r.right);
|
|
}
|
|
else
|
|
r.left = MAXX - r.right - x*CHARX;
|
|
}
|
|
|
|
if (y < 0)
|
|
{
|
|
y = -y;
|
|
if (wt != WC_EDIT && y == 1) y = 11;
|
|
if (y > 10)
|
|
{
|
|
const int num = y/10 -1;
|
|
const int tot = y%10;
|
|
const int spc = (MAXY - tot*r.bottom) / (tot+1);
|
|
r.top = spc + num*(spc+r.bottom);
|
|
}
|
|
else
|
|
r.top = MAXY - r.bottom - (y-1)*ROWY;
|
|
}
|
|
|
|
if (dx <= 0) r.right = MAXX + dx*CHARX;
|
|
else r.right += r.left;
|
|
if (dy <= 0) r.bottom = MAXY + dy*ROWY;
|
|
else r.bottom += r.top;
|
|
}
|
|
else
|
|
{
|
|
r.right += r.left;
|
|
r.bottom += r.top;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Emette un suono di default
|
|
void beep()
|
|
{ xvt_scr_beep(); }
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Event Handling
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TEvent_manager
|
|
{
|
|
enum { MAX = 16 };
|
|
WINDOW _w[MAX];
|
|
EVENT _e[MAX];
|
|
int _begin, _end;
|
|
|
|
public:
|
|
TEvent_manager() : _begin(0), _end(0) {}
|
|
void push(WINDOW win, const EVENT& event);
|
|
void pop();
|
|
};
|
|
|
|
HIDDEN TEvent_manager EM;
|
|
|
|
void TEvent_manager::push(WINDOW w, const EVENT& e)
|
|
{
|
|
CHECK(w, "You shouldn't send events to NULL_WIN!");
|
|
_w[_end] = w;
|
|
_e[_end] = e;
|
|
const int next = (_end+1) % MAX;
|
|
if (next == _begin)
|
|
warning_box("Hey, clicca piu' piano!");
|
|
else
|
|
_end = next;
|
|
}
|
|
|
|
void TEvent_manager::pop()
|
|
{
|
|
if (_begin != _end)
|
|
{
|
|
const int i = _begin;
|
|
_begin = (++_begin) % MAX; // Other events may occur!
|
|
xvt_win_dispatch_event(_w[i], &_e[i]);
|
|
}
|
|
|
|
WINDOW cw = cur_win();
|
|
if (cw != NULL_WIN)
|
|
{
|
|
TWindow* w = (TWindow*)xvt_vobj_get_data(cw);
|
|
CHECK(w != NULL, "Can't idle NULL window");
|
|
w->on_idle();
|
|
}
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Processa tutti gli eventi rimasti in coda
|
|
void do_events()
|
|
{
|
|
xvt_app_process_pending_events();
|
|
EM.pop();
|
|
#if XVT_OS == XVT_OS_SCOUNIX
|
|
nap(20);
|
|
#endif
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Permette di convertire un evento carattere in un codice carattere premuto
|
|
//
|
|
// @rdesc Ritorna il codice del carattere corrispondente all'evento
|
|
KEY e_char_to_key(
|
|
const EVENT* ep) // @parm Evento da codificare
|
|
|
|
// @comm Viene controllato se l'evento e' un e_car e viene tradotto, in caso
|
|
// controrio viene emesso un segnale d'errore.
|
|
{
|
|
CHECK(ep->type == E_CHAR, "I can't convert a Non-E_CHAR event to a key");
|
|
|
|
KEY key = ep->v.chr.ch;
|
|
if (key < K_INS || key > K_HELP)
|
|
{
|
|
if (ep->v.chr.shift && (key < ' ' || key >= K_UP)) key += K_SHIFT;
|
|
if (ep->v.chr.control && key >= ' ') key += K_CTRL;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Simula un evento
|
|
|
|
void dispatch_event(
|
|
WINDOW win, // @parm Finestra destinataria dell'evento
|
|
const EVENT& e, // @parm Evento da generare
|
|
bool post)
|
|
{
|
|
if (post)
|
|
EM.push(win, e);
|
|
else
|
|
xvt_win_dispatch_event(win, (EVENT*)&e);
|
|
}
|
|
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Simula la scelta di una voce di menu
|
|
void dispatch_e_menu(
|
|
WINDOW win, // @parm Finestra che contiene il menu
|
|
MENU_TAG item) // @parm Voce del menu da selezionare
|
|
|
|
// @xref <f dispatch_e_char> <f dispatch_e_scroll>
|
|
{
|
|
EVENT e; memset(&e, 0, sizeof(e));
|
|
e.type = E_COMMAND;
|
|
e.v.cmd.tag = item;
|
|
e.v.cmd.shift = e.v.cmd.control = 0;
|
|
dispatch_event(win, e, TRUE);
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Simula la scelta di una combinazione di caratteri
|
|
void dispatch_e_char(
|
|
WINDOW win, // @parm Finestra che contiene il menu
|
|
KEY key) // @parm Combinazione di caratteri da utilizzare
|
|
|
|
// @xref <f dispatch_e_menu> <f dispatch_e_scroll>
|
|
{
|
|
EVENT e; memset(&e, 0, sizeof(e));
|
|
|
|
e.type = E_CHAR;
|
|
|
|
if (key > K_CTRL)
|
|
{ e.v.chr.control = TRUE; key -= K_CTRL; }
|
|
|
|
if (key > K_SHIFT)
|
|
{ e.v.chr.shift = TRUE; key -= K_SHIFT; }
|
|
|
|
e.v.chr.ch = short(key);
|
|
|
|
dispatch_event(win, e, TRUE);
|
|
}
|
|
|
|
// @doc EXTERNAL
|
|
|
|
// @func Simula uno scroll all'interno di una finestra
|
|
void dispatch_e_scroll(
|
|
WINDOW win, // @parm Finestra nella quale operare
|
|
KEY key) // @parm Tasto utilizzato per lo scroll nella finestra
|
|
|
|
// @xref <f dispatch_e_menu> <f dispatch_e_char>
|
|
{
|
|
EVENT e; memset(&e, 0, sizeof(e));
|
|
EVENT_TYPE& t = e.type;
|
|
SCROLL_CONTROL& w = e.v.scroll.what;
|
|
short& p = e.v.scroll.pos;
|
|
|
|
w = SC_NONE;
|
|
|
|
switch(key)
|
|
{
|
|
case K_HOME:
|
|
t = E_HSCROLL;
|
|
w = SC_THUMB;
|
|
p = 0;
|
|
break;
|
|
case K_LHOME:
|
|
t = E_VSCROLL;
|
|
w = SC_THUMB;
|
|
p = 0;
|
|
break;
|
|
case K_UP:
|
|
t = E_VSCROLL;
|
|
w = SC_LINE_UP;
|
|
break;
|
|
case K_DOWN:
|
|
t = E_VSCROLL;
|
|
w = SC_LINE_DOWN;
|
|
break;
|
|
case K_BTAB:
|
|
t = E_HSCROLL;
|
|
w = SC_PAGE_UP;
|
|
break;
|
|
case K_TAB:
|
|
t = E_HSCROLL;
|
|
w = SC_PAGE_DOWN;
|
|
break;
|
|
case K_PREV:
|
|
t = E_VSCROLL;
|
|
w = SC_PAGE_UP;
|
|
break;
|
|
case K_NEXT:
|
|
t = E_VSCROLL;
|
|
w = SC_PAGE_DOWN;
|
|
break;
|
|
case K_LEFT:
|
|
t = E_HSCROLL;
|
|
w = SC_LINE_UP;
|
|
break;
|
|
case K_RIGHT:
|
|
t = E_HSCROLL;
|
|
w = SC_LINE_DOWN;
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
if (w != SC_NONE)
|
|
dispatch_event(win, e, FALSE);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Stabilisce i parametri standard dei controlli
|
|
void customize_controls(
|
|
bool on) // @parm Permette di inizializzare (TRUE) o scaricare (FALSE) i parametri
|
|
|
|
{
|
|
if (on)
|
|
{
|
|
#if XVT_OS == XVT_OS_WIN
|
|
long old_hook = xvt_vobj_get_attr(NULL_WIN,ATTR_EVENT_HOOK);
|
|
if (old_hook == 0)
|
|
xvt_vobj_set_attr(NULL_WIN,ATTR_EVENT_HOOK, (long)event_hook);
|
|
|
|
xvt_vobj_set_attr(NULL_WIN,ATTR_ERRMSG_HANDLER, (long)error_hook);
|
|
HInstance = (HINSTANCE)xvt_vobj_get_attr(NULL_WIN, ATTR_WIN_INSTANCE);
|
|
|
|
Ctl3dRegister(HInstance);
|
|
Ctl3dAutoSubclass(HInstance);
|
|
#endif
|
|
customize_colors();
|
|
init_controls();
|
|
}
|
|
else
|
|
{
|
|
#if XVT_OS == XVT_OS_WIN
|
|
// HINSTANCE _hInstance = (HINSTANCE)xvt_vobj_get_attr(NULL_WIN, ATTR_WIN_INSTANCE);
|
|
Ctl3dUnregister(HInstance);
|
|
deny_another_instance();
|
|
#endif
|
|
free_controls();
|
|
}
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di settare il font attivo nella finestra
|
|
void xvt_set_font(
|
|
WINDOW win, // @parm Finestra nella quale settare il font
|
|
const char* family, // @parm Nome del font da settare
|
|
int style, // @parm Stile da applicare al font
|
|
int dim) // @parm Dimensione del font
|
|
{
|
|
CHECK(win != NULL_WIN, "Can't set the font in a NULL window");
|
|
|
|
if ((family == NULL || *family == '\0') &&
|
|
(style == XVT_FS_NONE || style == XVT_FS_BOLD) &&
|
|
dim == 0)
|
|
{
|
|
xvt_dwin_set_font(win, xvt_default_font(style != XVT_FS_NONE));
|
|
}
|
|
else
|
|
{
|
|
XVT_FNTID font = xvt_dwin_get_font(TASK_WIN);
|
|
if (family && *family) xvt_font_set_family(font, (char*)family);
|
|
if (dim != 0) xvt_font_set_size(font, dim);
|
|
if (style != XVT_FS_NONE) xvt_font_set_style(font, style);
|
|
|
|
if(!xvt_font_is_mapped(font))
|
|
xvt_font_map(font, win);
|
|
|
|
xvt_dwin_set_font(win, font);
|
|
xvt_font_destroy(font);
|
|
}
|
|
}
|
|
|
|
void xvt_draw_rect(WINDOW win, const RCT& rect, COLOR lt, COLOR rb, short depth)
|
|
{
|
|
RCT r = rect;
|
|
|
|
CPEN pen;
|
|
pen.width = 1;
|
|
pen.pat = PAT_SOLID;
|
|
pen.style = P_SOLID;
|
|
pen.color = lt;
|
|
|
|
for (short d = 0; d < depth;)
|
|
{
|
|
xvt_dwin_set_cpen(win, &pen);
|
|
|
|
PNT p; // Current vertex of the rectangle
|
|
|
|
bool drawn = FALSE;
|
|
if (lt != MASK_BACK_COLOR)
|
|
{
|
|
p.h = r.left; p.v = r.bottom;
|
|
xvt_dwin_draw_set_pos(win, p);
|
|
|
|
p.v = r.top;
|
|
xvt_dwin_draw_line(win, p);
|
|
p.h = r.right;
|
|
xvt_dwin_draw_line(win, p);
|
|
drawn = TRUE;
|
|
}
|
|
|
|
if (rb != MASK_BACK_COLOR)
|
|
{
|
|
if (pen.color != rb)
|
|
{
|
|
pen.color = rb;
|
|
xvt_dwin_set_cpen(win, &pen);
|
|
}
|
|
if (!drawn)
|
|
{
|
|
p.h = r.right; p.v = r.top;
|
|
xvt_dwin_draw_set_pos(win, p);
|
|
}
|
|
p.v = r.bottom;
|
|
xvt_dwin_draw_line(win, p);
|
|
p.h = r.left;
|
|
xvt_dwin_draw_line(win, p);
|
|
}
|
|
|
|
if (++d < depth)
|
|
{
|
|
r.left++; r.top++;
|
|
r.right--; r.bottom--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di creare una finestra
|
|
//
|
|
// @rdesc Ritorna l'identificatore della finestra creata
|
|
WINDOW xvt_create_window(
|
|
WIN_TYPE wt, // @parm Tipo di finestra da creare
|
|
short x, // @parm Coordinata x della finestra (espresso in caratteri)
|
|
short y, // @parm Coordinata y della finestra (espresso in caratteri)
|
|
short dx, // @parm Larghezza della finestra (espresso in caratteri)
|
|
short dy, // @parm Altezza della finestra (espresso in caratteri)
|
|
const char* caption, // @parm Titolo da assegnare alla finestra
|
|
int menu, // @parm Menu della finestra (definito nelle risorse, 0=senza)
|
|
WINDOW parent, // @parm Identificatore della finestra padre
|
|
long flags, // @parm Attributi della finestra
|
|
EVENT_HANDLER eh, // @parm Funzioni per la gestione degli eventi diretti alla finestra
|
|
long app_data) // @parm Puntatore alla classe C++ che gestisce la finestra
|
|
|
|
{
|
|
RCT& rect = resize_rect(x, y, dx, dy, wt, parent);
|
|
|
|
if (wt == WD_MODAL) wt = W_DOC;
|
|
WINDOW win = xvt_win_create(wt,
|
|
&rect,
|
|
(char*)caption,
|
|
menu, parent,
|
|
flags,
|
|
EM_ALL, eh,
|
|
app_data);
|
|
|
|
CHECK(win, "Can't create a window: XVT error");
|
|
|
|
#if XVT_OS == XVT_OS_WIN
|
|
static bool to_set = TRUE;
|
|
HWND hwnd = (HWND)xvt_vobj_get_attr(win, ATTR_NATIVE_WINDOW);
|
|
if (to_set)
|
|
{
|
|
word style = GetClassWord(hwnd, GCW_STYLE);
|
|
style |= CS_BYTEALIGNCLIENT;
|
|
SetClassWord(hwnd, GCW_STYLE, style);
|
|
to_set = FALSE;
|
|
}
|
|
#endif
|
|
|
|
return win;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di creare i controlli all'interno di una finestra
|
|
//
|
|
// @rdesc Ritorna la finestra del controllo
|
|
WINDOW xvt_create_control(
|
|
WIN_TYPE wt, // @parm Tipo di controllo da creare
|
|
short x, // @parm Coordinata x del control
|
|
short y, // @parm Coordinata y del control
|
|
short dx, // @parm Larghezza della control
|
|
short dy, // @parm Altezza della control
|
|
const char* caption, // @parm Titolo da assegnare alla control
|
|
WINDOW parent, // @parm Identificatore della finestra padre
|
|
long flags, // @parm Attributi della finestra
|
|
long app_data, // @parm Puntatore alla classe C++ che gestisce la finestra
|
|
int id) // @parm Indentificatore del controlllo
|
|
{
|
|
RCT r = resize_rect(x, y, dx, dy, wt, parent);
|
|
while (*caption == '@') caption += 2;
|
|
WINDOW win = xvt_ctl_create(wt, &r, (char*)caption, parent,
|
|
flags, app_data, id);
|
|
if (win == NULL_WIN)
|
|
fatal_box("Can't create control %d: '%s'", id, caption);
|
|
|
|
return win;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Restituisce il titolo della finestra
|
|
//
|
|
// @rdesc Stringa contenente il titolo della finestra
|
|
const char* xvt_get_title(
|
|
WINDOW win) // @parm Finestra della quale si vuole conoscere il titolo
|
|
|
|
// @xref <f xvt_set_title>
|
|
{
|
|
xvt_vobj_get_title(win, __tmp_string, 80);
|
|
return __tmp_string;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di assegnare il titolo ad una finestra
|
|
void xvt_set_title(
|
|
WINDOW win, // @parm Finestra a cui assegnare il titolo
|
|
const char* cap) // @parm Titolo da assegnare
|
|
|
|
// @xref <f xvt_get_title>
|
|
{
|
|
xvt_vobj_set_title(win, (char*)cap);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di abilitare il focus su un controllo
|
|
void xvt_set_front_control(
|
|
WINDOW win) // @parm Finestra nella quale abilitare il focus
|
|
{
|
|
xvt_scr_set_focus_vobj(win);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di togliere il focus da un controllo
|
|
void xvt_kill_focus(
|
|
WINDOW win) // @parm Finestra nella quale togliere il focus
|
|
{
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di abilitare o disabilitare un controllo
|
|
void xvt_enable_control(
|
|
WINDOW win, // @parm Finestra all'interno della quale abilitare il controllo
|
|
bool on) // @parm Abilita (TRUE) o disabilita (FALSE) il controllo
|
|
{
|
|
xvt_vobj_set_enabled(win, on);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di gestire un check box all'interno di una finestra
|
|
void xvt_check_box(
|
|
WINDOW win, // @parm Finestra all'interno della quale abilitare il check box
|
|
bool on) // @parm Permette di inizializzare (TRUE) o scaricare (FALSE) i parametri
|
|
{
|
|
xvt_ctl_set_checked(win, on);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di controllare se un controllo e' stato selezionato
|
|
//
|
|
// @rdesc Ritorna i seguenti valori:
|
|
//
|
|
// @flag TRUE | Se il controllo e' stato selezionato
|
|
// @flag FALSE | Se il controllo non e' stato selezionato
|
|
bool xvt_get_checked_state(
|
|
WINDOW win) // @parm Finestra di cui si vuole conoscere lo stato
|
|
{
|
|
return xvt_ctl_is_checked(win) ? TRUE : FALSE;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di gestire un radio button all'interno di una finestra
|
|
void xvt_check_radio_button(
|
|
WINDOW win, // @parm Finestra all'interno della quale abilitare il radio button
|
|
const WINDOW* ctls, // @parm Array di stringhe contenenti le scelte del radiobutton
|
|
int count) // @parm Numero di elementi del radiobutton
|
|
{
|
|
xvt_ctl_check_radio_button(win, (WINDOW*)ctls, count);
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di controllare lo stato di un radiobutton
|
|
//
|
|
// @rdesc Ritorna il numero dell'elemento del radiobutton selezionato
|
|
int xvt_get_checked_radio(
|
|
const WINDOW* ctls, // @parm Array di stringhe contenenti le scelte del radiobutton
|
|
int count) // @parm Numero di elemnti del radiobutton
|
|
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di cambiare il colore di sfondo di un controllo
|
|
void xvt_set_ctrl_back_color(
|
|
WINDOW win, // @parm Finestra di cui si vuole cambiare lo sfondo
|
|
COLOR col) // @parm Colore dello sfondo
|
|
{
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Gestione Status bar
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN WINDOW _statbar = NULL_WIN;
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di creare la barra di stato del programma
|
|
//
|
|
// @rdesc Ritorna l'identificatore della barra di stato creata
|
|
WINDOW xvt_create_statbar()
|
|
|
|
// @xref <f xvt_statbar_set> <f xvt_statbar_refresh>
|
|
{
|
|
CHECK(_statbar == NULL_WIN, "Onli uan stabar, plis");
|
|
|
|
#if XVT_OS == XVT_OS_WIN
|
|
const int prop_count = 4;
|
|
char* prop_list[prop_count+1] =
|
|
{
|
|
"Status bar",
|
|
"HEIGHT=24",
|
|
"TASK_WIN",
|
|
"FIELD_OFFSET=24",
|
|
NULL
|
|
};
|
|
|
|
_statbar = statbar_create(0, 0, 600, 1024, 800, prop_count, prop_list,
|
|
TASK_WIN, 0, 0, "");
|
|
CHECK(_statbar, "Can't create the status bar");
|
|
|
|
statbar_set_fontid(_statbar, xvt_default_font());
|
|
|
|
#endif
|
|
|
|
return _statbar;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di settare una finestra con la barra di stato
|
|
void xvt_statbar_set(
|
|
const char* text, // @parm Testo da inserire nella barra di stato
|
|
bool def) // @parm (default FALSE)
|
|
|
|
// @comm Nella barra di stato vi e' sempre presente la data del sistema
|
|
//
|
|
// @xref <f xvt_create_statbar> <f xvt_statbar_refresh>
|
|
{
|
|
#if XVT_OS == XVT_OS_WIN
|
|
const TDate oggi(TODAY);
|
|
TString256 t(text);
|
|
t << '\t' << oggi.string() << " - " << main_app().title();
|
|
if (def)
|
|
statbar_set_default_title(_statbar, (char*)(const char*)t);
|
|
statbar_set_title(_statbar, (char*)(const char*)t);
|
|
#endif
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di cambiare il titolo alla barra di stato presente
|
|
void xvt_statbar_refresh()
|
|
|
|
// @xref <f xvt_create_statbar> <f xvt_statbar_set>
|
|
{
|
|
#if XVT_OS == XVT_OS_WIN
|
|
statbar_set_title(_statbar, NULL);
|
|
#endif
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Test menu
|
|
///////////////////////////////////////////////////////////
|
|
|
|
HIDDEN bool test_menu_tag(MENU_ITEM* mi, MENU_TAG tag)
|
|
{
|
|
while (mi->tag)
|
|
{
|
|
if (mi->tag == tag) return TRUE;
|
|
if (mi->child != NULL)
|
|
{
|
|
const bool ok = test_menu_tag(mi->child, tag);
|
|
if (ok) return TRUE;
|
|
}
|
|
mi++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Controlla se e' esiste una voce del menu'
|
|
//
|
|
// @rdesc Ritorna i seguenti valori
|
|
//
|
|
// @flag TRUE | Se esiste la voce di menu'
|
|
// @flag FALSE | Se non esiste la voce di menu'
|
|
bool xvt_test_menu_tag(
|
|
MENU_TAG tag) // @parm Menu' nel quale cercare la voce
|
|
|
|
{
|
|
MENU_ITEM *mi = xvt_menu_get_tree(TASK_WIN);
|
|
const bool ok = test_menu_tag(mi, tag);
|
|
xvt_res_free_menu_tree(mi);
|
|
return ok;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di convertire in attributi grafici i codici caratteri usati
|
|
// dalle funzioni di stampa
|
|
//
|
|
// @rdesc Ritorna il codice del colore convertito in attributo grafico
|
|
COLOR trans_color(
|
|
char c) // @parm Codice carattere da convertire
|
|
{
|
|
COLOR col;
|
|
switch (c)
|
|
{
|
|
case 'b':
|
|
col = COLOR_BLUE; break;
|
|
case 'c':
|
|
col = COLOR_CYAN; break;
|
|
case 'd':
|
|
col = COLOR_DKGRAY; break;
|
|
case 'g':
|
|
col = COLOR_GREEN; break;
|
|
case 'k':
|
|
col = COLOR_GRAY; break;
|
|
case 'l':
|
|
col = COLOR_LTGRAY; break;
|
|
case 'm':
|
|
col = MASK_BACK_COLOR; break;
|
|
case 'n':
|
|
col = COLOR_BLACK; break;
|
|
case 'r':
|
|
col = COLOR_RED; break;
|
|
case 'v':
|
|
col = COLOR_MAGENTA; break;
|
|
case 'w':
|
|
col = COLOR_WHITE; break;
|
|
case 'y':
|
|
col = COLOR_YELLOW; break;
|
|
default:
|
|
CHECK(0,"trans_color: Undefined color"); break;
|
|
}
|
|
return col;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
// @func HIDDEN void | set_cursor | Cambia il cursore del mouse
|
|
HIDDEN void set_cursor(
|
|
bool w) // @parm Indica il tipo di cursore da utilizzare:
|
|
//
|
|
// @flag TRUE | Cursore a clessidra per le wait
|
|
// @flag FALSE | Cursore a frecca normale
|
|
{
|
|
static int _count = 0;
|
|
|
|
if (w)
|
|
{
|
|
if (_count == 0)
|
|
xvt_win_set_cursor(TASK_WIN, CURSOR_WAIT);
|
|
_count++;
|
|
}
|
|
else
|
|
{
|
|
_count--;
|
|
CHECK(_count >= 0, "end_wait without matching begin_wait");
|
|
if (_count == 0)
|
|
xvt_win_set_cursor(TASK_WIN, CURSOR_ARROW);
|
|
}
|
|
}
|
|
|
|
void begin_wait()
|
|
{ set_cursor(TRUE); }
|
|
|
|
void end_wait()
|
|
{ set_cursor(FALSE); }
|
|
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di converitire lo stile del pattern in attributi grafici da
|
|
// codici carattere.
|
|
//
|
|
// @rdesc Ritorna il pattern convertito
|
|
PAT_STYLE trans_brush(
|
|
char p) // @parm Codice carattere da convertire
|
|
{
|
|
switch (p)
|
|
{
|
|
case 'n' :
|
|
return PAT_NONE;
|
|
case 'h' :
|
|
return PAT_HOLLOW;
|
|
case 's' :
|
|
return PAT_SOLID;
|
|
case '-' :
|
|
return PAT_HORZ;
|
|
case '|' :
|
|
return PAT_VERT;
|
|
case '/' :
|
|
return PAT_FDIAG;
|
|
case '\\':
|
|
return PAT_BDIAG;
|
|
case 'X' :
|
|
return PAT_DIAGCROSS;
|
|
case '+' :
|
|
return PAT_CROSS;
|
|
default :
|
|
CHECK(0,"trans_brush: Undefined pattern"); break;
|
|
}
|
|
return PAT_NONE;
|
|
}
|
|
|
|
// @doc INTERNAL
|
|
|
|
// @func Permette di convertire lo stile della penna da codice carattere
|
|
//
|
|
// @rdesc Ritorna lo stilo convertito
|
|
PEN_STYLE trans_pen(
|
|
char p) // @parm Codice carattere da convertire
|
|
{
|
|
PEN_STYLE ps = P_SOLID;
|
|
switch (p)
|
|
{
|
|
case 'n' :
|
|
ps = P_SOLID; break;
|
|
case '.' :
|
|
ps = P_DOT; break;
|
|
case '-' :
|
|
ps = P_DASH; break;
|
|
default:
|
|
CHECK(0, "trans_pen: Undefined pattern"); break;
|
|
}
|
|
return ps;
|
|
}
|
|
|