85a0bdd3d8
git-svn-id: svn://10.65.10.50/trunk@3300 c028cbd2-c16b-5b4b-a496-9718f37d4682
1136 lines
28 KiB
C++
Executable File
1136 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
|
|
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;
|
|
}
|
|
|