diff --git a/src/xvaga01/MD5Checksum.cpp b/src/xvaga01/MD5Checksum.cpp new file mode 100644 index 000000000..f4d0b4241 --- /dev/null +++ b/src/xvaga01/MD5Checksum.cpp @@ -0,0 +1,536 @@ +/***************************************************************************************** + +*** MD5Checksum.cpp: implementation of the MD5Checksum class. + +*** Developed by Langfine Ltd. +*** Released to the public domain 12/Nov/2001. +*** Please visit our website www.langfine.com + +*** Any modifications must be clearly commented to distinguish them from Langfine's +*** original source code. Please advise Langfine of useful modifications so that we +*** can make them generally available. + +*****************************************************************************************/ + + +/**************************************************************************************** +This software is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. +Incorporation of this statement is a condition of use; please see the RSA +Data Security Inc copyright notice below:- + +Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All +rights reserved. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*****************************************************************************************/ + +/**************************************************************************************** +This implementation of the RSA MD5 Algorithm was written by Langfine Ltd +(www.langfine.com). + +Langfine Ltd makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +In addition to the above, Langfine make no warrant or assurances regarding the +accuracy of this implementation of the MD5 checksum algorithm nor any assurances regarding +its suitability for any purposes. + +This implementation may be used freely provided that Langfine is credited +in a copyright or similar notices (eg, RSA MD5 Algorithm implemented by Langfine +Ltd.) and provided that the RSA Data Security notices are complied with. +*/ + + +#include "wxinc.h" + +#include "MD5Checksum.h" +#include "MD5ChecksumDefines.h" + +#include +#include "wx/filename.h" + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::GetMD5 +DETAILS: static, public +DESCRIPTION: Gets the MD5 checksum for a specified file +RETURNS: wxString : the hexadecimal MD5 checksum for the specified file +ARGUMENTS: wxString& strFilePath : the full pathname of the specified file +NOTES: Provides an interface to the wxMD5Checksum class. 'strFilePath' name should + hold the full pathname of the file, eg C:\My Documents\Arcticle.txt. + NB. If any problems occur with opening or reading this file, a CFileException + will be thrown; callers of this function should be ready to catch this + exception. +*****************************************************************************************/ +wxString wxMD5Checksum::GetMD5(const wxString& strFilePath) +{ + if(!wxFileName::FileExists(strFilePath)) + return wxEmptyString; + + //open the file as a binary file in readonly mode, denying write access + wxFile File(strFilePath, wxFile::read); + //the file has been successfully opened, so now get and return its checksum + return GetMD5(File); +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::GetMD5 +DETAILS: static, public +DESCRIPTION: Gets the MD5 checksum for a specified file +RETURNS: wxString : the hexadecimal MD5 checksum for the specified file +ARGUMENTS: wxFile& File : the specified file +NOTES: Provides an interface to the wxMD5Checksum class. 'File' should be open in + binary readonly mode before calling this function. + NB. Callers of this function should be ready to catch any CFileException + thrown by the wxFile functions +*****************************************************************************************/ +wxString wxMD5Checksum::GetMD5(wxFile& File) +{ + wxMD5Checksum MD5Checksum; //checksum object + int nLength = 0; //number of bytes read from the file + const int nBufferSize = 1024; //checksum the file in blocks of 1024 bytes + unsigned char Buffer[nBufferSize]; //buffer for data read from the file + + //checksum the file in blocks of 1024 bytes + while ((nLength = File.Read( Buffer, nBufferSize )) > 0 ) + { + MD5Checksum.Update( Buffer, nLength ); + } + + //finalise the checksum and return it + return MD5Checksum.Final(); + +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::GetMD5 +DETAILS: static, public +DESCRIPTION: Gets the MD5 checksum for data in a unsigned char array +RETURNS: wxString : the hexadecimal MD5 checksum for the specified data +ARGUMENTS: unsigned char* pBuf : pointer to the unsigned char array + unsigned int nLength : number of BYTEs of data to be checksumed +NOTES: Provides an interface to the wxMD5Checksum class. Any data that can + be cast to a unsigned char array of known length can be checksummed by this + function. Typically, wxString and char arrays will be checksumed, + although this function can be used to check the integrity of any unsigned char array. + A buffer of zero length can be checksummed; all buffers of zero length + will return the same checksum. +*****************************************************************************************/ +wxString wxMD5Checksum::GetMD5(unsigned char* pBuf, unsigned int nLength) +{ + //calculate and return the checksum + wxMD5Checksum MD5Checksum; + MD5Checksum.Update( pBuf, nLength ); + return MD5Checksum.Final(); +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::RotateLeft +DETAILS: private +DESCRIPTION: Rotates the bits in a 32 bit unsigned long left by a specified amount +RETURNS: The rotated unsigned long +ARGUMENTS: unsigned long x : the value to be rotated + int n : the number of bits to rotate by +*****************************************************************************************/ +unsigned long wxMD5Checksum::RotateLeft(unsigned long x, int n) +{ + //check that unsigned long is 4 bytes long - true in Visual C++ 6 and 32 bit Windows + wxASSERT( sizeof(x) == 4 ); + + //rotate and return x + return (x << n) | (x >> (32-n)); +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::FF +DETAILS: protected +DESCRIPTION: Implementation of basic MD5 transformation algorithm +RETURNS: none +ARGUMENTS: unsigned long &A, B, C, D : Current (partial) checksum + unsigned long X : Input data + unsigned long S : MD5_SXX Transformation constant + unsigned long T : MD5_TXX Transformation constant +NOTES: None +*****************************************************************************************/ +void wxMD5Checksum::FF( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T) +{ + unsigned long F = (B & C) | (~B & D); + A += F + X + T; + A = RotateLeft(A, S); + A += B; +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::GG +DETAILS: protected +DESCRIPTION: Implementation of basic MD5 transformation algorithm +RETURNS: none +ARGUMENTS: unsigned long &A, B, C, D : Current (partial) checksum + unsigned long X : Input data + unsigned long S : MD5_SXX Transformation constant + unsigned long T : MD5_TXX Transformation constant +NOTES: None +*****************************************************************************************/ +void wxMD5Checksum::GG( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T) +{ + unsigned long G = (B & D) | (C & ~D); + A += G + X + T; + A = RotateLeft(A, S); + A += B; +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::HH +DETAILS: protected +DESCRIPTION: Implementation of basic MD5 transformation algorithm +RETURNS: none +ARGUMENTS: unsigned long &A, B, C, D : Current (partial) checksum + unsigned long X : Input data + unsigned long S : MD5_SXX Transformation constant + unsigned long T : MD5_TXX Transformation constant +NOTES: None +*****************************************************************************************/ +void wxMD5Checksum::HH( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T) +{ + unsigned long H = (B ^ C ^ D); + A += H + X + T; + A = RotateLeft(A, S); + A += B; +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::II +DETAILS: protected +DESCRIPTION: Implementation of basic MD5 transformation algorithm +RETURNS: none +ARGUMENTS: unsigned long &A, B, C, D : Current (partial) checksum + unsigned long X : Input data + unsigned long S : MD5_SXX Transformation constant + unsigned long T : MD5_TXX Transformation constant +NOTES: None +*****************************************************************************************/ +void wxMD5Checksum::II( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T) +{ + unsigned long I = (C ^ (B | ~D)); + A += I + X + T; + A = RotateLeft(A, S); + A += B; +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::ByteToDWord +DETAILS: private +DESCRIPTION: Transfers the data in an 8 bit array to a 32 bit array +RETURNS: void +ARGUMENTS: unsigned long* Output : the 32 bit (unsigned long) destination array + unsigned char* Input : the 8 bit (unsigned char) source array + unsigned int nLength : the number of 8 bit data items in the source array +NOTES: Four BYTES from the input array are transferred to each unsigned long entry + of the output array. The first unsigned char is transferred to the bits (0-7) + of the output unsigned long, the second unsigned char to bits 8-15 etc. + The algorithm assumes that the input array is a multiple of 4 bytes long + so that there is a perfect fit into the array of 32 bit words. +*****************************************************************************************/ +void wxMD5Checksum::ByteToDWord(unsigned long* Output, unsigned char* Input, unsigned int nLength) +{ + //entry invariants + wxASSERT( nLength % 4 == 0 ); + + //initialisations + unsigned int i=0; //index to Output array + unsigned int j=0; //index to Input array + + //transfer the data by shifting and copying + for ( ; j < nLength; i++, j += 4) + { + Output[i] = (unsigned long)Input[j] | + (unsigned long)Input[j+1] << 8 | + (unsigned long)Input[j+2] << 16 | + (unsigned long)Input[j+3] << 24; + } +} + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::Transform +DETAILS: protected +DESCRIPTION: MD5 basic transformation algorithm; transforms 'm_lMD5' +RETURNS: void +ARGUMENTS: unsigned char Block[64] +NOTES: An MD5 checksum is calculated by four rounds of 'Transformation'. + The MD5 checksum currently held in m_lMD5 is merged by the + transformation process with data passed in 'Block'. +*****************************************************************************************/ +void wxMD5Checksum::Transform(unsigned char Block[64]) +{ + //initialise local data with current checksum + unsigned long a = m_lMD5[0]; + unsigned long b = m_lMD5[1]; + unsigned long c = m_lMD5[2]; + unsigned long d = m_lMD5[3]; + + //copy BYTES from input 'Block' to an array of ULONGS 'X' + unsigned long X[16]; + ByteToDWord( X, Block, 64 ); + + //Perform Round 1 of the transformation + FF (a, b, c, d, X[ 0], MD5_S11, MD5_T01); + FF (d, a, b, c, X[ 1], MD5_S12, MD5_T02); + FF (c, d, a, b, X[ 2], MD5_S13, MD5_T03); + FF (b, c, d, a, X[ 3], MD5_S14, MD5_T04); + FF (a, b, c, d, X[ 4], MD5_S11, MD5_T05); + FF (d, a, b, c, X[ 5], MD5_S12, MD5_T06); + FF (c, d, a, b, X[ 6], MD5_S13, MD5_T07); + FF (b, c, d, a, X[ 7], MD5_S14, MD5_T08); + FF (a, b, c, d, X[ 8], MD5_S11, MD5_T09); + FF (d, a, b, c, X[ 9], MD5_S12, MD5_T10); + FF (c, d, a, b, X[10], MD5_S13, MD5_T11); + FF (b, c, d, a, X[11], MD5_S14, MD5_T12); + FF (a, b, c, d, X[12], MD5_S11, MD5_T13); + FF (d, a, b, c, X[13], MD5_S12, MD5_T14); + FF (c, d, a, b, X[14], MD5_S13, MD5_T15); + FF (b, c, d, a, X[15], MD5_S14, MD5_T16); + + //Perform Round 2 of the transformation + GG (a, b, c, d, X[ 1], MD5_S21, MD5_T17); + GG (d, a, b, c, X[ 6], MD5_S22, MD5_T18); + GG (c, d, a, b, X[11], MD5_S23, MD5_T19); + GG (b, c, d, a, X[ 0], MD5_S24, MD5_T20); + GG (a, b, c, d, X[ 5], MD5_S21, MD5_T21); + GG (d, a, b, c, X[10], MD5_S22, MD5_T22); + GG (c, d, a, b, X[15], MD5_S23, MD5_T23); + GG (b, c, d, a, X[ 4], MD5_S24, MD5_T24); + GG (a, b, c, d, X[ 9], MD5_S21, MD5_T25); + GG (d, a, b, c, X[14], MD5_S22, MD5_T26); + GG (c, d, a, b, X[ 3], MD5_S23, MD5_T27); + GG (b, c, d, a, X[ 8], MD5_S24, MD5_T28); + GG (a, b, c, d, X[13], MD5_S21, MD5_T29); + GG (d, a, b, c, X[ 2], MD5_S22, MD5_T30); + GG (c, d, a, b, X[ 7], MD5_S23, MD5_T31); + GG (b, c, d, a, X[12], MD5_S24, MD5_T32); + + //Perform Round 3 of the transformation + HH (a, b, c, d, X[ 5], MD5_S31, MD5_T33); + HH (d, a, b, c, X[ 8], MD5_S32, MD5_T34); + HH (c, d, a, b, X[11], MD5_S33, MD5_T35); + HH (b, c, d, a, X[14], MD5_S34, MD5_T36); + HH (a, b, c, d, X[ 1], MD5_S31, MD5_T37); + HH (d, a, b, c, X[ 4], MD5_S32, MD5_T38); + HH (c, d, a, b, X[ 7], MD5_S33, MD5_T39); + HH (b, c, d, a, X[10], MD5_S34, MD5_T40); + HH (a, b, c, d, X[13], MD5_S31, MD5_T41); + HH (d, a, b, c, X[ 0], MD5_S32, MD5_T42); + HH (c, d, a, b, X[ 3], MD5_S33, MD5_T43); + HH (b, c, d, a, X[ 6], MD5_S34, MD5_T44); + HH (a, b, c, d, X[ 9], MD5_S31, MD5_T45); + HH (d, a, b, c, X[12], MD5_S32, MD5_T46); + HH (c, d, a, b, X[15], MD5_S33, MD5_T47); + HH (b, c, d, a, X[ 2], MD5_S34, MD5_T48); + + //Perform Round 4 of the transformation + II (a, b, c, d, X[ 0], MD5_S41, MD5_T49); + II (d, a, b, c, X[ 7], MD5_S42, MD5_T50); + II (c, d, a, b, X[14], MD5_S43, MD5_T51); + II (b, c, d, a, X[ 5], MD5_S44, MD5_T52); + II (a, b, c, d, X[12], MD5_S41, MD5_T53); + II (d, a, b, c, X[ 3], MD5_S42, MD5_T54); + II (c, d, a, b, X[10], MD5_S43, MD5_T55); + II (b, c, d, a, X[ 1], MD5_S44, MD5_T56); + II (a, b, c, d, X[ 8], MD5_S41, MD5_T57); + II (d, a, b, c, X[15], MD5_S42, MD5_T58); + II (c, d, a, b, X[ 6], MD5_S43, MD5_T59); + II (b, c, d, a, X[13], MD5_S44, MD5_T60); + II (a, b, c, d, X[ 4], MD5_S41, MD5_T61); + II (d, a, b, c, X[11], MD5_S42, MD5_T62); + II (c, d, a, b, X[ 2], MD5_S43, MD5_T63); + II (b, c, d, a, X[ 9], MD5_S44, MD5_T64); + + //add the transformed values to the current checksum + m_lMD5[0] += a; + m_lMD5[1] += b; + m_lMD5[2] += c; + m_lMD5[3] += d; +} + + +/***************************************************************************************** +CONSTRUCTOR: wxMD5Checksum +DESCRIPTION: Initialises member data +ARGUMENTS: None +NOTES: None +*****************************************************************************************/ +wxMD5Checksum::wxMD5Checksum() +{ + // zero members + memset( m_lpszBuffer, 0, 64 ); + m_nCount[0] = m_nCount[1] = 0; + + // Load magic state initialization constants + m_lMD5[0] = MD5_INIT_STATE_0; + m_lMD5[1] = MD5_INIT_STATE_1; + m_lMD5[2] = MD5_INIT_STATE_2; + m_lMD5[3] = MD5_INIT_STATE_3; +} + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::DWordToByte +DETAILS: private +DESCRIPTION: Transfers the data in an 32 bit array to a 8 bit array +RETURNS: void +ARGUMENTS: unsigned char* Output : the 8 bit destination array + unsigned long* Input : the 32 bit source array + unsigned int nLength : the number of 8 bit data items in the source array +NOTES: One unsigned long from the input array is transferred into four BYTES + in the output array. The first (0-7) bits of the first unsigned long are + transferred to the first output unsigned char, bits bits 8-15 are transferred from + the second unsigned char etc. + + The algorithm assumes that the output array is a multiple of 4 bytes long + so that there is a perfect fit of 8 bit BYTES into the 32 bit DWORDs. +*****************************************************************************************/ +void wxMD5Checksum::DWordToByte(unsigned char* Output, unsigned long* Input, unsigned int nLength ) +{ + //entry invariants + wxASSERT( nLength % 4 == 0 ); + + //transfer the data by shifting and copying + unsigned int i = 0; + unsigned int j = 0; + for ( ; j < nLength; i++, j += 4) + { + Output[j] = (UCHAR)(Input[i] & 0xff); + Output[j+1] = (UCHAR)((Input[i] >> 8) & 0xff); + Output[j+2] = (UCHAR)((Input[i] >> 16) & 0xff); + Output[j+3] = (UCHAR)((Input[i] >> 24) & 0xff); + } +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::Final +DETAILS: protected +DESCRIPTION: Implementation of main MD5 checksum algorithm; ends the checksum calculation. +RETURNS: wxString : the final hexadecimal MD5 checksum result +ARGUMENTS: None +NOTES: Performs the final MD5 checksum calculation ('Update' does most of the work, + this function just finishes the calculation.) +*****************************************************************************************/ +wxString wxMD5Checksum::Final() +{ + //Save number of bits + unsigned char Bits[8]; + DWordToByte( Bits, m_nCount, 8 ); + + //Pad out to 56 mod 64. + unsigned int nIndex = (unsigned int)((m_nCount[0] >> 3) & 0x3f); + unsigned int nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + Update( PADDING, nPadLen ); + + //Append length (before padding) + Update( Bits, 8 ); + + //Store final state in 'lpszMD5' + const int nMD5Size = 16; + unsigned char lpszMD5[ nMD5Size ]; + DWordToByte( lpszMD5, m_lMD5, nMD5Size ); + + //Convert the hexadecimal checksum to a wxString + wxString strMD5; + for ( int i=0; i < nMD5Size; i++) + { + wxString Str; + if (lpszMD5[i] == 0) { + Str = wxT("00"); + } + else if (lpszMD5[i] <= 15) { + Str.Printf(wxT("0%x"),lpszMD5[i]); + } + else { + Str.Printf(wxT("%x"),lpszMD5[i]); + } + + wxASSERT( Str.Length() == 2 ); + strMD5 += Str; + } + wxASSERT( strMD5.Length() == 32 ); + return strMD5; +} + + +/***************************************************************************************** +FUNCTION: wxMD5Checksum::Update +DETAILS: protected +DESCRIPTION: Implementation of main MD5 checksum algorithm +RETURNS: void +ARGUMENTS: unsigned char* Input : input block + unsigned int nInputLen : length of input block +NOTES: Computes the partial MD5 checksum for 'nInputLen' bytes of data in 'Input' +*****************************************************************************************/ +void wxMD5Checksum::Update( unsigned char* Input, unsigned long nInputLen ) +{ + //Compute number of bytes mod 64 + unsigned int nIndex = (unsigned int)((m_nCount[0] >> 3) & 0x3F); + + //Update number of bits + if ( ( m_nCount[0] += nInputLen << 3 ) < ( nInputLen << 3) ) + { + m_nCount[1]++; + } + m_nCount[1] += (nInputLen >> 29); + + //Transform as many times as possible. + unsigned int i=0; + unsigned int nPartLen = 64 - nIndex; + if (nInputLen >= nPartLen) + { + memcpy( &m_lpszBuffer[nIndex], Input, nPartLen ); + Transform( m_lpszBuffer ); + for (i = nPartLen; i + 63 < nInputLen; i += 64) + { + Transform( &Input[i] ); + } + nIndex = 0; + } + else + { + i = 0; + } + + // Buffer remaining input + memcpy( &m_lpszBuffer[nIndex], &Input[i], nInputLen-i); +} + + diff --git a/src/xvaga01/MD5Checksum.h b/src/xvaga01/MD5Checksum.h new file mode 100644 index 000000000..c95a44eb4 --- /dev/null +++ b/src/xvaga01/MD5Checksum.h @@ -0,0 +1,342 @@ +/***************************************************************************************** + +*** MD5Checksum.h: interface for the MD5Checksum class. + +*** Developed by Langfine Ltd. +*** Released to the public domain 12/Nov/2001. +*** Please visit our website www.langfine.com + +*** Any modifications must be clearly commented to distinguish them from Langfine's +*** original source code. Please advise Langfine of useful modifications so that we +*** can make them generally available. + +*****************************************************************************************/ + + +#ifndef __MD5CHECKSUM_H__ +#define __MD5CHECKSUM_H__ + +/**************************************************************************************** +This software is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. +Incorporation of this statement is a condition of use; please see the RSA +Data Security Inc copyright notice below:- + +Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All +rights reserved. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. +*****************************************************************************************/ + +/**************************************************************************************** +This implementation of the RSA MD5 Algorithm was written by Langfine Ltd. + +Langfine Ltd makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +In addition to the above, Langfine make no warrant or assurances regarding the +accuracy of this implementation of the MD5 checksum algorithm nor any assurances regarding +its suitability for any purposes. + +This implementation may be used freely provided that Langfine is credited +in a copyright or similar notices (eg, RSA MD5 Algorithm implemented by Langfine +Ltd.) and provided that the RSA Data Security notices are complied with. + +Langfine may be contacted at mail@langfine.com +*/ + +/***************************************************************************************** +CLASS: wxMD5Checksum +DESCRIPTION: Implements the "RSA Data Security, Inc. MD5 Message-Digest Algorithm". +NOTES: Calculates the RSA MD5 checksum for a file or congiguous array of data. + +Below are extracts from a memo on The MD5 Message-Digest Algorithm by R. Rivest of MIT +Laboratory for Computer Science and RSA Data Security, Inc., April 1992. + + 1. Executive Summary + This document describes the MD5 message-digest algorithm. The + algorithm takes as input a message of arbitrary length and produces + as output a 128-bit "fingerprint" or "message digest" of the input. + It is conjectured that it is computationally infeasible to produce + two messages having the same message digest, or to produce any + message having a given prespecified target message digest. The MD5 + algorithm is intended for digital signature applications, where a + large file must be "compressed" in a secure manner before being + encrypted with a private (secret) key under a public-key cryptosystem + such as RSA. + + The MD5 algorithm is designed to be quite fast on 32-bit machines. In + addition, the MD5 algorithm does not require any large substitution + tables; the algorithm can be coded quite compactly. + The MD5 algorithm is an extension of the MD4 message-digest algorithm + 1,2]. MD5 is slightly slower than MD4, but is more "conservative" in + design. MD5 was designed because it was felt that MD4 was perhaps + being adopted for use more quickly than justified by the existing + critical review; because MD4 was designed to be exceptionally fast, + it is "at the edge" in terms of risking successful cryptanalytic + attack. MD5 backs off a bit, giving up a little in speed for a much + greater likelihood of ultimate security. It incorporates some + suggestions made by various reviewers, and contains additional + optimizations. The MD5 algorithm is being placed in the public domain + for review and possible adoption as a standard. + + + 2. Terminology and Notation + In this document a "word" is a 32-bit quantity and a "byte" is an + eight-bit quantity. A sequence of bits can be interpreted in a + natural manner as a sequence of bytes, where each consecutive group + of eight bits is interpreted as a byte with the high-order (most + significant) bit of each byte listed first. Similarly, a sequence of + bytes can be interpreted as a sequence of 32-bit words, where each + consecutive group of four bytes is interpreted as a word with the + low-order (least significant) byte given first. + Let x_i denote "x sub i". If the subscript is an expression, we + surround it in braces, as in x_{i+1}. Similarly, we use ^ for + superscripts (exponentiation), so that x^i denotes x to the i-th power. + Let the symbol "+" denote addition of words (i.e., modulo-2^32 + addition). Let X <<< s denote the 32-bit value obtained by circularly + shifting (rotating) X left by s bit positions. Let not(X) denote the + bit-wise complement of X, and let X v Y denote the bit-wise OR of X + and Y. Let X xor Y denote the bit-wise XOR of X and Y, and let XY + denote the bit-wise AND of X and Y. + + + 3. MD5 Algorithm Description + We begin by supposing that we have a b-bit message as input, and that + we wish to find its message digest. Here b is an arbitrary + nonnegative integer; b may be zero, it need not be a multiple of + eight, and it may be arbitrarily large. We imagine the bits of the + message written down as follows: m_0 m_1 ... m_{b-1} + The following five steps are performed to compute the message digest + of the message. + + 3.1 Step 1. Append Padding Bits + The message is "padded" (extended) so that its length (in bits) is + congruent to 448, modulo 512. That is, the message is extended so + that it is just 64 bits shy of being a multiple of 512 bits long. + Padding is always performed, even if the length of the message is + already congruent to 448, modulo 512. + Padding is performed as follows: a single "1" bit is appended to the + message, and then "0" bits are appended so that the length in bits of + the padded message becomes congruent to 448, modulo 512. In all, at + least one bit and at most 512 bits are appended. + + 3.2 Step 2. Append Length + A 64-bit representation of b (the length of the message before the + padding bits were added) is appended to the result of the previous + step. In the unlikely event that b is greater than 2^64, then only + the low-order 64 bits of b are used. (These bits are appended as two + 32-bit words and appended low-order word first in accordance with the + previous conventions.) + At this point the resulting message (after padding with bits and with + b) has a length that is an exact multiple of 512 bits. Equivalently, + this message has a length that is an exact multiple of 16 (32-bit) + words. Let M[0 ... N-1] denote the words of the resulting message, + where N is a multiple of 16. + + 3.3 Step 3. Initialize MD Buffer + A four-word buffer (A,B,C,D) is used to compute the message digest. + Here each of A, B, C, D is a 32-bit register. These registers are + initialized to the following values in hexadecimal, low-order bytes first): + word A: 01 23 45 67 word B: 89 ab cd ef + word C: fe dc ba 98 word D: 76 54 32 10 + + 3.4 Step 4. Process Message in 16-Word Blocks + We first define four auxiliary functions that each take as input + three 32-bit words and produce as output one 32-bit word. + F(X,Y,Z) = XY v not(X) Z G(X,Y,Z) = XZ v Y not(Z) + H(X,Y,Z) = X xor Y xor Z I(X,Y,Z) = Y xor (X v not(Z)) + In each bit position F acts as a conditional: if X then Y else Z. + The function F could have been defined using + instead of v since XY + and not(X)Z will never have 1's in the same bit position.) It is + interesting to note that if the bits of X, Y, and Z are independent + and unbiased, the each bit of F(X,Y,Z) will be independent and unbiased. + The functions G, H, and I are similar to the function F, in that they + act in "bitwise parallel" to produce their output from the bits of X, + Y, and Z, in such a manner that if the corresponding bits of X, Y, + and Z are independent and unbiased, then each bit of G(X,Y,Z), + H(X,Y,Z), and I(X,Y,Z) will be independent and unbiased. Note that + the function H is the bit-wise "xor" or "parity" function of its inputs. + This step uses a 64-element table T[1 ... 64] constructed from the + sine function. Let T[i] denote the i-th element of the table, which + is equal to the integer part of 4294967296 times abs(sin(i)), where i + is in radians. The elements of the table are given in the appendix. + Do the following: + + //Process each 16-word block. + For i = 0 to N/16-1 do // Copy block i into X. + For j = 0 to 15 do + Set X[j] to M[i*16+j]. + end //of loop on j + + // Save A as AA, B as BB, C as CC, and D as DD. + AA = A BB = B + CC = C DD = D + + // Round 1. + // Let [abcd k s i] denote the operation + // a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). + // Do the following 16 operations. + [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] + [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] + [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] + [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16] + + // Round 2. + // Let [abcd k s i] denote the operation + // a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). + // Do the following 16 operations. + [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] + [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] + [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] + [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32] + + // Round 3. + // Let [abcd k s t] denote the operation + // a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). + // Do the following 16 operations. + [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] + [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] + [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] + [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48] + + // Round 4. + // Let [abcd k s t] denote the operation + // a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). + // Do the following 16 operations. + [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] + [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] + [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] + [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64] + + // Then perform the following additions. (That is increment each + // of the four registers by the value it had before this block + // was started.) + A = A + AA B = B + BB C = C + CC D = D + DD + + end // of loop on i + + 3.5 Step 5. Output + The message digest produced as output is A, B, C, D. That is, we + begin with the low-order byte of A, and end with the high-order byte of D. + This completes the description of MD5. + + Summary + The MD5 message-digest algorithm is simple to implement, and provides + a "fingerprint" or message digest of a message of arbitrary length. + It is conjectured that the difficulty of coming up with two messages + having the same message digest is on the order of 2^64 operations, + and that the difficulty of coming up with any message having a given + message digest is on the order of 2^128 operations. The MD5 algorithm + has been carefully scrutinized for weaknesses. It is, however, a + relatively new algorithm and further security analysis is of course + justified, as is the case with any new proposal of this sort. + + + 5. Differences Between MD4 and MD5 + The following are the differences between MD4 and MD5: + 1. A fourth round has been added. + 2. Each step now has a unique additive constant. + 3. The function g in round 2 was changed from (XY v XZ v YZ) to + (XZ v Y not(Z)) to make g less symmetric. + 4. Each step now adds in the result of the previous step. This + promotes a faster "avalanche effect". + 5. The order in which input words are accessed in rounds 2 and + 3 is changed, to make these patterns less like each other. + 6. The shift amounts in each round have been approximately + optimized, to yield a faster "avalanche effect." The shifts in + different rounds are distinct. + + References + [1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and + RSA Data Security, Inc., April 1992. + [2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes + and S.A. Vanstone, editors, Advances in Cryptology - CRYPTO '90 + Proceedings, pages 303-311, Springer-Verlag, 1991. + [3] CCITT Recommendation X.509 (1988), "The Directory - + Authentication Framework."APPENDIX A - Reference Implementation + + + The level of security discussed in this memo is considered to be + sufficient for implementing very high security hybrid digital- + signature schemes based on MD5 and a public-key cryptosystem. + Author's Address + Ronald L. Rivest Massachusetts Institute of Technology + Laboratory for Computer Science NE43-324 545 Technology Square + Cambridge, MA 02139-1986 Phone: (617) 253-5880 + EMail: rivest@theory.lcs.mit.edu + + +*****************************************************************************************/ + +#ifndef _WX_FILEH__ +class wxFile; +#endif + +class wxMD5Checksum +{ +public: + // interface functions for the RSA MD5 calculation + static wxString GetMD5(unsigned char* pBuf, unsigned int nLength); + static wxString GetMD5(wxFile& File); + static wxString GetMD5(const wxString& strFilePath); + +protected: + // constructor/destructor + wxMD5Checksum(); + virtual ~wxMD5Checksum() {}; + + // RSA MD5 implementation + void Transform(unsigned char Block[64]); + void Update(unsigned char* Input, unsigned long nInputLen); + wxString Final(); + inline unsigned long RotateLeft(unsigned long x, int n); + inline void FF( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T); + inline void GG( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T); + inline void HH( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T); + inline void II( unsigned long& A, unsigned long B, unsigned long C, unsigned long D, unsigned long X, unsigned long S, unsigned long T); + + // utility functions + inline void DWordToByte(unsigned char* Output, unsigned long* Input, unsigned int nLength); + inline void ByteToDWord(unsigned long* Output, unsigned char* Input, unsigned int nLength); + +private: + unsigned char m_lpszBuffer[64]; // input buffer + unsigned long m_nCount[2]; // number of bits, modulo 2^64 (lsb first) + unsigned long m_lMD5[4]; // MD5 checksum +}; + +#endif + + + + + + + + diff --git a/src/xvaga01/MD5ChecksumDefines.h b/src/xvaga01/MD5ChecksumDefines.h new file mode 100644 index 000000000..10b7df5a6 --- /dev/null +++ b/src/xvaga01/MD5ChecksumDefines.h @@ -0,0 +1,119 @@ +/***************************************************************************************** + +*** MD5ChecksumDefines.h : MD5 Checksum constants + +*** Developed by Langfine Ltd. +*** Released to the public domain 12/Nov/2001. +*** Please visit our website www.langfine.com + +*** Any modifications must be clearly commented to distinguish them from Langfine's +*** original source code. Please advise Langfine of useful modifications so that we +*** can make them generally available. + +*****************************************************************************************/ + + +//Magic initialization constants +#define MD5_INIT_STATE_0 0x67452301 +#define MD5_INIT_STATE_1 0xefcdab89 +#define MD5_INIT_STATE_2 0x98badcfe +#define MD5_INIT_STATE_3 0x10325476 + +//Constants for Transform routine. +#define MD5_S11 7 +#define MD5_S12 12 +#define MD5_S13 17 +#define MD5_S14 22 +#define MD5_S21 5 +#define MD5_S22 9 +#define MD5_S23 14 +#define MD5_S24 20 +#define MD5_S31 4 +#define MD5_S32 11 +#define MD5_S33 16 +#define MD5_S34 23 +#define MD5_S41 6 +#define MD5_S42 10 +#define MD5_S43 15 +#define MD5_S44 21 + +//Transformation Constants - Round 1 +#define MD5_T01 0xd76aa478 //Transformation Constant 1 +#define MD5_T02 0xe8c7b756 //Transformation Constant 2 +#define MD5_T03 0x242070db //Transformation Constant 3 +#define MD5_T04 0xc1bdceee //Transformation Constant 4 +#define MD5_T05 0xf57c0faf //Transformation Constant 5 +#define MD5_T06 0x4787c62a //Transformation Constant 6 +#define MD5_T07 0xa8304613 //Transformation Constant 7 +#define MD5_T08 0xfd469501 //Transformation Constant 8 +#define MD5_T09 0x698098d8 //Transformation Constant 9 +#define MD5_T10 0x8b44f7af //Transformation Constant 10 +#define MD5_T11 0xffff5bb1 //Transformation Constant 11 +#define MD5_T12 0x895cd7be //Transformation Constant 12 +#define MD5_T13 0x6b901122 //Transformation Constant 13 +#define MD5_T14 0xfd987193 //Transformation Constant 14 +#define MD5_T15 0xa679438e //Transformation Constant 15 +#define MD5_T16 0x49b40821 //Transformation Constant 16 + +//Transformation Constants - Round 2 +#define MD5_T17 0xf61e2562 //Transformation Constant 17 +#define MD5_T18 0xc040b340 //Transformation Constant 18 +#define MD5_T19 0x265e5a51 //Transformation Constant 19 +#define MD5_T20 0xe9b6c7aa //Transformation Constant 20 +#define MD5_T21 0xd62f105d //Transformation Constant 21 +#define MD5_T22 0x02441453 //Transformation Constant 22 +#define MD5_T23 0xd8a1e681 //Transformation Constant 23 +#define MD5_T24 0xe7d3fbc8 //Transformation Constant 24 +#define MD5_T25 0x21e1cde6 //Transformation Constant 25 +#define MD5_T26 0xc33707d6 //Transformation Constant 26 +#define MD5_T27 0xf4d50d87 //Transformation Constant 27 +#define MD5_T28 0x455a14ed //Transformation Constant 28 +#define MD5_T29 0xa9e3e905 //Transformation Constant 29 +#define MD5_T30 0xfcefa3f8 //Transformation Constant 30 +#define MD5_T31 0x676f02d9 //Transformation Constant 31 +#define MD5_T32 0x8d2a4c8a //Transformation Constant 32 + +//Transformation Constants - Round 3 +#define MD5_T33 0xfffa3942 //Transformation Constant 33 +#define MD5_T34 0x8771f681 //Transformation Constant 34 +#define MD5_T35 0x6d9d6122 //Transformation Constant 35 +#define MD5_T36 0xfde5380c //Transformation Constant 36 +#define MD5_T37 0xa4beea44 //Transformation Constant 37 +#define MD5_T38 0x4bdecfa9 //Transformation Constant 38 +#define MD5_T39 0xf6bb4b60 //Transformation Constant 39 +#define MD5_T40 0xbebfbc70 //Transformation Constant 40 +#define MD5_T41 0x289b7ec6 //Transformation Constant 41 +#define MD5_T42 0xeaa127fa //Transformation Constant 42 +#define MD5_T43 0xd4ef3085 //Transformation Constant 43 +#define MD5_T44 0x04881d05 //Transformation Constant 44 +#define MD5_T45 0xd9d4d039 //Transformation Constant 45 +#define MD5_T46 0xe6db99e5 //Transformation Constant 46 +#define MD5_T47 0x1fa27cf8 //Transformation Constant 47 +#define MD5_T48 0xc4ac5665 //Transformation Constant 48 + +//Transformation Constants - Round 4 +#define MD5_T49 0xf4292244 //Transformation Constant 49 +#define MD5_T50 0x432aff97 //Transformation Constant 50 +#define MD5_T51 0xab9423a7 //Transformation Constant 51 +#define MD5_T52 0xfc93a039 //Transformation Constant 52 +#define MD5_T53 0x655b59c3 //Transformation Constant 53 +#define MD5_T54 0x8f0ccc92 //Transformation Constant 54 +#define MD5_T55 0xffeff47d //Transformation Constant 55 +#define MD5_T56 0x85845dd1 //Transformation Constant 56 +#define MD5_T57 0x6fa87e4f //Transformation Constant 57 +#define MD5_T58 0xfe2ce6e0 //Transformation Constant 58 +#define MD5_T59 0xa3014314 //Transformation Constant 59 +#define MD5_T60 0x4e0811a1 //Transformation Constant 60 +#define MD5_T61 0xf7537e82 //Transformation Constant 61 +#define MD5_T62 0xbd3af235 //Transformation Constant 62 +#define MD5_T63 0x2ad7d2bb //Transformation Constant 63 +#define MD5_T64 0xeb86d391 //Transformation Constant 64 + + +//Null data (except for first unsigned char) used to finalise the checksum calculation +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + diff --git a/src/xvaga01/XFont.cpp b/src/xvaga01/XFont.cpp new file mode 100644 index 000000000..0d8a026a7 --- /dev/null +++ b/src/xvaga01/XFont.cpp @@ -0,0 +1,676 @@ +// XFont.cpp Version 1.1 +// +// Author: Philip Patrick (GetFontProperties) +// +// Version 1.0 - Initial release of GetFontProperties() +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.1: - Removed MFC dependency from GetFontProperties() +// - Converted CFile file I/O to memory mapped file +// - Added Unicode support +// - Combined with my GetFontFile() routine +// +/////////////////////////////////////////////////////////////////////////////// + +#include "XTrace.h" +#include "XFont.h" + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// +// If you do not want TRACE output you can +// uncomment the following lines: +// +#undef TRACE +#if _MSC_VER > 1300 + #define TRACE __noop +#else + #define TRACE ((void)0) +#endif +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma warning(disable : 4127) // conditional expression is constant + +/////////////////////////////////////////////////////////////////////////////// +// private routines +static LONG GetNextNameValue(HKEY key, LPCTSTR subkey, LPTSTR szName, LPTSTR szData); + +/////////////////////////////////////////////////////////////////////////////// +// defines used by GetWinVer() +#define WUNKNOWNSTR _T("unknown Windows version") + +#define W2KSTR _T("Windows 2000") +#define WXPSTR _T("Windows XP") +#define W2003STR _T("Windows Server 2003") +#define WVISTASTR _T("Windows Vista") +#define W2008STR _T("Windows Server 2008") +#define W2008R2STR _T("Windows Server 2008 R2") +#define W7STR _T("Windows 7") +#define W2012STR _T("Windows Server 2012") +#define W8STR _T("Windows 8") +#define W10STR _T("Windows 10") +#define W2016STR _T("Windows Server 2016") + +#define WUNKNOWN 0 + +#define W9XFIRST 1 +#define W95 1 +#define W95SP1 2 +#define W95OSR2 3 +#define W98 4 +#define W98SP1 5 +#define W98SE 6 +#define WME 7 +#define W9XLAST 99 + +#define WNTFIRST 101 +#define WNT351 101 +#define WNT4 102 +#define W2K 103 +#define WXP 104 +#define W2003 105 +#define WVISTA 106 +#define W2008 107 +#define W2008R2 108 +#define W7 109 +#define W2012 110 +#define W8 111 +#define W10 112 +#define W2016 103 +#define WNTLAST 199 + +#define WCEFIRST 201 +#define WCE 201 +#define WCELAST 299 + + +/////////////////////////////////////////////////////////////////////////////// +// +// structs used by GetFontProperties() +// +typedef struct _tagFONT_PROPERTIES_ANSI +{ + char csName[1024]; + char csCopyright[1024]; + char csTrademark[1024]; + char csFamily[1024]; +} FONT_PROPERTIES_ANSI; + +typedef struct _tagTT_OFFSET_TABLE +{ + USHORT uMajorVersion; + USHORT uMinorVersion; + USHORT uNumOfTables; + USHORT uSearchRange; + USHORT uEntrySelector; + USHORT uRangeShift; +} TT_OFFSET_TABLE; + +typedef struct _tagTT_TABLE_DIRECTORY +{ + char szTag[4]; //table name + ULONG uCheckSum; //Check sum + ULONG uOffset; //Offset from beginning of file + ULONG uLength; //length of the table in bytes +} TT_TABLE_DIRECTORY; + +typedef struct _tagTT_NAME_TABLE_HEADER +{ + USHORT uFSelector; //format selector. Always 0 + USHORT uNRCount; //Name Records count + USHORT uStorageOffset; //Offset for strings storage, from start of the table +} TT_NAME_TABLE_HEADER; + +typedef struct _tagTT_NAME_RECORD +{ + USHORT uPlatformID; + USHORT uEncodingID; + USHORT uLanguageID; + USHORT uNameID; + USHORT uStringLength; + USHORT uStringOffset; //from start of storage area +} TT_NAME_RECORD; + +#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) +#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) + + +/////////////////////////////////////////////////////////////////////////////// +// +// GetFontFile() +// +// Purpose: Find the name of font file from the font name +// +// Parameters: lpszFontName - name of font +// lpszDisplayName - pointer to buffer where font display name +// will be copied +// nDisplayNameSize - size of display name buffer in TCHARs +// lpszFontFile - pointer to buffer where font file name +// will be copied +// nFontFileSize - size of font file buffer in TCHARs +// +// Returns: BOOL - TRUE = success +// +// Notes: This is *not* a foolproof method for finding the name of a +// font file. If a font has been installed in a normal manner, +// and if it is in the Windows "Font" directory, then this method +// will probably work. It will probably work for most screen +// fonts and TrueType fonts. However, this method might not work +// for fonts that are created or installed dynamically, or that +// are specific to a particular device, or that are not installed +// into the font directory. +// +BOOL GetFontFile(LPCTSTR lpszFontName, + LPTSTR lpszDisplayName, + int nDisplayNameSize, + LPTSTR lpszFontFile, + int nFontFileSize) +{ + _ASSERTE(lpszFontName && lpszFontName[0] != 0); + if (!lpszFontName || lpszFontName[0] == 0) + return FALSE; + + _ASSERTE(lpszDisplayName); + if (!lpszDisplayName) + return FALSE; + + _ASSERTE(lpszFontFile); + if (!lpszFontFile) + return FALSE; + + lpszDisplayName[0] = _T('\0'); + lpszFontFile[0] = _T('\0'); + + TCHAR szName[2 * MAX_PATH]; + TCHAR szData[2 * MAX_PATH]; + + int nVersion; + TCHAR szVersion[100]; + GetWinVer(szVersion, sizeof(szVersion)/sizeof(TCHAR)-1, &nVersion); + + LPCTSTR szFontPath = NULL; + if ((nVersion >= WNTFIRST) && (nVersion <= WNTLAST)) + szFontPath = _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); + else + szFontPath = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Fonts"); + + BOOL bResult = FALSE; + + while (GetNextNameValue(HKEY_LOCAL_MACHINE, szFontPath, szName, szData) == ERROR_SUCCESS) + { + if (_tcsnicmp(lpszFontName, szName, _tcslen(lpszFontName)) == 0) + { + TRACE(_T("found font\n")); + _tcsncpy(lpszDisplayName, szName, nDisplayNameSize-1); + _tcsncpy(lpszFontFile, szData, nFontFileSize-1); + bResult = TRUE; + break; + } + szFontPath = _T(""); // this will get next value, same key + } + + GetNextNameValue(HKEY_LOCAL_MACHINE, NULL, NULL, NULL); // close the registry key + + return bResult; +} + +bool GetFontsFolder(LPTSTR lpszFontPath, int nFontPathSize) +{ + _ASSERTE(nFontPathSize >= _MAX_PATH); + *lpszFontPath = '\0'; + SHGetFolderPath(NULL, CSIDL_FONTS, NULL, 0, lpszFontPath); + return *lpszFontPath != '\0'; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// GetFontProperties() +// +// Purpose: Get font name from font file +// +// Parameters: lpszFilePath - file path of font file +// lpFontPropsX - pointer to font properties struct +// +// Returns: BOOL - TRUE = success +// +BOOL GetFontProperties(LPCTSTR lpszFilePath, FONT_PROPERTIES * lpFontPropsX) +{ + FONT_PROPERTIES_ANSI fp; + FONT_PROPERTIES_ANSI * lpFontProps = &fp; + + memset(lpFontProps, 0, sizeof(FONT_PROPERTIES_ANSI)); + + HANDLE hFile = INVALID_HANDLE_VALUE; + hFile = ::CreateFile(lpszFilePath, + GENERIC_READ,// | GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + TRACE(_T("ERROR: failed to open '%s'\n"), lpszFilePath); + TRACE(_T("ERROR: %s failed\n"), _T("CreateFile")); + return FALSE; + } + + // get the file size + DWORD dwFileSize = ::GetFileSize(hFile, NULL); + + if (dwFileSize == INVALID_FILE_SIZE) + { + TRACE(_T("ERROR: %s failed\n"), _T("GetFileSize")); + ::CloseHandle(hFile); + return FALSE; + } + + TRACE(_T("dwFileSize = %d\n"), dwFileSize); + + // Create a file mapping object that is the current size of the file + HANDLE hMappedFile = NULL; + hMappedFile = ::CreateFileMapping(hFile, + NULL, + PAGE_READONLY, //PAGE_READWRITE, + 0, + dwFileSize, + NULL); + + if (hMappedFile == NULL) + { + TRACE(_T("ERROR: %s failed\n"), _T("CreateFileMapping")); + ::CloseHandle(hFile); + return FALSE; + } + + LPBYTE lpMapAddress = (LPBYTE) ::MapViewOfFile(hMappedFile, // handle to file-mapping object + FILE_MAP_READ,//FILE_MAP_WRITE, // access mode + 0, // high-order DWORD of offset + 0, // low-order DWORD of offset + 0); // number of bytes to map + + if (lpMapAddress == NULL) + { + TRACE(_T("ERROR: %s failed\n"), _T("MapViewOfFile")); + ::CloseHandle(hMappedFile); + ::CloseHandle(hFile); + return FALSE; + } + + BOOL bRetVal = FALSE; + int index = 0; + + TT_OFFSET_TABLE ttOffsetTable; + memcpy(&ttOffsetTable, &lpMapAddress[index], sizeof(TT_OFFSET_TABLE)); + index += sizeof(TT_OFFSET_TABLE); + + ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); + ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); + ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); + + //check is this is a true type font and the version is 1.0 + if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) + return bRetVal; + + TT_TABLE_DIRECTORY tblDir; + memset(&tblDir, 0, sizeof(TT_TABLE_DIRECTORY)); + BOOL bFound = FALSE; + char szTemp[4096]; + memset(szTemp, 0, sizeof(szTemp)); + + for (int i = 0; i< ttOffsetTable.uNumOfTables; i++) + { + //f.Read(&tblDir, sizeof(TT_TABLE_DIRECTORY)); + memcpy(&tblDir, &lpMapAddress[index], sizeof(TT_TABLE_DIRECTORY)); + index += sizeof(TT_TABLE_DIRECTORY); + + strncpy(szTemp, tblDir.szTag, 4); + if (_stricmp(szTemp, "name") == 0) + { + bFound = TRUE; + tblDir.uLength = SWAPLONG(tblDir.uLength); + tblDir.uOffset = SWAPLONG(tblDir.uOffset); + break; + } + else if (szTemp[0] == 0) + { + break; + } + } + + if (bFound) + { + index = tblDir.uOffset; + + TT_NAME_TABLE_HEADER ttNTHeader; + memcpy(&ttNTHeader, &lpMapAddress[index], sizeof(TT_NAME_TABLE_HEADER)); + index += sizeof(TT_NAME_TABLE_HEADER); + + ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); + ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); + TT_NAME_RECORD ttRecord; + bFound = FALSE; + + for (int i = 0; + i < ttNTHeader.uNRCount && + (lpFontProps->csCopyright[0] == 0 || + lpFontProps->csName[0] == 0 || + lpFontProps->csTrademark[0] == 0 || + lpFontProps->csFamily[0] == 0); + i++) + { + memcpy(&ttRecord, &lpMapAddress[index], sizeof(TT_NAME_RECORD)); + index += sizeof(TT_NAME_RECORD); + + ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); + ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); + ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); + + if (ttRecord.uNameID == 1 || ttRecord.uNameID == 0 || ttRecord.uNameID == 7) + { + int nPos = index; //f.GetPosition(); + + index = tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset; + + memset(szTemp, 0, sizeof(szTemp)); + + memcpy(szTemp, &lpMapAddress[index], ttRecord.uStringLength); + index += ttRecord.uStringLength; + + if (szTemp[0] != 0) + { + _ASSERTE(strlen(szTemp) < sizeof(lpFontProps->csName)); + + switch (ttRecord.uNameID) + { + case 0: + if (lpFontProps->csCopyright[0] == 0) + strncpy(lpFontProps->csCopyright, szTemp, + sizeof(lpFontProps->csCopyright)-1); + break; + + case 1: + if (lpFontProps->csFamily[0] == 0) + strncpy(lpFontProps->csFamily, szTemp, + sizeof(lpFontProps->csFamily)-1); + bRetVal = TRUE; + break; + + case 4: + if (lpFontProps->csName[0] == 0) + strncpy(lpFontProps->csName, szTemp, + sizeof(lpFontProps->csName)-1); + break; + + case 7: + if (lpFontProps->csTrademark[0] == 0) + strncpy(lpFontProps->csTrademark, szTemp, + sizeof(lpFontProps->csTrademark)-1); + break; + + default: + break; + } + } + index = nPos; + } + } + } + + ::UnmapViewOfFile(lpMapAddress); + ::CloseHandle(hMappedFile); + ::CloseHandle(hFile); + + if (lpFontProps->csName[0] == 0) + strcpy(lpFontProps->csName, lpFontProps->csFamily); + + memset(lpFontPropsX, 0, sizeof(FONT_PROPERTIES)); + +#ifdef _UNICODE + ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csName, -1, lpFontPropsX->csName, + sizeof(lpFontPropsX->csName)/sizeof(TCHAR)-1); + ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csCopyright, -1, lpFontPropsX->csCopyright, + sizeof(lpFontPropsX->csCopyright)/sizeof(TCHAR)-1); + ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csTrademark, -1, lpFontPropsX->csTrademark, + sizeof(lpFontPropsX->csTrademark)/sizeof(TCHAR)-1); + ::MultiByteToWideChar(CP_ACP, 0, lpFontProps->csFamily, -1, lpFontPropsX->csFamily, + sizeof(lpFontPropsX->csFamily)/sizeof(TCHAR)-1); +#else + strcpy(lpFontPropsX->csName, lpFontProps->csName); + strcpy(lpFontPropsX->csCopyright, lpFontProps->csCopyright); + strcpy(lpFontPropsX->csTrademark, lpFontProps->csTrademark); + strcpy(lpFontPropsX->csFamily, lpFontProps->csFamily); +#endif + + return bRetVal; +} + + +/////////////////////////////////////////////////////////////////////////////// +// +// GetNextNameValue() +// +// Purpose: Get first/next name/value pair from registry +// +// Parameters: key - handle to open key, or predefined key +// pszSubkey - subkey name +// pszName - pointer to buffer that receives the value string +// pszData - pointer to buffer that receives the data string +// +// Returns: LONG - return code from registry function; ERROR_SUCCESS = success +// +// Notes: If pszSubkey, pszName, and pszData are all NULL, then the open +// handle will be closed. +// +// The first time GetNextNameValue is called, pszSubkey should be +// specified. On subsequent calls, pszSubkey should be NULL or +// an empty string. +// +static LONG GetNextNameValue(HKEY key, LPCTSTR pszSubkey, LPTSTR pszName, LPTSTR pszData) +{ + static HKEY hkey = NULL; // registry handle, kept open between calls + static DWORD dwIndex = 0; // count of values returned + LONG retval = ERROR_SUCCESS; + + // if all parameters are NULL then close key + if (pszSubkey == NULL && pszName == NULL && pszData == NULL) + { + TRACE(_T("closing key\n")); + if (hkey) + ::RegCloseKey(hkey); + hkey = NULL; + return ERROR_SUCCESS; + } + + // if subkey is specified then open key (first time) + if (pszSubkey && *pszSubkey) + { + // retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_ALL_ACCESS, &hkey); // Incapace... + retval = ::RegOpenKeyEx(key, pszSubkey, 0, KEY_READ, &hkey); // ... devi solo leggere! + if (retval != ERROR_SUCCESS) + { + TRACE(_T("ERROR: RegOpenKeyEx failed\n")); + return retval; + } + else + { + TRACE(_T("RegOpenKeyEx ok\n")); + } + dwIndex = 0; + } + else + { + dwIndex++; + } + + _ASSERTE(pszName != NULL && pszData != NULL); + + *pszName = 0; + *pszData = 0; + + TCHAR szValueName[MAX_PATH]; + DWORD dwValueNameSize = sizeof(szValueName)-1; + BYTE szValueData[MAX_PATH]; + DWORD dwValueDataSize = sizeof(szValueData)-1; + DWORD dwType = 0; + + retval = ::RegEnumValue(hkey, dwIndex, szValueName, &dwValueNameSize, NULL, + &dwType, szValueData, &dwValueDataSize); + if (retval == ERROR_SUCCESS) + { + TRACE(_T("szValueName=<%s> szValueData=<%s>\n"), szValueName, szValueData); + lstrcpy(pszName, (LPTSTR)szValueName); + lstrcpy(pszData, (LPTSTR)szValueData); + } + else + { + TRACE(_T("RegEnumKey failed\n")); + } + + return retval; +} + + +// from winbase.h +#ifndef VER_PLATFORM_WIN32s +#define VER_PLATFORM_WIN32s 0 +#endif +#ifndef VER_PLATFORM_WIN32_WINDOWS +#define VER_PLATFORM_WIN32_WINDOWS 1 +#endif +#ifndef VER_PLATFORM_WIN32_NT +#define VER_PLATFORM_WIN32_NT 2 +#endif +#ifndef VER_PLATFORM_WIN32_CE +#define VER_PLATFORM_WIN32_CE 3 +#endif + + +/* + This table has been assembled from Usenet postings, personal + observations, and reading other people's code. Please feel + free to add to it or correct it. + + + dwPlatFormID dwMajorVersion dwMinorVersion dwBuildNumber +95 1 4 0 950 +95 SP1 1 4 0 >950 && <=1080 +95 OSR2 1 4 <10 >1080 +98 1 4 10 1998 +98 SP1 1 4 10 >1998 && <2183 +98 SE 1 4 10 >=2183 +ME 1 4 90 3000 + +NT 3.51 2 3 51 +NT 4 2 4 0 1381 +2000 2 5 0 2195 +XP 2 5 1 2600 +2003 2 5 2 +Vista 2 6 0 +2008 2 6 0 +2008 R2 2 6 1 +Win7 2 6 1 3600 +Win8 2 6 2 +Win8.1 2 6 3 +Win10 2 6 4 +Win10 2 10 0 +CE 3 + +*/ + +/////////////////////////////////////////////////////////////////////////////// +// +// GetWinVer() +// +// Purpose: Get Windows version info +// +// Parameters: lpszVersion - pointer to buffer that receives the version +// string +// nVersionSize - size of the version buffer in TCHARs +// pnVersion - pointer to int that receives the version code +// +// Returns: BOOL - TRUE = success +// +/////////////////////////////////////////////////////////////////////////////// +// GetWinVer +bool GetWinVer(LPTSTR lpszVersion, int nVersionSize, int *pnVersion) +{ + int nVersion = WUNKNOWN; + LPCTSTR cp = WUNKNOWNSTR; + + OSVERSIONINFOEX osinfo; memset(&osinfo, 0, sizeof(osinfo)); + osinfo.dwOSVersionInfoSize = sizeof(osinfo); + if (::GetVersionEx((OSVERSIONINFO*)&osinfo)) + { + DWORD dwPlatformId = osinfo.dwPlatformId; + DWORD dwMinorVersion = osinfo.dwMinorVersion; + DWORD dwMajorVersion = osinfo.dwMajorVersion; + DWORD dwBuildNumber = osinfo.dwBuildNumber & 0xFFFF; // Win 95 needs this + const bool bServer = osinfo.wProductType != VER_NT_WORKSTATION; + + if (dwPlatformId == VER_PLATFORM_WIN32_NT) + { + if (dwMajorVersion <= 5) + { + switch (dwMinorVersion) + { + case 0: cp = W2KSTR; nVersion = W2K; break; + case 1: cp = WXPSTR; nVersion = WXP; break; + case 2: + default: cp = W2003STR; nVersion = W2003; break; + } + } else + if (dwMajorVersion == 6) + { + switch (dwMinorVersion) + { + case 0: + if (bServer) + { cp = W2008STR; nVersion = W2008; } + else + { cp = WVISTASTR; nVersion = WVISTA; } + break; + case 1: + if (bServer) + { cp = W2008R2STR; nVersion = W2008R2; } + else + { cp = W7STR; nVersion = W7; } + break; + case 2: + case 3: + if (bServer) + { cp = W2012STR; nVersion = W2012; } + else + { cp = W8STR; nVersion = W8; } + break; + default: + if (bServer) + { cp = W2016STR; nVersion = W2016; } + else + { cp = W10STR; nVersion = W10; } + break; + } + } else + if (dwMajorVersion >= 10) + { + if (bServer) + { cp = W2016STR; nVersion = W2016; } + else + { cp = W10STR; nVersion = W10; } + } + } + } + + if (lpszVersion != NULL && nVersionSize > 0) + _tcsncpy(lpszVersion, cp, nVersionSize-1); + if (pnVersion != NULL) + *pnVersion = nVersion; + + return nVersion == WUNKNOWN; +} diff --git a/src/xvaga01/XFont.h b/src/xvaga01/XFont.h new file mode 100644 index 000000000..0d3d23e37 --- /dev/null +++ b/src/xvaga01/XFont.h @@ -0,0 +1,39 @@ +// XFont.h Version 1.1 +// +// Copyright (C) 2003 Hans Dietrich +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XFONT_H +#define XFONT_H + +typedef struct _tagFONT_PROPERTIES +{ + TCHAR csName[1024]; + TCHAR csCopyright[1024]; + TCHAR csTrademark[1024]; + TCHAR csFamily[1024]; +} FONT_PROPERTIES, *LPFONT_PROPERTIES; + + +BOOL GetFontFile(LPCTSTR lpszFontName, + LPTSTR lpszDisplayName, + int nDisplayNameSize, + LPTSTR lpszFontFile, + int nFontFileSize); + + +BOOL GetFontProperties(LPCTSTR lpszFilePath, + LPFONT_PROPERTIES lpFontProps); + +bool GetFontsFolder(LPTSTR lpszFontPath, int nFontPathSize); +bool GetWinVer(LPTSTR lpszVersion, int nVersionSize, int *nVersion); + +#endif //XFONT_H diff --git a/src/xvaga01/XTrace.h b/src/xvaga01/XTrace.h new file mode 100644 index 000000000..557f4b3f4 --- /dev/null +++ b/src/xvaga01/XTrace.h @@ -0,0 +1,122 @@ +// XTrace.h Version 1.1 +// +// Author: Paul Mclachlan +// +// Modified by: Hans Dietrich +// hdietrich2@hotmail.com +// +// Version 1.1: added Unicode support +// added optional thread id to output string +// added option to enable/disable full path +// added TRACERECT macro +// changed name to avoid conflicts with Paul's class. +// +// This code was taken from article by Paul Mclachlan, "Getting around +// the need for a vararg #define just to automatically use __FILE__ and +// __LINE__ in a TRACE macro". For original article, see +// http://www.codeproject.com/useritems/location_trace.asp +// +// XTrace.h is a drop-in replacement for MFC's TRACE facility. It has no +// dependency on MFC. It is thread-safe and uses no globals or statics. +// +// It optionally adds source module/line number and thread id to each line +// of TRACE output. To control these features, use the following defines: +// +// XTRACE_SHOW_FULLPATH +// XTRACE_SHOW_THREAD_ID +// +// XTrace.h also provides the TRACERECT macro, which outputs the contents +// of a RECT struct. In Release builds, no output will be produced. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XTRACE_H +#define XTRACE_H + +#ifdef WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant + +#define XTRACE_SHOW_FULLPATH FALSE // FALSE = only show base name of file +#define XTRACE_SHOW_THREAD_ID TRUE // TRUE = include thread id in output + +class xtracing_output_debug_string +{ +public: + xtracing_output_debug_string(LPCTSTR lpszFile, int line) : + m_file(lpszFile), + m_line(line) + { + } + + void operator() (LPCTSTR lpszFormat, ...) + { + va_list va; + va_start(va, lpszFormat); + + TCHAR buf1[BUFFER_SIZE]; + TCHAR buf2[BUFFER_SIZE]; + + // add the __FILE__ and __LINE__ to the front + LPCTSTR cp = (LPCTSTR) m_file; + + if (!XTRACE_SHOW_FULLPATH) + { + cp = _tcsrchr(m_file, _T('\\')); + if (cp) + cp++; + } + + if (XTRACE_SHOW_THREAD_ID) + { + if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : [%X] %s"), + cp, m_line, GetCurrentThreadId(), lpszFormat) < 0) + buf1[BUFFER_SIZE-1] = _T('\0'); + } + else + { + if (_sntprintf(buf1, BUFFER_SIZE-1, _T("%s(%d) : %s"), + cp, m_line, lpszFormat) < 0) + buf1[BUFFER_SIZE-1] = _T('\0'); + } + + // format the message as requested + if (_vsntprintf(buf2, BUFFER_SIZE-1, buf1, va) < 0) + buf2[BUFFER_SIZE-1] = _T('\0'); + + va_end(va); + + // write it out + OutputDebugString(buf2); + } + +private: + LPCTSTR m_file; + int m_line; + enum { BUFFER_SIZE = 4096 }; +}; + +#undef TRACE + +#ifdef _DEBUG +#define TRACE (xtracing_output_debug_string(_T(__FILE__), __LINE__ )) +#define TRACEERROR (xtracing_output_debug_string(_T(__FILE__), __LINE__ )) +#else +#define TRACE ((void)0) +#define TRACEERROR ((void)0) +#endif + +#define TRACERECT(r) TRACE(_T(#r) _T(": left = %d top = %d right = %d bottom = %d\n"), \ + (r).left, (r).top, (r).right, (r).bottom) + +#pragma warning(pop) + +#endif //XTRACE_H diff --git a/src/xvaga01/agasys.cpp b/src/xvaga01/agasys.cpp new file mode 100644 index 000000000..159132df7 --- /dev/null +++ b/src/xvaga01/agasys.cpp @@ -0,0 +1,799 @@ +#include "wxinc.h" +#include "incstr.h" + +#include "agasys.h" +#include "xvt.h" +#include "guid.hpp" + +/////////////////////////////////////////////////////////// +// Unzip support +/////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +static unsigned int aga_getziplist(const char* zipfile, wxArrayString& aFiles) +{ + wxFFileInputStream fin(zipfile); + wxZipInputStream zip(fin); + for (wxZipEntry* z = zip.GetNextEntry(); z; z = zip.GetNextEntry()) + { + const wxString str = z->GetInternalName(); + aFiles.Add(str); + } + + return aFiles.GetCount(); +} + +bool aga_unzip(const char* zipfile, const char* destdir) +{ + wxArrayString aFiles; + const unsigned int files = aga_getziplist(zipfile, aFiles); + + WINDOW pi = xvt_dm_progress_create(NULL_WIN, "Unzip", files, TRUE); + for (unsigned int f = 0; f < files; f++) + { + const wxString& strFileName = aFiles[f]; + xvt_dm_progress_set_text(pi, strFileName); + + if (wxEndsWithPathSeparator(strFileName) || strFileName.Find('.') < 0) // Is dir name + { + wxString strOutDir = destdir; + if (!wxEndsWithPathSeparator(strOutDir)) + strOutDir += wxFILE_SEP_PATH; + strOutDir += strFileName; + xvt_fsys_mkdir(strOutDir); + } + else + { + wxFFileInputStream file(zipfile); + wxZipInputStream fin(file); + + wxZipEntry* entry = nullptr; + do entry = fin.GetNextEntry(); + while (entry && entry->GetInternalName() != strFileName); + if (entry == nullptr || !fin.OpenEntry(*entry)) + continue; + + wxString strOutFile = destdir; + if (!wxEndsWithPathSeparator(strOutFile) && !wxIsPathSeparator(strFileName[0])) + strOutFile += wxFILE_SEP_PATH; + strOutFile += strFileName; + + wxString strPath; + ::wxSplitPath(strOutFile, &strPath, nullptr, nullptr); + xvt_fsys_mkdir(strPath); + + wxFileOutputStream fout(strOutFile); + fout.Write(fin); + } + if (!xvt_dm_progress_set_status(pi, f+1, files)) + break; + } + xvt_dm_progress_destroy(pi); + return files > 0; +} + +/////////////////////////////////////////////////////////// +// Zip support +/////////////////////////////////////////////////////////// + +static void AddFileToZip(const wxString& strPrefix, const wxString& strFile, + wxZipOutputStream& zip) +{ + if (!wxFileExists(strFile)) + return; + + wxString strPath, strName, strExt; + wxSplitPath(strFile, &strPath, &strName, &strExt); + + wxString strRelName; + strRelName = strPath.Mid(strPrefix.Length()); + if (!strRelName.IsEmpty()) + strRelName += '/'; + strRelName += strName; + strRelName += '.'; + strRelName += strExt; + + zip.PutNextEntry(strRelName); + wxFileInputStream fin(strFile); + zip.Write(fin); // Scrivo file compresso +} + +static bool AddFilesToZip(const wxString& strBase, wxArrayString& aFiles, const char* zipfile) +{ + wxFFileOutputStream out(zipfile); + wxZipOutputStream zip(out); + const size_t nFiles = aFiles.GetCount(); + WINDOW pi = xvt_dm_progress_create(NULL_WIN, "Zip", nFiles, TRUE); + + for (size_t i = 0; i < nFiles; i++) + { + const wxString& str = aFiles[i]; + xvt_dm_progress_set_text(pi, str); + AddFileToZip(strBase, str, zip); + if (!xvt_dm_progress_set_status(pi, i+1, nFiles)) + break; + } + xvt_dm_progress_destroy(pi); + return true; +} + +bool aga_zip(const char* srcfiles, const char* zipfile) +{ + wxString strBase, strMask, strExt; + wxSplitPath(srcfiles, &strBase, &strMask, &strExt); + strMask += '.'; + strMask += strExt; + + wxArrayString aFiles; + wxDir::GetAllFiles(strBase, &aFiles, strMask); + + return AddFilesToZip(strBase, aFiles, zipfile); +} + +bool aga_zip_filelist(const char* filelist, const char* zipfile) +{ + wxArrayString aFiles; + ifstream fin(filelist); + while (!fin.eof()) + { + char name[_MAX_PATH] = { 0 }; + fin.getline(name, sizeof(name)); + if (*name) + aFiles.Add(name); + else + break; + } + return AddFilesToZip("", aFiles, zipfile); +} + +/////////////////////////////////////////////////////////// +// DDE +/////////////////////////////////////////////////////////// + +#include +#define wxAgaClient wxDDEClient + +static wxAgaClient* _net_client = nullptr; +static unsigned long _net_conns = 0; + +class wxAgaConnection : public wxDDEConnection +{ +public: + bool ExecuteAsync(const wxChar *data, int size, wxIPCFormat format = wxIPC_TEXT); +}; + +bool wxAgaConnection::ExecuteAsync(const wxChar *data, int size, wxIPCFormat WXUNUSED(format)) +{ + DWORD result; + if (size < 0) + size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL + + bool ok = DdeClientTransaction((LPBYTE)data, size, (HCONV)m_hConv, nullptr, + 0, XTYP_EXECUTE, TIMEOUT_ASYNC, &result) != 0; + return ok; +} + +unsigned long aga_dde_connect(const char* host, const char* service, const char* topic) +{ + if (_net_client == nullptr) + { + _net_client = new wxAgaClient; + _net_conns = 0; + } + + wxConnectionBase* conn = _net_client->MakeConnection(host, service, topic); + if (conn != nullptr) + _net_conns++; + + return (unsigned long)conn; +} + +bool aga_dde_poke(unsigned long connection, const char* item, const char* data) +{ + return false; +} + +int aga_dde_request(unsigned long connection, const char* item, char* data, int max_size) +{ + int len = 0; + if (connection != 0) + { + wxAgaConnection* conn = (wxAgaConnection*)connection; + wxChar* buff = conn->Request(item, &len); + if (max_size > 0) + memcpy(data, buff, min(max_size, len)); + } + return len; +} + + +bool aga_dde_execute(unsigned long connection, const char* msg) +{ + bool ok = false; + if (connection != 0) + { + wxAgaConnection* conn = (wxAgaConnection*)connection; + const bool bLogEnabled = wxLog::EnableLogging(false); + ok = conn->Execute(msg, -1); + wxLog::EnableLogging(bLogEnabled); + } + return ok; +} + +bool aga_dde_execute_async(unsigned long connection, const char* msg) +{ + bool ok = false; + if (connection != 0) + { + wxAgaConnection* conn = (wxAgaConnection*)connection; + ok = conn->ExecuteAsync(msg, -1); + } + return ok; +} + +bool aga_dde_terminate(unsigned long connection) +{ + bool ok = false; + if (connection != 0 && _net_client != nullptr) + { + wxAgaConnection* conn = (wxAgaConnection*)connection; + ok = conn->Disconnect(); + if (ok && _net_conns > 0) + { + _net_conns--; + if (_net_conns == 0) + { + delete _net_client; + _net_client = nullptr; + } + } + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Multi file operations +/////////////////////////////////////////////////////////// + +//Solo da Vista in poi... +#include +#include + +static IFileOperation* CreatePFO() +{ + HRESULT hr = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + if (!SUCCEEDED(hr)) + return nullptr; + + IFileOperation *pfo = nullptr; + hr = ::CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo)); + if (!SUCCEEDED(hr)) + return nullptr; + + pfo->SetOperationFlags(FOF_NOCONFIRMATION); + + return pfo; +} + +static void DeleteIUnknown(IUnknown* iu) +{ + if (iu) + { + iu->Release(); + iu = nullptr; + } +} + + +int xvt_fsys_files_remove(const char* src, SLIST names) +{ + int nDone = 0; + IFileOperation *pfo = CreatePFO(); + if (!pfo) + return -1; + + HRESULT hr = 0; + + if (xvt_slist_count(names) == 0) + { + wxString n = src; + wxWritableWCharBuffer wcb = n.wchar_str(); + IShellItem * psiFolder = nullptr; + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiFolder)); + if (SUCCEEDED(hr)) + { + IEnumShellItems * pEnum = nullptr; + hr = psiFolder->BindToHandler(nullptr, BHID_EnumItems, IID_IEnumShellItems, (void**)&pEnum); + if (SUCCEEDED(hr)) + { + hr = pfo->DeleteItems(pEnum); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(pEnum); + } + DeleteIUnknown(psiFolder); + } + } + else + { + wxString srcpath(src); + + for (SLIST_ELT e = xvt_slist_get_first(names); e; e = xvt_slist_get_next(names, e)) + { + wxFileName n = xvt_slist_get(names, e, nullptr); + wxString name = n.GetFullPath(); + + if (!n.IsAbsolute() && name.Find(srcpath) == wxNOT_FOUND) + n.PrependDir(src); + wxWritableWCharBuffer wcb = n.GetFullPath().wchar_str(); + IShellItem* psiItem = nullptr; + + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiItem)); + if (SUCCEEDED(hr)) + { + hr = pfo->DeleteItem(psiItem, nullptr); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(psiItem); + } + } + } + hr = pfo->PerformOperations(); + DeleteIUnknown(pfo); + return SUCCEEDED(hr) ? nDone : -1; +} + +int xvt_fsys_files_copy(const char* src, SLIST names, const char* dst) +{ + int nDone = 0; + IFileOperation *pfo = CreatePFO(); + if (!pfo) + return -1; + wxString d = dst; + wxWritableWCharBuffer wcbd = d.wchar_str(); + HRESULT hrd = 0; + IShellItem * pdiFolder = nullptr; + + hrd = ::SHCreateItemFromParsingName(wcbd, nullptr, IID_PPV_ARGS(&pdiFolder)); + if (!SUCCEEDED(hrd)) + return -1; + + HRESULT hr = 0; + + if (xvt_slist_count(names) == 0) + { + wxString n = src; + wxWritableWCharBuffer wcb = n.wchar_str(); + IShellItem * psiFolder = nullptr; + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiFolder)); + if (SUCCEEDED(hr)) + { + IEnumShellItems * pEnum = nullptr; + hr = psiFolder->BindToHandler(nullptr, BHID_EnumItems, IID_IEnumShellItems, (void**)&pEnum); + if (SUCCEEDED(hr)) + { + hr = pfo->CopyItems(pEnum, pdiFolder); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(pEnum); + } + DeleteIUnknown(psiFolder); + } + } + else + { + for (SLIST_ELT e = xvt_slist_get_first(names); e; e = xvt_slist_get_next(names, e)) + { + wxFileName n = xvt_slist_get(names, e, nullptr); + if (!n.IsAbsolute()) + n.PrependDir(src); + wxWritableWCharBuffer wcb = n.GetFullPath().wchar_str(); + IShellItem* psiItem = nullptr; + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiItem)); + if (SUCCEEDED(hr)) + { + hr = pfo->CopyItem(psiItem, pdiFolder, nullptr, nullptr); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(psiItem); + } + } + } + hr = pfo->PerformOperations(); + DeleteIUnknown(pdiFolder); + DeleteIUnknown(pfo); + return SUCCEEDED(hr) ? nDone : -1; +} + +int xvt_fsys_files_move(const char* src, SLIST names, const char* dst) +{ + int nDone = 0; + IFileOperation *pfo = CreatePFO(); + if (!pfo) + return -1; + + wxString d = dst; + wxWritableWCharBuffer wcbd = d.wchar_str(); + HRESULT hrd = 0; + IShellItem * pdiFolder = nullptr; + + hrd = ::SHCreateItemFromParsingName(wcbd, nullptr, IID_PPV_ARGS(&pdiFolder)); + if (!SUCCEEDED(hrd)) + return -1; + + HRESULT hr = 0; + + if (xvt_slist_count(names) == 0) + { + wxString n = src; + wxWritableWCharBuffer wcb = n.wchar_str(); + IShellItem * psiFolder = nullptr; + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiFolder)); + if (SUCCEEDED(hr)) + { + IEnumShellItems * pEnum = nullptr; + hr = psiFolder->BindToHandler(nullptr, BHID_EnumItems, IID_IEnumShellItems, (void**)&pEnum); + if (SUCCEEDED(hr)) + { + hr = pfo->MoveItems(pEnum, pdiFolder); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(pEnum); + } + DeleteIUnknown(psiFolder); + } + } + else + { + for (SLIST_ELT e = xvt_slist_get_first(names); e; e = xvt_slist_get_next(names, e)) + { + wxFileName n = xvt_slist_get(names, e, nullptr); + if (!n.IsAbsolute()) + n.PrependDir(src); + wxWritableWCharBuffer wcb = n.GetFullPath().wchar_str(); + IShellItem* psiItem = nullptr; + hr = ::SHCreateItemFromParsingName(wcb, nullptr, IID_PPV_ARGS(&psiItem)); + if (SUCCEEDED(hr)) + { + hr = pfo->MoveItem(psiItem, pdiFolder, nullptr, nullptr); + if (SUCCEEDED(hr)) + nDone++; + DeleteIUnknown(psiItem); + } + } + } + hr = pfo->PerformOperations(); + DeleteIUnknown(pfo); + DeleteIUnknown(pdiFolder); + return SUCCEEDED(hr) ? nDone : -1; +} + +void xvt_fsys_get_sys_dir(int what_dir, char * dir) +{ + wxFileName d; + wxString out; + + switch (what_dir) + { + case XVT_DESKTOP_DIR: + { + d = wxStandardPaths::Get().GetDocumentsDir(); + + d.SetName(wxString("Desktop")); + out = d.GetFullPath(); + } + break; + case XVT_DOCUMENTS_DIR: + d = wxStandardPaths::Get().GetDocumentsDir(); + out = d.GetFullPath(); + break; + case XVT_EXEC_DIR: + d = wxFileName::DirName(wxStandardPaths::Get().GetExecutablePath()); + out = d.GetFullPath(); + break; + case XVT_INSTALL_DIR: + d = wxStandardPaths::Get().GetDocumentsDir(); + out = d.GetVolume(); out << wxFileName::GetVolumeSeparator().c_str() << "\\"; + break; + case XVT_TEMP_DIR: + d = wxStandardPaths::Get().GetTempDir(); + out = d.GetFullPath(); + break; + default: + break; + } + wxStrncpy(dir, out, MAX_PATH); +} + +/////////////////////////////////////////////////////////// +// TProgressIndicator +/////////////////////////////////////////////////////////// + +class TProgressIndicator : public wxDialog +{ + enum { MAX_GAUGES = 16 }; + wxGauge* m_pGauge[MAX_GAUGES]; + wxStaticText* m_pPassed; + wxStaticText* m_pResidual; + wxStaticText* m_pEstimated; + wxStopWatch m_chrono; + long m_nNextUpdate; + +protected: + DECLARE_EVENT_TABLE(); + + void Init(wxString msg, int nGauges, bool bCancellable); + wxString msec2str(long ms) const; + long Elapsed() const { return m_chrono.Time(); } + +public: + void SetRange(int nRange, int nGauge = 0); + bool SetProgress(int nPos, int nGauge = 0); + void SetMessage(wxString msg); + + TProgressIndicator(wxString msg, bool bCancellable, int nGauges); + TProgressIndicator(size_t nRange, wxString msg, bool bCancellable); + virtual ~TProgressIndicator(); +}; + +BEGIN_EVENT_TABLE(TProgressIndicator, wxDialog) +// EVT_MENU(wxID_CANCEL, TProgressIndicator::OnCancel) +END_EVENT_TABLE() + +wxString TProgressIndicator::msec2str(long ms) const +{ + int s = ms/1000; + const int h = s / 3600; + s -= h*3600; + const int m = s / 60; + s -= m*60; + return wxString::Format(wxT("%02d:%02d:%02d"), h, m, s); +} + +void TProgressIndicator::SetRange(int nRange, int nGauge) +{ + wxASSERT(nRange >= 0 && nGauge >= 0 && nGauge < MAX_GAUGES); + m_pGauge[nGauge]->SetRange(nRange); +} + +bool TProgressIndicator::SetProgress(int nPos, int nGauge) +{ + if (!IsShown()) + return false; + + wxASSERT(nPos >= 0 && nGauge >= 0 && nGauge < MAX_GAUGES); + m_pGauge[nGauge]->SetValue(nPos); + + const long elap = Elapsed(); + if (elap > m_nNextUpdate) + { + m_nNextUpdate = elap+CLOCKS_PER_SEC; + m_pPassed->SetLabel(msec2str(elap)); + + wxLongLong_t nTotValue = 0, nTotRange = 0; + for (int i = 0; i < MAX_GAUGES && m_pGauge[i]; i++) + { + const int nValue = m_pGauge[i]->GetValue(); + const int nRange = m_pGauge[i]->GetRange(); + if (nValue < nRange) // Escludi dal calcolo i processi già terminati + { + nTotValue += nValue; + nTotRange += nRange; + } + } + if (nTotValue > 0) + { + const long est = long(elap * nTotRange / nTotValue); + m_pEstimated->SetLabel(msec2str(est)); + m_pResidual->SetLabel(msec2str(est-elap)); + } + + wxYield(); + } + + return true; +} + +void TProgressIndicator::SetMessage(wxString msg) +{ SetLabel(msg); } + +void TProgressIndicator::Init(wxString msg, int nGauges, bool bCancellable) +{ + const int nGap = 4; + wxBoxSizer* pTopSizer = new wxBoxSizer(wxVERTICAL); + SetSizer(pTopSizer); + + memset(m_pGauge, 0, sizeof(m_pGauge)); + for (int i = 0; i < nGauges; i++) + { + m_pGauge[i] = new wxGauge(this, 1001+i, 100, wxDefaultPosition, wxSize(400, -1)); + pTopSizer->Add(m_pGauge[i], 0, wxALL, nGap); + } + + wxGridSizer* pTimersSizer = new wxGridSizer(1, 3, nGap, nGap); + pTopSizer->Add(pTimersSizer, 0, wxEXPAND); + + wxStaticBoxSizer* pPassed = new wxStaticBoxSizer(wxVERTICAL, this, _("Elapsed Time")); + pTimersSizer->Add(pPassed, 0, wxEXPAND); + m_pPassed = new wxStaticText(this, 1101, wxT("00:00:00")); + pPassed->Add(m_pPassed, 0, wxALL|wxALIGN_CENTER, 0); + + wxStaticBoxSizer* pResidual = new wxStaticBoxSizer(wxVERTICAL, this, _("Residual Time")); + pTimersSizer->Add(pResidual, 0, wxEXPAND); + m_pResidual = new wxStaticText(this, 1102, wxT("00:00:00")); + pResidual->Add(m_pResidual, 0, wxALL|wxALIGN_CENTER, 0); + + wxStaticBoxSizer* pEstimated = new wxStaticBoxSizer(wxVERTICAL, this, _("Estimated Time")); + pTimersSizer->Add(pEstimated, 0, wxEXPAND); + m_pEstimated = new wxStaticText(this, 1103, wxT("00:00:00")); + pEstimated->Add(m_pEstimated, 0, wxALL|wxALIGN_CENTER, 0); + + wxButton* pCancel = nullptr; + if (bCancellable) + { + pCancel = new wxButton(this, wxID_CANCEL, _("Cancel")); + pTopSizer->Add(pCancel, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, nGap); + } + + pTopSizer->SetSizeHints(this); + + SetMessage(msg); + + Show(); + Enable(); + Update(); + + m_nNextUpdate = 0; + m_chrono.Start(); +} + +TProgressIndicator::TProgressIndicator(size_t nRange, wxString msg, bool bCancellable) + : wxDialog(nullptr, wxID_ANY, msg) +{ + Init(msg, 1, bCancellable); + SetRange(nRange, 0); +} + +TProgressIndicator::TProgressIndicator(wxString msg, bool bCancellable, int nGauges) + : wxDialog(nullptr, wxID_ANY, msg) +{ + Init(msg, nGauges, bCancellable); +} + +TProgressIndicator::~TProgressIndicator() +{ } + +/////////////////////////////////////////////////////////// +// Multiprocess +/////////////////////////////////////////////////////////// + +class TWorker : public wxThread +{ + XVT_MULTITHREAD_CALLBACK m_pFunc; + void* m_pCaller; + void* m_pData; + int m_nFirst, m_nLast, m_nTotal; + TProgressIndicator* m_pi; + int m_nGauge; + +protected: + virtual ExitCode Entry(); + +public: + TWorker(XVT_MULTITHREAD_CALLBACK func, void* pCaller, void* pData, + int nFirst, int nLast, int nTotal, TProgressIndicator* pi, int nGauge); +}; + +wxThread::ExitCode TWorker::Entry() +{ + ExitCode ec = 0; + if (m_pi != nullptr) + { + m_pi->SetRange(m_nLast-m_nFirst, m_nGauge); + for (int i = m_nFirst; i < m_nLast && ec == 0; i++) + { + ec = (ExitCode)m_pFunc(m_pCaller, m_pData, i, m_nTotal); + if (!m_pi->SetProgress(i-m_nFirst+1, m_nGauge)) + ec = ExitCode(-1); + } + } + else + { + for (int i = m_nFirst; i < m_nLast && ec == 0; i++) + ec = (ExitCode)m_pFunc(m_pCaller, m_pData, i, m_nTotal); + } + return ec; +} + +TWorker::TWorker(XVT_MULTITHREAD_CALLBACK func, void* pCaller, void* pData, + int nFirst, int nLast, int nTotal, TProgressIndicator* pi, int nGauge) + : wxThread(wxTHREAD_JOINABLE), m_pFunc(func), m_pCaller(pCaller), m_pData(pData), + m_nFirst(nFirst), m_nLast(nLast), m_nTotal(nTotal), m_pi(pi), m_nGauge(nGauge) + +{ +// SetPriority(WXTHREAD_MIN_PRIORITY); + Create(); +} + +BOOLEAN xvt_sys_multithread(XVT_MULTITHREAD_CALLBACK pFunc, void* pCaller, void* pData, + int tot, const char* msg) +{ + const int MAX_WORKERS = 16; + + // Bilanciamento automatico + int nWorkers = wxThread::GetCPUCount(); + if (nWorkers <= 0) + nWorkers = 1; + if (nWorkers > tot) + nWorkers = tot; + if (nWorkers > MAX_WORKERS) + nWorkers = MAX_WORKERS; + + int ret = 0; + if (nWorkers > 1) + { + TProgressIndicator* pi = nullptr; + if (msg && *msg) + pi = new TProgressIndicator(msg, tot > nWorkers, nWorkers); + + TWorker* worker[MAX_WORKERS]; memset(worker, 0, sizeof(worker)); + + int nFirst, nLast = 0, w; + for (w = 0; w < nWorkers; w++) + { + nFirst = nLast; + nLast = tot*(w+1)/nWorkers; + worker[w] = new TWorker(pFunc, pCaller, pData, nFirst, nLast, tot, pi, w); + } + + for (w = 0; w < nWorkers; w++) + worker[w]->Run(); + + if (pi != nullptr) + pi->Refresh(); + + for (w = 0; w < nWorkers; w++) + { + const wxThread::ExitCode r = worker[w]->Wait(); + if (ret == 0 && r != 0) + ret = int(r); + delete worker[w]; + worker[w] = nullptr; + } + + if (pi != nullptr) + delete pi; + } + else + { + if (msg && *msg) + { + TProgressIndicator pi(size_t(tot), msg, tot > nWorkers); + for (int i = 0; i < tot && ret == 0; i++) + { + ret = pFunc(pCaller, pData, i, tot); + if (!pi.SetProgress(i+1)) + ret = -1; + } + } + else + { + for (int i = 0; i < tot && ret == 0; i++) + ret = pFunc(pCaller, pData, i, tot); + } + } + + return ret; +} + +XVTDLL char * xvt_GUID() +{ + strstream strguid; + + strguid << xg::newGuid() << '\0'; + return strguid.str(); +} \ No newline at end of file diff --git a/src/xvaga01/agasys.h b/src/xvaga01/agasys.h new file mode 100644 index 000000000..cb32c0de7 --- /dev/null +++ b/src/xvaga01/agasys.h @@ -0,0 +1,25 @@ +#ifndef __AGASYS_H__ +#define __AGASYS_H__ + +#ifdef WIN32 +#if XVAGADLL == 1 + #define XVTDLL __declspec(dllexport) +#else + #define XVTDLL __declspec(dllimport) +#endif +#else +#define XVTDLL +#endif + +XVTDLL bool aga_unzip(const char* zipfile, const char* destdir); +XVTDLL bool aga_zip(const char* zipmask, const char* zipfile); +XVTDLL bool aga_zip_filelist(const char* filelist, const char* zipfile); + +XVTDLL unsigned long aga_dde_connect(const char* host, const char* service, const char* topic); +XVTDLL bool aga_dde_execute(unsigned long connection, const char* command); +XVTDLL bool aga_dde_execute_async(unsigned long connection, const char* command); +XVTDLL bool aga_dde_poke(unsigned long connection, const char* item, const char* data); +XVTDLL int aga_dde_request(unsigned long connection, const char* item, char* data, int max_size); +XVTDLL bool aga_dde_terminate(unsigned long connection); + +#endif diff --git a/src/xvaga01/checksum.md5 b/src/xvaga01/checksum.md5 new file mode 100644 index 000000000..b29d75992 --- /dev/null +++ b/src/xvaga01/checksum.md5 @@ -0,0 +1,4 @@ +; MD5 checksums created by TeraCopy +; teracopy.com + +DD6B72874B85200006D9EDCA2FC2DB23 *xvt_sw.cpp diff --git a/src/xvaga01/fastapi.h b/src/xvaga01/fastapi.h new file mode 100644 index 000000000..8af877e48 --- /dev/null +++ b/src/xvaga01/fastapi.h @@ -0,0 +1,697 @@ +/****************************************************************************/ +/** **/ +/** Hardlock **/ +/** API-Structures and definitions **/ +/** **/ +/** This file contains some helpful defines to access a Hardlock using **/ +/** the application programming interface (API) for Hardlock. **/ +/** **/ +/** Aladdin Germany **/ +/** **/ +/** Revision history **/ +/** ---------------- +*** $Log: not supported by cvs2svn $ +*** Revision 1.52 2003/04/30 12:21:14 chris +*** fix structure packing for Borland +*** +*** Revision 1.51 2003/02/24 08:00:28 werner +*** Added RUS-Flag: DISABLE_TS_CHECK for Terminal Server detection +*** +*** Revision 1.50 2003/01/30 09:48:13 axel +*** added functions API_GETHLSADDR 108, API_GETHLSTEXT 109 +*** added error NO_LOCAL_FUNCTION 61 +*** +*** Revision 1.49 2002/08/23 10:47:10 axel +*** added API_READ_HLS, API_CALC_HLS and NO_REMOTE_FUNCTION +*** (used for detecting HL-Server Hardlock licenses) +*** +*** Revision 1.48 2002/08/22 16:15:27 alex +*** added define _AKS_QT_APPLICATION_ if you want to compile with Qt, +*** because slots from lic structure is a Qt keyword +*** +*** Revision 1.47 2002/03/18 13:24:34 chris +*** Win64 changes +*** +*** Revision 1.46 2000/12/19 16:37:41 chris +*** detect MacOS X +*** +*** Revision 1.45 2000/07/30 22:22:17 chris +*** ia64 detection +*** +*** Revision 1.44 2000/07/10 09:45:09 chris +*** Module2 field +*** +*** Revision 1.43 2000/05/25 14:11:43 chris +*** added some HASP stuff +*** +*** Revision 1.42 2000/03/21 14:18:28 chris +*** HL_SIS and HL_LIS structure definitions +*** +*** Revision 1.41 2000/02/18 14:04:44 chris +*** fixed pascal define for CygWin & MingW32 +*** +*** Revision 1.40 1999/12/06 13:06:11 chris +*** fixed structure packing for MSC compiler +*** +*** Revision 1.39 1999/11/28 01:39:46 chris +*** added 64bit support (only tested with AlphaLinux currently) +*** +*** Revision 1.38 1999/10/07 11:28:45 chris +*** Duplicate revision +*** +*** Revision 1.37 1999/10/07 11:28:45 Henri +*** Removed uneeded TLV defines. +*** +*** Revision 1.36 1999/10/07 10:47:04 Henri +*** Removed unused flags. +*** +*** Revision 1.35 1999/09/30 09:27:46 Henri +*** Added PORT_BUSY. +*** +*** Revision 1.34 1999/09/24 07:49:43 Werner +*** Added RUS_RTB_EXPIRED and RUS_SERIAL_MISMATCH +*** error codes. +*** +*** Revision 1.33 1999/09/21 12:06:57 Henri +*** Arranged error codes. +*** +*** Revision 1.32 1999/09/20 12:56:28 Werner +*** Added FORCE_ALF_CREATE constant. +*** +*** Revision 1.31 1999/09/15 17:04:18 Henri +*** Changed WriteLicense. +*** +*** Revision 1.30 1999/09/01 15:06:44 Adi +*** Added special handling of global expiration date. +*** +*** Revision 1.29 1999/08/16 13:03:58 chris +*** restore previous structure packing after HL_API definition +*** (for MSVC) +*** +*** Revision 1.28 1999/08/08 23:10:55 chris +*** added 2 bytes to reserved field: API structure was 2 bytes too short +*** +*** Revision 1.27 1999/08/04 13:04:41 chris +*** API_FFS_GETRUSINFO define +*** +*** Revision 1.26 1999/08/04 11:03:33 chris +*** API_FFS_WRITE_LIC definition and some more status codes +*** +*** Revision 1.25 1999/08/03 20:36:15 chris +*** renamed FIB structure to RUS_FIB to avoid clash +*** with api_defs.h +*** +*** Revision 1.24 1999/07/26 10:58:28 Henri +*** Added FIB structure. +*** +*** Revision 1.23 1999/07/19 10:29:35 Henri +*** Renamed define for BUFFER_TOO_SMALL +*** +*** Revision 1.22 1999/07/19 10:11:30 Henri +*** Added RUS functionality. +*** +*** Revision 1.21 1998/10/21 15:56:53 Henri +*** Changed defines for Borland Builder. +*** +*** Revision 1.20 1998/08/14 11:33:54 Henri +*** Changed driver comment. +*** +*** Revision 1.19 1998/07/10 12:34:05 Henri +*** Added define for Borland Builder. +*** +*** Revision 1.18 1998/06/29 09:01:36 Henri +*** Extended API struc. +*** +*** Revision 1.17 1998/06/08 16:36:31 chris +*** fixed structure packing on gcc version 2.7 and above +*** +*** Revision 1.16 1998/05/08 14:11:33 Henri +*** Added defines for HL_READID. +*** +*** Revision 1.15 1998/04/07 13:14:59 chris +*** added API_READ_ID function code +*** +*** Revision 1.14 1998/02/17 21:56:19 Henri +*** Added pragma pack(1) for Watcom 11/DOS +*** +*** Revision 1.13 1997/07/01 13:56:54 henri +*** Fixed defines for LabView. +*** +*** Revision 1.12 1997/04/28 15:30:53 chris +*** define UNIX32 ifdef __QNX__ +*** +*** Revision 1.11 1997/02/03 18:08:36 henri +*** Renamed error 17 +*** +*** Revision 1.10 1997/01/30 17:16:55 henri +*** Added LM return codes. +*** +*** Revision 1.9 1997/01/28 08:23:30 henri +*** Missed a semicolon ;-) +*** +*** Revision 1.8 1997/01/27 17:57:11 henri +*** Added slot number in API structure. +*** +*** Revision 1.7 1997/01/16 18:18:11 henri +*** Added API_LMINIT function code. +*** +*** Revision 1.6 1996/11/13 16:55:49 chris +*** added SOLARIS & UNIX32 define +*** +*** Revision 1.5 1996/08/12 16:23:43 henri +*** Added VCS log. +*** +**/ +/****************************************************************************/ + +#if !defined(_FASTAPI_H_) +#define _FASTAPI_H_ + +#if defined(LINUX) || defined(SOLARIS) || defined(SCO) || defined(__QNX__) || defined(DARWIN) || defined(MACOSX) + #define UNIX32 + #if defined(__alpha__) || defined(__ia64__) + #ifndef __64BIT__ + #define __64BIT__ + #endif + #define NO_UNALIGN + #endif +#endif + +#ifdef __OS2__ + #ifdef INTERNAL_16BITDLL + #define LOAD_DS + #else + #ifdef __WATCOMC__ + #ifdef __386__ /* not the 16bit compiler */ + #include + #endif + #else + #include + #endif + #endif + #ifdef OS_16 + #define RET_ Word + #define FAR_ far pascal + #define DATAFAR_ far + #else + #define RET_ APIRET + #define FAR_ + #define CALL_ APIENTRY + #define DATAFAR_ + #endif + #pragma pack(2) +#endif + +#ifdef UNIX32 + #define __386__ + #define pascal + #pragma pack(1) +#endif + +#ifdef __GNUC__ + #define __386__ + #if !defined(__CYGWIN__) && !defined(__MINGW32__) + #define pascal + #endif + #if ((__GNUC__==2) && (__GNUC_MINOR__>=7)) || (__GNUC__>2) + #define ALIGN_GCC __attribute__ ((__packed__)) + #ifdef NO_UNALIGN + #define AS_ALIGN __attribute__ ((__aligned__(8))) + #endif + #else + #pragma pack(1) + #endif +#endif + +#ifdef _MSC_VER +#if _MSC_VER >= 900 + #pragma pack(push,_fastapi_h_,1) +#else + #pragma pack(1) +#endif +#endif + +#ifdef __BORLANDC__ + #pragma pack(1) +#endif + +#if defined(WINNT) || defined(__WIN32__) || defined(_WIN32) + #if !defined(_WIN64) && !defined(WIN64) + #ifndef __386__ /* Watcom doesnt like it */ + #define __386__ + #endif + #endif + #ifdef DLL + #define CALL_ __stdcall + #else + #define CALL_ + #endif +#endif + +#if defined(_WIN64) || defined(WIN64) + #ifndef __64BIT__ + #define __64BIT__ + #endif + #define DATAFAR_ + #define FAR_ + #define pascal __stdcall +#endif + +#ifdef DOS386 /* Symantec C */ + #define __386__ + #pragma pack(2) +#endif + +#ifdef __HIGHC__ /* Metaware High C */ + #define __386__ + #define _PACKED _Packed +#endif + +#ifdef __ZTC__ /* Zortech C */ + #define __386__ +#endif + +#ifdef SALFORD /* Salford C */ + #define ALIGN_ 8 +#endif + +#ifdef __WATCOMC__ + #pragma pack(1) + #ifndef __386__ + #ifndef OS_16 + #define CALL_ cdecl + #endif + #endif +#endif + +#ifdef _CVI_ /* LabWindows/CVI */ + #define RET_ Word + #ifndef _NI_mswin32_ + #define CALL_ pascal + #else /* No pascal in WIN32-Version of LabWindows/CVI 4.0.1 */ + #define CALL_ _stdcall + #endif + #ifndef __386__ /* __386__ defined by LabWindows/CVI */ + #define FAR_ far + #define DATAFAR_ far + #endif +#endif + +#ifdef __386__ + #define DATAFAR_ + #define FAR_ +#endif + +#ifdef HLHIGH_DLL + #define CALL_ pascal _export +#endif + +#ifdef LOAD_DS + #define CALL_ _loadds +#endif + +#ifndef CALL_ + #define CALL_ +#endif + +#ifndef _PACKED + #define _PACKED +#endif + +#ifndef ALIGN_GCC +# define ALIGN_GCC +#endif + +#ifndef DATAFAR_ + #define DATAFAR_ far +#endif + +#ifndef FAR_ + #define FAR_ far +#endif + +#ifndef RET_ + #define RET_ Word +#endif + +#ifndef ALIGN_ + #define ALIGN_ +#endif + +#ifndef AS_ALIGN + #define AS_ALIGN +#endif + +/* -------------------------------- */ +/* Definitions and API structures : */ +/* -------------------------------- */ +#ifdef __64BIT__ +typedef unsigned int Long; +#if !defined(_WIN64) && !defined(WIN64) +typedef unsigned long Int64; +#else +typedef unsigned __int64 Int64; /* stupid Windows convention */ +#endif +#else +typedef unsigned long Long; +#endif +#ifndef __BCPLUSPLUS__ + typedef unsigned char Byte; + typedef unsigned short Word; +#else + #ifndef VCL_H + typedef unsigned char Byte; + typedef unsigned short Word; + #endif +#endif +#ifndef __64BIT__ +#define set_data_ptr(api,buf) (api)->Data=(Byte DATAFAR_ *)(buf) +#define get_data_ptr(api) ((void *)((api)->Data)) +#else /* above macros for <=32 bit, below macros for >32 bit */ +#define set_data_ptr(api,buf) do { (api)->Data=(((Long)(buf)) & 0xffffffffu); \ + (api)->DataHigh=(((Long)(((Int64)(buf))>>32)) \ + & 0xffffffffu);} while (0) +#define get_data_ptr(api) ((void *)((Int64)((api)->Data) | \ + (((Int64)((api)->DataHigh))<<32))) +#endif + +typedef struct + { + Word Use_Key; + Byte Key[8]; + } ALIGN_GCC DES_MODE; + +typedef struct + { + Word ModAd; /* Hardlock module address */ + Word Reg; /* Memory register adress */ + Word Value; /* Memory value */ + Byte Reserved[4]; + } ALIGN_GCC EYE_MODE; + +typedef struct + { + Long PW1; /* HASP passwords */ + Long PW2; + Word P1; + } ALIGN_GCC HASP_MODE; + +typedef struct + { + Word LT_Reserved; + Word Reg; /* Memory register adress */ + Word Value; /* Memory value */ + Word Password[2]; /* Access passwords */ + } ALIGN_GCC LT_MODE; + +typedef union + { + DES_MODE Des; + EYE_MODE Eye; + LT_MODE Lt; + HASP_MODE Hasp; + } HARDWARE; + +typedef struct + { + Word P2; + Word P3; + } ALIGN_GCC HASP_MODE2; + +typedef union + { + HASP_MODE2 Hasp2; + } HARDWARE2; + +typedef struct rus_fib + { + Byte MARKER[2]; + Long SERIAL_ID; + Byte VERSION[2]; + Word FIXED; + Word VAR; + Word CRC; + } ALIGN_GCC RUS_FIB; + +typedef _PACKED struct ALIGN_ hl_api + { + Byte API_Version_ID[2]; /* Version */ + Word API_Options[2]; /* API Optionflags */ + Word ModID; /* Modul-ID (EYE = 0...) */ + HARDWARE Module; /* Hardware type */ + +#ifdef __OS2__ /* Pointer to cipher data */ + #ifdef OS_16 + void far *Data; + #else + #ifdef __BORLANDC__ + void FAR16PTR Data; + #else + void * _Seg16 Data; + #endif + #endif +#else + #ifndef __64BIT__ + void DATAFAR_ *Data; + #else + Long Data; /* low part only */ + #endif +#endif + + Word Bcnt; /* Number of blocks */ + Word Function; /* Function number */ + Word Status; /* Actual status */ + Word Remote; /* Remote or local?? */ + Word Port; /* Port address if local */ + Word Speed; /* Speed of port if local */ + Word NetUsers; /* Current Logins (HL-Server) */ + Byte ID_Ref[8]; /* Referencestring */ + Byte ID_Verify[8]; /* Encrypted ID_Ref */ + Long Task_ID; /* Multitasking program ID */ + Word MaxUsers; /* Maximum Logins (HL-Server) */ + Long Timeout; /* Login Timeout in minutes */ + Word ShortLife; /* (multiple use) */ + Word Application; /* Application number */ + Word Protocol; /* Protocol flags */ + Word PM_Host; /* DOS Extender type */ + Long OSspecific; /* ptr to OS specific data */ + Word PortMask; /* Default local search (in) */ + Word PortFlags; /* Default local search (out) */ + Word EnvMask; /* Use env string search (in) */ + Word EnvFlags; /* Use env string search (out) */ + Byte EEFlags; /* EE type flags */ + Word Prot4Info; /* (internal use) */ + Byte FuncOptions; /* Enable add. functionality */ + Word Slot_ID; /* Licence slot number */ + Word Slot_ID_HIGH; /* Licence slot High value */ + Word RUS_ExpDate; /* RUS Expiration date */ + Long DataHigh; /* Pointer to data high value */ +#ifndef __64BIT__ + void DATAFAR_ *VendorKey; /* Pointer to RUS vendor key */ +#else + Long VendorKey; /* dto. */ +#endif + Long VendorKeyHigh; /* Vendor key high value */ + Long OSspecificHigh; /* ptr to OS specific data */ + Long RUS_MaxInfo; /* RUS max user/counter */ + Long RUS_CurInfo; /* RUS current user/counter */ + RUS_FIB RUS_Fib; /* RUS FIB structure */ + HARDWARE2 Module2; /* 2nd hw dependend fields */ + Byte Reserved2[122]; /* Reserved area */ + } ALIGN_GCC AS_ALIGN HL_API, LT_API, HS_API; + +typedef _PACKED struct ALIGN_ { /* HL_LIS slot information */ + Long max_user; + Long cur_user; + Word exp_date; + Byte flag; /* singularity flag */ + Byte res; /* filler to make structure size multiple of 4 bytes */ +} ALIGN_GCC HL_SIS; + +/* License Information Structure (HL_LIS) */ +typedef _PACKED struct ALIGN_ { + Word current_date; + Word res; + Long num_slots; + Word glob_exp_date; + Word res2; /* filler to make size multiple of 4 bytes */ +#ifdef __AKS_QT_APPLICATION__ + HL_SIS slot[1]; /* slots is a keyword in Qt application, renamed array */ +#else + HL_SIS slots[1]; + #endif +} ALIGN_GCC HL_LIS; + +#ifdef UNIX32 + #pragma pack() +#endif + +#ifdef __OS2__ + #pragma pack() +#endif + +#ifdef __BORLANDC__ + #pragma pack(1) +#endif + +#ifdef _MSC_VER +#if _MSC_VER >= 900 + #pragma pack(pop,_fastapi_h_) +#else + #pragma pack() +#endif +#endif + + +/* ------------- */ +/* Module-ID's : */ +/* ------------- */ +#define EYE_DONGLE 0 /* Hardlock E-Y-E */ +#define DES_DONGLE 1 /* FAST DES */ +#define LT_DONGLE 3 /* Hardlock LT */ +#define HASP_DONGLE 4 /* HASP */ + +/* --------------------- */ +/* API function calls : */ +/* --------------------- */ +#define API_INIT 0 /* Init API structure */ +#define API_DOWN 1 /* Free API structure */ +#define API_FORCE_DOWN 31 /* Force deinintialization */ +#define API_MULTI_SHELL_ON 2 /* MTS is enabled */ +#define API_MULTI_SHELL_OFF 3 /* MTS is disabled */ +#define API_MULTI_ON 4 /* Enable MTS */ +#define API_MULTI_OFF 5 /* Disable MTS */ +#define API_AVAIL 6 /* Dongle available? */ +#define API_LOGIN 7 /* Login dongle server */ +#define API_LOGOUT 8 /* Logout dongle server */ +#define API_INFO 9 /* Get API informations */ +#define API_GET_TASKID 32 /* Get TaskID from API */ +#define API_LOGIN_INFO 34 /* Get API Login informations */ + +/* --------------------------- */ +/* Data and memory functions : */ +/* --------------------------- */ +#define API_KEYE 11 /* Use KEYE for encryption */ +#define API_READ 20 /* Read one word of dongle EEPROM */ +#define API_WRITE 21 /* Write one word of dongle EEPROM */ +#define API_READ_BLOCK 23 /* Read EEPROM in one block */ +#define API_WRITE_BLOCK 24 /* Write EEPROM in one block */ +#define API_READ_ID 29 /* Read USB ID memory */ +#define API_ABORT 51 /* Critical Error Abort */ + +/* -------------- */ +/* LM functions : */ +/* -------------- */ +#define API_LMINIT 40 /* LM compatible API_INIT replacement */ +#define API_LMPING 41 /* checks if LM dongle and slot is available */ +#define API_LMINFO 42 /* info about currently used LIMA */ + +#define API_READ_HLS 78 /* get number of licences for USB server HL */ +#define API_CALC_HLS 79 /* calculate num of licenses for parallel server HL */ + + +#define API_GETHLSADDR 108 /* get addr struc of currently used HLS */ +#define API_GETHLSTEXT 109 /* get text addr of currently used HLS */ + + +/* --------------- */ +/* RUS functions : */ +/* --------------- */ +#define API_FFS_INIT 256 /* RUS init function, downed with API_DOWN */ +#define API_FFS_ISRUSHL 257 /* Is RUS HL ? */ +#define API_FFS_LOGIN 258 /* RUS Login to Hardlock server */ +#define API_FFS_CHECK_LIC 259 /* RUS Create LIS */ +#define API_FFS_READ_LICBLOCK 260 /* RUS Read LIC Block */ +#define API_FFS_QUERY_SLOT 261 /* RUS query slot function */ +#define API_FFS_FREE_SLOT 262 /* RUS free slot */ +#define API_FFS_OCCUPY_SLOT 263 /* RUS occupies a slot */ +#define API_FFS_INC_CNTR 264 /* RUS counter increment */ +#define API_FFS_PARSERTB 265 /* RUS Parse RTB */ +#define API_FFS_GET_HWDEP_INFO 266 /* RUS get hardware dependent information */ +#define API_FFS_WRITE_LIC 267 /* RUS write updated license information */ +#define API_FFS_GETRUSINFO 269 /* get RUS info */ + +/* -------------------- */ +/* Dongle access mode : */ +/* -------------------- */ +#define LOCAL_DEVICE 1 /* Query local HL only */ +#define NET_DEVICE 2 /* Query remote HL only */ +#define DONT_CARE 3 /* Query local or remote HL */ + +/* -------------------- */ +/* EnvMask/Port Flags : */ +/* -------------------- */ +#define USB_DEVICE 256 /* Port flag for USB use */ +#define IGNORE_ENVIRONMENT 0x8000 /* Ignore HL_SEARCH */ +#define EEF_NOAUTOUSB 8 /* No automatic USB search */ + +/* ---------- */ +/* RUS flags: */ +/* ---------- */ +#define FORCE_RUS 1 /* Enable RUS init without VK */ +#define DISABLE_TS_CHECK 2 /* Disable Terminal Server Detection */ +#define FORCE_ALF_CREATE 1 /* Force creation of ALF file in HLM_WRITELICENSE */ + +/* ------------------ */ +/* API PM_Host ID's : */ +/* ------------------ */ +#define API_XTD_DETECT 0 +#define API_XTD_DPMI 1 /* QDPMI, Borland, Windows ... */ +#define API_XTD_PHAR386 2 +#define API_XTD_PHAR286 3 +#define API_XTD_CODEBLDR 4 /* Intel Code Builder */ +#define API_XTD_COBOLXM 5 + +/* ------------------ */ +/* API Status Codes : */ +/* ------------------ */ +#define STATUS_OK 0 /* API call was succesfull */ +#define NOT_INIT 1 /* DONGLE not initialized */ +#define ALREADY_INIT 2 /* Already initialized */ +#define UNKNOWN_DONGLE 3 /* Device not supported */ +#define UNKNOWN_FUNCTION 4 /* Function not supported */ +#define HLS_FULL 6 /* HL-Server login table full */ +#define NO_DONGLE 7 /* No device available */ +#define NETWORK_ERROR 8 /* A network error occured */ +#define NO_ACCESS 9 /* No device available */ +#define INVALID_PARAM 10 /* A wrong parameter occured */ +#define VERSION_MISMATCH 11 /* HL-Server not API version */ +#define DOS_ALLOC_ERROR 12 /* Error on memory allocation */ +#define CANNOT_OPEN_DRIVER 14 /* Can not open Hardlock driver */ +#define INVALID_ENV 15 /* Invalid environment string */ +#define DYNALINK_FAILED 16 /* Unable to get a function entry */ +#define INVALID_LIC 17 /* No valid licence info (LM) */ +#define NO_LICENSE 18 /* Slot/licence not enabled (LM) */ +#define PORT_BUSY 19 /* Cannot acquire port */ +#define RUS_NO_DEVICE 20 /* Key is no Hardlock RUS key */ +#define RUS_INVALID_LIC 21 /* Invalid RUS license */ +#define RUS_SYNC_ERR 22 /* FIB in key and api struc mismatch */ +#define NOT_IMPLEMENTED 23 /* not (yet) implemented */ +#define BUFFER_TOO_SMALL 24 /* Buffer for function too small */ +#define UNKNOWN_HW_TYPE 25 /* unknown hardware descriptor */ +#define RUS_INV_FBPOS 26 /* unknown fixed block position */ +#define RUS_INVALID_SLOT 27 /* Non-existing slot number given */ +#define RUS_DATE_FAKE 28 /* RUS Date fake detected */ +#define RUS_COUNT_DOWN 29 /* RUS dead counter limit reached */ +#define RUS_INVALID_VK 30 /* RUS Vendor key is invalid */ +#define RUS_NO_LIC_FILE 31 /* RUS License file not found */ +#define RUS_INV_VBLOCK 32 /* RUS invalid variable block */ +#define RUS_LIC_FILE_WRITE_ERR 33 /* error writing (updated) license file */ +#define RUS_NO_INFO_AVAILABLE 34 /* GET_HWDEP_INFO: no info there */ +#define RUS_INFO_PACK_ERR 35 /* " " " " : cannot TLV encode data */ +#define RUS_LIC_WRITE_ERR 36 /* write license failed */ +#define RUS_DATE_EXPIRED 37 /* RUS Expiration Date reached. */ +#define TS_DETECTED 38 /* Term. Server / Citrix Winframe detected*/ +#define RUS_INVALID_RTB 39 /* Invalid updated data (RTB) */ +#define RUS_RTB_EXPIRED 40 /* Update data (RTB) has expired. */ +#define RUS_SERIAL_MISMATCH 41 /* Update data serial does not match */ +#define NO_REMOTE_FUNCTION 60 /* function is available locally only */ +#define NO_LOCAL_FUNCTION 61 /* function is available remotely only */ + +#define TOO_MANY_USERS 256 /* Login table full (remote) */ +#define SELECT_DOWN 257 /* Printer not On-line */ +#define NO_SERIALID 258 /* Serial ID not readable or n/a */ + +#endif /*_FASTAPI_H_*/ +/* eof */ + diff --git a/src/xvaga01/fstrcmp.c b/src/xvaga01/fstrcmp.c new file mode 100644 index 000000000..b95dc38ad --- /dev/null +++ b/src/xvaga01/fstrcmp.c @@ -0,0 +1,607 @@ +/* Functions to make fuzzy comparisons between strings + Copyright (C) 1988-1989, 1992-1993, 1995, 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + Derived from GNU diff 2.7, analyze.c et al. + + The basic algorithm is described in: + "An O(ND) Difference Algorithm and its Variations", Eugene Myers, + Algorithmica Vol. 1 No. 2, 1986, pp. 251-266; + see especially section 4.2, which describes the variation used below. + + The basic algorithm was independently discovered as described in: + "Algorithms for Approximate String Matching", E. Ukkonen, + Information and Control Vol. 64, 1985, pp. 100-118. + + Modified to work on strings rather than files + by Peter Miller , October 1995 */ + +/* Specification. */ +#include "fstrcmp.h" + +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#endif + +/* + * Data on one input string being compared. + */ +struct string_data +{ + /* The string to be compared. */ + const char *data; + + /* The length of the string to be compared. */ + int data_length; + + /* The number of characters inserted or deleted. */ + int edit_count; +}; + +static struct string_data string[2]; + + +#ifdef MINUS_H_FLAG + +/* This corresponds to the diff -H flag. With this heuristic, for + strings with a constant small density of changes, the algorithm is + linear in the strings size. This is unlikely in typical uses of + fstrcmp, and so is usually compiled out. Besides, there is no + interface to set it true. */ +static int heuristic; + +#endif + + +/* Vector, indexed by diagonal, containing 1 + the X coordinate of the + point furthest along the given diagonal in the forward search of the + edit matrix. */ +static int *fdiag; + +/* Vector, indexed by diagonal, containing the X coordinate of the point + furthest along the given diagonal in the backward search of the edit + matrix. */ +static int *bdiag; + +/* Edit scripts longer than this are too expensive to compute. */ +static int too_expensive; + +/* Snakes bigger than this are considered `big'. */ +#define SNAKE_LIMIT 20 + +struct partition +{ + /* Midpoints of this partition. */ + int xmid, ymid; + + /* Nonzero if low half will be analyzed minimally. */ + int lo_minimal; + + /* Likewise for high half. */ + int hi_minimal; +}; + + +/* NAME + diag - find diagonal path + + SYNOPSIS + int diag(int xoff, int xlim, int yoff, int ylim, int minimal, + struct partition *part); + + DESCRIPTION + Find the midpoint of the shortest edit script for a specified + portion of the two strings. + + Scan from the beginnings of the strings, and simultaneously from + the ends, doing a breadth-first search through the space of + edit-sequence. When the two searches meet, we have found the + midpoint of the shortest edit sequence. + + If MINIMAL is nonzero, find the minimal edit script regardless + of expense. Otherwise, if the search is too expensive, use + heuristics to stop the search and report a suboptimal answer. + + RETURNS + Set PART->(XMID,YMID) to the midpoint (XMID,YMID). The diagonal + number XMID - YMID equals the number of inserted characters + minus the number of deleted characters (counting only characters + before the midpoint). Return the approximate edit cost; this is + the total number of characters inserted or deleted (counting + only characters before the midpoint), unless a heuristic is used + to terminate the search prematurely. + + Set PART->LEFT_MINIMAL to nonzero iff the minimal edit script + for the left half of the partition is known; similarly for + PART->RIGHT_MINIMAL. + + CAVEAT + This function assumes that the first characters of the specified + portions of the two strings do not match, and likewise that the + last characters do not match. The caller must trim matching + characters from the beginning and end of the portions it is + going to specify. + + If we return the "wrong" partitions, the worst this can do is + cause suboptimal diff output. It cannot cause incorrect diff + output. */ + +static int diag (int xoff, int xlim, int yoff, int ylim, int minimal, struct partition * part) +{ + int *const fd = fdiag; /* Give the compiler a chance. */ + int *const bd = bdiag; /* Additional help for the compiler. */ + const char *const xv = string[0].data; /* Still more help for the compiler. */ + const char *const yv = string[1].data; /* And more and more . . . */ + const int dmin = xoff - ylim; /* Minimum valid diagonal. */ + const int dmax = xlim - yoff; /* Maximum valid diagonal. */ + const int fmid = xoff - yoff; /* Center diagonal of top-down search. */ + const int bmid = xlim - ylim; /* Center diagonal of bottom-up search. */ + int fmin = fmid; + int fmax = fmid; /* Limits of top-down search. */ + int bmin = bmid; + int bmax = bmid; /* Limits of bottom-up search. */ + int c; /* Cost. */ + int odd = (fmid - bmid) & 1; + + /* + * True if southeast corner is on an odd diagonal with respect + * to the northwest. + */ + fd[fmid] = xoff; + bd[bmid] = xlim; + for (c = 1;; ++c) + { + int d; /* Active diagonal. */ + int big_snake; + + big_snake = 0; + /* Extend the top-down search by an edit step in each diagonal. */ + if (fmin > dmin) + fd[--fmin - 1] = -1; + else + ++fmin; + if (fmax < dmax) + fd[++fmax + 1] = -1; + else + --fmax; + for (d = fmax; d >= fmin; d -= 2) + { + int x; + int y; + int oldx; + int tlo; + int thi; + + tlo = fd[d - 1], + thi = fd[d + 1]; + + if (tlo >= thi) + x = tlo + 1; + else + x = thi; + oldx = x; + y = x - d; + while (x < xlim && y < ylim && xv[x] == yv[y]) + { + ++x; + ++y; + } + if (x - oldx > SNAKE_LIMIT) + big_snake = 1; + fd[d] = x; + if (odd && bmin <= d && d <= bmax && bd[d] <= x) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c - 1; + } + } + /* Similarly extend the bottom-up search. */ + if (bmin > dmin) + bd[--bmin - 1] = INT_MAX; + else + ++bmin; + if (bmax < dmax) + bd[++bmax + 1] = INT_MAX; + else + --bmax; + for (d = bmax; d >= bmin; d -= 2) + { + int x; + int y; + int oldx; + int tlo; + int thi; + + tlo = bd[d - 1], + thi = bd[d + 1]; + if (tlo < thi) + x = tlo; + else + x = thi - 1; + oldx = x; + y = x - d; + while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) + { + --x; + --y; + } + if (oldx - x > SNAKE_LIMIT) + big_snake = 1; + bd[d] = x; + if (!odd && fmin <= d && d <= fmax && x <= fd[d]) + { + part->xmid = x; + part->ymid = y; + part->lo_minimal = part->hi_minimal = 1; + return 2 * c; + } + } + + if (minimal) + continue; + +#ifdef MINUS_H_FLAG + /* Heuristic: check occasionally for a diagonal that has made lots + of progress compared with the edit distance. If we have any + such, find the one that has made the most progress and return + it as if it had succeeded. + + With this heuristic, for strings with a constant small density + of changes, the algorithm is linear in the strings size. */ + if (c > 200 && big_snake && heuristic) + { + int best; + + best = 0; + for (d = fmax; d >= fmin; d -= 2) + { + int dd; + int x; + int y; + int v; + + dd = d - fmid; + x = fd[d]; + y = x - d; + v = (x - xoff) * 2 - dd; + + if (v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if + ( + v > best + && + xoff + SNAKE_LIMIT <= x + && + x < xlim + && + yoff + SNAKE_LIMIT <= y + && + y < ylim + ) + { + /* We have a good enough best diagonal; now insist + that it end with a significant snake. */ + int k; + + for (k = 1; xv[x - k] == yv[y - k]; k++) + { + if (k == SNAKE_LIMIT) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + } + if (best > 0) + { + part->lo_minimal = 1; + part->hi_minimal = 0; + return 2 * c - 1; + } + best = 0; + for (d = bmax; d >= bmin; d -= 2) + { + int dd; + int x; + int y; + int v; + + dd = d - bmid; + x = bd[d]; + y = x - d; + v = (xlim - x) * 2 + dd; + + if (v > 12 * (c + (dd < 0 ? -dd : dd))) + { + if (v > best && xoff < x && x <= xlim - SNAKE_LIMIT && + yoff < y && y <= ylim - SNAKE_LIMIT) + { + /* We have a good enough best diagonal; now insist + that it end with a significant snake. */ + int k; + + for (k = 0; xv[x + k] == yv[y + k]; k++) + { + if (k == SNAKE_LIMIT - 1) + { + best = v; + part->xmid = x; + part->ymid = y; + break; + } + } + } + } + } + if (best > 0) + { + part->lo_minimal = 0; + part->hi_minimal = 1; + return 2 * c - 1; + } + } +#endif /* MINUS_H_FLAG */ + + /* Heuristic: if we've gone well beyond the call of duty, give up + and report halfway between our best results so far. */ + if (c >= too_expensive) + { + int fxybest; + int fxbest; + int bxybest; + int bxbest; + + /* Pacify `gcc -Wall'. */ + fxbest = 0; + bxbest = 0; + + /* Find forward diagonal that maximizes X + Y. */ + fxybest = -1; + for (d = fmax; d >= fmin; d -= 2) + { + int x; + int y; + + x = fd[d] < xlim ? fd[d] : xlim; + y = x - d; + + if (ylim < y) + { + x = ylim + d; + y = ylim; + } + if (fxybest < x + y) + { + fxybest = x + y; + fxbest = x; + } + } + /* Find backward diagonal that minimizes X + Y. */ + bxybest = INT_MAX; + for (d = bmax; d >= bmin; d -= 2) + { + int x; + int y; + + x = xoff > bd[d] ? xoff : bd[d]; + y = x - d; + + if (y < yoff) + { + x = yoff + d; + y = yoff; + } + if (x + y < bxybest) + { + bxybest = x + y; + bxbest = x; + } + } + /* Use the better of the two diagonals. */ + if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff)) + { + part->xmid = fxbest; + part->ymid = fxybest - fxbest; + part->lo_minimal = 1; + part->hi_minimal = 0; + } + else + { + part->xmid = bxbest; + part->ymid = bxybest - bxbest; + part->lo_minimal = 0; + part->hi_minimal = 1; + } + return 2 * c - 1; + } + } +} + + +/* NAME + compareseq - find edit sequence + + SYNOPSIS + void compareseq(int xoff, int xlim, int yoff, int ylim, int minimal); + + DESCRIPTION + Compare in detail contiguous subsequences of the two strings + which are known, as a whole, to match each other. + + The subsequence of string 0 is [XOFF, XLIM) and likewise for + string 1. + + Note that XLIM, YLIM are exclusive bounds. All character + numbers are origin-0. + + If MINIMAL is nonzero, find a minimal difference no matter how + expensive it is. */ + +static void compareseq (int xoff, int xlim, int yoff, int ylim, int minimal) +{ + const char *const xv = string[0].data; /* Help the compiler. */ + const char *const yv = string[1].data; + + /* Slide down the bottom initial diagonal. */ + while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff]) + { + ++xoff; + ++yoff; + } + + /* Slide up the top initial diagonal. */ + while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1]) + { + --xlim; + --ylim; + } + + /* Handle simple cases. */ + if (xoff == xlim) + { + while (yoff < ylim) + { + ++string[1].edit_count; + ++yoff; + } + } + else if (yoff == ylim) + { + while (xoff < xlim) + { + ++string[0].edit_count; + ++xoff; + } + } + else + { + int c; + struct partition part; + + /* Find a point of correspondence in the middle of the strings. */ + c = diag (xoff, xlim, yoff, ylim, minimal, &part); + if (c == 1) + { +#if 0 + /* This should be impossible, because it implies that one of + the two subsequences is empty, and that case was handled + above without calling `diag'. Let's verify that this is + true. */ + abort (); +#else + /* The two subsequences differ by a single insert or delete; + record it and we are done. */ + if (part.xmid - part.ymid < xoff - yoff) + ++string[1].edit_count; + else + ++string[0].edit_count; +#endif + } + else + { + /* Use the partitions to split this problem into subproblems. */ + compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal); + compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal); + } + } +} + + +/* NAME + fstrcmp - fuzzy string compare + + SYNOPSIS + double fstrcmp(const char *, const char *); + + DESCRIPTION + The fstrcmp function may be used to compare two string for + similarity. It is very useful in reducing "cascade" or + "secondary" errors in compilers or other situations where + symbol tables occur. + + RETURNS + double; 0 if the strings are entirely dissimilar, 1 if the + strings are identical, and a number in between if they are + similar. */ + +double fstrcmp (const char * string1, const char *string2) +{ + int i; + + size_t fdiag_len; + static int *fdiag_buf; + static size_t fdiag_max; + + /* set the info for each string. */ + string[0].data = string1; + string[0].data_length = strlen (string1); + string[1].data = string2; + string[1].data_length = strlen (string2); + + /* short-circuit obvious comparisons */ + if (string[0].data_length == 0 && string[1].data_length == 0) + return 1.0; + if (string[0].data_length == 0 || string[1].data_length == 0) + return 0.0; + + /* Set TOO_EXPENSIVE to be approximate square root of input size, + bounded below by 256. */ + too_expensive = 1; + for (i = string[0].data_length + string[1].data_length; i != 0; i >>= 2) + too_expensive <<= 1; + if (too_expensive < 256) + too_expensive = 256; + + /* Because fstrcmp is typically called multiple times, while scanning + symbol tables, etc, attempt to minimize the number of memory + allocations performed. Thus, we use a static buffer for the + diagonal vectors, and never free them. */ + fdiag_len = string[0].data_length + string[1].data_length + 3; + if (fdiag_len > fdiag_max) + { + fdiag_max = fdiag_len; + fdiag_buf = realloc (fdiag_buf, fdiag_max * (2 * sizeof (int))); // era xrealloc + } + fdiag = fdiag_buf + string[1].data_length + 1; + bdiag = fdiag + fdiag_len; + + /* Now do the main comparison algorithm */ + string[0].edit_count = 0; + string[1].edit_count = 0; + compareseq (0, string[0].data_length, 0, string[1].data_length, 0); + + /* The result is + ((number of chars in common) / (average length of the strings)). + This is admittedly biased towards finding that the strings are + similar, however it does produce meaningful results. */ + return ((double) (string[0].data_length + string[1].data_length + - string[1].edit_count - string[0].edit_count) + / (string[0].data_length + string[1].data_length)); +} diff --git a/src/xvaga01/fstrcmp.h b/src/xvaga01/fstrcmp.h new file mode 100644 index 000000000..e5d134b14 --- /dev/null +++ b/src/xvaga01/fstrcmp.h @@ -0,0 +1,33 @@ +/* GNU gettext - internationalization aids + Copyright (C) 1995, 2000 Free Software Foundation, Inc. + + This file was written by Peter Miller + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _FSTRCMP_H +#define _FSTRCMP_H + +#ifdef __cplusplus +extern "C" { // No mangling! +#endif + +double fstrcmp(const char * string1, const char *string2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xvaga01/guid.cpp b/src/xvaga01/guid.cpp new file mode 100644 index 000000000..d53d12737 --- /dev/null +++ b/src/xvaga01/guid.cpp @@ -0,0 +1,407 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 Graeme Hill (http://graemehill.ca) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +#include +#include "guid.hpp" + +#ifdef GUID_LIBUUID +#include +#endif + +#ifdef GUID_CFUUID +#include +#endif + +#ifdef GUID_WINDOWS +#include +#endif + +#ifdef GUID_ANDROID +#include +#include +#endif + +BEGIN_XG_NAMESPACE + +#ifdef GUID_ANDROID +AndroidGuidInfo androidInfo; + +AndroidGuidInfo AndroidGuidInfo::fromJniEnv(JNIEnv *env) +{ + AndroidGuidInfo info; + info.env = env; + auto localUuidClass = env->FindClass("java/util/UUID"); + info.uuidClass = (jclass)env->NewGlobalRef(localUuidClass); + env->DeleteLocalRef(localUuidClass); + info.newGuidMethod = env->GetStaticMethodID( + info.uuidClass, "randomUUID", "()Ljava/util/UUID;"); + info.mostSignificantBitsMethod = env->GetMethodID( + info.uuidClass, "getMostSignificantBits", "()J"); + info.leastSignificantBitsMethod = env->GetMethodID( + info.uuidClass, "getLeastSignificantBits", "()J"); + info.initThreadId = std::this_thread::get_id(); + return info; +} + +void initJni(JNIEnv *env) +{ + androidInfo = AndroidGuidInfo::fromJniEnv(env); +} +#endif + +// overload << so that it's easy to convert to a string +std::ostream &operator<<(std::ostream &s, const Guid &guid) +{ + std::ios_base::fmtflags f(s.flags()); // politely don't leave the ostream in hex mode + s << std::hex << std::setfill('0') + << std::setw(2) << (int)guid._bytes[0] + << std::setw(2) << (int)guid._bytes[1] + << std::setw(2) << (int)guid._bytes[2] + << std::setw(2) << (int)guid._bytes[3] + << "-" + << std::setw(2) << (int)guid._bytes[4] + << std::setw(2) << (int)guid._bytes[5] + << "-" + << std::setw(2) << (int)guid._bytes[6] + << std::setw(2) << (int)guid._bytes[7] + << "-" + << std::setw(2) << (int)guid._bytes[8] + << std::setw(2) << (int)guid._bytes[9] + << "-" + << std::setw(2) << (int)guid._bytes[10] + << std::setw(2) << (int)guid._bytes[11] + << std::setw(2) << (int)guid._bytes[12] + << std::setw(2) << (int)guid._bytes[13] + << std::setw(2) << (int)guid._bytes[14] + << std::setw(2) << (int)guid._bytes[15]; + s.flags(f); + return s; +} + +bool operator<(const xg::Guid &lhs, const xg::Guid &rhs) +{ + return lhs.bytes() < rhs.bytes(); +} + +bool Guid::isValid() const +{ + xg::Guid empty; + return *this != empty; +} + +// convert to string using std::snprintf() and std::string +std::string Guid::str() const +{ + char one[10], two[6], three[6], four[6], five[14]; + + snprintf(one, 10, "%02x%02x%02x%02x", + _bytes[0], _bytes[1], _bytes[2], _bytes[3]); + snprintf(two, 6, "%02x%02x", + _bytes[4], _bytes[5]); + snprintf(three, 6, "%02x%02x", + _bytes[6], _bytes[7]); + snprintf(four, 6, "%02x%02x", + _bytes[8], _bytes[9]); + snprintf(five, 14, "%02x%02x%02x%02x%02x%02x", + _bytes[10], _bytes[11], _bytes[12], _bytes[13], _bytes[14], _bytes[15]); + const std::string sep("-"); + std::string out(one); + + out += sep + two; + out += sep + three; + out += sep + four; + out += sep + five; + + return out; +} + +// conversion operator for std::string +Guid::operator std::string() const +{ + return str(); +} + +// Access underlying bytes +const std::array& Guid::bytes() const +{ + return _bytes; +} + +// create a guid from vector of bytes +Guid::Guid(const std::array &bytes) : _bytes(bytes) +{ } + +// create a guid from vector of bytes +Guid::Guid(std::array &&bytes) : _bytes(std::move(bytes)) +{ } + +// converts a single hex char to a number (0 - 15) +unsigned char hexDigitToChar(char ch) +{ + // 0-9 + if (ch > 47 && ch < 58) + return ch - 48; + + // a-f + if (ch > 96 && ch < 103) + return ch - 87; + + // A-F + if (ch > 64 && ch < 71) + return ch - 55; + + return 0; +} + +bool isValidHexChar(char ch) +{ + // 0-9 + if (ch > 47 && ch < 58) + return true; + + // a-f + if (ch > 96 && ch < 103) + return true; + + // A-F + if (ch > 64 && ch < 71) + return true; + + return false; +} + +// converts the two hexadecimal characters to an unsigned char (a byte) +unsigned char hexPairToChar(char a, char b) +{ + return hexDigitToChar(a) * 16 + hexDigitToChar(b); +} + +// create a guid from string +/* +Guid::Guid(std::string_view fromString) +{ + char charOne = '\0'; + char charTwo = '\0'; + bool lookingForFirstChar = true; + unsigned nextByte = 0; + + for (const char &ch : fromString) + { + if (ch == '-') + continue; + + if (nextByte >= 16 || !isValidHexChar(ch)) + { + // Invalid string so bail + zeroify(); + return; + } + + if (lookingForFirstChar) + { + charOne = ch; + lookingForFirstChar = false; + } + else + { + charTwo = ch; + auto byte = hexPairToChar(charOne, charTwo); + _bytes[nextByte++] = byte; + lookingForFirstChar = true; + } + } + + + // if there were fewer than 16 bytes in the string then guid is bad + if (nextByte < 16) + { + zeroify(); + return; + } +} +*/ + +// create empty guid +Guid::Guid() : _bytes{ {0} } +{ } + +// set all bytes to zero +void Guid::zeroify() +{ + std::fill(_bytes.begin(), _bytes.end(), static_cast(0)); +} + +// overload equality operator +bool Guid::operator==(const Guid &other) const +{ + return _bytes == other._bytes; +} + +// overload inequality operator +bool Guid::operator!=(const Guid &other) const +{ + return !((*this) == other); +} + +// member swap function +void Guid::swap(Guid &other) +{ + _bytes.swap(other._bytes); +} + +// This is the linux friendly implementation, but it could work on other +// systems that have libuuid available +#ifdef GUID_LIBUUID +Guid newGuid() +{ + std::array data; + static_assert(std::is_same::value, "Wrong type!"); + uuid_generate(data.data()); + return Guid{std::move(data)}; +} +#endif + +// this is the mac and ios version +#ifdef GUID_CFUUID +Guid newGuid() +{ + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array byteArray = + {{ + bytes.byte0, + bytes.byte1, + bytes.byte2, + bytes.byte3, + bytes.byte4, + bytes.byte5, + bytes.byte6, + bytes.byte7, + bytes.byte8, + bytes.byte9, + bytes.byte10, + bytes.byte11, + bytes.byte12, + bytes.byte13, + bytes.byte14, + bytes.byte15 + }}; + return Guid{std::move(byteArray)}; +} +#endif + +// obviously this is the windows version +#ifdef GUID_WINDOWS +Guid newGuid() +{ + GUID newId; + CoCreateGuid(&newId); + + std::array bytes = + { + (unsigned char)((newId.Data1 >> 24) & 0xFF), + (unsigned char)((newId.Data1 >> 16) & 0xFF), + (unsigned char)((newId.Data1 >> 8) & 0xFF), + (unsigned char)((newId.Data1) & 0xff), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xff), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + (unsigned char)newId.Data4[0], + (unsigned char)newId.Data4[1], + (unsigned char)newId.Data4[2], + (unsigned char)newId.Data4[3], + (unsigned char)newId.Data4[4], + (unsigned char)newId.Data4[5], + (unsigned char)newId.Data4[6], + (unsigned char)newId.Data4[7] + }; + + return Guid{std::move(bytes)}; +} +#endif + +// android version that uses a call to a java api +#ifdef GUID_ANDROID +Guid newGuid(JNIEnv *env) +{ + assert(env != androidInfo.env || std::this_thread::get_id() == androidInfo.initThreadId); + + jobject javaUuid = env->CallStaticObjectMethod( + androidInfo.uuidClass, androidInfo.newGuidMethod); + jlong mostSignificant = env->CallLongMethod(javaUuid, + androidInfo.mostSignificantBitsMethod); + jlong leastSignificant = env->CallLongMethod(javaUuid, + androidInfo.leastSignificantBitsMethod); + + std::array bytes = + { + (unsigned char)((mostSignificant >> 56) & 0xFF), + (unsigned char)((mostSignificant >> 48) & 0xFF), + (unsigned char)((mostSignificant >> 40) & 0xFF), + (unsigned char)((mostSignificant >> 32) & 0xFF), + (unsigned char)((mostSignificant >> 24) & 0xFF), + (unsigned char)((mostSignificant >> 16) & 0xFF), + (unsigned char)((mostSignificant >> 8) & 0xFF), + (unsigned char)((mostSignificant) & 0xFF), + (unsigned char)((leastSignificant >> 56) & 0xFF), + (unsigned char)((leastSignificant >> 48) & 0xFF), + (unsigned char)((leastSignificant >> 40) & 0xFF), + (unsigned char)((leastSignificant >> 32) & 0xFF), + (unsigned char)((leastSignificant >> 24) & 0xFF), + (unsigned char)((leastSignificant >> 16) & 0xFF), + (unsigned char)((leastSignificant >> 8) & 0xFF), + (unsigned char)((leastSignificant) & 0xFF) + }; + + env->DeleteLocalRef(javaUuid); + + return Guid{std::move(bytes)}; +} + +Guid newGuid() +{ + return newGuid(androidInfo.env); +} +#endif + + +END_XG_NAMESPACE + +// Specialization for std::swap() -- +// call member swap function of lhs, passing rhs +namespace std +{ + template <> + void swap(xg::Guid &lhs, xg::Guid &rhs) noexcept + { + lhs.swap(rhs); + } +} diff --git a/src/xvaga01/guid.hpp b/src/xvaga01/guid.hpp new file mode 100644 index 000000000..c5342367a --- /dev/null +++ b/src/xvaga01/guid.hpp @@ -0,0 +1,150 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 Graeme Hill (http://graemehill.ca) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#define GUID_WINDOWS + +#ifdef GUID_ANDROID +#include +#include +#endif + +#include +#include +#include +#include +//#include +#include +#include + +#define BEGIN_XG_NAMESPACE namespace xg { +#define END_XG_NAMESPACE } + +BEGIN_XG_NAMESPACE + +// Class to represent a GUID/UUID. Each instance acts as a wrapper around a +// 16 byte value that can be passed around by value. It also supports +// conversion to string (via the stream operator <<) and conversion from a +// string via constructor. +class Guid +{ +public: + explicit Guid(const std::array &bytes); + explicit Guid(std::array &&bytes); + +// explicit Guid(std::string_view fromString); + Guid(); + + Guid(const Guid &other) = default; + Guid &operator=(const Guid &other) = default; + Guid(Guid &&other) = default; + Guid &operator=(Guid &&other) = default; + + bool operator==(const Guid &other) const; + bool operator!=(const Guid &other) const; + + std::string str() const; + operator std::string() const; + const std::array& bytes() const; + void swap(Guid &other); + bool isValid() const; + +private: + void zeroify(); + + // actual data + std::array _bytes; + + // make the << operator a friend so it can access _bytes + friend std::ostream &operator<<(std::ostream &s, const Guid &guid); + friend bool operator<(const Guid &lhs, const Guid &rhs); +}; + +Guid newGuid(); + +#ifdef GUID_ANDROID +struct AndroidGuidInfo +{ + static AndroidGuidInfo fromJniEnv(JNIEnv *env); + + JNIEnv *env; + jclass uuidClass; + jmethodID newGuidMethod; + jmethodID mostSignificantBitsMethod; + jmethodID leastSignificantBitsMethod; + std::thread::id initThreadId; +}; + +extern AndroidGuidInfo androidInfo; + +void initJni(JNIEnv *env); + +// overloading for multi-threaded calls +Guid newGuid(JNIEnv *env); +#endif + +namespace details +{ + template struct hash; + + template + struct hash : public std::hash + { + using std::hash::hash; + }; + + + template + struct hash + { + inline std::size_t operator()(const T& v, const Rest&... rest) { + std::size_t seed = hash{}(rest...); + seed ^= hash{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } + }; +} + +END_XG_NAMESPACE + +namespace std +{ + // Template specialization for std::swap() -- + // See guid.cpp for the function definition + template <> + void swap(xg::Guid &guid0, xg::Guid &guid1) noexcept; + + // Specialization for std::hash -- this implementation + // uses std::hash on the stringification of the guid + // to calculate the hash + template <> + struct hash + { + std::size_t operator()(xg::Guid const &guid) const + { + const uint64_t* p = reinterpret_cast(guid.bytes().data()); + return xg::details::hash{}(p[0], p[1]); + } + }; +} diff --git a/src/xvaga01/hlapi_c.h b/src/xvaga01/hlapi_c.h new file mode 100644 index 000000000..73c910791 --- /dev/null +++ b/src/xvaga01/hlapi_c.h @@ -0,0 +1,75 @@ +/* $Id: hlapi_c.h,v 1.2 2010-02-09 10:14:58 guy Exp $ */ + +#include "fastapi.h" + +/* --------------------- */ +/* Function prototypes : */ +/* --------------------- */ +#ifdef __cplusplus + extern "C" { +#endif + +/* ------------------ */ +/* Basic Hardlock API */ +/* ------------------ */ +RET_ FAR_ CALL_ HL_LOGIN (Word ModAd, Word Access, Byte DATAFAR_ *RefKey, Byte DATAFAR_ *VerKey); +RET_ FAR_ CALL_ HL_LOGOUT (void); +RET_ FAR_ CALL_ HL_AVAIL (void); +RET_ FAR_ CALL_ HL_PORTINF (void); +RET_ FAR_ CALL_ HL_ACCINF (void); +RET_ FAR_ CALL_ HL_USERINF (void); +RET_ FAR_ CALL_ HL_MAXUSER (void); +RET_ FAR_ CALL_ HL_MEMINF (void); +RET_ FAR_ CALL_ HL_CODE (void DATAFAR_ *Data, Word Count); +RET_ FAR_ CALL_ HL_WRITE (Word Reg, Word Value); +RET_ FAR_ CALL_ HL_READ (Word Reg, Word DATAFAR_ *Value); +RET_ FAR_ CALL_ HL_READBL (Byte DATAFAR_ *Eeprom); +RET_ FAR_ CALL_ HL_WRITEBL (Byte DATAFAR_ *Eeprom); +RET_ FAR_ CALL_ HL_ABORT (void); +RET_ FAR_ CALL_ HL_VERSION (void); +RET_ FAR_ CALL_ HL_HLSVERS (void); +RET_ FAR_ CALL_ HL_SELECT (HL_API DATAFAR_ *hl_ptr); +RET_ FAR_ CALL_ HL_READID (Word DATAFAR_ *IDLow, Word DATAFAR_ *IDHigh); +RET_ FAR_ CALL_ HL_SERVERLICENSES (Word DATAFAR_ *Value); +RET_ FAR_ CALL_ HL_SERVERADDR (char *text, Long *textsize); + + +/* ---------------- */ +/* Hardlock RUS API */ +/* ---------------- */ +RET_ FAR_ CALL_ HLM_LOGIN (Word ModAd, Word Access, Byte DATAFAR_ *RefKey, Byte DATAFAR_ *VerKey, Byte DATAFAR_ * VKey, Long RUSOptions, Byte DATAFAR_ * SearchStr); +RET_ FAR_ CALL_ HLM_OCCUPYSLOT (Long Slot); +RET_ FAR_ CALL_ HLM_FREESLOT (Long Slot); +RET_ FAR_ CALL_ HLM_CHECKSLOT (Long Slot, Long * MaxUser, Long * CurrentUser); +RET_ FAR_ CALL_ HLM_CHECKCOUNTER (Word IncVal, Long * MaxCounter, Long * CurrentCounter); +RET_ FAR_ CALL_ HLM_CHECKEXPDATE (Long Slot, Word * Year, Word * Month, Word * Day); +RET_ FAR_ CALL_ HLM_GETRUSINFO (Long * BufLen, Byte DATAFAR_ * RTBBuffer, Word Base64); +RET_ FAR_ CALL_ HLM_WRITELICENSE (Long BufLen, Byte DATAFAR_ * RTBBuffer, Word Access, Byte DATAFAR_ * SearchStr,Word Options); +RET_ FAR_ CALL_ HLM_ISRUSHL (Long * ID); +RET_ FAR_ CALL_ HLM_CHECKALLSLOTS (Long *BufLen, HL_LIS *Buffer); +RET_ FAR_ CALL_ HLM_LOGOUT (void); + +/* ---------------------- */ +/* Hardlock Error Routine */ +/* ---------------------- */ +const char * FAR_ CALL_ HL_ERRMSG (Word num, Long options, Byte ** errdefine, Byte ** errextmsg); + +/* ------------------------------------------- */ +/* Obsolete functions, for compatiblity only!! */ +/* ------------------------------------------- */ +#ifndef __OS2__ +void FAR_ CALL_ HL_ON (Word Port, Word ModAd); +void FAR_ CALL_ HL_OFF (Word Port); +Word FAR_ CALL_ K_EYE (Word Port, char DATAFAR_ *Inp, Word BlkCnt); +void FAR_ CALL_ HL_WR (Word Port, Word Reg, Word Val); +Word FAR_ CALL_ HL_RD (Word Port, Word Reg); +void FAR_ CALL_ INT_ON (void); +void FAR_ CALL_ INT_OFF (void); +#endif +RET_ FAR_ CALL_ HL_CALC (Word i1, Word i2, Word i3, Word i4); +RET_ FAR_ CALL_ HL_LMLOGIN (Word ModAd, Word Access, Byte DATAFAR_ *RefKey, Byte DATAFAR_ *VerKey, Word SlotID, Byte DATAFAR_ *SearchStr); + +#ifdef __cplusplus + }; +#endif +/* eof */ diff --git a/src/xvaga01/incstr.cpp b/src/xvaga01/incstr.cpp new file mode 100644 index 000000000..4ce11bd12 --- /dev/null +++ b/src/xvaga01/incstr.cpp @@ -0,0 +1,15 @@ +#include + +istream & eatwhite(istream & i) +{ + char c; + while (i.get(c)) + { + if (!isspace(c)) + { + i.putback(c); + break; + } + } + return i; +} diff --git a/src/xvaga01/incstr.h b/src/xvaga01/incstr.h new file mode 100644 index 000000000..955f11f24 --- /dev/null +++ b/src/xvaga01/incstr.h @@ -0,0 +1,9 @@ +#ifndef __INCSTR_H +#define __INCRSTR_H + +#include +#include +#include +using namespace std; + +#endif diff --git a/src/xvaga01/matche.cpp b/src/xvaga01/matche.cpp new file mode 100644 index 000000000..35ac2fb9e --- /dev/null +++ b/src/xvaga01/matche.cpp @@ -0,0 +1,197 @@ +#include + +#include "matche.h" + +// codici di ritorno della matche() +#define regexp_MATCH_PATTERN (6) // pattern non valido +#define regexp_MATCH_LITERAL (5) // il pattern non coincide su un carattere comune +#define regexp_MATCH_RANGE (4) // il pattern non coincide in un costrutto [..] +#define regexp_MATCH_ABORT (3) // il stringa da confrontare è terminata anticipatamente +#define regexp_MATCH_END (2) // il pattern è terminato anticipatamente +#define regexp_MATCH_VALID (1) // pattern e stringa coincidono + +// codici di ritorno della is_valid_pattern() +#define regexp_PATTERN_VALID (0) // il pattern è valido +#define regexp_PATTERN_ESC (-1) // è presente un escape aperto a fine pattern +#define regexp_PATTERN_RANGE (-2) // c'è un range non chiuso all'interno di un costrutto [..] +#define regexp_PATTERN_CLOSE (-3) // manca la parentesi di chiusura in un costrutto [..] +#define regexp_PATTERN_EMPTY (-4) // c'è un costrutto vuoto + +// prototipi delle funzioni interne +static int matche(const char *pat, const char *str); // ritorna un codice della classe regexp_MATCH che indica se e in che modo pattern e stringa coincidono +static int matche_after_star(const char *pat, const char *str); // chiama ricorsivamente la matche() con i segmenti puri del pattern e della stringa +static bool is_pattern(const char *pat); // ritorna true se la stringa è un pattern +static bool is_valid_pattern(const char *pat, int *err= NULL); // ritorna true se la stringa è un pattern valido, indica un codice di ritorno della classe regexp_PATTERN nel secondo parametro + +static bool is_pattern(const char *p) { + while (*p) { + switch (*p++) { + case '?': + case '*': + case '[': + case '\\': + return true; + } + } + return false; +} + +static bool is_valid_pattern(const char *p, int *error_type) { + if (error_type != NULL) *error_type= regexp_PATTERN_VALID; // inizializzazione del tipo d'errore + while (*p) { // ciclo all'interno del pattern fino a fine stringa + switch(*p) { // determinazione del tipo di wild card nel pattern + case '\\': // controllo dell'escape, non può essere a fine pattern + if (!*++p) { + if (error_type != NULL) *error_type= regexp_PATTERN_ESC; + return false; + } + p++; + break; + case '[': // controllo della costruzione del costrutto [..] + p++; + if (*p == ']') { // se il prossimo carattere è ']' il costrutto è vuoto + if (error_type != NULL) *error_type= regexp_PATTERN_EMPTY; + return false; + } + if (!*p) { // se si è a fine stringa il costrutto non è chiuso + if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE; + return false; + } + while (*p != ']') { // ciclo fino a fine costrutto [..] + if (*p == '\\') { // controllo per gli escape + p++; + if (!*p++) { // controllo che l'escape non sia a fine pattern + if (error_type != NULL) *error_type= regexp_PATTERN_ESC; + return false; + } + } else p++; + if (!*p) { // se si è a fine stringa il costrutto non è chiuso + if (error_type != NULL) *error_type= regexp_PATTERN_CLOSE; + return false; + } + if (*p == '-') { // controllo di un eventuale range + if (!*++p || *p == ']') { // deve esistere una fine del range + if (error_type != NULL) *error_type= regexp_PATTERN_RANGE; + return false; + } else { + if (*p == '\\') p++; // controllo degli escape + if (!*p++) { // controllo che l'escape non sia a fine pattern + if (error_type != NULL) *error_type= regexp_PATTERN_ESC; + return false; + } + } + } + } + break; + case '*': // tutti gli altri caratteri sono elementi validi del pattern + case '?': + default: + p++; // caratteri normali + break; + } + } + return true; +} + +static int matche_after_star(const char *p, const char *t) { + int match= 0; + while (*p == '?' || *p == '*') { // salto degli eventuali '*' e '?' + if (*p == '?') // salto di un carattere per ciascun '?' + if (!*t++) return regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza + p++; // posizionamento sul prossimo carattere del pattern + } + if (!*p) return regexp_MATCH_VALID; //se il pattern è concluso c'è coincidenza + int nextp= *p; // prelevamento del prossimo carattere, normale o '[' + if (nextp == '\\') { + nextp= p[1]; + if (!nextp) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido + } + do { // ciclo fino a conclusione di stringa o pattern + if (nextp == *t || nextp == '[') match= matche(p, t); // è necessario che il carattere corrente del testo coincida con il carattere corrente del pattern, oppure che il pattern abbia un inizio di costrutto [..] + if (!*t++) match= regexp_MATCH_ABORT; // se la stringa termina qui non c'è coincidenza + } while (match != regexp_MATCH_VALID && match != regexp_MATCH_ABORT && match != regexp_MATCH_PATTERN); + return match; // ritorno del risultato +} + +static int matche(const char *p, const char *t) { + for (; *p; p++, t++) { + if (!*t) // se si è alla fine della stringa, il confronto è concluso + return (*p == '*' && *++p == '\0') ? regexp_MATCH_VALID : regexp_MATCH_ABORT; + switch (*p) { // determina il tipo di wild card del pattern + case '?': // carattere singolo, qualunque carattere coincide + break; + case '*': // sottostringa, coincide qualunque sequenza di caratteri + return matche_after_star (p, t); + case '[': { // costrutto [..], controllo di coincidenza per inclusione o esclusione su un solo carattere + p++; // posizionamento all'inizio del range + bool invert= false; // controllo di inclusione o esclusione del costrutto + if (*p == '!' || *p == '^') { + invert= true; + p++; + } + if (*p == ']') // se si è su una chiusura di costrutto il pattern non è valido + return regexp_MATCH_PATTERN; + bool member_match= false; + bool loop= true; + while (loop) { + char range_start, range_end; // inizio e fine del range corrente + if (*p == ']') { // se si è alla fine del costrutto il ciclo si conclude + loop= false; + continue; + } + if (*p == '\\') // controllo di coincidenza su un metacarattere, dopo un escape + range_start= range_end= *++p; + else + range_start= range_end= *p; + if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina non è valido + if (*++p == '-') { // controllo del segno di sottoinsieme + range_end= *++p; // impostazione della fine del range + if (range_end == '\0' || range_end == ']') return regexp_MATCH_PATTERN; // se il costrutto [..] o il pattern terminano qui allora il pattern non è valido + if (range_end == '\\') { // la fine del range è un metacarattere + range_end= *++p; + if (!range_end) return regexp_MATCH_PATTERN; // se il pattern termina non è valido + } + p++; // posizionamento oltre il range + } + if (range_start < range_end) { // confronto del carattere corrente con il costrutto, controllo della sequenzialità degli estremi del range + if (*t >= range_start && *t <= range_end) { + member_match= true; + loop= false; + } + } else { + if (*t >= range_end && *t <= range_start) { + member_match= true; + loop= false; + } + } + } + if ((invert && member_match) || !(invert || member_match)) // controllo del risultato dell'ultimo confronto nel costrutto [..] + return regexp_MATCH_RANGE; + if (member_match) { // salto del resto del costrutto se non è esclusivo + while (*p != ']') { + if (!*p) return regexp_MATCH_PATTERN; // se si è a fine pattern il costrutto non è valido + if (*p == '\\') { // salto di un confronto con un metacarattere + p++; + if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido + } + p++; // posizionamento sul prossimo carattere del pattern + } + } + break; + } + case '\\': // confronto con un metacarattere + p++; // posizionamento sul carattere da confrontare + if (!*p) return regexp_MATCH_PATTERN; // se il pattern termina qui non è valido + default: // confronto con un carattere normale + if (*p != *t) return regexp_MATCH_LITERAL; + } + } + if (*t) return regexp_MATCH_END; // se la stringa non è conclusa non c'è coincidenza + else return regexp_MATCH_VALID; +} + +bool match(const char *pat, const char *str) +{ + const int err = matche(pat, str); + return (err == regexp_MATCH_VALID); // ritorna true se il pattern e la stringa coincidono +} diff --git a/src/xvaga01/matche.h b/src/xvaga01/matche.h new file mode 100644 index 000000000..2be5843eb --- /dev/null +++ b/src/xvaga01/matche.h @@ -0,0 +1 @@ +bool match(const char *pat, const char *str); diff --git a/src/xvaga01/oslinux.cpp b/src/xvaga01/oslinux.cpp new file mode 100644 index 000000000..5494ea07e --- /dev/null +++ b/src/xvaga01/oslinux.cpp @@ -0,0 +1,386 @@ +#include "wxinc.h" +#include "wx/print.h" +#include "wx/printdlg.h" + +#include "xvt.h" +#include "oslinux.h" + +#include "xvt_menu.h" +#include "xvt_help.h" +#include "xvintern.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +wxString OsLinux_File2App(const char* filename) +{ + wxString app; + + SORRY_BOX(); + return app; +} + +int OsLinux_EnumerateFamilies(char** families, int max_count) +{ + wxFontEnumerator ef; + + ef.EnumerateFacenames(); + wxArrayString * fonts = ef.GetFacenames(); + + size_t items = fonts->GetCount(); + size_t i; + + for (i = 0; i < items; i++) + families[i] = xvt_str_duplicate((*fonts)[i].c_str()); + + return items; +} + +int OsLinux_EnumerateSizes(const char* name, long* sizes, short* scalable, int max_count) +{ + int i = 0; + *scalable = 1; + + for (int size = 4; size < 80; size++) + sizes[i++] = size; + return i; +} + +void OsLinux_PlaceProcessInWindow(unsigned int instance, const char* name, unsigned int parent) +{ + SORRY_BOX(); +} + +void OsLinux_UpdateWindow(unsigned int handle) +{ + // non deve fare nulla in Linux, sembra di si verificare SORRY_BOX(); +} + +void OsLinux_Set_FileTime(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime) +{ + +} + + +/////////////////////////////////////////////////////////// +// Hardlock Support +/////////////////////////////////////////////////////////// + +#include "hlapi_c.h" + +bool OsLinux_HL_Login(unsigned short address, const unsigned char* label, const unsigned char* password) +{ + int err = HL_LOGIN(address, LOCAL_DEVICE, (unsigned char*)label, (unsigned char*)password); + return err == STATUS_OK; +} + +bool OsLinux_HL_Logout() +{ + HL_LOGOUT(); + return TRUE; +} + +bool OsLinux_HL_Read(unsigned short reg, unsigned short* data) +{ + int err = HL_READ(reg, data); + return err == STATUS_OK; +} + +bool OsLinux_HL_ReadBlock(unsigned char* data) +{ + int err = HL_READBL(data); + return err == STATUS_OK; +} + +bool OsLinux_HL_Write(unsigned short reg, unsigned short data) +{ + int err = HL_WRITE(reg, data); + return err == STATUS_OK; +} + +bool OsLinux_HL_Crypt(unsigned short* data) // Array di 4 words (8 bytes) +{ + int err = HL_CODE(data, 1); + return err == STATUS_OK; +} + +/////////////////////////////////////////////////////////// +// Eutron Smartlink Support +/////////////////////////////////////////////////////////// + +#include "skeylinux.h" + +static SKEY_DATA skey; + +bool OsLinux_SL_Crypt(unsigned short* data) +{ + skey.command = SCRAMBLING_MODE; + memset(skey.data, 0, sizeof(skey.data)); + memcpy(skey.data, data, 8); + clink(&skey); + const bool ok = (skey.status == ST_OK); + if (ok) + memcpy(data, skey.data, 8); + return ok; +} + +bool OsLinux_SL_Login(const unsigned char* label, const unsigned char* password) +{ + memset(&skey, 0, sizeof(SKEY_DATA)); + skey.command = LOCATING_MODE; + skey.status = ST_HW_FAILURE; // Don't leave ST_OK = 0 here! + memcpy(skey.label, label, strlen((const char*)label)); + memcpy(skey.password, password, strlen((const char*)password)); + + clink(&skey); + return skey.status == ST_OK; +} + +bool OsLinux_SL_Logout() +{ + skey.command = 0; + clink(&skey); + return true; +} + +bool OsLinux_SL_ReadBlock(unsigned short reg, unsigned short size, unsigned short* data) +{ + skey.command = BLOCK_READING_MODE; + unsigned short* pointer = (unsigned short*)(&skey.data[0]); + unsigned short* number = (unsigned short*)(&skey.data[2]); + *pointer = reg; + *number = size; + clink(&skey); + const bool ok = skey.status == ST_OK; + if (ok) + memcpy(data, &skey.data[4], size*sizeof(unsigned short)); + return ok; +} + +bool OsLinux_SL_WriteBlock(unsigned short reg, unsigned short size, const unsigned short* data) +{ + skey.command = BLOCK_WRITING_MODE; + unsigned short* pointer = (unsigned short*)(&skey.data[0]); + unsigned short* number = (unsigned short*)(&skey.data[2]); + *pointer = reg; + *number = size; + memcpy(&skey.data[4], data, size*sizeof(unsigned short)); + clink(&skey); + return skey.status == ST_OK; +} + +void OsLinux_GetFileSys(const char* path, char * dev, char * dir, char * type) +{ + struct mntent *m; + FILE *f = setmntent("/etc/mnttab", "r"); + + while ((m = getmntent(f)) && strncmp(path, m->mnt_dir, strlen(m->mnt_dir)) != 0); + if (m) + { + if (dev) strcpy(dev, m->mnt_fsname); + if (dir) strcpy(dir, m->mnt_dir); + if (type) strcpy(type, m->mnt_type); + } + else + { + if (dev) *dev = '\0'; + if (dir) *dir = '\0'; + if (type) *type = '\0'; + } + endmntent(f); +} + + +bool OsLinux_IsNetworkDrive(const char * path) +{ + struct statfs buf; + + if (statfs(path, &buf) == -1) + return FALSE; + return (buf.f_type == 0x6969 /*NFS_SUPER_MAGIC */) || + (buf.f_type == 0x517B /*SMB_SUPER_MAGIC)*/); +} + +int64_t OsLinux_GetDiskFreeSpace(const char * path) +{ + struct statfs buf; + int64_t nBytes = 0L; + + if (statfs(path, &buf) != -1) + { + nBytes = buf.f_bsize; + nBytes *= buf.f_bavail; + nBytes *= 1024; + } + + return nBytes; +} + +#include "wx/settings.h" +#include "X11/Xutil.h" + +#ifndef MWM_DECOR_BORDER +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) +#define MWM_FUNC_ALL (1L << 0) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) +#define MWM_INPUT_MODELESS 0 +#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 +#define MWM_INPUT_SYSTEM_MODAL 2 +#define MWM_INPUT_FULL_APPLICATION_MODAL 3 +#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL +#define MWM_TEAROFF_WINDOW (1L<<0) +#endif + +struct MwmHints { + long flags; + long functions; + long decorations; + long input_mode; +}; +#define PROP_MOTIF_WM_HINTS_ELEMENTS 5 +// Set the window manager decorations according to the +// given wxWindows style +bool wxSetWMDecorations(Window w, long style) +{ + Atom mwm_wm_hints = XInternAtom((Display * )wxGetDisplay(),"_MOTIF_WM_HINTS", False); + if (mwm_wm_hints == 0) + return FALSE; + + MwmHints hints; + hints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; + hints.decorations = 0; + hints.functions = 0; + +// if ((style & wxSIMPLE_BORDER) || (style & wxNO_BORDER)) + if (style & wxNO_BORDER) + { + // leave zeros + } + else + { + hints.decorations = MWM_DECOR_BORDER; + hints.functions = MWM_FUNC_MOVE | MWM_FUNC_CLOSE; + if ((style & wxCAPTION) != 0) + hints.decorations |= MWM_DECOR_TITLE; + + if ((style & wxSYSTEM_MENU) != 0) + { + hints.decorations |= MWM_DECOR_MENU; + } + + if ((style & wxMINIMIZE_BOX) != 0) + { + hints.functions |= MWM_FUNC_MINIMIZE; + hints.decorations |= MWM_DECOR_MINIMIZE; + } + + if ((style & wxMAXIMIZE_BOX) != 0) + { + hints.functions |= MWM_FUNC_MAXIMIZE; + hints.decorations |= MWM_DECOR_MAXIMIZE; + } + + if ((style & wxRESIZE_BORDER) != 0) + { + hints.functions |= MWM_FUNC_RESIZE; + hints.decorations |= MWM_DECOR_RESIZEH; + } + } + XChangeProperty((Display *) wxGetDisplay(), w, mwm_wm_hints, mwm_wm_hints, 32, PropModeReplace, + (unsigned char *) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS); + return TRUE; +} + +#include +#include +#include +#include + +void OsLinux_SetCaptionStyle(wxWindow * w, long style) +{ + wxSetWMDecorations(GDK_WINDOW_XID(w->m_widget->window), style); +} + + +int OsLinux_GetSessionId() +{ + char s[256]; + wxStrncpy(s, wxGetEnv("DISPLAY"), sizeof(s)); + + char* p = strchr(s, ':'); + if (p == NULL) + p = s; + else + p++; + + char * e = strchr(p, '.'); + + if (e != NULL) + *e = '\0'; + + return atoi(p); +} + +bool OsLinux_IsdTaskbarVisible() +{ + return true; +} + +unsigned long OsLinux_GetDriveSerialNumber(char * path) +{ + unsigned long SerialNumber = 0L; + char buf[256]; + char dev[256]; + char dir[256]; + char type[256]; + + OsLinux_GetFileSys(path, dev, dir, type); + if (*dev) + { + len = readlink(dev, buf, 256); + buf[len] = 0; + sprintf(buf2, "%s/%s", "/sys/block/", buf); + for (i = 0; i < 6; i++) { + p = strrchr(buf2, '/'); + *p = 0; + } + strcat(buf2, "/serial"); + + int f = open(buf2, 0); + len = read(f, buf, 256); + if (len <= 0) { + perror("read()"); + } + buf[len] = 0; + len = 0; + for (const char * s = buf; *s, ; s++) + { + if (isdigit(s)) + dev[i++] = *s; + } + dev[i] = '\0'; + SerialNumber = atol(dev); + } + return (long)SerialNumber; +} diff --git a/src/xvaga01/oslinux.h b/src/xvaga01/oslinux.h new file mode 100644 index 000000000..9851ea0a7 --- /dev/null +++ b/src/xvaga01/oslinux.h @@ -0,0 +1,30 @@ +wxString OsLinux_File2App(const char* filename); + +int OsLinux_EnumerateFamilies(char** families, int max_count); +int OsLinux_EnumerateSizes(const char* name, long* sizes, short* scalable, int max_count); + +void OsLinux_PlaceProcessInWindow(unsigned int instance, const char* name, unsigned int parent); +void OsLinux_UpdateWindow(unsigned int handle); + +void OsLinux_Set_FileTime(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime); + +bool OsLinux_HL_Crypt(unsigned short* data); +bool OsLinux_HL_Login(unsigned short address, const unsigned char* label, const unsigned char* password); +bool OsLinux_HL_Logout() ; +bool OsLinux_HL_Read(unsigned short reg, unsigned short* data); +bool OsLinux_HL_ReadBlock(unsigned char* data); +bool OsLinux_HL_Write(unsigned short reg, unsigned short data); +bool OsLinux_SL_Crypt(unsigned short* data); +bool OsLinux_SL_Login(const unsigned char* label, const unsigned char* password); +bool OsLinux_SL_Logout() ; +bool OsLinux_SL_ReadBlock(unsigned short reg, unsigned short size, unsigned short* data); +bool OsLinux_SL_WriteBlock(unsigned short reg, unsigned short size, const unsigned short* data); +void OsLinux_GetFileSys(const char* path, char * dev, char * dir, char * type); +bool OsLinux_IsNetworkDrive(const char * path); +int64_t OsLinux_GetDiskFreeSpace(const char * path); +void OsLinux_SetCaptionStyle(wxWindow * w, long style); +int OsLinux_GetSessionId(); + +bool OsLinux_IsdTaskbarVisible(); + +unsigned long OsLinux_GetDriveSerialNumber(char * path); \ No newline at end of file diff --git a/src/xvaga01/oswin32.cpp b/src/xvaga01/oswin32.cpp new file mode 100644 index 000000000..b2ab51be1 --- /dev/null +++ b/src/xvaga01/oswin32.cpp @@ -0,0 +1,1474 @@ +#include "wxinc.h" +#include "wx/filename.h" +#include "wx/image.h" +#include "wx/paper.h" +#include "wx/printdlg.h" +#include "wx/msw/helpchm.h" + +#include "oswin32.h" + +/*#include "xvt_menu.h" +#include "xvt_help.h" + +#include "xvt_defs.h" +#include "xvt_env.h" +#include "xvt_type.h"*/ +#include "xvtart.h" +#include "xvt.h" +#include "xvtwin.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define STR_MAC_SIZE 18 + +template void safe_delete(T*& a) +{ + delete a; + a = nullptr; +} + +const char * OsWin32_CommandLine() +{ + return GetCommandLine(); +} + +bool OsWin32_CheckPrinterInfo(const void* data, unsigned int size) +{ + bool ok = data != NULL; + if (ok) + { + LPDEVMODE pdm = (LPDEVMODE)data; + const unsigned int s = pdm->dmSize + pdm->dmDriverExtra; + ok = s > 0 && s == size; + } + return ok; +} + +static int AdjustDevmodePlease(PDEVMODE dm) +{ + // Forse dovremmo fare una Black List su file delle stampanti incompatibili): + // 1) "NRG SP 4100N PCL 5e" + // 2) aggiungere qui le altre + // Ma per ora zappiamo tutti i driver troppo grandi (> 3Kb) + if (dm->dmDriverExtra > 3*1024) + dm->dmDriverExtra = 0; + + // Controllo il formato della carta + wxPrintPaperType* paper = wxThePrintPaperDatabase->FindPaperTypeByPlatformId(dm->dmPaperSize); + if (paper == NULL) + { + dm->dmFields |= DM_PAPERSIZE; + wxThePrintPaperDatabase->WXADDPAPER((wxPaperSize)dm->dmPaperSize /*wxPAPER_NONE*/, dm->dmPaperSize, + dm->dmFormName, dm->dmPaperWidth, dm->dmPaperLength); + } + + return dm->dmSize + dm->dmDriverExtra; +} + +void* OsWin32_ConvertFromNativePrinterInfo(void* hGlobal, unsigned int& nDataSize) +{ + void* buff = NULL; + if (hGlobal != NULL) + { + PDEVMODE dm = (PDEVMODE)::GlobalLock(hGlobal); + nDataSize = AdjustDevmodePlease(dm); + buff = new char[nDataSize]; + memcpy(buff, dm, nDataSize); + ::GlobalUnlock(hGlobal); + } + return buff; +} + +void* OsWin32_ConvertToNativePrinterInfo(void* data, unsigned int nDataSize) +{ + HGLOBAL hGlobal = ::GlobalAlloc(GHND, nDataSize); // Alloco lo spazio necessario + if (hGlobal != NULL) + { + PDEVMODE dm = (PDEVMODE)::GlobalLock(hGlobal); // Trasformo l'handle in puntatore + memcpy(dm, data, nDataSize); // Ricopio i dati della stampante + const unsigned int sz = AdjustDevmodePlease(dm); // Metto a posto parametri non standard + wxASSERT(nDataSize == sz); + ::GlobalUnlock(hGlobal); // Libero il lock sull'handle + } + return hGlobal; +} + +struct XvtData +{ + char** families; + long* sizes; + short* scalable; + int max_count; + int cur_count; + + XvtData() { memset(this, 0, sizeof(XvtData)); } +}; + +int CALLBACK FamilyEnumerator( + const LOGFONT *plf, // pointer to logical-font data + const TEXTMETRIC * WXUNUSED(lpntme), // pointer to physical-font data + unsigned long WXUNUSED(FontType), // type of font + LPARAM lParam // application-defined data +) +{ + XvtData* d = (XvtData*)lParam; + int& n = d->cur_count; + int i; + for (i = n-1; i >= 0 && wxStricmp(d->families[i], plf->lfFaceName); i--); + if (i < 0) // Controlla che il nome del font non ci sia gia' + d->families[n++] = wxStrdup(plf->lfFaceName); + return n < d->max_count; +} + +int CALLBACK SizeEnumerator( + const LOGFONT *plf, // pointer to logical-font data + const TEXTMETRIC *lpntme, // pointer to physical-font data + unsigned long WXUNUSED(FontType), // type of font + LPARAM lParam // application-defined data +) +{ + XvtData* d = (XvtData*)lParam; + int& i = d->cur_count; + int size = (plf->lfHeight+5) / 10; + if (size <= 0) + { + for (const char* n = plf->lfFaceName; *n; n++) + if (*n >= '1' && *n <= '9') + { + size = int(120.0 / atoi(n) + 0.5); + break; + } + if (size <= 0) + size = 12; + } + if (i == 0 || size > d->sizes[i-1]) + { + d->sizes[i] = size; + if (lpntme->tmPitchAndFamily & TMPF_TRUETYPE) + *d->scalable = TRUE; + i++; + } + return i < d->max_count; +} + +int FamilySorter(const void* p1,const void* p2) +{ + const char* s1 = *(const char**)p1; + const char* s2 = *(const char**)p2; + return wxStricmp(s1, s2); +} + +int OsWin32_EnumerateFamilies(WXHDC hDC, char** families, int max_count) +{ + XvtData data; + data.families = families; + data.max_count = max_count; + LOGFONT lf; memset(&lf, 0, sizeof(lf)); + lf.lfCharSet = DEFAULT_CHARSET; + ::EnumFontFamiliesEx((HDC)hDC, &lf, FamilyEnumerator, (LPARAM)&data, 0); + qsort(families, data.cur_count, sizeof(char*), FamilySorter); + return data.cur_count; +} + +int OsWin32_EnumerateSizes(WXHDC hDC, const char* name, long* sizes, short* scalable, int max_count) +{ + XvtData data; + data.sizes = sizes; + data.scalable = scalable; + data.max_count = max_count; + LOGFONT lf; memset(&lf, 0, sizeof(lf)); + lf.lfCharSet = DEFAULT_CHARSET; + strcpy(lf.lfFaceName, name); + ::EnumFontFamiliesEx((HDC)hDC, &lf, SizeEnumerator, (LPARAM)&data, 0); + + return data.cur_count; +} + +void* OsWin32_GetPrinterInfo(int& size, const char* printer) +{ + LPDEVMODE pdm = NULL; + size = 0; + + char name[_MAX_PATH] = ""; + if (printer == NULL || *printer == '\0') + { + unsigned long namelen = _MAX_PATH; + ::GetDefaultPrinter(name, &namelen); + } + else + wxStrncpy(name, printer, sizeof(name)); + + HANDLE hPrinter = NULL; + if (::OpenPrinter(name, &hPrinter, NULL)) + { + size = ::DocumentProperties(0, hPrinter, name, NULL, NULL, 0); // Determina dimensione DEVMODE + if (size > 0) + { + pdm = (LPDEVMODE)new BYTE[size]; // Alloca un DEVMODE sufficientemente capiente + memset(pdm, 0, size); // Azzera tutto per bene + ::DocumentProperties(0, hPrinter, name, pdm, NULL, DM_OUT_BUFFER); // Legge DEVMODE + size = AdjustDevmodePlease(pdm); + if (size <= 0) + { + wxString msg = "DocumentProperties fallita fase 2 - stampante "; msg << name; + MessageBox(NULL, msg, "ERRORE", MB_ABORTRETRYIGNORE); + } + } + else + { + wxString msg = "DocumentProperties fallita fase 1 - stampante "; msg << name; + MessageBox(NULL, msg, "ERRORE", MB_ABORTRETRYIGNORE); + size = 0; + } + + ::ClosePrinter(hPrinter); + } + else + { + wxString msg = "OpenPrinte fallita - stampante "; msg << name; + MessageBox(NULL, msg, "ERRORE", MB_ABORTRETRYIGNORE); + } + return pdm; +} + +void OsWin32_SetCaptionStyle(WXHWND handle, long style) +{ + HWND hWnd = (HWND)handle; + LONG s = ::GetWindowLong(hWnd, GWL_STYLE); + + if (style & wxSYSTEM_MENU) + s |= WS_CAPTION; + else + s &= ~WS_CAPTION; + + if (style & wxCLOSE_BOX) + s |= WS_SYSMENU; + else + s &= ~WS_SYSMENU; + + s |= WS_CLIPSIBLINGS; // Forzatura necessaria da wx261 + ::SetWindowLong(hWnd, GWL_STYLE, s); + + if (style & wxCLOSE_BOX) + { + HMENU hMenu = ::GetSystemMenu(hWnd, FALSE); + ::EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); + + WXHICON hIcon = xvtart_GetIconResource(0).GetHICON(); + ::SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + } +} + +/////////////////////////////////////////////////////////// +// Drawing bitmaps +/////////////////////////////////////////////////////////// + +HBITMAP OsWin32_CreateBitmap(const wxImage& img, wxDC& dc) +{ + static wxPalette pal; + + HDC hDC = (HDC)dc.GetHDC(); + int nDepth = dc.GetDepth(); + + // Altrimenti le stampanti in B/N perdono i toni di grigio + if (nDepth == 1 && !OsWin32_IsWindowsServer()) + { + hDC = NULL; + nDepth = 24; + } + + if (nDepth == 8) + { + if (!pal.Ok()) + { + unsigned char red[256], green[256], blue[256]; + PALETTEENTRY pe[256]; memset(pe, 0, sizeof(pe)); + UINT nEntries = ::GetSystemPaletteEntries(hDC, 0, 256, pe); + for (UINT i = 0; i < nEntries; i++) + { + red[i] = pe[i].peRed; + green[i] = pe[i].peGreen; + blue[i] = pe[i].peBlue; + } + pal.Create(nEntries, red, green, blue); + } + dc.SetPalette(pal); + } + + const int nWidth = img.GetWidth(); + const int nHeight = img.GetHeight(); + + int nBytesPerLine = 0; + int nPadding = 0; + int nBitCount = 24; + + switch (nDepth) + { + case 32: // Better if > Win98 :-) too + nBitCount = 32; + nBytesPerLine = nWidth*4; + break; + default: + nBytesPerLine = nWidth*3; + break; + } + const int nResto = nBytesPerLine % 4; + if (nResto != 0) + { + nPadding = 4 - nResto; + nBytesPerLine += nPadding; + } + + const int nImageSize = nHeight*nBytesPerLine; + + // Create the DIB section + unsigned char* pbits = (unsigned char*)calloc(nImageSize, 1); + const size_t bi_size = sizeof(BITMAPINFOHEADER); + BITMAPINFO* bi = (BITMAPINFO*)calloc(bi_size, 1); + bi->bmiHeader.biSize = bi_size; + bi->bmiHeader.biWidth = nWidth; + bi->bmiHeader.biHeight = -nHeight; + bi->bmiHeader.biCompression = BI_RGB; + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = nBitCount; + bi->bmiHeader.biSizeImage = nImageSize; + + switch (nBitCount) + { + case 24: + { + unsigned char* d = img.GetData(); + unsigned char* p = pbits; + for (int y = 0; y < nHeight; y++) + { + for (int x = 0; x < nWidth; x++) + { + *(p++) = *(d+2); + *(p++) = *(d+1); + *(p++) = *(d+0); + d += 3; + } + for (int i = 0; i < nPadding; i++) + *(p++) = 0; + } + } + break; + case 32: + { + unsigned char* d = img.GetData(); + unsigned char* p = pbits; + for (int y = 0; y < nHeight; y++) + { + for (int x = 0; x < nWidth; x++) + { + *(p++) = *(d+2); + *(p++) = *(d+1); + *(p++) = *(d+0); + *(p++) = 0; + d += 3; + } + } + } + break; + default: + break; + } + + HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight); + if (hBitmap) + { + HDC memdc = ::CreateCompatibleDC( hDC ); + HBITMAP hOldBitmap = (HBITMAP)::SelectObject( memdc, hBitmap); + + HPALETTE hOldPalette = NULL; + if (nDepth == 8) + { + hOldPalette = ::SelectPalette(memdc, (HPALETTE)pal.GetHPALETTE(), FALSE); + ::RealizePalette(memdc); + } + ::StretchDIBits( memdc, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, pbits, bi, DIB_RGB_COLORS, SRCCOPY); + + if (hOldBitmap) + ::SelectObject(memdc, hOldBitmap); + if (hOldPalette) + ::SelectPalette(memdc, hOldPalette, FALSE); + ::DeleteDC(memdc); + + } + + free(pbits); + free(bi); + + return hBitmap; +} + +bool OsWin32_DrawBitmap(HBITMAP hBMP, wxDC& dc, const wxRect& dst, const wxRect& src) +{ + static wxPalette pal; + + bool ok = hBMP != NULL; + + if (ok) + { + HDC hDC = (HDC)dc.GetHDC(); + const int nTechno = ::GetDeviceCaps(hDC, TECHNOLOGY); + + HDC hMemDC = NULL; + if (OsWin32_IsWindowsServer()) + hMemDC = ::CreateCompatibleDC(hDC); // Per Terminal Server devo fare cosi' + else + hMemDC = ::CreateCompatibleDC(NULL); // Per gli altri sistemi devo fare cosa' + + BITMAP bmp; ::GetObject(hBMP, sizeof(bmp), &bmp); + + if (nTechno == DT_RASPRINTER) // Sto stampando! + { + const size_t bi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD); + BITMAPINFO* bi = (BITMAPINFO*)calloc(bi_size, 1); // Alloca ed azzera + BITMAPINFOHEADER& bih = bi->bmiHeader; + bih.biSize = sizeof(bih); + GetDIBits(hMemDC, hBMP, 0, bmp.bmHeight, NULL, bi, DIB_RGB_COLORS); + ok = bih.biSizeImage > 0; + if (ok) + { + LPBYTE bits = new BYTE[bih.biSizeImage]; + ::GetDIBits(hMemDC, hBMP, 0, src.height, bits, bi, DIB_RGB_COLORS); + ::StretchDIBits(hDC, dst.x, dst.y, dst.width, dst.height, src.x, src.y, src.width, src.height, + bits, bi, DIB_RGB_COLORS, SRCCOPY); + delete bits; + } + free(bi); + } + else + { + HGDIOBJ hOldBitmap = ::SelectObject(hMemDC, hBMP); + ::SetStretchBltMode(hDC, HALFTONE); + ::StretchBlt(hDC, dst.x, dst.y, dst.width, dst.height, + hMemDC, src.x, src.y, src.width, src.height, SRCCOPY); + ::SelectObject(hMemDC, hOldBitmap); + } + + ::DeleteDC(hMemDC); + } + return ok; +} + +void OsWin32_DrawDottedRect(WXHDC hDC, int left, int top, int right, int bottom) +{ + LOGBRUSH lBrush; + lBrush.lbHatch = 0; lBrush.lbStyle = BS_SOLID; + lBrush.lbColor = ::GetTextColor((HDC)hDC); + HPEN hPen = ::ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lBrush, 0, NULL); + HGDIOBJ hOldPen = ::SelectObject((HDC)hDC, hPen); + HGDIOBJ hBrush = ::GetStockObject(HOLLOW_BRUSH); + HGDIOBJ hOldBrush = ::SelectObject((HDC)hDC, hBrush); + ::Rectangle((HDC)hDC, left, top, right, bottom); + ::SelectObject((HDC)hDC, hOldBrush); + ::SelectObject((HDC)hDC, hOldPen); + ::DeleteObject(hPen); +} + +void OsWin32_Beep(int severity) +{ + switch (severity) + { + case 1: ::MessageBeep(MB_ICONEXCLAMATION); break; + case 2: ::MessageBeep(MB_ICONSTOP); break; + default: ::MessageBeep(MB_OK); break; + } +} + +static wxString GetHelpDir() +{ return "htmlhelp/"; } + +static wxString FindHelpFile(const char* topic) +{ + wxString strTopic = topic; + + wxString strApp; + wxFileName::SplitPath(wxTheApp->argv[0], NULL, &strApp, NULL); + + if (strTopic.IsEmpty()) + { + strTopic = strApp; + strTopic += "100a"; + } + + wxString str; + for (int i = 0; i < 2; i++) + { + str = GetHelpDir(); + str += i == 0 ? strTopic.Left(2) : strApp.Left(2); + str += "help.pdf"; + if (::wxFileExists(str)) + return str; + } + + for (int i = 0; i < 2; i++) + { + str = GetHelpDir(); + str += i == 0 ? strTopic.Left(2) : strApp.Left(2); + str += "help.chm"; + if (::wxFileExists(str)) + return str; + } + for (int i = 0; i < 2; i++) + { + str = GetHelpDir(); + str += i == 0 ? strTopic.Left(2) : strApp.Left(2); + str += "/"; + str += strTopic; + str += ".html"; + if (::wxFileExists(str)) + return str; + } + + return wxEmptyString; +} + +int OsWin32_Help(WXHWND handle, const char* hlp, unsigned int cmd, const char* topic) +{ + wxString str = hlp; + if (str.IsEmpty() || !wxFileExists(str)) + { + switch(cmd) + { + case M_HELP_ONCONTEXT: + str = FindHelpFile(topic); + if (wxFileExists(str)) + break; + default: + str = FindHelpFile(topic); + if (wxFileExists(str)) + { + topic = NULL; + } + else + { + str = GetHelpDir(); + str += "index.html"; + } + break; + } + } + if (!str.IsEmpty() && wxFileExists(str)) + { + if (str.EndsWith(".pdf")) + { + wxString strCmd = OsWin32_File2App(str); + if (topic && *topic) + strCmd << " /A nameddest=" << topic; + strCmd << " " << str; + ::wxExecute(strCmd); + } else + if (str.EndsWith(".chm")) + { + static wxCHMHelpController* hlp = new wxCHMHelpController; + if (hlp->LoadFile(str)) + { + wxString strSection = topic; + strSection += ".html"; + hlp->DisplaySection(strSection); + } + } else + if (str.EndsWith(".html")) + { + wxFileName fn = str; + fn.MakeAbsolute(); + str = fn.GetFullPath(); + ::ShellExecute((HWND)handle, "open", str, NULL, NULL, SW_SHOWNORMAL); + } + + return true; + } + OsWin32_Beep(1); // Error beep + return false; +} + +/////////////////////////////////////////////////////////// +// Execute in window support +/////////////////////////////////////////////////////////// + +struct TFindWindowInfo +{ + HINSTANCE _instance; + wxString _file; + HWND _hwnd; + + TFindWindowInfo() : _instance(NULL), _hwnd(NULL) { } +}; + +static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + TFindWindowInfo* w = (TFindWindowInfo*)lParam; + + if (w->_instance != NULL) + { + HINSTANCE inst = (HINSTANCE)::GetWindowLong(hwnd, GWL_HINSTANCE); + if (inst == w->_instance) + { + // Cerco di capire se e' la finetra principale dal fatto che abbia la caption ed i bottoni di chiusura + const DWORD dwWanted = WS_CAPTION | WS_SYSMENU; + const DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + if ((style & dwWanted) == dwWanted) + { + w->_hwnd = hwnd; + return FALSE; + } + return TRUE; + } + } + + if (!w->_file.IsEmpty()) + { + char str[_MAX_PATH]; + if (::GetWindowText(hwnd, str, sizeof(str))) + { + wxString title = str; + title.MakeUpper(); + if (title.Find(w->_file) >= 0) + { + w->_hwnd = hwnd; + return FALSE; + } + } + } + + return TRUE; +} + +WXHINSTANCE OsWin32_ProcessModule(const char* name) +{ + WXHINSTANCE hModule = NULL; + + DWORD* aProcesses = NULL; + DWORD nItems = 0, nFound = 0; + for (nItems = 256; ; nItems *= 2) + { + DWORD cbNeeded = 0; + free(aProcesses); + aProcesses = (DWORD*)calloc(nItems, sizeof(DWORD)); + if (!EnumProcesses(aProcesses, nItems*sizeof(DWORD), &cbNeeded)) + { + free(aProcesses); + return false; + } + nFound = cbNeeded / sizeof(DWORD); + if (nFound < nItems) + break; + } + + for (DWORD i = 0; i < nFound && !hModule; i++) if (aProcesses[i]) + { + HANDLE hProcess = ::OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] ); + if (hProcess != NULL) + { + HMODULE hMod; DWORD cbNeeded; + if (::EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded) ) + { + TCHAR szProcessName[MAX_PATH] = { 0 }; + ::GetModuleBaseName( hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) ); + if (wxStricmp(szProcessName, name) == 0) + hModule = (WXHINSTANCE)hMod; + } + // Release the handle to the process. + CloseHandle( hProcess ); + } + } + + free(aProcesses); + return hModule; +} + +void OsWin32_PlaceProcessInWindow(unsigned int instance, const char* name, unsigned int parent) +{ + TFindWindowInfo w; + w._instance = (HINSTANCE)instance; + w._file = name; + w._file.MakeUpper(); + + for (int i = 0; w._hwnd == NULL && i < 20; i++) + { + ::wxMilliSleep(500); + ::EnumWindows(EnumWindowsProc, LPARAM(&w)); + } + + if (w._hwnd != NULL) // L'ho trovata! + { + RECT rct; ::GetClientRect((HWND)parent, &rct); + ::SetParent(w._hwnd, (HWND)parent); + const int fx = ::GetSystemMetrics(SM_CXFRAME); + const int fy = ::GetSystemMetrics(SM_CYFRAME); + int cy = ::GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYBORDER); + if (::GetMenu(w._hwnd) != NULL) + cy += ::GetSystemMetrics(SM_CYMENU); + ::SetWindowPos(w._hwnd, (HWND)parent, -fx, -fy-cy, rct.right+2*fx, rct.bottom+cy+2*fy, SWP_NOZORDER); + } +} + +static BOOL CALLBACK EnumCampoChildrenProc(HWND hwnd, LPARAM lParam) +{ + char str[_MAX_PATH]; + if (::GetWindowText(hwnd, str, sizeof(str))) + { + TFindWindowInfo* w = (TFindWindowInfo*)lParam; + if (w->_file == str) // str == "__CAMPO_HOST_WINDOW__" + { + str[13] = '\0'; // Impedisce che questa finestra abbia altri figli indesiderati + ::SetWindowText(hwnd, str); + w->_hwnd = hwnd; + return FALSE; // Fine della ricerca + } + } + return TRUE; // Continua a cercare +} + +static BOOL CALLBACK EnumCampoMenuChildrenProc(HWND hwnd, LPARAM lParam) +{ + char str[_MAX_PATH]; + if (::GetWindowText(hwnd, str, sizeof(str))) + { + if (strstr(str, " - ") != NULL) + { + const TFindWindowInfo* w = (TFindWindowInfo*)lParam; + ::EnumChildWindows(hwnd, EnumCampoChildrenProc, lParam); + if (w->_hwnd != NULL) + return FALSE; // Fine della ricerca + } + } + return TRUE; // Continua a cercare +} + +unsigned int OsWin32_FindMenuContainer() +{ + wxString strApp; + wxFileName::SplitPath(wxTheApp->argv[0], NULL, &strApp, NULL); + strApp.MakeLower(); + if (strApp == "ba0" || strApp == "ba1" || strApp == "ba7") + return 0; // Special programs that can't be hosted by ba0 + + TFindWindowInfo w; + w._file = "__CAMPO_HOST_WINDOW__"; + ::EnumWindows(EnumCampoMenuChildrenProc, LPARAM(&w)); + return (unsigned int)w._hwnd; +} + +static BOOL CALLBACK CountChildrenProc(HWND WXUNUSED(hwnd), LPARAM lParam) +{ + if (lParam) + { + LONG* n = (LONG*)lParam; + (*n)++; + } + return TRUE; +} + +long OsWin32_GetChildrenCount(unsigned int parent) +{ + LONG n = 0; + ::EnumChildWindows((HWND)parent, CountChildrenProc, (LPARAM)&n); + return n; +} + +static BOOL CALLBACK CloseChildrenProc(HWND hwnd, LPARAM lParam) +{ + ::PostMessage(hwnd, WM_CLOSE, 0, 0); + return CountChildrenProc(hwnd, lParam); +} + +long OsWin32_CloseChildren(unsigned int parent) +{ + LONG n = 0; + ::EnumChildWindows((HWND)parent, CloseChildrenProc, (LPARAM)&n); + return n; +} + +/////////////////////////////////////////////////////////// +// Ex-Golem utilities +/////////////////////////////////////////////////////////// + +static long GetRegistryString(HKEY key, const char* subkey, wxString& retstr) +{ + HKEY hkey; + long retval = ::RegOpenKey(key, subkey, &hkey); + if (retval == ERROR_SUCCESS) + { + char retdata[_MAX_PATH]; + long datasize = sizeof(retdata); + ::RegQueryValue(hkey, NULL, retdata, &datasize); + ::RegCloseKey(hkey); + retstr = retdata; + } + return retval; +} + +wxString OsWin32_File2App(const char* filename) +{ + wxString app; + + if (*filename != '.') + { + char retdata[_MAX_PATH]; + HINSTANCE hinst = ::FindExecutable(filename, ".", retdata); + DWORD* pinst = (DWORD*)hinst; + UINT err = LOWORD(pinst); + if (err > 32) + app = retdata; + } + + if (app.IsEmpty()) + { + wxString ext; + if (*filename == '.') + ext = filename; + else + { + wxSplitPath(filename, NULL, NULL, &ext); + if (!ext.StartsWith(".")) + ext = "." + ext; + } + ext.MakeLower(); + + wxString key; + if (GetRegistryString(HKEY_CLASSES_ROOT, ext, key) == ERROR_SUCCESS) + { + key << "\\shell\\open\\command"; + if (GetRegistryString(HKEY_CLASSES_ROOT, key, key) == ERROR_SUCCESS) + { + key.Replace("\"", " "); + int pos = key.Find("%1"); + if (pos > 0) + key.Truncate(pos); + key.Trim(false); key.Trim(true); + app = key; + } + } + } + + return app; +} + +static bool IsInternetAddress(const char* filename) +{ + wxString url(filename); url.MakeLower(); + if (url.StartsWith("http:") || url.StartsWith("ftp:")) + return true; + if (url.Find("www.") >= 0) + return true; + + wxString ext; wxFileName::SplitPath(url, NULL, NULL, NULL, &ext); + const char* const extensions[] = { "com","edu","eu","gov","it","mil","net","org", NULL }; + for (int e = 0; extensions[e]; e++) + if (ext == extensions[e]) + return true; + + return false; +} + +wxIcon OsWin32_LoadIcon(const char* filename) +{ + int icon_number = 0; + + wxString ext; + if (*filename == '.' && strlen(filename) < _MAX_EXT) + ext = filename; + else + { + if (IsInternetAddress(filename)) + ext = ".htm"; + else + { + wxFileName::SplitPath(filename, NULL, NULL, NULL, &ext); + if (!ext.StartsWith(".")) + ext.insert(0, "."); + } + } + ext.MakeLower(); + + wxString key; + if (ext != ".exe") + { + if (::GetRegistryString(HKEY_CLASSES_ROOT, ext, key) == ERROR_SUCCESS) + { + key << "\\DefaultIcon"; + if (::GetRegistryString(HKEY_CLASSES_ROOT, key, key) == ERROR_SUCCESS) // Windows 95 only + { + const int comma = key.find(','); + if (comma > 0) + { + icon_number = atoi(key.Mid(comma+1)); + key.Truncate(comma); + } + } + else + { + key = OsWin32_File2App(filename); + if (key.IsEmpty()) + key = OsWin32_File2App(".htm"); + } + } + } + else + key = filename; + + // Toglie eventuali parametri sulla riga si comando + const int ext_pos = key.Find(".exe"); + if (ext_pos > 0) + key.Truncate(ext_pos+4); + + wxString strFullName = key; + if (icon_number > 0) + strFullName << ";" << icon_number; + + wxIcon ico(strFullName, wxBITMAP_TYPE_ICO); + return ico; +} + +static void TimetToFileTime(time_t t, LPFILETIME pft) +{ + ULARGE_INTEGER time_value; + time_value.QuadPart = (t * 10000000LL) + 116444736000000000LL; + pft->dwLowDateTime = time_value.LowPart; + pft->dwHighDateTime = time_value.HighPart; +} + +void OsWin32_Set_FileTime(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime) +{ + HANDLE h = CreateFileA(file, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + FILETIME *fctime = nullptr; + FILETIME *fatime = nullptr; + FILETIME *fmtime = nullptr; + + if (ctime != nullptr) + { + time_t t = mktime(ctime); + + fctime = new FILETIME; + TimetToFileTime(t, fctime); + } + if (atime != nullptr) + { + time_t t = mktime(atime); + + fatime = new FILETIME; + TimetToFileTime(t, fatime); + } + if (mtime != nullptr) + { + time_t t = mktime(mtime); + + fmtime = new FILETIME; + TimetToFileTime(t, fmtime); + } + SetFileTime(h, fctime, fatime, fmtime); + safe_delete(fctime); + safe_delete(fatime); + safe_delete(fmtime); + CloseHandle(h); +} + +// action = [ open, edit, print ]; +bool OsWin32_GotoUrl(const char* url, const char* action) +{ + bool ok = false; + + // Sarebbe meglio un flag esplicito, ma per ora attendiamo solo le stampe + if (action && wxStricmp(action, "print") == 0) + { + SHELLEXECUTEINFO sei; memset(&sei, 0, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; + sei.lpVerb = action; + sei.lpFile = url; + sei.nShow = SW_SHOWNORMAL; + if (::ShellExecuteEx(&sei)) + { + if (sei.hProcess != NULL) + { + ::WaitForSingleObject(sei.hProcess, 0); + ::CloseHandle(sei.hProcess); + } + ok = true; + } + } else + if (wxStrstr(url, ".jar")) + { + const wxFileName fn = url; + wxString args; args << "-jar " << fn.GetFullPath(); + HINSTANCE hinst = ::ShellExecute(NULL, NULL, "java.exe", args, fn.GetPath(), SW_HIDE); // Hide java console + DWORD winst = DWORD((DWORD*)hinst); // Tutto 'sto giro per evitare un warning + ok = UINT(winst) > 32; + } + else + { + HINSTANCE hinst = ::ShellExecute(NULL, action, url, NULL, NULL, SW_SHOWNORMAL); + DWORD winst = DWORD((DWORD*)hinst); // Tutto 'sto giro per evitare un warning + ok = UINT(winst) > 32; + } + return ok; +} + +#ifdef SPEECH_API + +#include + +static ISpVoice* m_pVoice = NULL; + +bool OsWin32_InitializeSpeech() +{ + if (m_pVoice == NULL) + CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&m_pVoice); + return m_pVoice != NULL; +} + +void OsWin32_DeinitializeSpeech() +{ + if (m_pVoice != NULL) + { + m_pVoice->WaitUntilDone(1000); + m_pVoice->Release(); + m_pVoice = NULL; + } +} + +bool OsWin32_Speak(const char* text, bool async) +{ + if (m_pVoice != NULL) + { + WCHAR str[1204]; + MultiByteToWideChar(CP_ACP, 0, text, -1, str, strlen(text)+1); + if (async) + m_pVoice->Speak(str, SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); + else + m_pVoice->Speak(str, SPF_PURGEBEFORESPEAK, NULL); + return true; + } + return false; +} + +#endif + +int OsWin32_GetSessionId() +{ + DWORD session = 0; + ::ProcessIdToSessionId(::GetCurrentProcessId(), &session); + return (int)session; + // return WTSGetActiveConsoleSessionId(); // Always 1! :-( +} + +bool OsWin32_IsWindowsServer() +{ + bool bServer = IsWindowsServer(); + +/* OSVERSIONINFOEXW osinfo; memset(&osinfo, 0, sizeof(osinfo)); + bool bServer = false; + + osinfo.dwOSVersionInfoSize = sizeof(osinfo); + if (::GetVersionExW((OSVERSIONINFOW*)&osinfo)) + bServer = osinfo.wProductType != VER_NT_WORKSTATION; + return bServer;*/ + // return ::GetSystemMetrics(SM_REMOTESESSION) != 0; + return bServer; +} + +void OsWin32_NumberFormat(char* str, int size) +{ + static char decsep = '\0', thosep = '\0'; + + char buf[80] = ""; + if (!decsep) + { + ::GetNumberFormat(LOCALE_USER_DEFAULT, 0, "1936.27", NULL, buf, sizeof(buf)); + decsep = buf[strlen(buf)-3]; + thosep = buf[1] == '9' ? '\0' : buf[1]; + } + + if (str && *str) + { + int j = 0; + for (int i = 0; str[i]; i++) + { + switch (str[i]) + { + case '.': buf[j++] = decsep; break; + case ',': break; // Ignore thousand separator + default : buf[j++] = str[i]; break; + } + } + buf[j] = '\0'; + wxStrncpy(str, buf, size); + } +} + +/////////////////////////////////////////////////////////// +// OsWin32_Progress... +/////////////////////////////////////////////////////////// + +static const wchar_t* str2wstr(const char* str, int maxlen = -1) +{ + static wchar_t wstr[260]; + if (str && *str && maxlen) + { + if (maxlen < 0 || maxlen > 256) + maxlen = strlen(str); + wxConvCurrent->ToWChar(wstr, 260, str, maxlen); + } + else + wstr[0] = '\0'; + return wstr; +} + +class Win32ProgressIndicator +{ + IProgressDialog* m_ppd; + long _curr, _total, _perc; + bool _cancellable; + int _lines; + clock_t _start; + + static int __nProgress; // Instances + +public: + bool IsOk() const { return m_ppd != NULL; } + bool SetProgress(long curr, long tot); + void SetText(const char* msg); + + Win32ProgressIndicator(WXHWND hwndParent, const char* strTitle, long nMax, bool bCanCancel); + ~Win32ProgressIndicator(); +}; + +int Win32ProgressIndicator::__nProgress = 0; + +bool Win32ProgressIndicator::SetProgress(long nCurrent, long nTotal) +{ + bool ok = IsOk(); + if (ok) + { + if (nCurrent <= 0 || nTotal != _total) + { + m_ppd->Timer(PDTIMER_RESET, NULL); + _start = clock(); + _perc = 0; + } + m_ppd->SetProgress(nCurrent, nTotal); + _curr = nCurrent; + _total = nTotal; + + if (_lines < 2) + { + const int newperc = nTotal > 0 && nCurrent > 0 ? nCurrent*100/nTotal : 0; + if (newperc != _perc) + { + _perc = newperc; + const long nSec = (clock() -_start) / CLOCKS_PER_SEC; + if (nSec > 0) + { + const int nSpeed = nCurrent / nSec > 0 ? nCurrent / nSec : 1; + const int nRemaining = nTotal - nCurrent; + const int remainingTime = nSpeed > 0 ? nRemaining / nSpeed : 0; + int s = nSec; + const int h = s / 3600; s %= 3600; + const int m = s / 60; s %= 60; + wxString str; + + str = str.Format("%d%% - Trascorsi %02d:%02d:%02d", _perc, h, m, s); + if (nSpeed < 120) + str << str.Format(" - Velocità %d/sec - %d sec.alla fine", nSpeed, remainingTime); + else + { + const int mins = remainingTime / 60; + + str << str.Format(" - Velocità %d/min", nSpeed * 60); + if (mins < 2) + str << str.Format(" - %d sec.alla fine", remainingTime); + else + str << str.Format(" - %d min.alla fine", mins); + } + m_ppd->SetLine(2, str2wstr(str), FALSE, NULL); + } + } + } + + if (_cancellable && m_ppd->HasUserCancelled()) + ok = false; + } + return ok; +} + +void Win32ProgressIndicator::SetText(const char* msg) +{ + if (IsOk()) + { + if (msg && *msg) + { + const char* acapo = strchr(msg, '\n'); + if (acapo) + { + m_ppd->SetLine(1, str2wstr(msg, acapo-msg), FALSE, NULL); + m_ppd->SetLine(2, str2wstr(acapo+1), FALSE, NULL); + _lines = 2; + } + else + { + m_ppd->SetLine(1, str2wstr(msg), FALSE, NULL); + m_ppd->SetLine(2, L"", FALSE, NULL); + _lines = 1; + } + } + else + { + m_ppd->SetLine(1, L"", FALSE, NULL); + m_ppd->SetLine(2, L"", FALSE, NULL); + _lines = 0; + } + } +} + +Win32ProgressIndicator::Win32ProgressIndicator(WXHWND hwndParent, const char* strTitle, long nMax, bool bCanCancel) +{ + m_ppd = NULL; + ::CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC_SERVER, IID_IProgressDialog, (void **)&m_ppd); + if (m_ppd) + { + if (strTitle && *strTitle) + m_ppd->SetTitle(str2wstr(strTitle)); // Set the title of the dialog. + + DWORD dwFlags = PROGDLG_NOTIME | PROGDLG_MODAL | PROGDLG_NOMINIMIZE; + if (nMax <= 1) + { + if (nMax == 1) + dwFlags |= PROGDLG_MARQUEEPROGRESS; + else + dwFlags |= PROGDLG_NOPROGRESSBAR; + } + + _cancellable = bCanCancel && nMax > 1; + if (_cancellable) + m_ppd->SetCancelMsg(L"Attendere prego...", NULL); // Will only be displayed if Cancel button is pressed. + else + dwFlags |= PROGDLG_NOCANCEL; + + _lines = 0; // No text right now! + _perc = 0; // No progress right now + m_ppd->StartProgressDialog((HWND)hwndParent, NULL, dwFlags, NULL); // Display and enable automatic estimated time remaining. + m_ppd->Timer(PDTIMER_RESET, NULL); + _start = clock(); + + IOleWindow* m_wnd = NULL; + if (SUCCEEDED(m_ppd->QueryInterface(IID_IOleWindow, (void**)m_wnd))) + { + HWND hwnd = NULL; + if (m_wnd && SUCCEEDED(m_wnd->GetWindow(&hwnd))) + { + RECT rct; ::GetWindowRect(hwnd, &rct); + const int x = rct.left; + const int y = int((1.5*__nProgress+0.5)*(rct.bottom-rct.top)); + ::SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + WXHICON hIcon = xvtart_GetIconResource(0).GetHICON(); + ::SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + } + } + __nProgress++; + } +} + +Win32ProgressIndicator::~Win32ProgressIndicator() +{ + if (m_ppd) + { + wxASSERT(__nProgress >= 0); + m_ppd->StopProgressDialog(); + m_ppd->Release(); + m_ppd = NULL; + __nProgress--; + } +} + +WXHWND OsWin32_ProgressCreate(WXHWND hwndParent, const char* strTitle, long nMax, bool bCanCancel) +{ + Win32ProgressIndicator* pi = new Win32ProgressIndicator(hwndParent, strTitle, nMax, bCanCancel); + if (pi && !pi->IsOk()) + { + delete pi; + pi = NULL; + } + return (WXHWND)pi; +} + +void OsWin32_ProgressDestroy(WXHWND prog) +{ + if (prog) + { + Win32ProgressIndicator* ppd = (Win32ProgressIndicator*)prog; + delete ppd; + } +} + +bool OsWin32_ProgressSetStatus(WXHWND prog, long nCurrent, long nTotal) +{ + bool ok = true; + if (prog) + { + Win32ProgressIndicator* ppd = (Win32ProgressIndicator*)prog; + ok = ppd->SetProgress(nCurrent, nTotal); + } + return ok; +} + +void OsWin32_ProgressSetText(WXHWND prog, const char* msg) +{ + Win32ProgressIndicator* pd = (Win32ProgressIndicator*)prog; + if (pd && pd->IsOk()) + pd->SetText(msg); +} + +bool OsWin32_IsdTaskbarVisible() +{ + HWND hTaskbarWnd = FindWindow("Shell_TrayWnd", NULL); + HMONITOR hMonitor = MonitorFromWindow(hTaskbarWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO info = { sizeof(MONITORINFO) }; + + if (GetMonitorInfo(hMonitor, &info)) + { + RECT rect; + GetWindowRect(hTaskbarWnd, &rect); + + if ((rect.top >= info.rcMonitor.bottom - 4) || + (rect.right <= 2) || + (rect.bottom <= 4) || + (rect.left >= info.rcMonitor.right - 2)) + return false; + } + return (IsWindowVisible(hTaskbarWnd)); + +} + +wxString OsWin32_get_disk_root(const char* path) +{ + wxString str; + if (path && *path) + { + str = path; + if (!wxEndsWithPathSeparator(str)) + str << wxFILE_SEP_PATH; + + wxChar drive[_MAX_DRIVE], dir[_MAX_DIR]; + xvt_fsys_parse_pathname(str, drive, dir, NULL, NULL, NULL); + + if (*drive) + str = drive; + else + str = dir; + + if (!wxEndsWithPathSeparator(str)) + str << wxFILE_SEP_PATH; + } + return str; +} + +long OsWin32_get_MAC_adresses(char * adresses) +{ + PIP_ADAPTER_INFO AdapterInfo; + DWORD dwBufLen = 0; + DWORD dwRetVal = 0; + + *adresses = '\0'; + // Make an initial call to GetAdaptersInfo to get the necessary size into the dwBufLen variable + if (GetAdaptersInfo(nullptr, &dwBufLen) == ERROR_BUFFER_OVERFLOW) + { + AdapterInfo = (IP_ADAPTER_INFO *)malloc(dwBufLen); + if (AdapterInfo == nullptr) + return ENOMEM; + } + + if ((dwRetVal = GetAdaptersInfo(AdapterInfo, &dwBufLen)) == NO_ERROR) + { + // Contains pointer to current adapter info + PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo; + do + { + char mac_addr[STR_MAC_SIZE]; + + // technically should look at pAdapterInfo->AddressLength + // and not assume it is 6. + *mac_addr = '\0'; + if (*adresses) + strcat(adresses, "|"); + + UINT chksum = pAdapterInfo->Address[0] + pAdapterInfo->Address[1] + pAdapterInfo->Address[2] + pAdapterInfo->Address[3] + pAdapterInfo->Address[4] + pAdapterInfo->Address[5]; + + if (chksum != 0) + sprintf(mac_addr, "%02X:%02X:%02X:%02X:%02X:%02X", + pAdapterInfo->Address[0], pAdapterInfo->Address[1], + pAdapterInfo->Address[2], pAdapterInfo->Address[3], + pAdapterInfo->Address[4], pAdapterInfo->Address[5]); + + strcat(adresses, mac_addr); + pAdapterInfo = pAdapterInfo->Next; + } while (pAdapterInfo); + } + free(AdapterInfo); + return dwRetVal; +} + +unsigned long OsWin32_GetDriveSerialNumber(char * path) +{ + CHAR szVolumeNameBuffer[256]; //this will have the name of your drive + DWORD dwVolumeSerialNumber; //this will have the serial number of your drive + DWORD dwMaximumComponentLength; //this is the max length in between each \ in a path + DWORD dwFileSystemFlags; //this will return flags about the drive's file system + CHAR szFileSystemNameBuffer[256]; //this will contain the type of file system (ex: NTFS) + + GetVolumeInformation(path, szVolumeNameBuffer, 256, &dwVolumeSerialNumber, &dwMaximumComponentLength, &dwFileSystemFlags, szFileSystemNameBuffer, 256); + return (unsigned long)dwVolumeSerialNumber; +} + +int OsWin32_TaskList(const char ** list) +{ + DWORD aProcesses[MAX_TASKS + 1], cbNeeded = 0, cProcesses; + unsigned int ntasks = 0; + + if (EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) + { + // Calculate how many process identifiers were returned. + cProcesses = cbNeeded / sizeof(DWORD); + // Print the name and process identifier for each process. + for (unsigned int i = 0; i < cProcesses; i++) + { + if (aProcesses[i] != 0) + { + TCHAR szProcessName[MAX_PATH] = TEXT(""); + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, aProcesses[i]); // Get a handle to the process. + + // Get the process name. + if (NULL != hProcess) + { + HMODULE hMod; + DWORD cbNeeded; + + if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), + &cbNeeded)) + { + GetModuleBaseName(hProcess, hMod, szProcessName, + sizeof(szProcessName) / sizeof(TCHAR)); + list[ntasks++] = _strdup(szProcessName); + } + } + +// Release the handle to the process. + CloseHandle(hProcess); + } + } + } + return ntasks; +} \ No newline at end of file diff --git a/src/xvaga01/oswin32.h b/src/xvaga01/oswin32.h new file mode 100644 index 000000000..3ed25d05d --- /dev/null +++ b/src/xvaga01/oswin32.h @@ -0,0 +1,55 @@ +void OsWin32_Beep(int severity); +const char * OsWin32_CommandLine(); +bool OsWin32_CheckPrinterInfo(const void* data, unsigned int size); +void* OsWin32_ConvertFromNativePrinterInfo(void* hGlobal, unsigned int& nSize); +void* OsWin32_ConvertToNativePrinterInfo(void* data, unsigned int nSize); +HBITMAP OsWin32_CreateBitmap(const wxImage& img, wxDC& dc); +bool OsWin32_DrawBitmap(HBITMAP hBMP, wxDC& dc, const wxRect& dst, const wxRect& src); +void OsWin32_DrawDottedRect(WXHDC hDC, int left, int top, int right, int bottom); + +wxString OsWin32_File2App(const char* filename); +bool OsWin32_GotoUrl(const char* url, const char* action); +wxIcon OsWin32_LoadIcon(const char* file); + +void OsWin32_Set_FileTime(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime); + +int OsWin32_EnumerateFamilies(WXHDC hDC, char** families, int max_count); +int OsWin32_EnumerateSizes(WXHDC hDC, const char* name, long* sizes, short* scalable, int max_count); +void OsWin32_SetCaptionStyle(WXHWND handle, long style); +void* OsWin32_GetPrinterInfo(int& size, const char* printer); + +WXHINSTANCE OsWin32_ProcessModule(const char* name); +void OsWin32_PlaceProcessInWindow(unsigned int instance, const char* name, unsigned int parent); +unsigned int OsWin32_FindMenuContainer(); +long OsWin32_GetChildrenCount(unsigned int parent); +long OsWin32_CloseChildren(unsigned int parent); +void OsWin32_CloseSiblings(unsigned int parent); +void OsWin32_UpdateWindow(unsigned int handle); + +void OsWin32_NumberFormat(char* str, int size); + +int OsWin32_Help(WXHWND handle, const char* hlp, unsigned int cmd, const char* topic); + +int OsWin32_GetSessionId(); +bool OsWin32_IsWindowsServer(); + +WXHWND OsWin32_ProgressCreate(WXHWND hwndOwner, const char* strTtle, long nTotal, bool bCanCancel); +void OsWin32_ProgressDestroy(WXHWND hProgDlg); +bool OsWin32_ProgressSetStatus(WXHWND hProgDlg, long nCurrent, long nTotal); +void OsWin32_ProgressSetText(WXHWND hProgDlg, const char* msg); + +bool OsWin32_IsdTaskbarVisible(); + +long OsWin32_get_MAC_adresses(char * addresses); + +wxString OsWin32_get_disk_root(const char* path); +unsigned long OsWin32_GetDriveSerialNumber(char * path); +int OsWin32_TaskList(const char ** list); + +//#define SPEECH_API 1 +#ifdef SPEECH_API + bool OsWin32_InitializeSpeech(); + bool OsWin32_Speak(const char* text, bool async); + void OsWin32_DeinitializeSpeech(); +#endif + diff --git a/src/xvaga01/smapi.cpp b/src/xvaga01/smapi.cpp new file mode 100644 index 000000000..d4aa3b7ce --- /dev/null +++ b/src/xvaga01/smapi.cpp @@ -0,0 +1,523 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: smapi.cpp +// Purpose: Simple MAPI classes +// Author: PJ Naughter +// Modified by: Julian Smart +// Created: 2001-08-21 +// RCS-ID: $Id: smapi.cpp,v 1.5 2010-04-22 15:26:15 guy Exp $ +// Copyright: (c) PJ Naughter +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// +#include "wxinc.h" + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifdef __WXMSW__ + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/string.h" +#include "wx/msw/private.h" + +// mapi.h in Cygwin's include directory isn't a full implementation and is +// not sufficient for this lib. However recent versions of Cygwin also +// have another mapi.h in include/w32api which can be used. +// +#ifdef __CYGWIN__ +#include +#else +#include +#endif + +#include "smapi.h" + +class wxMapiData +{ +public: + wxMapiData() + { + m_hSession = 0; + m_nLastError = 0; + m_hMapi = NULL; + m_lpfnMAPILogon = NULL; + m_lpfnMAPILogoff = NULL; + m_lpfnMAPISendMail = NULL; + m_lpfnMAPIResolveName = NULL; + m_lpfnMAPIFreeBuffer = NULL; + } + + //Data + LHANDLE m_hSession; //Mapi Session handle + long m_nLastError; //Last Mapi error value + HINSTANCE m_hMapi; //Instance handle of the MAPI dll + LPMAPILOGON m_lpfnMAPILogon; //MAPILogon function pointer + LPMAPILOGOFF m_lpfnMAPILogoff; //MAPILogoff function pointer + LPMAPISENDMAIL m_lpfnMAPISendMail; //MAPISendMail function pointer + LPMAPIRESOLVENAME m_lpfnMAPIResolveName; //MAPIResolveName function pointer + LPMAPIFREEBUFFER m_lpfnMAPIFreeBuffer; //MAPIFreeBuffer function pointer +}; + + +////////////////////////////////// Implementation ///////////////////////////// + +wxMapiSession::wxMapiSession() +{ + m_data = new wxMapiData; + + Initialise(); +} + +wxMapiSession::~wxMapiSession() +{ + //Logoff if logged on + Logoff(); + + //Unload the MAPI dll + Deinitialise(); + + delete m_data; +} + +void wxMapiSession::Initialise() +{ + //First make sure the "WIN.INI" entry for MAPI is present aswell + //as the MAPI32 dll being present on the system + bool bMapiInstalled = (::GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0) && + (SearchPath(NULL, _T("MAPI32.DLL"), NULL, 0, NULL, NULL) != 0); + + if (bMapiInstalled) + { + //Load up the MAPI dll and get the function pointers we are interested in + m_data->m_hMapi = ::LoadLibrary(_T("MAPI32.DLL")); + if (m_data->m_hMapi) + { + m_data->m_lpfnMAPILogon = (LPMAPILOGON) GetProcAddress(m_data->m_hMapi, "MAPILogon"); + m_data->m_lpfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress(m_data->m_hMapi, "MAPILogoff"); + m_data->m_lpfnMAPISendMail = (LPMAPISENDMAIL) GetProcAddress(m_data->m_hMapi, "MAPISendMail"); + m_data->m_lpfnMAPIResolveName = (LPMAPIRESOLVENAME) GetProcAddress(m_data->m_hMapi, "MAPIResolveName"); + m_data->m_lpfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(m_data->m_hMapi, "MAPIFreeBuffer"); + + //If any of the functions are not installed then fail the load + if (m_data->m_lpfnMAPILogon == NULL || + m_data->m_lpfnMAPILogoff == NULL || + m_data->m_lpfnMAPISendMail == NULL || + m_data->m_lpfnMAPIResolveName == NULL || + m_data->m_lpfnMAPIFreeBuffer == NULL) + { + wxLogDebug(_T("Failed to get one of the functions pointer in MAPI32.DLL\n")); + Deinitialise(); + } + } + } + else + { + wxMessageBox("Mapi is not installed on this computer", "MAPIInitialise", wxOK|wxCENTRE|wxICON_ERROR); + } +} + +void wxMapiSession::Deinitialise() +{ + if (m_data->m_hMapi) + { + //Unload the MAPI dll and reset the function pointers to NULL + FreeLibrary(m_data->m_hMapi); + m_data->m_hMapi = NULL; + m_data->m_lpfnMAPILogon = NULL; + m_data->m_lpfnMAPILogoff = NULL; + m_data->m_lpfnMAPISendMail = NULL; + m_data->m_lpfnMAPIResolveName = NULL; + m_data->m_lpfnMAPIFreeBuffer = NULL; + } +} + +bool wxMapiSession::Logon(const wxString& sProfileName, const wxString& sPassword, wxWindow* pParentWnd) +{ + wxASSERT(MapiInstalled()); //MAPI must be installed + wxASSERT(m_data->m_lpfnMAPILogon); //Function pointer must be valid + + //Initialise the function return value + bool bSuccess = FALSE; + + //Just in case we are already logged in + Logoff(); + + //Setup the ascii versions of the profile name and password + int nProfileLength = sProfileName.Length(); + + LPSTR pszProfileName = NULL; + LPSTR pszPassword = NULL; + wxCharBuffer cbProfile(1),cbPassword(1); + if (nProfileLength) + { +#ifndef UNICODE + pszProfileName = (LPSTR) sProfileName.c_str(); + pszPassword = (LPSTR) sPassword.c_str(); +#else + cbProfile = sProfileName.mb_str(); + cbPassword = sPassword.mb_str(); + pszProfileName = cbProfile.data(); + pszPassword = cbPassword.data(); +#endif + } + + //Setup the flags & UIParam parameters used in the MapiLogon call + FLAGS flags = 0; + ULONG nUIParam = 0; + if (nProfileLength == 0) + { + //No profile name given, then we must interactively request a profile name + if (pParentWnd) + { + nUIParam = (ULONG) (HWND) pParentWnd->GetHWND(); + flags |= MAPI_LOGON_UI; + } + else + { + //No window given, just use the main window of the app as the parent window + if (wxTheApp->GetTopWindow()) + { + nUIParam = (ULONG) (HWND) wxTheApp->GetTopWindow()->GetHWND(); + flags |= MAPI_LOGON_UI; + } + } + } + + //First try to acquire a new MAPI session using the supplied settings using the MAPILogon functio + ULONG nError = m_data->m_lpfnMAPILogon(nUIParam, pszProfileName, pszPassword, flags | MAPI_NEW_SESSION, 0, &m_data->m_hSession); + if (nError != SUCCESS_SUCCESS && nError != MAPI_E_USER_ABORT) + { + //Failed to create a create mapi session, try to acquire a shared mapi session + wxLogDebug(_T("Failed to logon to MAPI using a new session, trying to acquire a shared one\n")); + nError = m_data->m_lpfnMAPILogon(nUIParam, NULL, NULL, 0, 0, &m_data->m_hSession); + if (nError == SUCCESS_SUCCESS) + { + m_data->m_nLastError = SUCCESS_SUCCESS; + bSuccess = TRUE; + } + else + { + wxLogDebug(_T("Failed to logon to MAPI using a shared session, Error:%ld\n"), nError); + m_data->m_nLastError = nError; + } + } + else if (nError == SUCCESS_SUCCESS) + { + m_data->m_nLastError = SUCCESS_SUCCESS; + bSuccess = TRUE; + } + + return bSuccess; +} + +bool wxMapiSession::LoggedOn() const +{ + return (m_data->m_hSession != 0); +} + +bool wxMapiSession::MapiInstalled() const +{ + return (m_data->m_hMapi != NULL); +} + +bool wxMapiSession::Logoff() +{ + wxASSERT(MapiInstalled()); //MAPI must be installed + wxASSERT(m_data->m_lpfnMAPILogoff); //Function pointer must be valid + + //Initialise the function return value + bool bSuccess = FALSE; + + if (m_data->m_hSession) + { + //Call the MAPILogoff function + ULONG nError = m_data->m_lpfnMAPILogoff(m_data->m_hSession, 0, 0, 0); + if (nError != SUCCESS_SUCCESS) + { + wxLogDebug(_T("Failed in call to MapiLogoff, Error:%ld"), nError); + m_data->m_nLastError = nError; + bSuccess = TRUE; + } + else + { + m_data->m_nLastError = SUCCESS_SUCCESS; + bSuccess = TRUE; + } + m_data->m_hSession = 0; + } + + return bSuccess; +} + +bool wxMapiSession::Resolve(const wxString& sName, void* lppRecip1) +{ + lpMapiRecipDesc* lppRecip = (lpMapiRecipDesc*) lppRecip1; + + wxASSERT(MapiInstalled()); //MAPI must be installed + wxASSERT(m_data->m_lpfnMAPIResolveName); //Function pointer must be valid + wxASSERT(LoggedOn()); //Must be logged on to MAPI + wxASSERT(m_data->m_hSession); //MAPI session handle must be valid + + //Call the MAPIResolveName function +#ifndef UNICODE + LPSTR lpszAsciiName = (LPSTR) sName.c_str(); +#else + wxCharBuffer cbName(1); + cbName = sName.mb_str(); + LPSTR lpszAsciiName = cbName.data(); +#endif + ULONG nError = m_data->m_lpfnMAPIResolveName(m_data->m_hSession, 0, lpszAsciiName, 0, 0, lppRecip); + if (nError != SUCCESS_SUCCESS) + { + wxLogDebug(_T("Failed to resolve the name: %s, Error:%ld\n"), + sName.c_str(), nError); + m_data->m_nLastError = nError; + } + + return (nError == SUCCESS_SUCCESS); +} + +bool wxMapiSession::Send(wxMailMessage& message, bool show_ui) +{ + wxASSERT(MapiInstalled()); //MAPI must be installed + wxASSERT(m_data->m_lpfnMAPISendMail); //Function pointer must be valid + wxASSERT(m_data->m_lpfnMAPIFreeBuffer); //Function pointer must be valid + wxASSERT(LoggedOn()); //Must be logged on to MAPI + wxASSERT(m_data->m_hSession); //MAPI session handle must be valid + + //Initialise the function return value + bool bSuccess = FALSE; + + //Create the MapiMessage structure to match the message parameter send into us + MapiMessage mapiMessage; + ZeroMemory(&mapiMessage, sizeof(mapiMessage)); +#ifndef UNICODE + mapiMessage.lpszSubject = (LPSTR) message.m_subject.c_str(); + mapiMessage.lpszNoteText = (LPSTR) message.m_body.c_str(); +#else + wxCharBuffer cbSubject(1),cbBody(1),cbOriginator(1); + cbSubject = message.m_subject.mb_str(); + cbBody = message.m_body.mb_str(); + mapiMessage.lpszSubject = cbSubject.data(); + mapiMessage.lpszNoteText = cbBody.data(); +#endif + mapiMessage.nRecipCount = message.m_to.GetCount() + message.m_cc.GetCount() + message.m_bcc.GetCount(); + wxASSERT(mapiMessage.nRecipCount); //Must have at least 1 recipient! + + //Allocate the recipients array + mapiMessage.lpRecips = new MapiRecipDesc[mapiMessage.nRecipCount]; + + // If we have a 'From' field, use it + if (!message.m_from.IsEmpty()) + { + mapiMessage.lpOriginator = new MapiRecipDesc; + ZeroMemory(mapiMessage.lpOriginator, sizeof(MapiRecipDesc)); + + mapiMessage.lpOriginator->ulRecipClass = MAPI_ORIG; + // TODO Do we have to call Resolve? +#ifndef UNICODE + mapiMessage.lpOriginator->lpszName = (LPSTR) message.m_from.c_str(); +#else + cbOriginator = message.m_from.mb_str(); + mapiMessage.lpOriginator->lpszName = cbOriginator.data(); +#endif + } + + //Setup the "To" recipients + int nRecipIndex = 0; + int nToSize = message.m_to.GetCount(); + int i; + for (i=0; ilpszName,*wxConvCurrent); + + //Don't forget to free up the memory MAPI allocated for us + m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); + } +#ifndef UNICODE + recip.lpszName = (LPSTR) sName.c_str(); +#else + recip.lpszName = sName.mb_str().release(); +#endif + + ++nRecipIndex; + } + + //Setup the "CC" recipients + int nCCSize = message.m_cc.GetCount(); + for (i=0; ilpszName,*wxConvCurrent); + + //Don't forget to free up the memory MAPI allocated for us + m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); + } +#ifndef UNICODE + recip.lpszName = (LPSTR) sName.c_str(); +#else + recip.lpszName = sName.mb_str().release(); +#endif + + ++nRecipIndex; + } + + //Setup the "BCC" recipients + int nBCCSize = message.m_bcc.GetCount(); + for (i=0; ilpszName,wxConvCurrent); + + //Don't forget to free up the memory MAPI allocated for us + m_data->m_lpfnMAPIFreeBuffer(lpTempRecip); + } +#ifndef UNICODE + recip.lpszName = (LPSTR) sName.c_str(); +#else + recip.lpszName = sName.mb_str().release(); +#endif + + ++nRecipIndex; + } + + //Setup the attachments + int nAttachmentSize = message.m_attachments.GetCount(); + int nTitleSize = message.m_attachmentTitles.GetCount(); + if (nTitleSize) + { + wxASSERT(nTitleSize == nAttachmentSize); //If you are going to set the attachment titles then you must set + //the attachment title for each attachment + } + if (nAttachmentSize) + { + mapiMessage.nFileCount = nAttachmentSize; + mapiMessage.lpFiles = new MapiFileDesc[nAttachmentSize]; + for (i=0; i 0 && message.m_query_receipt) + mapiMessage.flFlags |= MAPI_RECEIPT_REQUESTED; + + //Do the actual send using MAPISendMail + const UINT nFlags = show_ui ? MAPI_DIALOG : 0; + ULONG nError = m_data->m_lpfnMAPISendMail(m_data->m_hSession, 0, &mapiMessage, nFlags, 0); + if (nError == SUCCESS_SUCCESS) + { + bSuccess = TRUE; + m_data->m_nLastError = SUCCESS_SUCCESS; + } + else + { + wxString msg = "Impossibile inviare il messaggio: Errore "; + msg << nError; + wxMessageBox(msg, "MAPISendMail", wxOK|wxCENTRE|wxICON_ERROR); + m_data->m_nLastError = nError; + } + + //Tidy up the Attachements + if (nAttachmentSize) + { +#ifdef UNICODE + for (i = 0;i < nAttachmentSize;i++) + { + free(mapiMessage.lpFiles[i].lpszPathName); + free(mapiMessage.lpFiles[i].lpszFileName); + } +#endif + delete [] mapiMessage.lpFiles; + } + + //Free up the Recipients and Originator memory +#ifdef UNICODE + for (i = 0;i < nRecipIndex;i++) + free(mapiMessage.lpRecips[i].lpszName); +#endif + delete [] mapiMessage.lpRecips; + + delete mapiMessage.lpOriginator; + + return bSuccess; +} + +long wxMapiSession::GetLastError() const +{ + return m_data->m_nLastError; +} + +bool wxMailMessage::Send(const wxString& profileName, bool bUI, const wxString& WXUNUSED(sendMail)) +{ + wxASSERT(m_to.GetCount() > 0) ; + + wxString profile(profileName); + + wxMapiSession session; + + if (!session.MapiInstalled()) + return FALSE; + if (!session.Logon(profile)) + return FALSE; + + return session.Send(*this, bUI); +} + +#endif // __WXMSW__ + diff --git a/src/xvaga01/smapi.h b/src/xvaga01/smapi.h new file mode 100644 index 000000000..3cbe0b9ac --- /dev/null +++ b/src/xvaga01/smapi.h @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: smapi.h +// Purpose: Simple MAPI classes +// Author: PJ Naughter +// Modified by: Julian Smart +// Created: 2001-08-21 +// RCS-ID: $Id: smapi.h,v 1.4 2010-04-22 15:26:15 guy Exp $ +// Copyright: (c) PJ Naughter +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_SMAPI_H_ +#define _WX_SMAPI_H_ + +class wxMailMessage +{ +public: + + // A common usage + wxMailMessage(const wxString& subject, const wxString& to, + const wxString& body, const wxString& from = wxEmptyString, + const wxString& attachment = wxEmptyString, + const wxString& attachmentTitle = wxEmptyString) : m_query_receipt(false) + { + m_to.Add(to); + m_subject = subject; + m_body = body; + m_from = from; + if (!attachment.IsEmpty()) + { + m_attachments.Add(attachment); + m_attachmentTitles.Add(attachmentTitle); + } + } + + wxMailMessage() : m_query_receipt(false) {} + +//// Accessors + + void AddTo(const wxString& to) { m_to.Add(to); } + void AddCc(const wxString& cc) { m_cc.Add(cc); } + void AddBcc(const wxString& bcc) { m_bcc.Add(bcc); } + void AddAttachment(const wxString& attach, const wxString& title = wxEmptyString) + { m_attachments.Add(attach); m_attachmentTitles.Add(title); } + + void SetSubject(const wxString& subject) { m_subject = subject; } + void SetBody(const wxString& body) { m_body = body; } + void SetFrom(const wxString& from) { m_from = from; } + bool Send(const wxString& profileName = wxEmptyString, + bool bShowUI = false, const wxString& sendMail = wxT("/usr/sbin/sendmail -t")); + +public: + wxArrayString m_to; //The To: Recipients + wxString m_from; //The From: email address (optional) + wxArrayString m_cc; //The CC: Recipients + wxArrayString m_bcc; //The BCC Recipients + wxString m_subject; //The Subject of the message + wxString m_body; //The Body of the message + wxArrayString m_attachments; //Files to attach to the email + wxArrayString m_attachmentTitles; //Titles to use for the email file attachments + bool m_query_receipt; //Query receipt message +}; + +class wxMapiData; + +//The class which encapsulates the MAPI connection +class wxMapiSession +{ +public: + //Constructors / Destructors + wxMapiSession(); + ~wxMapiSession(); + + //Logon / Logoff Methods + bool Logon(const wxString& sProfileName, const wxString& sPassword = wxEmptyString, wxWindow* pParentWnd = NULL); + bool LoggedOn() const; + bool Logoff(); + + //Send a message + bool Send(wxMailMessage& message, bool show_ui); + + //General MAPI support + bool MapiInstalled() const; + + //Error Handling + long GetLastError() const; + +protected: + //Methods + void Initialise(); + void Deinitialise(); + bool Resolve(const wxString& sName, void* lppRecip1); + + wxMapiData* m_data; + +}; + + +#endif //_WX_SMAPI_H_ diff --git a/src/xvaga01/statbar.h b/src/xvaga01/statbar.h new file mode 100644 index 000000000..a7d0a84b9 --- /dev/null +++ b/src/xvaga01/statbar.h @@ -0,0 +1,59 @@ +/* STATBAR.H for dynamic custom control for XVT/Design 2.01 + + $Revision: 1.5 $ $Author: guy $ $Date: 2008-05-20 14:06:05 $ + + This code was written by Christopher Williamson, + May be distributed in object form only when embedded in a + registered XVT user's application. + Copyright 1993-1994, XVT Software Inc., All Rights Reserved. + */ +#ifndef STATBAR_H +#define STATBAR_H + +#if defined(_cplusplus) || defined(__cplusplus) +extern "C" { +#endif + +/* internal constants for sizing arrays, defaults, etc... */ +//#define STATBAR_MAX_LEN 256 /* maximum length of status bar string */ +//#define STATBAR_MAX_NUM 128 /* maximum number of status bars in an app */ +//#define STATBAR_FONT_SIZE 10 /* default font size on Windows/PM/NT/CH */ + +/* the following CIS functions are external and may be called by the app */ +XVTDLL const char* statbar_set_title(WINDOW win, const char *text); +XVTDLL const char* statbar_set_default_title(WINDOW win, const char *text); + +/* the following CIS functions are external and are usable in all font modes */ + +XVTDLL XVT_FNTID statbar_set_fontid(WINDOW win, XVT_FNTID fontid); +XVTDLL XVT_FNTID statbar_get_fontid(WINDOW win, XVT_FNTID fontid); + +/* the event handler and create function for statbar */ +XVTDLL WINDOW statbar_create + (int cid, int left, int top, int right, int bottom, + int prop_count, char **prop_list, WINDOW parent_win, + int parent_rid, long parent_flags, char *parent_class); + +XVTDLL BOOLEAN statbar_destroy(WINDOW win); + +/* toolbar supports different types of controls */ +enum TOOL_TYPE { TOOL_SEPARATOR = -1, TOOL_BUTTON, TOOL_TOGLBUTN, TOOL_RADIOBUTN }; + +/* the following CIS functions are external and may be called by the app */ +XVTDLL BOOLEAN xvt_toolbar_add_control(WINDOW win, int cid, TOOL_TYPE type, const char *title, + int ico, int cust_width, int idx); +XVTDLL WINDOW xvt_toolbar_create(int cid, int left, int top, int right, int bottom, + long style, WINDOW parent_win); +XVTDLL void xvt_toolbar_enable_control(WINDOW win, int cid, BOOLEAN on); +XVTDLL void xvt_toolbar_realize(WINDOW win); +XVTDLL BOOLEAN xvt_toolbar_remove_control(WINDOW win, int cid); +XVTDLL BOOLEAN xvt_toolbar_set_last_tool(WINDOW win, int cid); +XVTDLL void xvt_toolbar_show_control(WINDOW win, int cid, BOOLEAN on); +XVTDLL BOOLEAN xvt_toolbar_toggle_control(WINDOW win, int cid, BOOLEAN on); +XVTDLL BOOLEAN xvt_toolbar_set_image(WINDOW win, int cid, int ico); + +#if defined(_cplusplus) || defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* STATBAR_H */ diff --git a/src/xvaga01/treelistctrl.cpp b/src/xvaga01/treelistctrl.cpp new file mode 100644 index 000000000..6d9692f89 --- /dev/null +++ b/src/xvaga01/treelistctrl.cpp @@ -0,0 +1,5077 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: treelistctrl.cpp +// Purpose: multi column tree control implementation +// Author: Robert Roebling +// Maintainer: $Author: guy $ +// Created: 01/02/97 +// RCS-ID: $Id: treelistctrl.cpp,v 1.1.2.1 2011-04-06 14:09:31 guy Exp $ +// Copyright: (c) 2004-2008 Robert Roebling, Julian Smart, Alberto Griggio, +// Vadim Zeitlin, Otto Wyss, Ronan Chartois +// Licence: wxWindows +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +#if defined(__GNUG__) && !defined(__APPLE__) + #pragma implementation "treelistctrl.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wxinc.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if wxCHECK_VERSION(2, 7, 0) +#include +#endif +#include +#include +#include + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#endif + +#include // only required for debugging purpose + +#undef WXDLLEXPORT +#define WXDLLEXPORT +#include "treelistctrl.h" + +// --------------------------------------------------------------------------- +// array types +// --------------------------------------------------------------------------- + +class wxTreeListItem; + +#if !wxCHECK_VERSION(2, 5, 0) +2WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems); +#else +WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems); +#endif + +#include +WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo); +#include +WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo); + + +// -------------------------------------------------------------------------- +// constants +// -------------------------------------------------------------------------- + +static const int NO_IMAGE = -1; + +static const int LINEHEIGHT = 10; +static const int LINEATROOT = 5; +static const int MARGIN = 2; +static const int MININDENT = 16; +static const int BTNWIDTH = 9; +static const int BTNHEIGHT = 9; +static const int EXTRA_WIDTH = 4; +static const int EXTRA_HEIGHT = 4; +static const int HEADER_OFFSET_X = 0; // changed from 1 to 0 on 2009.03.10 for Windows (other OS untested) +static const int HEADER_OFFSET_Y = 1; + +static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms +static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms +static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms + +const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl"); + +static wxTreeListColumnInfo wxInvalidTreeListColumnInfo; + + +// --------------------------------------------------------------------------- +// private classes +// --------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// wxTreeListHeaderWindow (internal) +//----------------------------------------------------------------------------- + +class wxTreeListHeaderWindow : public wxWindow +{ +protected: + wxTreeListMainWindow *m_owner; + const wxCursor *m_currentCursor; + const wxCursor *m_resizeCursor; + bool m_isDragging; + + // column being resized + int m_column; + + // divider line position in logical (unscrolled) coords + int m_currentX; + + // minimal position beyond which the divider line can't be dragged in + // logical coords + int m_minX; + + wxArrayTreeListColumnInfo m_columns; + + // total width of the columns + int m_total_col_width; + +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) + // which col header is currently highlighted with mouse-over + int m_hotTrackCol; + int XToCol(int x); + void RefreshColLabel(int col); +#endif + +public: + wxTreeListHeaderWindow(); + + wxTreeListHeaderWindow( wxWindow *win, + wxWindowID id, + wxTreeListMainWindow *owner, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + long style = 0, + const wxString &name = _T("wxtreelistctrlcolumntitles") ); + + virtual ~wxTreeListHeaderWindow(); + + void DoDrawRect( wxDC *dc, int x, int y, int w, int h ); + void DrawCurrent(); + void AdjustDC(wxDC& dc); + + void OnPaint( wxPaintEvent &event ); + void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // reduce flicker + void OnMouse( wxMouseEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + + // total width of all columns + int GetWidth() const { return m_total_col_width; } + + // column manipulation + int GetColumnCount() const { return (int)m_columns.GetCount(); } + + void AddColumn (const wxTreeListColumnInfo& colInfo); + + void InsertColumn (int before, const wxTreeListColumnInfo& colInfo); + + void RemoveColumn (int column); + + // column information manipulation + const wxTreeListColumnInfo& GetColumn (int column) const{ + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + wxInvalidTreeListColumnInfo, _T("Invalid column")); + return m_columns[column]; + } + wxTreeListColumnInfo& GetColumn (int column) { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + wxInvalidTreeListColumnInfo, _T("Invalid column")); + return m_columns[column]; + } + void SetColumn (int column, const wxTreeListColumnInfo& info); + + wxString GetColumnText (int column) const { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + wxEmptyString, _T("Invalid column")); + return m_columns[column].GetText(); + } + void SetColumnText (int column, const wxString& text) { + wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), + _T("Invalid column")); + m_columns[column].SetText (text); + } + + int GetColumnAlignment (int column) const { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + wxALIGN_LEFT, _T("Invalid column")); + return m_columns[column].GetAlignment(); + } + void SetColumnAlignment (int column, int flag) { + wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), + _T("Invalid column")); + m_columns[column].SetAlignment (flag); + } + + int GetColumnWidth (int column) const { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + -1, _T("Invalid column")); + return m_columns[column].GetWidth(); + } + void SetColumnWidth (int column, int width); + + bool IsColumnEditable (int column) const { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + false, _T("Invalid column")); + return m_columns[column].IsEditable(); + } + + bool IsColumnShown (int column) const { + wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()), + true, _T("Invalid column")); + return m_columns[column].IsShown(); + } + + // needs refresh + bool m_dirty; + +private: + // common part of all ctors + void Init(); + + void SendListEvent(wxEventType type, wxPoint pos); + + DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow) + DECLARE_EVENT_TABLE() +}; + + +//----------------------------------------------------------------------------- +// wxTreeListMainWindow (internal) +//----------------------------------------------------------------------------- + +class wxEditTextCtrl; + + +// this is the "true" control +class wxTreeListMainWindow: public wxScrolledWindow +{ +public: + // creation + // -------- + wxTreeListMainWindow() { Init(); } + + wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = _T("wxtreelistmainwindow")) + { + Init(); + Create (parent, id, pos, size, style, validator, name); + } + + virtual ~wxTreeListMainWindow(); + + bool Create(wxTreeListCtrl *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = _T("wxtreelistctrl")); + + // accessors + // --------- + + // return true if this is a virtual list control + bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); } + + // get the total number of items in the control + size_t GetCount() const; + + // indent is the number of pixels the children are indented relative to + // the parents position. SetIndent() also redraws the control + // immediately. + unsigned int GetIndent() const { return m_indent; } + void SetIndent(unsigned int indent); + + // see wxTreeListCtrl for the meaning + unsigned int GetLineSpacing() const { return m_linespacing; } + void SetLineSpacing(unsigned int spacing); + + // image list: these functions allow to associate an image list with + // the control and retrieve it. Note that when assigned with + // SetImageList, the control does _not_ delete + // the associated image list when it's deleted in order to allow image + // lists to be shared between different controls. If you use + // AssignImageList, the control _does_ delete the image list. + + // The normal image list is for the icons which correspond to the + // normal tree item state (whether it is selected or not). + // Additionally, the application might choose to show a state icon + // which corresponds to an app-defined item state (for example, + // checked/unchecked) which are taken from the state image list. + wxImageList *GetImageList() const { return m_imageListNormal; } + wxImageList *GetStateImageList() const { return m_imageListState; } + wxImageList *GetButtonsImageList() const { return m_imageListButtons; } + + void SetImageList(wxImageList *imageList); + void SetStateImageList(wxImageList *imageList); + void SetButtonsImageList(wxImageList *imageList); + void AssignImageList(wxImageList *imageList); + void AssignStateImageList(wxImageList *imageList); + void AssignButtonsImageList(wxImageList *imageList); + + void SetToolTip(const wxString& tip); + void SetToolTip(wxToolTip *tip); + void SetItemToolTip(const wxTreeItemId& item, const wxString &tip); + + // Functions to work with tree ctrl items. + + // accessors + // --------- + + // retrieve item's label + wxString GetItemText (const wxTreeItemId& item) const + { return GetItemText (item, GetMainColumn()); } + wxString GetItemText (const wxTreeItemId& item, int column) const; + wxString GetItemText (wxTreeItemData* item, int column) const; + + // get one of the images associated with the item (normal by default) + int GetItemImage (const wxTreeItemId& item, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return GetItemImage (item, GetMainColumn(), which); } + int GetItemImage (const wxTreeItemId& item, int column, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const; + + // get the data associated with the item + wxTreeItemData *GetItemData(const wxTreeItemId& item) const; + + bool GetItemBold(const wxTreeItemId& item) const; + wxColour GetItemTextColour(const wxTreeItemId& item) const; + wxColour GetItemBackgroundColour(const wxTreeItemId& item) const; + wxFont GetItemFont(const wxTreeItemId& item) const; + + // modifiers + // --------- + + // set item's label + void SetItemText (const wxTreeItemId& item, const wxString& text) + { SetItemText (item, GetMainColumn(), text); } + void SetItemText (const wxTreeItemId& item, int column, const wxString& text); + + // get one of the images associated with the item (normal by default) + void SetItemImage (const wxTreeItemId& item, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal) + { SetItemImage (item, GetMainColumn(), image, which); } + void SetItemImage (const wxTreeItemId& item, int column, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal); + + // associate some data with the item + void SetItemData(const wxTreeItemId& item, wxTreeItemData *data); + + // force appearance of [+] button near the item. This is useful to + // allow the user to expand the items which don't have any children now + // - but instead add them only when needed, thus minimizing memory + // usage and loading time. + void SetItemHasChildren(const wxTreeItemId& item, bool has = true); + + // the item will be shown in bold + void SetItemBold(const wxTreeItemId& item, bool bold = true); + + // set the item's text colour + void SetItemTextColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's background colour + void SetItemBackgroundColour(const wxTreeItemId& item, const wxColour& colour); + + // set the item's font (should be of the same height for all items) + void SetItemFont(const wxTreeItemId& item, const wxFont& font); + + // set the window font + virtual bool SetFont( const wxFont &font ); + + // set the styles. No need to specify a GetWindowStyle here since + // the base wxWindow member function will do it for us + void SetWindowStyle(const long styles); + + // item status inquiries + // --------------------- + + // is the item visible (it might be outside the view or not expanded)? + bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const; + // does the item has any children? + bool HasChildren(const wxTreeItemId& item) const; + // is the item expanded (only makes sense if HasChildren())? + bool IsExpanded(const wxTreeItemId& item) const; + // is this item currently selected (the same as has focus)? + bool IsSelected(const wxTreeItemId& item) const; + // is item text in bold font? + bool IsBold(const wxTreeItemId& item) const; + // does the layout include space for a button? + + // number of children + // ------------------ + + // if 'recursively' is false, only immediate children count, otherwise + // the returned number is the number of all items in this branch + size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true); + + // navigation + // ---------- + + // wxTreeItemId.IsOk() will return false if there is no such item + + // get the root tree item + wxTreeItemId GetRootItem() const { return m_rootItem; } // implict cast from wxTreeListItem * + + // get the item currently selected, only if a single item is selected + wxTreeItemId GetSelection() const { return m_selectItem; } + + // get all the items currently selected, return count of items + size_t GetSelections(wxArrayTreeItemIds&) const; + + // get the parent of this item (may return NULL if root) + wxTreeItemId GetItemParent(const wxTreeItemId& item) const; + + // for this enumeration function you must pass in a "cookie" parameter + // which is opaque for the application but is necessary for the library + // to make these functions reentrant (i.e. allow more than one + // enumeration on one and the same object simultaneously). Of course, + // the "cookie" passed to GetFirstChild() and GetNextChild() should be + // the same! + + // get child of this item +#if !wxCHECK_VERSION(2, 5, 0) + wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const; +#else + wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; +#endif + + // get sibling of this item + wxTreeItemId GetNextSibling(const wxTreeItemId& item) const; + wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const; + + // get item in the full tree (currently only for internal use) + wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const; + wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const; + + // get expanded item, see IsExpanded() + wxTreeItemId GetFirstExpandedItem() const; + wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const; + wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const; + + // get visible item, see IsVisible() + wxTreeItemId GetFirstVisible( bool fullRow, bool within) const; + wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const; + wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const; + wxTreeItemId GetLastVisible ( bool fullRow, bool within) const; + + // operations + // ---------- + + // add the root node to the tree + wxTreeItemId AddRoot (const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the first child of the parent + wxTreeItemId PrependItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item after a given one + wxTreeItemId InsertItem(const wxTreeItemId& parent, + const wxTreeItemId& idPrevious, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item before the one with the given index + wxTreeItemId InsertItem(const wxTreeItemId& parent, + size_t index, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the last child of the parent + wxTreeItemId AppendItem(const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // delete this item and associated data if any + void Delete(const wxTreeItemId& item); + // delete all children (but don't delete the item itself) + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteChildren(const wxTreeItemId& item); + // delete the root and all its children from the tree + // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events + void DeleteRoot(); + + // expand this item + void Expand(const wxTreeItemId& item); + // expand this item and all subitems recursively + void ExpandAll(const wxTreeItemId& item); + // collapse the item without removing its children + void Collapse(const wxTreeItemId& item); + // collapse the item and remove all children + void CollapseAndReset(const wxTreeItemId& item); + // toggles the current state + void Toggle(const wxTreeItemId& item); + + // remove the selection from currently selected item (if any) + void Unselect(); + void UnselectAll(); + // select this item + bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL, + bool unselect_others = true); + void SelectAll(); + // make sure this item is visible (expanding the parent item and/or + // scrolling to this item if necessary) + void EnsureVisible(const wxTreeItemId& item); + // scroll to this item (but don't expand its parent) + void ScrollTo(const wxTreeItemId& item); + void AdjustMyScrollbars(); + + // The first function is more portable (because easier to implement + // on other platforms), but the second one returns some extra info. + wxTreeItemId HitTest (const wxPoint& point) + { int flags; int column; return HitTest (point, flags, column); } + wxTreeItemId HitTest (const wxPoint& point, int& flags) + { int column; return HitTest (point, flags, column); } + wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column); + + + // get the bounding rectangle of the item (or of its label only) + bool GetBoundingRect(const wxTreeItemId& item, + wxRect& rect, + bool textOnly = false) const; + + // Start editing the item label: this (temporarily) replaces the item + // with a one line edit control. The item will be selected if it hadn't + // been before. + void EditLabel (const wxTreeItemId& item, int column); + + // sorting + // this function is called to compare 2 items and should return -1, 0 + // or +1 if the first item is less than, equal to or greater than the + // second one. The base class version performs alphabetic comparaison + // of item labels (GetText) + virtual int OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2); + // sort the children of this item using OnCompareItems + // + // NB: this function is not reentrant and not MT-safe (FIXME)! + void SortChildren(const wxTreeItemId& item); + + // searching + wxTreeItemId FindItem (const wxTreeItemId& item, const wxString& str, int mode = 0); + + // implementation only from now on + + // overridden base class virtuals + virtual bool SetBackgroundColour(const wxColour& colour); + virtual bool SetForegroundColour(const wxColour& colour); + + // drop over item + void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL); + + // callbacks + void OnPaint( wxPaintEvent &event ); + void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // to reduce flicker + void OnSetFocus( wxFocusEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + void OnChar( wxKeyEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnIdle( wxIdleEvent &event ); + void OnScroll(wxScrollWinEvent& event); + void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; } + + // implementation helpers + int GetColumnCount() const + { return m_owner->GetHeaderWindow()->GetColumnCount(); } + + void SetMainColumn (int column) + { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; } + + int GetMainColumn() const { return m_main_column; } + + int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId()); + int GetItemWidth (int column, wxTreeListItem *item); + wxFont GetItemFont (wxTreeListItem *item); + + void SetFocus(); + +protected: + wxTreeListCtrl* m_owner; + + int m_main_column; + + friend class wxTreeListItem; + friend class wxTreeListRenameTimer; + friend class wxEditTextCtrl; + + wxFont m_normalFont; + wxFont m_boldFont; + + wxTreeListItem *m_rootItem; // root item + wxTreeListItem *m_curItem; // current item, either selected or marked + wxTreeListItem *m_shiftItem; // item, where the shift key was pressed + wxTreeListItem *m_selectItem; // current selected item, not with wxTR_MULTIPLE + + int m_curColumn; + + int m_btnWidth, m_btnWidth2; + int m_btnHeight, m_btnHeight2; + int m_imgWidth, m_imgWidth2; + int m_imgHeight, m_imgHeight2; + unsigned short m_indent; + int m_lineHeight; + unsigned short m_linespacing; + wxPen m_dottedPen; + wxBrush *m_hilightBrush, + *m_hilightUnfocusedBrush; + bool m_hasFocus; +public: + bool m_dirty; +protected: + bool m_ownsImageListNormal, + m_ownsImageListState, + m_ownsImageListButtons; + bool m_lastOnSame; // last click on the same item as prev + bool m_left_down_selection; + + wxImageList *m_imageListNormal, + *m_imageListState, + *m_imageListButtons; + + bool m_isDragStarted; // set at the very beginning of dragging + bool m_isDragging; // set once a drag begin event was fired + wxPoint m_dragStartPos; // set whenever m_isDragStarted is set to true + wxTreeListItem *m_dragItem; + int m_dragCol; + + wxTreeListItem *m_editItem; // item, which is currently edited + wxTimer *m_editTimer; + bool m_editAccept; // currently unused, OnRenameAccept() argument makes it redundant + wxString m_editRes; + int m_editCol; + wxEditTextCtrl *m_editControl; + + // char navigation + wxTimer *m_findTimer; + wxString m_findStr; + + bool m_isItemToolTip; // true if individual item tooltips were set (disable global tooltip) + wxString m_toolTip; // global tooltip + wxTreeListItem *m_toolTipItem; // item whose tip is currently shown (NULL==global, -1==not displayed) + + // the common part of all ctors + void Init(); + + // misc helpers + wxTreeItemId DoInsertItem(const wxTreeItemId& parent, + size_t previous, + const wxString& text, + int image, int selectedImage, + wxTreeItemData *data); + void DoDeleteItem (wxTreeListItem *item); + void SetCurrentItem(wxTreeListItem *item); + bool HasButtons(void) const + { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); } + + void CalculateLineHeight(); + int GetLineHeight(wxTreeListItem *item) const; + void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y, + int x_maincol); + void PaintItem( wxTreeListItem *item, wxDC& dc); + + void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y, + int x_maincol); + void CalculatePositions(); + void CalculateSize( wxTreeListItem *item, wxDC &dc ); + + void RefreshSubtree (wxTreeListItem *item); + void RefreshLine (wxTreeListItem *item); + // redraw all selected items + void RefreshSelected(); + // RefreshSelected() recursive helper + void RefreshSelectedUnder (wxTreeListItem *item); + + void OnRenameTimer(); + void OnRenameAccept(bool isCancelled); + + void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const; + bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item); + bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item); + void UnselectAllChildren (wxTreeListItem *item ); + bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL); // returns true if processed + +private: + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow) +}; + + +// timer used for enabling in-place edit +class wxTreeListRenameTimer: public wxTimer +{ +public: + wxTreeListRenameTimer( wxTreeListMainWindow *owner ); + + void Notify(); + +private: + wxTreeListMainWindow *m_owner; +}; + +// control used for in-place edit +class wxEditTextCtrl: public wxTextCtrl +{ +public: + wxEditTextCtrl (wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeListMainWindow *owner, + const wxString &value = wxEmptyString, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + int style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString &name = wxTextCtrlNameStr ); + ~wxEditTextCtrl(); + + virtual bool Destroy(); // wxWindow override + void EndEdit(bool isCancelled); + void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; } + + void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + + +private: + wxTreeListMainWindow *m_owner; + bool *m_accept; + wxString *m_res; + wxString m_startValue; + bool m_finished; // true==deleting, don't process events anymore + + DECLARE_EVENT_TABLE() +}; + + +// a tree item (NOTE: this class is storage only, does not generate events) +class wxTreeListItem +{ +public: + // ctors & dtor + wxTreeListItem() { m_data = NULL; m_toolTip = NULL; } + wxTreeListItem( wxTreeListMainWindow *owner, + wxTreeListItem *parent, + const wxArrayString& text, + int image, + int selImage, + wxTreeItemData *data ); + + ~wxTreeListItem(); + + // trivial accessors + wxArrayTreeListItems& GetChildren() { return m_children; } + + const wxString GetText() const + { + return GetText(0); + } + const wxString GetText (int column) const + { + if(m_text.GetCount() > 0) + { + if( IsVirtual() ) return m_owner->GetItemText( m_data, column ); + else return m_text[column]; + } + return wxEmptyString; + } + + int GetImage (wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return m_images[which]; } + int GetImage (int column, wxTreeItemIcon which=wxTreeItemIcon_Normal) const + { + if(column == m_owner->GetMainColumn()) return m_images[which]; + if(column < (int)m_col_images.GetCount()) return m_col_images[column]; + return NO_IMAGE; + } + + wxTreeItemData *GetData() const { return m_data; } + + const wxString * GetToolTip() const { return m_toolTip; } + + // returns the current image for the item (depending on its + // selected/expanded/whatever state) + int GetCurrentImage() const; + + void SetText (const wxString &text ); + void SetText (int column, const wxString& text) + { + if (column < (int)m_text.GetCount()) { + m_text[column] = text; + }else if (column < m_owner->GetColumnCount()) { + int howmany = m_owner->GetColumnCount(); + for (int i = (int)m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString); + m_text[column] = text; + } + } + void SetImage (int image, wxTreeItemIcon which) { m_images[which] = image; } + void SetImage (int column, int image, wxTreeItemIcon which) + { + if (column == m_owner->GetMainColumn()) { + m_images[which] = image; + }else if (column < (int)m_col_images.GetCount()) { + m_col_images[column] = image; + }else if (column < m_owner->GetColumnCount()) { + int howmany = m_owner->GetColumnCount(); + for (int i = (int)m_col_images.GetCount(); i < howmany; ++i) m_col_images.Add (NO_IMAGE); + m_col_images[column] = image; + } + } + + void SetData(wxTreeItemData *data) { m_data = data; } + + void SetToolTip(const wxString &tip) { + if (m_toolTip) { + delete m_toolTip; m_toolTip = NULL; + } + if (tip.length() > 0) { + m_toolTip = new wxString(tip); + } + } + + void SetHasPlus(bool has = true) { m_hasPlus = has; } + + void SetBold(bool bold) { m_isBold = bold; } + + int GetX() const { return m_x; } + int GetY() const { return m_y; } + + void SetX (int x) { m_x = x; } + void SetY (int y) { m_y = y; } + + int GetHeight() const { return m_height; } + int GetWidth() const { return m_width; } + + void SetHeight (int height) { m_height = height; } + void SetWidth (int width) { m_width = width; } + + int GetTextX() const { return m_text_x; } + void SetTextX (int text_x) { m_text_x = text_x; } + + wxTreeListItem *GetItemParent() const { return m_parent; } + + // operations + // deletes all children + void DeleteChildren(); + + // get count of all children (and grand children if 'recursively') + size_t GetChildrenCount(bool recursively = true) const; + + void Insert(wxTreeListItem *child, size_t index) + { m_children.Insert(child, index); } + + void GetSize( int &x, int &y, const wxTreeListMainWindow* ); + + // return the item at given position (or NULL if no item), onButton is + // true if the point belongs to the item's button, otherwise it lies + // on the button's label + wxTreeListItem *HitTest (const wxPoint& point, + const wxTreeListMainWindow *, + int &flags, int& column, int level); + + void Expand() { m_isCollapsed = false; } + void Collapse() { m_isCollapsed = true; } + + void SetHilight( bool set = true ) { m_hasHilight = set; } + + // status inquiries + bool HasChildren() const { return !m_children.IsEmpty(); } + bool IsSelected() const { return m_hasHilight != 0; } + bool IsExpanded() const { return !m_isCollapsed; } + bool HasPlus() const { return m_hasPlus || HasChildren(); } + bool IsBold() const { return m_isBold != 0; } + bool IsVirtual() const { return m_owner->IsVirtual(); } + + // attributes + // get them - may be NULL + wxTreeItemAttr *GetAttributes() const { return m_attr; } + // get them ensuring that the pointer is not NULL + wxTreeItemAttr& Attr() + { + if ( !m_attr ) + { + m_attr = new wxTreeItemAttr; + m_ownsAttr = true; + } + return *m_attr; + } + // set them + void SetAttributes(wxTreeItemAttr *attr) + { + if ( m_ownsAttr ) delete m_attr; + m_attr = attr; + m_ownsAttr = false; + } + // set them and delete when done + void AssignAttributes(wxTreeItemAttr *attr) + { + SetAttributes(attr); + m_ownsAttr = true; + } + +private: + wxTreeListMainWindow *m_owner; // control the item belongs to + + // since there can be very many of these, we save size by chosing + // the smallest representation for the elements and by ordering + // the members to avoid padding. + wxArrayString m_text; // labels to be rendered for item + + wxTreeItemData *m_data; // user-provided data + + wxString *m_toolTip; + + wxArrayTreeListItems m_children; // list of children + wxTreeListItem *m_parent; // parent of this item + + wxTreeItemAttr *m_attr; // attributes??? + + // tree ctrl images for the normal, selected, expanded and + // expanded+selected states + short m_images[wxTreeItemIcon_Max]; + wxArrayShort m_col_images; // images for the various columns (!= main) + + // main column item positions + wxCoord m_x; // (virtual) offset from left (vertical line) + wxCoord m_y; // (virtual) offset from top + wxCoord m_text_x; // item offset from left + short m_width; // width of this item + unsigned char m_height; // height of this item + + // use bitfields to save size + int m_isCollapsed :1; + int m_hasHilight :1; // same as focused + int m_hasPlus :1; // used for item which doesn't have + // children but has a [+] button + int m_isBold :1; // render the label in bold font + int m_ownsAttr :1; // delete attribute when done +}; + +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// wxTreeListRenameTimer (internal) +// --------------------------------------------------------------------------- + +wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner ) +{ + m_owner = owner; +} + +void wxTreeListRenameTimer::Notify() +{ + m_owner->OnRenameTimer(); +} + +//----------------------------------------------------------------------------- +// wxEditTextCtrl (internal) +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl) + EVT_CHAR (wxEditTextCtrl::OnChar) + EVT_KEY_UP (wxEditTextCtrl::OnKeyUp) + EVT_KILL_FOCUS (wxEditTextCtrl::OnKillFocus) +END_EVENT_TABLE() + +wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent, + const wxWindowID id, + bool *accept, + wxString *res, + wxTreeListMainWindow *owner, + const wxString &value, + const wxPoint &pos, + const wxSize &size, + int style, + const wxValidator& validator, + const wxString &name) + : wxTextCtrl (parent, id, value, pos, size, style | wxSIMPLE_BORDER, validator, name) +{ + m_res = res; + m_accept = accept; + m_owner = owner; + (*m_accept) = false; + (*m_res) = wxEmptyString; + m_startValue = value; + m_finished = false; +} + +wxEditTextCtrl::~wxEditTextCtrl() { + EndEdit(true); // cancelled +} + +void wxEditTextCtrl::EndEdit(bool isCancelled) { + if (m_finished) return; + m_finished = true; + + if (m_owner) { + (*m_accept) = ! isCancelled; + (*m_res) = isCancelled ? m_startValue : GetValue(); + m_owner->OnRenameAccept(*m_res == m_startValue); + m_owner->m_editControl = NULL; + m_owner->m_editItem = NULL; + m_owner->SetFocus(); // This doesn't work. TODO. + m_owner = NULL; + } + + Destroy(); +} + +bool wxEditTextCtrl::Destroy() { + Hide(); + wxTheApp->GetTraits()->ScheduleForDestroy(this); + return true; +} + +void wxEditTextCtrl::OnChar( wxKeyEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + if (event.GetKeyCode() == WXK_RETURN) + { + EndEdit(false); // not cancelled + return; + } + if (event.GetKeyCode() == WXK_ESCAPE) + { + EndEdit(true); // cancelled + return; + } + event.Skip(); +} + +void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + // auto-grow the textctrl: + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = GetPosition(); + wxSize mySize = GetSize(); + int sx, sy; + GetTextExtent(GetValue() + _T("M"), &sx, &sy); + if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x; + if (mySize.x > sx) sx = mySize.x; + SetSize(sx, -1); + + event.Skip(); +} + +void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + EndEdit(false); // not cancelled +} + +//----------------------------------------------------------------------------- +// wxTreeListHeaderWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow); + +BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow) + EVT_PAINT (wxTreeListHeaderWindow::OnPaint) + EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground) // reduce flicker + EVT_MOUSE_EVENTS (wxTreeListHeaderWindow::OnMouse) + EVT_SET_FOCUS (wxTreeListHeaderWindow::OnSetFocus) +END_EVENT_TABLE() + + +void wxTreeListHeaderWindow::Init() +{ + m_currentCursor = (wxCursor *) NULL; + m_isDragging = false; + m_dirty = false; + m_total_col_width = 0; +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) + m_hotTrackCol = -1; +#endif + + // prevent any background repaint in order to reducing flicker + SetBackgroundStyle(wxBG_STYLE_CUSTOM); +} + +wxTreeListHeaderWindow::wxTreeListHeaderWindow() +{ + Init(); + + m_owner = (wxTreeListMainWindow *) NULL; + m_resizeCursor = (wxCursor *) NULL; +} + +wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win, + wxWindowID id, + wxTreeListMainWindow *owner, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString &name ) + : wxWindow( win, id, pos, size, style, name ) +{ + Init(); + + m_owner = owner; + m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE); + +#if !wxCHECK_VERSION(2, 5, 0) + SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE)); +#else + SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE)); +#endif +} + +wxTreeListHeaderWindow::~wxTreeListHeaderWindow() +{ + delete m_resizeCursor; +} + +void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h ) +{ +#if !wxCHECK_VERSION(2, 5, 0) + wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID); +#else + wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID); +#endif + + const int m_corner = 1; + + dc->SetBrush( *wxTRANSPARENT_BRUSH ); +#if defined( __WXMAC__ ) + dc->SetPen (pen); +#else // !GTK, !Mac + dc->SetPen( *wxBLACK_PEN ); +#endif + dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer) + dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) + +#if defined( __WXMAC__ ) + pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID ); +#endif + dc->SetPen( pen ); + dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner) + dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) + + dc->SetPen( *wxWHITE_PEN ); + dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer) + dc->DrawRectangle( x, y, 1, h ); // left (outer) + dc->DrawLine( x, y+h-1, x+1, y+h-1 ); + dc->DrawLine( x+w-1, y, x+w-1, y+1 ); +} + +// shift the DC origin to match the position of the main window horz +// scrollbar: this allows us to always use logical coords +void wxTreeListHeaderWindow::AdjustDC(wxDC& dc) +{ + int xpix; + m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); + int x; + m_owner->GetViewStart( &x, NULL ); + + // account for the horz scrollbar offset + dc.SetDeviceOrigin( -x * xpix, 0 ); +} + +void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxAutoBufferedPaintDC dc( this ); + AdjustDC( dc ); + + int x = HEADER_OFFSET_X; + + // width and height of the entire header window + int w, h; + GetClientSize( &w, &h ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + dc.SetBackgroundMode(wxTRANSPARENT); + +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) + int numColumns = GetColumnCount(); + for ( int i = 0; i < numColumns && x < w; i++ ) + { + if (!IsColumnShown (i)) continue; // do next column if not shown + + wxHeaderButtonParams params; + + // TODO: columnInfo should have label colours... + params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); + params.m_labelFont = GetFont(); + + wxTreeListColumnInfo& column = GetColumn(i); + int wCol = column.GetWidth(); + int flags = 0; + wxRect rect(x, 0, wCol, h); + x += wCol; + + if ( i == m_hotTrackCol) + flags |= wxCONTROL_CURRENT; + + params.m_labelText = column.GetText(); + params.m_labelAlignment = column.GetAlignment(); + + int image = column.GetImage(); + wxImageList* imageList = m_owner->GetImageList(); + if ((image != -1) && imageList) + params.m_labelBitmap = imageList->GetBitmap(image); + + wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, ¶ms); + } + + if (x < w) { + wxRect rect(x, 0, w-x, h); + wxRendererNative::Get().DrawHeaderButton(this, dc, rect); + } + +#else // not 2.7.0.1+ + + dc.SetFont( GetFont() ); + + // do *not* use the listctrl colour for headers - one day we will have a + // function to set it separately + //dc.SetTextForeground( *wxBLACK ); +#if !wxCHECK_VERSION(2, 5, 0) + dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT )); +#else + dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT )); +#endif + + int numColumns = GetColumnCount(); + for ( int i = 0; i < numColumns && x < w; i++ ) + { + if (!IsColumnShown (i)) continue; // do next column if not shown + + wxTreeListColumnInfo& column = GetColumn(i); + int wCol = column.GetWidth(); + + // the width of the rect to draw: make it smaller to fit entirely + // inside the column rect + int cw = wCol - 2; + +#if !wxCHECK_VERSION(2, 7, 0) + dc.SetPen( *wxWHITE_PEN ); + DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 ); +#else + wxRect rect(x, HEADER_OFFSET_Y, cw, h-2); + wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect); +#endif + + // if we have an image, draw it on the right of the label + int image = column.GetImage(); //item.m_image; + int ix = -2, iy = 0; + wxImageList* imageList = m_owner->GetImageList(); + if ((image != -1) && imageList) { + imageList->GetSize (image, ix, iy); + } + + // extra margins around the text label + int text_width = 0; + int text_x = x; + int image_offset = cw - ix - 1; + + switch(column.GetAlignment()) { + case wxALIGN_LEFT: + text_x += EXTRA_WIDTH; + cw -= ix + 2; + break; + case wxALIGN_RIGHT: + dc.GetTextExtent (column.GetText(), &text_width, NULL); + text_x += cw - text_width - EXTRA_WIDTH - MARGIN; + image_offset = 0; + break; + case wxALIGN_CENTER: + dc.GetTextExtent(column.GetText(), &text_width, NULL); + text_x += (cw - text_width)/2 + ix + 2; + image_offset = (cw - text_width - ix - 2)/2 - MARGIN; + break; + } + + // draw the image + if ((image != -1) && imageList) { + imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/, + HEADER_OFFSET_Y + (h - 4 - iy)/2, + wxIMAGELIST_DRAW_TRANSPARENT); + } + + // draw the text clipping it so that it doesn't overwrite the column boundary + wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 ); + dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT ); + + // next column + x += wCol; + } + + int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X; + if (more_w > 0) { +#if !wxCHECK_VERSION(2, 7, 0) + DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 ); +#else + wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2); + wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect); +#endif + } + +#endif // 2.7.0.1 +} + +void wxTreeListHeaderWindow::DrawCurrent() +{ + int x1 = m_currentX; + int y1 = 0; + ClientToScreen (&x1, &y1); + + int x2 = m_currentX-1; +#ifdef __WXMSW__ + ++x2; // but why ???? +#endif + int y2 = 0; + m_owner->GetClientSize( NULL, &y2 ); + m_owner->ClientToScreen( &x2, &y2 ); + + wxScreenDC dc; + dc.SetLogicalFunction (wxINVERT); + dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID)); + dc.SetBrush (*wxTRANSPARENT_BRUSH); + + AdjustDC(dc); + dc.DrawLine (x1, y1, x2, y2); + dc.SetLogicalFunction (wxCOPY); + dc.SetPen (wxNullPen); + dc.SetBrush (wxNullBrush); +} + +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) +int wxTreeListHeaderWindow::XToCol(int x) +{ + int colLeft = 0; + int numColumns = GetColumnCount(); + for ( int col = 0; col < numColumns; col++ ) + { + if (!IsColumnShown(col)) continue; + wxTreeListColumnInfo& column = GetColumn(col); + + if ( x < (colLeft + column.GetWidth()) ) + return col; + + colLeft += column.GetWidth(); + } + return -1; +} + +void wxTreeListHeaderWindow::RefreshColLabel(int col) +{ + if ( col > GetColumnCount() ) + return; + + int x = 0; + int width = 0; + int idx = 0; + do { + if (!IsColumnShown(idx)) continue; + wxTreeListColumnInfo& column = GetColumn(idx); + x += width; + width = column.GetWidth(); + } while (++idx <= col); + + m_owner->CalcScrolledPosition(x, 0, &x, NULL); + RefreshRect(wxRect(x, 0, width, GetSize().GetHeight())); +} +#endif + +void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) { + + // we want to work with logical coords + int x; + m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL); + +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) + if ( event.Moving() ) + { + int col = XToCol(x); + if ( col != m_hotTrackCol ) + { + // Refresh the col header so it will be painted with hot tracking + // (if supported by the native renderer.) + RefreshColLabel(col); + + // Also refresh the old hot header + if ( m_hotTrackCol >= 0 ) + RefreshColLabel(m_hotTrackCol); + + m_hotTrackCol = col; + } + } + + if ( event.Leaving() && m_hotTrackCol >= 0 ) + { + // Leaving the window so clear any hot tracking indicator that may be present + RefreshColLabel(m_hotTrackCol); + m_hotTrackCol = -1; + } +#endif + + if (m_isDragging) { + + SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition()); + + // we don't draw the line beyond our window, but we allow dragging it + // there + int w = 0; + GetClientSize( &w, NULL ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + w -= 6; + + // erase the line if it was drawn + if (m_currentX < w) DrawCurrent(); + + if (event.ButtonUp()) { + m_isDragging = false; + if (HasCapture()) ReleaseMouse(); + m_dirty = true; + SetColumnWidth (m_column, m_currentX - m_minX); + Refresh(); + SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition()); + }else{ + m_currentX = wxMax (m_minX + 7, x); + + // draw in the new location + if (m_currentX < w) DrawCurrent(); + } + + }else{ // not dragging + + m_minX = 0; + bool hit_border = false; + + // end of the current column + int xpos = 0; + + // find the column where this event occured + int countCol = GetColumnCount(); + for (int column = 0; column < countCol; column++) { + if (!IsColumnShown (column)) continue; // do next if not shown + + xpos += GetColumnWidth (column); + m_column = column; + if (abs (x-xpos) < 3) { + // near the column border + hit_border = true; + break; + } + + if (x < xpos) { + // inside the column + break; + } + + m_minX = xpos; + } + + if (event.LeftDown() || event.RightUp()) { + if (hit_border && event.LeftDown()) { + m_isDragging = true; + CaptureMouse(); + m_currentX = x; + DrawCurrent(); + SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition()); + }else{ // click on a column + wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK: + wxEVT_COMMAND_LIST_COL_RIGHT_CLICK; + SendListEvent (evt, event.GetPosition()); + } + }else if (event.LeftDClick() && hit_border) { + SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column)); + Refresh(); + + }else if (event.Moving()) { + bool setCursor; + if (hit_border) { + setCursor = m_currentCursor == wxSTANDARD_CURSOR; + m_currentCursor = m_resizeCursor; + }else{ + setCursor = m_currentCursor != wxSTANDARD_CURSOR; + m_currentCursor = wxSTANDARD_CURSOR; + } + if (setCursor) SetCursor (*m_currentCursor); + } + + } +} + +void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) { + m_owner->SetFocus(); +} + +void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) { + wxWindow *parent = GetParent(); + wxListEvent le (type, parent->GetId()); + le.SetEventObject (parent); + le.m_pointDrag = pos; + + // the position should be relative to the parent window, not + // this one for compatibility with MSW and common sense: the + // user code doesn't know anything at all about this header + // window, so why should it get positions relative to it? + le.m_pointDrag.y -= GetSize().y; + le.m_col = m_column; + parent->GetEventHandler()->ProcessEvent (le); +} + +void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) { + m_columns.Add (colInfo); + m_total_col_width += colInfo.GetWidth(); + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = true; +} + +void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) { + wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column")); + m_total_col_width -= m_columns[column].GetWidth(); + m_columns[column].SetWidth(width); + m_total_col_width += width; + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = true; +} + +void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) { + wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column")); + m_columns.Insert (colInfo, before); + m_total_col_width += colInfo.GetWidth(); + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = true; +} + +void wxTreeListHeaderWindow::RemoveColumn (int column) { + wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column")); + m_total_col_width -= m_columns[column].GetWidth(); + m_columns.RemoveAt (column); + m_owner->AdjustMyScrollbars(); + m_owner->m_dirty = true; +} + +void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) { + wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column")); + int w = m_columns[column].GetWidth(); + m_columns[column] = info; + if (w != info.GetWidth()) { + m_total_col_width += info.GetWidth() - w; + m_owner->AdjustMyScrollbars(); + } + m_owner->m_dirty = true; +} + +// --------------------------------------------------------------------------- +// wxTreeListItem +// --------------------------------------------------------------------------- + +wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner, + wxTreeListItem *parent, + const wxArrayString& text, + int image, int selImage, + wxTreeItemData *data) + : m_text (text) { + + m_images[wxTreeItemIcon_Normal] = image; + m_images[wxTreeItemIcon_Selected] = selImage; + m_images[wxTreeItemIcon_Expanded] = NO_IMAGE; + m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE; + + m_data = data; + m_toolTip = NULL; + m_x = 0; + m_y = 0; + m_text_x = 0; + + m_isCollapsed = true; + m_hasHilight = false; + m_hasPlus = false; + m_isBold = false; + + m_owner = owner; + m_parent = parent; + + m_attr = (wxTreeItemAttr *)NULL; + m_ownsAttr = false; + + // We don't know the height here yet. + m_width = 0; + m_height = 0; +} + +wxTreeListItem::~wxTreeListItem() { + delete m_data; + if (m_toolTip) delete m_toolTip; + if (m_ownsAttr) delete m_attr; + + wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor")); +} + +void wxTreeListItem::DeleteChildren () { + m_children.Empty(); +} + +void wxTreeListItem::SetText (const wxString &text) { + if (m_text.GetCount() > 0) { + m_text[0] = text; + }else{ + m_text.Add (text); + } +} + +size_t wxTreeListItem::GetChildrenCount (bool recursively) const { + size_t count = m_children.Count(); + if (!recursively) return count; + + size_t total = count; + for (size_t n = 0; n < count; ++n) { + total += m_children[n]->GetChildrenCount(); + } + return total; +} + +void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) { + int bottomY = m_y + theButton->GetLineHeight (this); + if (y < bottomY) y = bottomY; + int width = m_x + m_width; + if ( x < width ) x = width; + + if (IsExpanded()) { + size_t count = m_children.Count(); + for (size_t n = 0; n < count; ++n ) { + m_children[n]->GetSize (x, y, theButton); + } + } +} + +wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point, + const wxTreeListMainWindow *theCtrl, + int &flags, int& column, int level) { + + // reset any previous hit infos + flags = 0; + column = -1; + + // for a hidden root node, don't evaluate it, but do evaluate children + if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) { + + wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow(); + + // check for right of all columns (outside) + if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL; + // else find column + for (int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) { + if (!header_win->IsColumnShown(j)) continue; + int w = header_win->GetColumnWidth (j); + if (point.x >= x && point.x < x+w) { + column = j; + break; + } + x += w; + } + + // evaluate if y-pos is okay + int h = theCtrl->GetLineHeight (this); + if ((point.y >= m_y) && (point.y <= m_y + h)) { + + // check for above/below middle + int y_mid = m_y + h/2; + if (point.y < y_mid) { + flags |= wxTREE_HITTEST_ONITEMUPPERPART; + }else{ + flags |= wxTREE_HITTEST_ONITEMLOWERPART; + } + + // check for button hit + if (HasPlus() && theCtrl->HasButtons()) { + int bntX = m_x - theCtrl->m_btnWidth2; + int bntY = y_mid - theCtrl->m_btnHeight2; + if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) && + (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) { + flags |= wxTREE_HITTEST_ONITEMBUTTON; + return this; + } + } + + // check for image hit + if (theCtrl->m_imgWidth > 0) { + int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN; + int imgY = y_mid - theCtrl->m_imgHeight2; + if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) && + (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) { + flags |= wxTREE_HITTEST_ONITEMICON; + return this; + } + } + + // check for label hit + if ((point.x >= m_text_x) && (point.x <= (m_text_x + m_width))) { + flags |= wxTREE_HITTEST_ONITEMLABEL; + return this; + } + + // check for indent hit after button and image hit + if (point.x < m_x) { + flags |= wxTREE_HITTEST_ONITEMINDENT; +// Ronan, 2008.07.17: removed, not consistent column = -1; // considered not belonging to main column + return this; + } + + // check for right of label + int end = 0; + for (int i = 0; i <= theCtrl->GetMainColumn(); ++i) end += header_win->GetColumnWidth (i); + if ((point.x > (m_text_x + m_width)) && (point.x <= end)) { + flags |= wxTREE_HITTEST_ONITEMRIGHT; +// Ronan, 2008.07.17: removed, not consistent column = -1; // considered not belonging to main column + return this; + } + + // else check for each column except main + if (column >= 0 && column != theCtrl->GetMainColumn()) { + flags |= wxTREE_HITTEST_ONITEMCOLUMN; + return this; + } + + // no special flag or column found + return this; + + } + + // if children not expanded, return no item + if (!IsExpanded()) return (wxTreeListItem*) NULL; + } + + // in any case evaluate children + wxTreeListItem *child; + size_t count = m_children.Count(); + for (size_t n = 0; n < count; n++) { + child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1); + if (child) return child; + } + + // not found + return (wxTreeListItem*) NULL; +} + +int wxTreeListItem::GetCurrentImage() const { + int image = NO_IMAGE; + if (IsExpanded()) { + if (IsSelected()) { + image = GetImage (wxTreeItemIcon_SelectedExpanded); + }else{ + image = GetImage (wxTreeItemIcon_Expanded); + } + }else{ // not expanded + if (IsSelected()) { + image = GetImage (wxTreeItemIcon_Selected); + }else{ + image = GetImage (wxTreeItemIcon_Normal); + } + } + + // maybe it doesn't have the specific image, try the default one instead + if (image == NO_IMAGE) image = GetImage(); + + return image; +} + +// --------------------------------------------------------------------------- +// wxTreeListMainWindow implementation +// --------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow) + EVT_PAINT (wxTreeListMainWindow::OnPaint) + EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground) // to reduce flicker + EVT_MOUSE_EVENTS (wxTreeListMainWindow::OnMouse) + EVT_CHAR (wxTreeListMainWindow::OnChar) + EVT_SET_FOCUS (wxTreeListMainWindow::OnSetFocus) + EVT_KILL_FOCUS (wxTreeListMainWindow::OnKillFocus) + EVT_IDLE (wxTreeListMainWindow::OnIdle) + EVT_SCROLLWIN (wxTreeListMainWindow::OnScroll) + EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost) +END_EVENT_TABLE() + + +// --------------------------------------------------------------------------- +// construction/destruction +// --------------------------------------------------------------------------- + + +void wxTreeListMainWindow::Init() { + + m_rootItem = (wxTreeListItem*)NULL; + m_curItem = (wxTreeListItem*)NULL; + m_shiftItem = (wxTreeListItem*)NULL; + m_editItem = (wxTreeListItem*)NULL; + m_selectItem = (wxTreeListItem*)NULL; + + m_curColumn = -1; // no current column + + m_hasFocus = false; + m_dirty = false; + + m_lineHeight = LINEHEIGHT; + m_indent = MININDENT; // min. indent + m_linespacing = 4; + +#if !wxCHECK_VERSION(2, 5, 0) + m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID); + m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID); +#else + m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID); + m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID); +#endif + + m_imageListNormal = (wxImageList *) NULL; + m_imageListButtons = (wxImageList *) NULL; + m_imageListState = (wxImageList *) NULL; + m_ownsImageListNormal = m_ownsImageListButtons = + m_ownsImageListState = false; + + m_imgWidth = 0, m_imgWidth2 = 0; + m_imgHeight = 0, m_imgHeight2 = 0; + m_btnWidth = 0, m_btnWidth2 = 0; + m_btnHeight = 0, m_btnHeight2 = 0; + + m_isDragStarted = m_isDragging = false; + m_dragItem = NULL; + m_dragCol = -1; + + m_editTimer = new wxTreeListRenameTimer (this); + m_editControl = NULL; + + m_lastOnSame = false; + m_left_down_selection = false; + + m_findTimer = new wxTimer (this, -1); + +#if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__) + m_normalFont.MacCreateThemeFont (kThemeViewsFont); +#else + m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT); +#endif + m_boldFont = wxFont( m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName(), + m_normalFont.GetEncoding()); + + m_toolTip.clear(); + m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed + m_isItemToolTip = false; // so far no item-specific tooltip +} + +bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator &validator, + const wxString& name) { + +#ifdef __WXMAC__ + if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS; + if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS; + style &= ~wxTR_LINES_AT_ROOT; + style |= wxTR_NO_LINES; + + int major,minor; + wxGetOsVersion( &major, &minor ); + if (major < 10) style |= wxTR_ROW_LINES; +#endif + + wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif + +#if !wxCHECK_VERSION(2, 5, 0) + SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX)); +#else + SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX)); +#endif + // prevent any background repaint in order to reducing flicker + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + +#ifdef __WXMSW__ + { + int i, j; + wxBitmap bmp(8, 8); + wxMemoryDC bdc; + bdc.SelectObject(bmp); + bdc.SetPen(*wxGREY_PEN); + bdc.DrawRectangle(-1, -1, 10, 10); + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + if (!((i + j) & 1)) { + bdc.DrawPoint(i, j); + } + } + } + + m_dottedPen = wxPen(bmp, 1); + } +#else +//? m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT ); // too slow under XFree86 + m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK! +#endif + + m_owner = parent; + m_main_column = 0; + + return true; +} + +wxTreeListMainWindow::~wxTreeListMainWindow() { + delete m_hilightBrush; + delete m_hilightUnfocusedBrush; + + delete m_editTimer; + delete m_findTimer; + if (m_ownsImageListNormal) delete m_imageListNormal; + if (m_ownsImageListState) delete m_imageListState; + if (m_ownsImageListButtons) delete m_imageListButtons; + + if (m_editControl) { + m_editControl->SetOwner(NULL); // prevent control from calling us during delete + delete m_editControl; + } + + DeleteRoot(); +} + + +//----------------------------------------------------------------------------- +// accessors +//----------------------------------------------------------------------------- + +size_t wxTreeListMainWindow::GetCount() const { + return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount(); +} + +void wxTreeListMainWindow::SetIndent (unsigned int indent) { + m_indent = wxMax ((unsigned)MININDENT, indent); + m_dirty = true; +} + +void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) { + m_linespacing = spacing; + m_dirty = true; + CalculateLineHeight(); +} + +size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item, + bool recursively) { + wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item")); + return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively); +} + +void wxTreeListMainWindow::SetWindowStyle (const long styles) { + // change to selection mode, reset selection + if ((styles ^ m_windowStyle) & wxTR_MULTIPLE) { UnselectAll(); } + // right now, just sets the styles. Eventually, we may + // want to update the inherited styles, but right now + // none of the parents has updatable styles + m_windowStyle = styles; + m_dirty = true; +} + +void wxTreeListMainWindow::SetToolTip(const wxString& tip) { + m_isItemToolTip = false; + m_toolTip = tip; + m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh) +} +void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) { + m_isItemToolTip = false; + m_toolTip = (tip == NULL) ? wxString() : tip->GetTip(); + m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh) +} + +void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + m_isItemToolTip = true; + ((wxTreeListItem*) item.m_pItem)->SetToolTip(tip); + m_toolTipItem = (wxTreeListItem *)-1; // no tooltip displayed (force refresh) +} + + +//----------------------------------------------------------------------------- +// functions to work with tree items +//----------------------------------------------------------------------------- + +int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column, + wxTreeItemIcon which) const { + wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which); +} + +wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->GetData(); +} + +bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const { + wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item")); + return ((wxTreeListItem *)item.m_pItem)->IsBold(); +} + +wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetTextColour(); +} + +wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetBackgroundColour(); +} + +wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + return pItem->Attr().GetFont(); +} + +void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column, + int image, wxTreeItemIcon which) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->SetImage (column, image, which); + wxClientDC dc (this); + CalculateSize (pItem, dc); + RefreshLine (pItem); +} + +void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, + wxTreeItemData *data) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + ((wxTreeListItem*) item.m_pItem)->SetData(data); +} + +void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item, + bool has) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->SetHasPlus (has); + RefreshLine (pItem); +} + +void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, bool bold) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + if (pItem->IsBold() != bold) { // avoid redrawing if no real change + pItem->SetBold (bold); + RefreshLine (pItem); + } +} + +void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, + const wxColour& colour) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetTextColour (colour); + RefreshLine (pItem); +} + +void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, + const wxColour& colour) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetBackgroundColour (colour); + RefreshLine (pItem); +} + +void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, + const wxFont& font) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + pItem->Attr().SetFont (font); + RefreshLine (pItem); +} + +bool wxTreeListMainWindow::SetFont (const wxFont &font) { + wxScrolledWindow::SetFont (font); + m_normalFont = font; + m_boldFont = wxFont (m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName()); + CalculateLineHeight(); + return true; +} + + +// ---------------------------------------------------------------------------- +// item status inquiries +// ---------------------------------------------------------------------------- + +bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow, bool within) const { + wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item")); + + // An item is only visible if it's not a descendant of a collapsed item + wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem; + wxTreeListItem* parent = pItem->GetItemParent(); + while (parent) { + if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break; + if (!parent->IsExpanded()) return false; + parent = parent->GetItemParent(); + } + + // and the item is only visible if it is currently (fully) within the view + if (within) { + wxSize clientSize = GetClientSize(); + wxRect rect; + if ((!GetBoundingRect (item, rect)) || + ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) || + (rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) || + (!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x))) return false; + } + + return true; +} + +bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item")); + + // consider that the item does have children if it has the "+" button: it + // might not have them (if it had never been expanded yet) but then it + // could have them as well and it's better to err on this side rather than + // disabling some operations which are restricted to the items with + // children for an item which does have them + return ((wxTreeListItem*) item.m_pItem)->HasPlus(); +} + +bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->IsExpanded(); +} + +bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->IsSelected(); +} + +bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->IsBold(); +} + +// ---------------------------------------------------------------------------- +// navigation +// ---------------------------------------------------------------------------- + +wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + return ((wxTreeListItem*) item.m_pItem)->GetItemParent(); +} + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item, + long& cookie) const { +#else +wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const { +#endif + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren(); + cookie = 0; + return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId(); +} + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item, + long& cookie) const { +#else +wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const { +#endif + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren(); + // it's ok to cast cookie to long, we never have indices which overflow "void*" + long *pIndex = ((long*)&cookie); + return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId(); +} + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item, + long& cookie) const { +#else +wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const { +#endif + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren(); + // it's ok to cast cookie to long, we never have indices which overflow "void*" + long *pIndex = (long*)&cookie; + return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId(); +} + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item, + long& cookie) const { +#else +wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const { +#endif + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren(); + // it's ok to cast cookie to long, we never have indices which overflow "void*" + long *pIndex = ((long*)&cookie); + (*pIndex) = (long)children.Count(); + return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId(); +} + +wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + + // get parent + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + wxTreeListItem *parent = i->GetItemParent(); + if (!parent) return wxTreeItemId(); // root item doesn't have any siblings + + // get index + wxArrayTreeListItems& siblings = parent->GetChildren(); + size_t index = siblings.Index (i); + wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent? + return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId(); +} + +wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + + // get parent + wxTreeListItem *i = (wxTreeListItem*) item.m_pItem; + wxTreeListItem *parent = i->GetItemParent(); + if (!parent) return wxTreeItemId(); // root item doesn't have any siblings + + // get index + wxArrayTreeListItems& siblings = parent->GetChildren(); + size_t index = siblings.Index(i); + wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent? + return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId(); +} + +// Only for internal use right now, but should probably be public +wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + + // if there are any children, return first child + if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) { + wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren(); + if (children.GetCount() > 0) return children.Item (0); + } + + // get sibling of this item or of the ancestors instead + wxTreeItemId next; + wxTreeItemId parent = item; + do { + next = GetNextSibling (parent); + parent = GetItemParent (parent); + } while (!next.IsOk() && parent.IsOk()); + return next; +} + +// Only for internal use right now, but should probably be public +wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + + // if there are no previous sibling get parent + wxTreeItemId prev = GetPrevSibling (item); + if (! prev.IsOk()) return GetItemParent (item); + + // while previous sibling has children, return last + while (fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) { + wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren(); + if (children.GetCount() == 0) break; + prev = children.Item (children.GetCount() - 1); + } + + return prev; +} + +wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const { + return GetNextExpanded (GetRootItem()); +} + +wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + return GetNext (item, false); +} + +wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + return GetPrev (item, false); +} + +wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const { + if (HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within)) { + return GetNextVisible (GetRootItem(), fullRow, within); + } else { + return GetRootItem(); + } +} + +wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxTreeItemId id = GetNext (item, false); + while (id.IsOk()) { + if (IsVisible (id, fullRow, within)) return id; + id = GetNext (id, false); + } + return wxTreeItemId(); +} + +wxTreeItemId wxTreeListMainWindow::GetLastVisible ( bool fullRow, bool within) const { + wxCHECK_MSG (GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxTreeItemId id = GetRootItem(); + wxTreeItemId res = id; + while ((id = GetNext (id, false)).IsOk()) { + if (IsVisible (id, fullRow, within)) res = id; + } + return res; +} + +wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const { + wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item")); + wxTreeItemId id = GetPrev (item, true); + while (id.IsOk()) { + if (IsVisible (id, fullRow, within)) return id; + id = GetPrev(id, true); + } + return wxTreeItemId(); +} + +// ---------------------------------------------------------------------------- +// operations +// ---------------------------------------------------------------------------- + +// ---------------------------- ADD OPERATION ------------------------------- + +wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId, + size_t previous, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem; + wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") ); + m_dirty = true; // do this first so stuff below doesn't cause flicker + + wxArrayString arr; + arr.Alloc (GetColumnCount()); + for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString); + arr[m_main_column] = text; + wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data); + if (data != NULL) { +#if !wxCHECK_VERSION(2, 5, 0) + data->SetId ((long)item); +#else + data->SetId (item); +#endif + } + parent->Insert (item, previous); + + return item; +} + +wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root")); + wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item")); + m_dirty = true; // do this first so stuff below doesn't cause flicker + + wxArrayString arr; + arr.Alloc (GetColumnCount()); + for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString); + arr[m_main_column] = text; + m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data); + if (data != NULL) { +#if !wxCHECK_VERSION(2, 5, 0) + data->SetId((long)m_rootItem); +#else + data->SetId(m_rootItem); +#endif + } + if (HasFlag(wxTR_HIDE_ROOT)) { + // if we will hide the root, make sure children are visible + m_rootItem->SetHasPlus(); + m_rootItem->Expand(); +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + // TODO: suspect that deleting and recreating a root can leave a number of members dangling + // (here m_curItem should actually be set via SetCurrentItem() ) + m_curItem = (wxTreeListItem*)GetFirstChild (m_rootItem, cookie).m_pItem; + } + return m_rootItem; +} + +wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + return DoInsertItem (parent, 0u, text, image, selImage, data); +} + +wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId, + const wxTreeItemId& idPrevious, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem; + wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") ); + + int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem); + wxASSERT_MSG( index != wxNOT_FOUND, + _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") ); + + return DoInsertItem (parentId, ++index, text, image, selImage, data); +} + +wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId, + size_t before, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem; + wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") ); + + return DoInsertItem (parentId, before, text, image, selImage, data); +} + +wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) { + wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem; + wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") ); + + return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data); +} + + +// -------------------------- DELETE OPERATION ------------------------------ + +void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) { + if (! itemId.IsOk()) return; + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + wxTreeListItem *parent = item->GetItemParent(); + wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!")); + + // recursive delete + DoDeleteItem(item); + + // update parent --CAUTION: must come after delete itself, so that item's + // siblings may be found + if (parent) { + parent->GetChildren().Remove (item); // remove by value + } +} + + +void wxTreeListMainWindow::DeleteRoot() { + if (! m_rootItem) return; + + SetCurrentItem((wxTreeListItem*)NULL); + m_selectItem = (wxTreeListItem*)NULL; + m_shiftItem = (wxTreeListItem*)NULL; + + DeleteChildren (m_rootItem); + SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem); + delete m_rootItem; m_rootItem = NULL; +} + + +void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) { + if (! itemId.IsOk()) return; + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + // recursive delete on all children, starting from the right to prevent + // multiple selection changes (see m_curItem handling in DoDeleteItem() ) + wxArrayTreeListItems& children = item->GetChildren(); + for (size_t n = children.GetCount(); n>0; n--) { + DoDeleteItem(children[n-1]); + // immediately remove child from array, otherwise it might get selected + // as current item (see m_curItem handling in DoDeleteItem() ) + children.RemoveAt(n-1); + } +} + + +void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) { + wxCHECK_RET (item, _T("invalid item for delete!")); + + m_dirty = true; // do this first so stuff below doesn't cause flicker + + // cancel any editing + if (m_editControl) { + m_editControl->EndEdit(true); // cancelled + } + + // cancel any dragging + if (item == m_dragItem) { + // stop dragging + m_isDragStarted = m_isDragging = false; + if (HasCapture()) ReleaseMouse(); + } + + // don't stay with invalid m_curItem: take next sibling or reset to NULL + // NOTE: this might be slighty inefficient when deleting a whole tree + // but has the advantage that all deletion side-effects are handled here + if (item == m_curItem) { + SetCurrentItem(item->GetItemParent()); + if (m_curItem) { + wxArrayTreeListItems& siblings = m_curItem->GetChildren(); + size_t index = siblings.Index (item); + wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent? + SetCurrentItem(index < siblings.Count()-1 ? siblings[index+1]: (wxTreeListItem*)NULL); + } + } + // don't stay with invalid m_shiftItem: reset it to NULL + if (item == m_shiftItem) m_shiftItem = (wxTreeListItem*)NULL; + // don't stay with invalid m_selectItem: default to current item + if (item == m_selectItem) { + m_selectItem = m_curItem; + SelectItem(m_selectItem, (wxTreeItemId*)NULL, true); // unselect others + } + + // recurse children, starting from the right to prevent multiple selection + // changes (see m_curItem handling above) + wxArrayTreeListItems& children = item->GetChildren(); + for (size_t n = children.GetCount(); n>0; n--) { + DoDeleteItem(children[n-1]); + // immediately remove child from array, otherwise it might get selected + // as current item (see m_curItem handling above) + children.RemoveAt(n-1); + } + + // delete item itself + SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item); + delete item; +} + + +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) { +wxTreeListItem *old_item; + + old_item = m_curItem; m_curItem = item; + + // change of item, redraw previous + if (old_item != NULL && old_item != item) { + RefreshLine(old_item); + } + +} + +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) { + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") ); + + if (!item->HasPlus() || item->IsExpanded()) return; + + // send event to user code + wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0); + event.SetInt(m_curColumn); + if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled + + item->Expand(); + m_dirty = true; + + // send event to user code + event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED); + SendEvent(0, NULL, &event); +} + +void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) { + wxCHECK_RET (itemId.IsOk(), _T("invalid tree item")); + + Expand (itemId); + if (!IsExpanded (itemId)) return; +#if !wxCHECK_VERSION(2, 5, 0) + long cookie; +#else + wxTreeItemIdValue cookie; +#endif + wxTreeItemId child = GetFirstChild (itemId, cookie); + while (child.IsOk()) { + ExpandAll (child); + child = GetNextChild (itemId, cookie); + } +} + +void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) { + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") ); + + if (!item->HasPlus() || !item->IsExpanded()) return; + + // send event to user code + wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 ); + event.SetInt(m_curColumn); + if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled + + item->Collapse(); + m_dirty = true; + + // send event to user code + event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED); + SendEvent(0, NULL, &event); +} + +void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) { + wxCHECK_RET (item.IsOk(), _T("invalid tree item")); + + Collapse (item); + DeleteChildren (item); +} + +void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) { + wxCHECK_RET (itemId.IsOk(), _T("invalid tree item")); + + if (IsExpanded (itemId)) { + Collapse (itemId); + }else{ + Expand (itemId); + } +} + +void wxTreeListMainWindow::Unselect() { + if (m_selectItem) { + m_selectItem->SetHilight (false); + RefreshLine (m_selectItem); + m_selectItem = (wxTreeListItem*)NULL; + } +} + +void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) { + wxCHECK_RET (item, _T("invalid tree item")); + + if (item->IsSelected()) { + item->SetHilight (false); + RefreshLine (item); + if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL; + if (item != m_curItem) m_lastOnSame = false; // selection change, so reset edit marker + } + if (item->HasChildren()) { + wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.Count(); + for (size_t n = 0; n < count; ++n) { + UnselectAllChildren (children[n]); + } + } +} + +void wxTreeListMainWindow::UnselectAll() { + UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem); +} + +// Recursive function ! +// To stop we must have crt_itemGetItemParent(); + + if (!parent) {// This is root item + return TagAllChildrenUntilLast (crt_item, last_item); + } + + wxArrayTreeListItems& children = parent->GetChildren(); + int index = children.Index(crt_item); + wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent? + + if ((parent->HasChildren() && parent->IsExpanded()) || + ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) { + size_t count = children.Count(); + for (size_t n = (index+1); n < count; ++n) { + if (TagAllChildrenUntilLast (children[n], last_item)) return true; + } + } + + return TagNextChildren (parent, last_item); +} + +bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item, + wxTreeListItem *last_item) { + crt_item->SetHilight (true); + RefreshLine(crt_item); + + if (crt_item==last_item) return true; + + if (crt_item->HasChildren() && crt_item->IsExpanded()) { + wxArrayTreeListItems& children = crt_item->GetChildren(); + size_t count = children.Count(); + for (size_t n = 0; n < count; ++n) { + if (TagAllChildrenUntilLast (children[n], last_item)) return true; + } + } + + return false; +} + +bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId, + const wxTreeItemId& lastId, + bool unselect_others) { + + wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL; + + // send selecting event to the user code + wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0); + event.SetInt(m_curColumn); +#if !wxCHECK_VERSION(2, 5, 0) + event.SetOldItem ((long)m_curItem); +#else + event.SetOldItem (m_curItem); +#endif + if (SendEvent(0, item, &event) && !event.IsAllowed()) return false; // veto on selection change + + // unselect all if unselect other items + bool bUnselectedAll = false; // see that UnselectAll is done only once + if (unselect_others) { + if (HasFlag(wxTR_MULTIPLE)) { + UnselectAll(); bUnselectedAll = true; + }else{ + Unselect(); // to speed up thing + } + } + + // select item range + if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) { + + if (! bUnselectedAll) UnselectAll(); + wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem; + + // ensure that the position of the item it calculated in any case + if (m_dirty) CalculatePositions(); + + // select item range according Y-position + if (last->GetY() < item->GetY()) { + if (!TagAllChildrenUntilLast (last, item)) { + TagNextChildren (last, item); + } + }else{ + if (!TagAllChildrenUntilLast (item, last)) { + TagNextChildren (item, last); + } + } + + // or select single item + }else if (itemId.IsOk()) { + + // select item according its old selection + item->SetHilight (!item->IsSelected()); + RefreshLine (item); + if (unselect_others) { + m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL; + } + + // or select nothing + } else { + if (! bUnselectedAll) UnselectAll(); + } + + // send event to user code + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + SendEvent(0, NULL, &event); + + return true; +} + +void wxTreeListMainWindow::SelectAll() { + wxTreeItemId root = GetRootItem(); + wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style")); + wxCHECK_RET (root.IsOk(), _T("no tree")); + + // send event to user code + wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0); +#if !wxCHECK_VERSION(2, 5, 0) + event.SetOldItem ((long)m_curItem); +#else + event.SetOldItem (m_curItem); +#endif + event.SetInt (-1); // no colum clicked + if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return; // selection change vetoed + +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem; + wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem; + if (!TagAllChildrenUntilLast (first, last)) { + TagNextChildren (first, last); + } + + // send event to user code + event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED); + SendEvent(0, NULL, &event); +} + +void wxTreeListMainWindow::FillArray (wxTreeListItem *item, + wxArrayTreeItemIds &array) const { + if (item->IsSelected()) array.Add (wxTreeItemId(item)); + + if (item->HasChildren()) { + wxArrayTreeListItems& children = item->GetChildren(); + size_t count = children.GetCount(); + for (size_t n = 0; n < count; ++n) FillArray (children[n], array); + } +} + +size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const { + array.Empty(); + wxTreeItemId idRoot = GetRootItem(); + if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array); + return array.Count(); +} + +void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) { + if (!item.IsOk()) return; // do nothing if no item + + // first expand all parent branches + wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem; + wxTreeListItem *parent = gitem->GetItemParent(); + while (parent) { + Expand (parent); + parent = parent->GetItemParent(); + } + + ScrollTo (item); + RefreshLine (gitem); +} + +void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) { + if (!item.IsOk()) return; // do nothing if no item + + // ensure that the position of the item it calculated in any case + if (m_dirty) CalculatePositions(); + + wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem; + + // now scroll to the item + int item_y = gitem->GetY(); + + int xUnit, yUnit; + GetScrollPixelsPerUnit (&xUnit, &yUnit); + int start_x = 0; + int start_y = 0; + GetViewStart (&start_x, &start_y); + start_y *= yUnit; + + int client_h = 0; + int client_w = 0; + GetClientSize (&client_w, &client_h); + + int x = 0; + int y = 0; + m_rootItem->GetSize (x, y, this); + x = m_owner->GetHeaderWindow()->GetWidth(); + y += yUnit + 2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos( wxHORIZONTAL ); + + if (item_y < start_y+3) { + // going down, item should appear at top + SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0); + }else if (item_y+GetLineHeight(gitem) > start_y+client_h) { + // going up, item should appear at bottom + item_y += yUnit + 2; + SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 ); + } +} + +// FIXME: tree sorting functions are not reentrant and not MT-safe! +static wxTreeListMainWindow *s_treeBeingSorted = NULL; + +static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, + wxTreeListItem **item2) +{ + wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") ); + + return s_treeBeingSorted->OnCompareItems(*item1, *item2); +} + +int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + return m_owner->OnCompareItems (item1, item2); +} + +void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId) { + wxCHECK_RET (itemId.IsOk(), _T("invalid tree item")); + + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + wxCHECK_RET (!s_treeBeingSorted, + _T("wxTreeListMainWindow::SortChildren is not reentrant") ); + + wxArrayTreeListItems& children = item->GetChildren(); + if ( children.Count() > 1 ) { + m_dirty = true; + s_treeBeingSorted = this; + children.Sort(tree_ctrl_compare_func); + s_treeBeingSorted = NULL; + } +} + +wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, const wxString& str, int mode) { + wxString itemText; + // determine start item + wxTreeItemId next = item; + if (next.IsOk()) { + if (mode & wxTL_MODE_NAV_LEVEL) { + next = GetNextSibling (next); + }else if (mode & wxTL_MODE_NAV_VISIBLE) { // + next = GetNextVisible (next, false, true); + }else if (mode & wxTL_MODE_NAV_EXPANDED) { + next = GetNextExpanded (next); + }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default + next = GetNext (next, true); + } + } + +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + if (!next.IsOk()) { + next = GetRootItem(); + if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) { + next = GetFirstChild (GetRootItem(), cookie); + } + } + if (!next.IsOk()) return (wxTreeItemId*)NULL; + + // start checking the next items + while (next.IsOk() && (next != item)) { + if (mode & wxTL_MODE_FIND_PARTIAL) { + itemText = GetItemText (next).Mid (0, str.Length()); + }else{ + itemText = GetItemText (next); + } + if (mode & wxTL_MODE_FIND_NOCASE) { + if (itemText.CmpNoCase (str) == 0) return next; + }else{ + if (itemText.Cmp (str) == 0) return next; + } + if (mode & wxTL_MODE_NAV_LEVEL) { + next = GetNextSibling (next); + }else if (mode & wxTL_MODE_NAV_VISIBLE) { // + next = GetNextVisible (next, false, true); + }else if (mode & wxTL_MODE_NAV_EXPANDED) { + next = GetNextExpanded (next); + }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default + next = GetNext (next, true); + } + if (!next.IsOk() && item.IsOk()) { + next = (wxTreeListItem*)GetRootItem().m_pItem; + if (HasFlag(wxTR_HIDE_ROOT)) { + next = (wxTreeListItem*)GetNextChild (GetRootItem().m_pItem, cookie).m_pItem; + } + } + } + return (wxTreeItemId*)NULL; +} + +void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) { + wxTreeListItem *prevItem = m_dragItem; + m_dragItem = (wxTreeListItem*) item.m_pItem; + if (prevItem) RefreshLine (prevItem); + if (m_dragItem) RefreshLine (m_dragItem); +} + +void wxTreeListMainWindow::CalculateLineHeight() { + wxClientDC dc (this); + dc.SetFont (m_normalFont); + m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing); + + if (m_imageListNormal) { + // Calculate a m_lineHeight value from the normal Image sizes. + // May be toggle off. Then wxTreeListMainWindow will spread when + // necessary (which might look ugly). + int n = m_imageListNormal->GetImageCount(); + for (int i = 0; i < n ; i++) { + int width = 0, height = 0; + m_imageListNormal->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height + m_linespacing; + } + } + + if (m_imageListButtons) { + // Calculate a m_lineHeight value from the Button image sizes. + // May be toggle off. Then wxTreeListMainWindow will spread when + // necessary (which might look ugly). + int n = m_imageListButtons->GetImageCount(); + for (int i = 0; i < n ; i++) { + int width = 0, height = 0; + m_imageListButtons->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height + m_linespacing; + } + } + + if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels + m_lineHeight += 2; // minimal 2 pixel space + }else{ + m_lineHeight += m_lineHeight / 10; // otherwise 10% space + } +} + +void wxTreeListMainWindow::SetImageList (wxImageList *imageList) { + if (m_ownsImageListNormal) delete m_imageListNormal; + m_imageListNormal = imageList; + m_ownsImageListNormal = false; + m_dirty = true; + CalculateLineHeight(); +} + +void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) { + if (m_ownsImageListState) delete m_imageListState; + m_imageListState = imageList; + m_ownsImageListState = false; +} + +void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) { + if (m_ownsImageListButtons) delete m_imageListButtons; + m_imageListButtons = imageList; + m_ownsImageListButtons = false; + m_dirty = true; + CalculateLineHeight(); +} + +void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) { + SetImageList(imageList); + m_ownsImageListNormal = true; +} + +void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) { + SetStateImageList(imageList); + m_ownsImageListState = true; +} + +void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) { + SetButtonsImageList(imageList); + m_ownsImageListButtons = true; +} + +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::AdjustMyScrollbars() { + if (m_rootItem) { + int xUnit, yUnit; + GetScrollPixelsPerUnit (&xUnit, &yUnit); + if (xUnit == 0) xUnit = GetCharWidth(); + if (yUnit == 0) yUnit = m_lineHeight; + int x = 0, y = 0; + m_rootItem->GetSize (x, y, this); + y += yUnit + 2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos (wxHORIZONTAL); + int y_pos = GetScrollPos (wxVERTICAL); + x = m_owner->GetHeaderWindow()->GetWidth() + 2; + if (x < GetClientSize().GetWidth()) x_pos = 0; + SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos); + }else{ + SetScrollbars (0, 0, 0, 0); + } +} + +int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const { + if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) { + return item->GetHeight(); + }else{ + return m_lineHeight; + } +} + +void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) { + + wxTreeItemAttr *attr = item->GetAttributes(); + + dc.SetFont (GetItemFont (item)); + + wxColour colText; + if (attr && attr->HasTextColour()) { + colText = attr->GetTextColour(); + }else{ + colText = GetForegroundColour(); + } +#if !wxCHECK_VERSION(2, 5, 0) + wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT); +#else + wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT); +#endif + + int total_w = m_owner->GetHeaderWindow()->GetWidth(); + int total_h = GetLineHeight(item); + int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0; + int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0; + wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line + + int text_w = 0, text_h = 0; + dc.GetTextExtent( item->GetText(GetMainColumn()).size() > 0 + ? item->GetText(GetMainColumn()) + : _T(" "), // dummy text to avoid zero height and no highlight width + &text_w, &text_h ); + + // determine background and show it + wxColour colBg; + if (attr && attr->HasBackgroundColour()) { + colBg = attr->GetBackgroundColour(); + }else{ + colBg = m_backgroundColour; + } + dc.SetBrush (wxBrush (colBg, wxSOLID)); + dc.SetPen (*wxTRANSPARENT_PEN); + if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) { + if (item->IsSelected()) { + if (! m_isDragging && m_hasFocus) { + dc.SetBrush (*m_hilightBrush); +#ifndef __WXMAC__ // don't draw rect outline if we already have the background color + dc.SetPen (*wxBLACK_PEN); +#endif // !__WXMAC__ + }else{ + dc.SetBrush (*m_hilightUnfocusedBrush); +#ifndef __WXMAC__ // don't draw rect outline if we already have the background color + dc.SetPen (*wxTRANSPARENT_PEN); +#endif // !__WXMAC__ + } + dc.SetTextForeground (colTextHilight); + }else if (item == m_curItem) { + dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN); + }else{ + dc.SetTextForeground (colText); + } + dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h); + }else{ + dc.SetTextForeground (colText); + } + + int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0; + int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0; + int x_colstart = 0; + for (int i = 0; i < GetColumnCount(); ++i ) { + if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue; + + int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i); + wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column + + int x = 0; + int image = NO_IMAGE; + int image_w = 0; + if(i == GetMainColumn()) { + x = item->GetX() + MARGIN; + if (HasButtons()) { + x += (m_btnWidth-m_btnWidth2) + LINEATROOT; + }else{ + x -= m_indent/2; + } + if (m_imageListNormal) image = item->GetCurrentImage(); + }else{ + x = x_colstart + MARGIN; + image = item->GetImage(i); + } + if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN; + + // honor text alignment + wxString text = item->GetText(i); + int w = 0; + switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) { + case wxALIGN_LEFT: + // nothing to do, already left aligned + break; + case wxALIGN_RIGHT: + dc.GetTextExtent (text, &text_w, NULL); + w = col_w - (image_w + text_w + off_w + MARGIN); + x += (w > 0)? w: 0; + break; + case wxALIGN_CENTER: + dc.GetTextExtent(text, &text_w, NULL); + w = (col_w - (image_w + text_w + off_w + MARGIN))/2; + x += (w > 0)? w: 0; + break; + } + int text_x = x + image_w; + if (i == GetMainColumn()) item->SetTextX (text_x); + + if (!HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) { + if (i == GetMainColumn()) { + if (item->IsSelected()) { + if (!m_isDragging && m_hasFocus) { + dc.SetBrush (*m_hilightBrush); +#ifndef __WXMAC__ // don't draw rect outline if we already have the background color + dc.SetPen (*wxBLACK_PEN); +#endif // !__WXMAC__ + }else{ + dc.SetBrush (*m_hilightUnfocusedBrush); +#ifndef __WXMAC__ // don't draw rect outline if we already have the background color + dc.SetPen (*wxTRANSPARENT_PEN); +#endif // !__WXMAC__ + } + dc.SetTextForeground (colTextHilight); + }else if (item == m_curItem) { + dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN); + }else{ + dc.SetTextForeground (colText); + } + dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h); + }else{ + dc.SetTextForeground (colText); + } + } + + if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns +#if !wxCHECK_VERSION(2, 5, 0) + wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID); +#else + wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID); +#endif + dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN); + dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h); + } + + dc.SetBackgroundMode (wxTRANSPARENT); + + if (image != NO_IMAGE) { + int y = item->GetY() + img_extraH; + m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + } + int text_y = item->GetY() + text_extraH; + dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y); + + x_colstart += col_w; + } + + // restore normal font + dc.SetFont( m_normalFont ); +} + +// Now y stands for the top of the item, whereas it used to stand for middle ! +void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc, + int level, int &y, int x_maincol) { + + // Handle hide root (only level 0) + if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) { + wxArrayTreeListItems& children = item->GetChildren(); + for (size_t n = 0; n < children.Count(); n++) { + PaintLevel (children[n], dc, 1, y, x_maincol); + } + // end after expanding root + return; + } + + // calculate position of vertical lines + int x = x_maincol + MARGIN; // start of column + if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root + if (HasButtons()) { + x += (m_btnWidth-m_btnWidth2); // half button space + }else{ + x += (m_indent-m_indent/2); + } + if (HasFlag(wxTR_HIDE_ROOT)) { + x += m_indent * (level-1); // indent but not level 1 + }else{ + x += m_indent * level; // indent according to level + } + + // set position of vertical line + item->SetX (x); + item->SetY (y); + + int h = GetLineHeight (item); + int y_top = y; + int y_mid = y_top + (h/2); + y += h; + + int exposed_x = dc.LogicalToDeviceX(0); + int exposed_y = dc.LogicalToDeviceY(y_top); + + if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much + + if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows + //dc.DestroyClippingRegion(); + int total_width = m_owner->GetHeaderWindow()->GetWidth(); + // if the background colour is white, choose a + // contrasting color for the lines +#if !wxCHECK_VERSION(2, 5, 0) + wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID); +#else + wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID); +#endif + dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN); + dc.DrawLine (0, y_top, total_width, y_top); + dc.DrawLine (0, y_top+h, total_width, y_top+h); + } + + // draw item + PaintItem (item, dc); + + // restore DC objects + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(m_dottedPen); + + // clip to the column width + int clip_width = m_owner->GetHeaderWindow()-> + GetColumn(m_main_column).GetWidth(); + wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000); + + if (!HasFlag(wxTR_NO_LINES)) { // connection lines + + // draw the horizontal line here + dc.SetPen(m_dottedPen); + int x2 = x - m_indent; + if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN; + int x3 = x + (m_btnWidth-m_btnWidth2); + if (HasButtons()) { + if (item->HasPlus()) { + dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid); + dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid); + }else{ + dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid); + } + }else{ + dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid); + } + } + + if (item->HasPlus() && HasButtons()) { // should the item show a button? + + if (m_imageListButtons) { + + // draw the image button here + int image = wxTreeItemIcon_Normal; + if (item->IsExpanded()) image = wxTreeItemIcon_Expanded; + if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal; + int xx = x - m_btnWidth2 + MARGIN; + int yy = y_mid - m_btnHeight2; + dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight); + m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT); + dc.DestroyClippingRegion(); + + }else if (HasFlag (wxTR_TWIST_BUTTONS)) { + + // draw the twisty button here + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*m_hilightBrush); + wxPoint button[3]; + if (item->IsExpanded()) { + button[0].x = x - (m_btnWidth2+1); + button[0].y = y_mid - (m_btnHeight/3); + button[1].x = x + (m_btnWidth2+1); + button[1].y = button[0].y; + button[2].x = x; + button[2].y = button[0].y + (m_btnHeight2+1); + }else{ + button[0].x = x - (m_btnWidth/3); + button[0].y = y_mid - (m_btnHeight2+1); + button[1].x = button[0].x; + button[1].y = y_mid + (m_btnHeight2+1); + button[2].x = button[0].x + (m_btnWidth2+1); + button[2].y = y_mid; + } + dc.DrawPolygon(3, button); + + }else{ // if (HasFlag(wxTR_HAS_BUTTONS)) + + // draw the plus sign here +#if !wxCHECK_VERSION(2, 7, 0) + dc.SetPen(*wxGREY_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight); + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid); + if (!item->IsExpanded()) { // change "-" to "+" + dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1)); + } +#else + wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight); + int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0; + wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag); +#endif + + } + + } + + } + + // restore DC objects + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(m_dottedPen); + dc.SetTextForeground(*wxBLACK); + + if (item->IsExpanded()) + { + wxArrayTreeListItems& children = item->GetChildren(); + + // clip to the column width + int clip_width = m_owner->GetHeaderWindow()-> + GetColumn(m_main_column).GetWidth(); + + // process lower levels + int oldY; + if (m_imgWidth > 0) { + oldY = y_mid + m_imgHeight2; + }else{ + oldY = y_mid + h/2; + } + int y2; + for (size_t n = 0; n < children.Count(); ++n) { + + y2 = y + h/2; + PaintLevel (children[n], dc, level+1, y, x_maincol); + + // draw vertical line + wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000); + if (!HasFlag (wxTR_NO_LINES)) { + x = item->GetX(); + dc.DrawLine (x, oldY, x, y2); + oldY = y2; + } + } + } +} + + +// ---------------------------------------------------------------------------- +// wxWindows callbacks +// ---------------------------------------------------------------------------- + +void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) { + + // init device context, clear background (BEFORE changing DC origin...) + wxAutoBufferedPaintDC dc (this); + wxBrush brush(GetBackgroundColour(), wxSOLID); + dc.SetBackground(brush); + dc.Clear(); + DoPrepareDC (dc); + + if (!m_rootItem || (GetColumnCount() <= 0)) return; + + // calculate button size + if (m_imageListButtons) { + m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight); + }else if (HasButtons()) { + m_btnWidth = BTNWIDTH; + m_btnHeight = BTNHEIGHT; + } + m_btnWidth2 = m_btnWidth/2; + m_btnHeight2 = m_btnHeight/2; + + // calculate image size + if (m_imageListNormal) { + m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight); + } + m_imgWidth2 = m_imgWidth/2; + m_imgHeight2 = m_imgHeight/2; + + // calculate indent size + if (m_imageListButtons) { + m_indent = wxMax (MININDENT, m_btnWidth + MARGIN); + }else if (HasButtons()) { + m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT); + } + + // set default values + dc.SetFont( m_normalFont ); + dc.SetPen( m_dottedPen ); + + // calculate column start and paint + int x_maincol = 0; + int i = 0; + for (i = 0; i < (int)GetMainColumn(); ++i) { + if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue; + x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i); + } + int y = 0; + PaintLevel (m_rootItem, dc, 0, y, x_maincol); +} + +void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) { + m_hasFocus = true; + RefreshSelected(); + if (m_curItem) RefreshLine (m_curItem); + event.Skip(); +} + +void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event ) +{ + m_hasFocus = false; + RefreshSelected(); + if (m_curItem) RefreshLine (m_curItem); + event.Skip(); +} + +void wxTreeListMainWindow::OnChar (wxKeyEvent &event) { + // send event to user code + wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 ); + nevent.SetInt(m_curColumn); + nevent.SetKeyEvent (event); + if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code + + // if no item current, select root + bool curItemSet = false; + if (!m_curItem) { + if (! GetRootItem().IsOk()) return; + SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem); + if (HasFlag(wxTR_HIDE_ROOT)) { +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem); + } + SelectItem(m_curItem, (wxTreeItemId*)NULL, true); // unselect others + curItemSet = true; + } + + // remember item at shift down + if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) { + if (!m_shiftItem) m_shiftItem = m_curItem; + }else{ + m_shiftItem = (wxTreeListItem*)NULL; + } + + if (curItemSet) return; // if no item was current until now, do nothing more + + // process all cases + wxTreeItemId newItem = (wxTreeItemId*)NULL; + switch (event.GetKeyCode()) { + + // '+': Expand subtree + case '+': + case WXK_ADD: { + if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem); + }break; + + // '-': collapse subtree + case '-': + case WXK_SUBTRACT: { + if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem); + }break; + + // '*': expand/collapse all subtrees // TODO: Mak it more useful + case '*': + case WXK_MULTIPLY: { + if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) { + ExpandAll (m_curItem); + }else if (m_curItem->HasPlus()) { + Collapse (m_curItem); // TODO: CollapseAll + } + }break; + + // ' ': toggle current item + case ' ': { + SelectItem (m_curItem, (wxTreeListItem*)NULL, false); + }break; + + // : activate current item + case WXK_RETURN: { + if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) { + + // if the user code didn't process the activate event, + // handle it ourselves by toggling the item when it is + // double clicked + if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem); + } + }break; + + // : go to the parent without collapsing + case WXK_BACK: { + newItem = GetItemParent (m_curItem); + if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) { + newItem = GetPrevSibling (m_curItem); // get sibling instead of root + } + }break; + + // : go to first visible + case WXK_HOME: { + newItem = GetFirstVisible(false, false); + }break; + + // : go to the top of the page, or if we already are then one page back + case WXK_PAGEUP: { + int flags = 0; + int col = 0; + wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1)); + // PAGE-UP: first go the the first visible row + newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0); + newItem = GetFirstVisible(false, true); + // if we are already there then scroll back one page + if (newItem == m_curItem) { + abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight(); + if (abs_p.y < 0) abs_p.y = 0; + newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0); + } + // newItem should never be NULL + } break; + + // : go to the previous sibling or for the last of its children, to the parent + case WXK_UP: { + newItem = GetPrevSibling (m_curItem); + if (newItem) { +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + while (IsExpanded (newItem) && HasChildren (newItem)) { + newItem = GetLastChild (newItem, cookie); + } + }else { + newItem = GetItemParent (m_curItem); + if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) { + newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden + } + } + }break; + + // : if expanded collapse subtree, else go to the parent + case WXK_LEFT: { + if (IsExpanded (m_curItem)) { + Collapse (m_curItem); + }else{ + newItem = GetItemParent (m_curItem); + if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) { + newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden + } + } + }break; + + // : if possible expand subtree, else go go to the first child + case WXK_RIGHT: { + if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) { + Expand (m_curItem); + }else{ + if (IsExpanded (m_curItem) && HasChildren (m_curItem)) { +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + newItem = GetFirstChild (m_curItem, cookie); + } + } + }break; + + // : if expanded go to the first child, else to the next sibling, ect + case WXK_DOWN: { + if (IsExpanded (m_curItem) && HasChildren (m_curItem)) { +#if !wxCHECK_VERSION(2, 5, 0) + long cookie = 0; +#else + wxTreeItemIdValue cookie = 0; +#endif + newItem = GetFirstChild( m_curItem, cookie ); + } + if (!newItem) { + wxTreeItemId parent = m_curItem; + do { + newItem = GetNextSibling (parent); + parent = GetItemParent (parent); + } while (!newItem && parent); + } + }break; + + // : go to the bottom of the page, or if we already are then one page further + case WXK_PAGEDOWN: { + int flags = 0; + int col = 0; + wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight())); + // PAGE-UP: first go the the first visible row + newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0); + newItem = GetLastVisible(false, true); + // if we are already there then scroll down one page + if (newItem == m_curItem) { + abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight(); +// if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1; + newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0); + } + // if we reached the empty area below the rows, return last item instead + if (! newItem) newItem = GetLastVisible(false, false); + } break; + + // : go to last item of the root + case WXK_END: { + newItem = GetLastVisible (false, false); + }break; + + // any char: go to the next matching string + default: + if (event.GetKeyCode() >= (int)' ') { + if (!m_findTimer->IsRunning()) m_findStr.Clear(); + m_findStr.Append (event.GetKeyCode()); + m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT); + wxTreeItemId prev = m_curItem? (wxTreeItemId*)m_curItem: (wxTreeItemId*)NULL; + while (true) { + newItem = FindItem (prev, m_findStr, wxTL_MODE_NAV_EXPANDED | + wxTL_MODE_FIND_PARTIAL | + wxTL_MODE_FIND_NOCASE); + if (newItem || (m_findStr.Length() <= 1)) break; + m_findStr.RemoveLast(); + }; + } + event.Skip(); + + } + + // select and show the new item + if (newItem) { + if (!event.ControlDown()) { + bool unselect_others = !((event.ShiftDown() || event.ControlDown()) && + HasFlag(wxTR_MULTIPLE)); + SelectItem (newItem, m_shiftItem, unselect_others); + } + EnsureVisible (newItem); + wxTreeListItem *oldItem = m_curItem; + SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item + RefreshLine (oldItem); + } + +} + +wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) { + + int w, h; + GetSize(&w, &h); + flags=0; + column = -1; + if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT; + if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT; + if (point.y<0) flags |= wxTREE_HITTEST_ABOVE; + if (point.y>h) flags |= wxTREE_HITTEST_BELOW; + if (flags) return wxTreeItemId(); + + if (!m_rootItem) { + flags = wxTREE_HITTEST_NOWHERE; + column = -1; + return wxTreeItemId(); + } + + wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point), + this, flags, column, 0); + if (!hit) { + flags = wxTREE_HITTEST_NOWHERE; + column = -1; + return wxTreeItemId(); + } + return hit; +} + +// get the bounding rectangle of the item (or of its label only) +bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect, + bool WXUNUSED(textOnly)) const { + wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") ); + + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + + int xUnit, yUnit; + GetScrollPixelsPerUnit (&xUnit, &yUnit); + int startX, startY; + GetViewStart(& startX, & startY); + + rect.x = item->GetX() - startX * xUnit; + rect.y = item->GetY() - startY * yUnit; + rect.width = item->GetWidth(); + rect.height = GetLineHeight (item); + + return true; +} + +/* **** */ + +void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) { + +// validate + if (!item.IsOk()) return; + if (!((column >= 0) && (column < GetColumnCount()))) return; + +// cancel any editing + if (m_editControl) { + m_editControl->EndEdit(true); // cancelled + } + +// prepare edit (position) + m_editItem = (wxTreeListItem*) item.m_pItem; + + wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 ); + te.SetInt (column); + SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return; + + // ensure that the position of the item it calculated in any case + if (m_dirty) CalculatePositions(); + + wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow(); + + // position & size are rather unpredictable (tsssk, tssssk) so were + // set by trial & error (on Win 2003 pre-XP style) + int x = 0; + int w = +4; // +4 is necessary, don't know why (simple border erronously counted somewhere ?) + int y = m_editItem->GetY() + 1; // this is cell, not text + int h = m_editItem->GetHeight() - 1; // consequence from above + long style = 0; + if (column == GetMainColumn()) { + x += m_editItem->GetTextX() - 2; // wrong by 2, don't know why + w += m_editItem->GetWidth(); + } else { + for (int i = 0; i < column; ++i) x += header_win->GetColumnWidth (i); // start of column + w += header_win->GetColumnWidth (column); // currently non-main column width not pre-computed + } + switch (header_win->GetColumnAlignment (column)) { + case wxALIGN_LEFT: {style = wxTE_LEFT; x -= 1; break;} + case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;} + case wxALIGN_RIGHT: {style = wxTE_RIGHT; x += 0; break;} // yes, strange but that's the way it is + } + // wxTextCtrl simple border style requires 2 extra pixels before and after + // (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() ) + y -= 2; x -= 2; + w += 4; h += 4; + + wxClientDC dc (this); + PrepareDC (dc); + x = dc.LogicalToDeviceX (x); + y = dc.LogicalToDeviceY (y); + +// now do edit (change state, show control) + m_editCol = column; // only used in OnRenameAccept() + m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes, + this, m_editItem->GetText (column), + wxPoint (x, y), wxSize (w, h), style); + m_editControl->SetFocus(); +} + +void wxTreeListMainWindow::OnRenameTimer() { + EditLabel (m_curItem, m_curColumn); +} + +void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) { + + // TODO if the validator fails this causes a crash + wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 ); + le.SetLabel( m_editRes ); + le.SetEditCanceled(isCancelled); + le.SetInt(m_editCol); + SendEvent(0, m_editItem, &le); if (! isCancelled && le.IsAllowed()) + { + SetItemText (m_editItem, le.GetInt(), le.GetLabel()); + } +} + +void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) { +bool mayDrag = true; +bool maySelect = true; // may change selection +bool mayClick = true; // may process DOWN clicks to expand, send click events +bool mayDoubleClick = true; // implies mayClick +bool bSkip = true; + + // send event to user code + if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code + if (!m_rootItem) return; + + +// ---------- DETERMINE EVENT ---------- +/* +wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>", + event.LeftDown(), event.MiddleDown(), event.RightDown(), + event.LeftUp(), event.MiddleUp(), event.RightUp(), + event.LeftDClick(), event.Dragging()); +*/ + wxPoint p = wxPoint (event.GetX(), event.GetY()); + int flags = 0; + wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p), + this, flags, m_curColumn, 0); + bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON)); + // we were dragging + if (m_isDragging) { + maySelect = mayDoubleClick = false; + } + // we are starting or continuing to drag + if (event.Dragging()) { + maySelect = mayDoubleClick = mayClick = false; + } + // crosshair area is special + if (bCrosshair) { + // left click does not select + if (event.LeftDown()) maySelect = false; + // double click is ignored + mayDoubleClick = false; + } + // double click only if simple click + if (mayDoubleClick) mayDoubleClick = mayClick; + // selection conditions --remember also that selection exludes editing + if (maySelect) maySelect = mayClick; // yes, select/unselect requires a click + if (maySelect) { + + // multiple selection mode complicates things, sometimes we + // select on button-up instead of down: + if (HasFlag(wxTR_MULTIPLE)) { + + // CONTROL/SHIFT key used, don't care about anything else, will + // toggle on key down + if (event.ControlDown() || event.ShiftDown()) { + maySelect = maySelect && (event.LeftDown() || event.RightDown()); + m_lastOnSame = false; // prevent editing when keys are used + + // already selected item: to allow drag or contextual menu for multiple + // items, we only select/unselect on click-up --and only on LEFT + // click, right is reserved for contextual menu + } else if ((item != NULL && item->IsSelected())) { + maySelect = maySelect && event.LeftUp(); + + // non-selected items: select on click-down like simple select (so + // that a right-click contextual menu may be chained) + } else { + maySelect = maySelect && (event.LeftDown() || event.RightDown()); + } + + // single-select is simply on left or right click-down + } else { + maySelect = maySelect && (event.LeftDown() || event.RightDown()); + } + } + + +// ---------- GENERAL ACTIONS ---------- + + // set focus if window clicked + if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus(); + + // tooltip change ? + if (item != m_toolTipItem) { + + // not over an item, use global tip + if (item == NULL) { + m_toolTipItem = NULL; + wxScrolledWindow::SetToolTip(m_toolTip); + + // over an item + } else { + const wxString *tip = item->GetToolTip(); + + // is there an item-specific tip ? + if (tip) { + m_toolTipItem = item; + wxScrolledWindow::SetToolTip(*tip); + + // no item tip, but we are in item-specific mode (SetItemToolTip() + // was called after SetToolTip() ) + } else if (m_isItemToolTip) { + m_toolTipItem = item; + wxScrolledWindow::SetToolTip(wxString()); + + // no item tip, display global tip instead; item change ignored + } else if (m_toolTipItem != NULL) { + m_toolTipItem = NULL; + wxScrolledWindow::SetToolTip(m_toolTip); + } + } + } + + +// ---------- HANDLE SIMPLE-CLICKS (selection change, contextual menu) ---------- + if (mayClick) { + + // 2nd left-click on an item might trigger edit + if (event.LeftDown()) m_lastOnSame = (item == m_curItem); + + // left-click on haircross is expand (and no select) + if (bCrosshair && event.LeftDown()) { + + bSkip = false; + + // note that we only toggle the item for a single click, double + // click on the button doesn't do anything + Toggle (item); + } + + if (maySelect) { + bSkip = false; + + // set / remember item at shift down before current item gets changed + if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) { + if (!m_shiftItem) m_shiftItem = m_curItem; + }else{ + m_shiftItem = (wxTreeListItem*)NULL; + } + + // how is selection altered + // keep or discard already selected ? + bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && ( + event.ShiftDown() + || event.ControlDown() + )); + + // check is selection change is not vetoed + if (SelectItem(item, m_shiftItem, unselect_others)) { + // make the new item the current item + EnsureVisible (item); + SetCurrentItem(item); + } + } + + // generate click & menu events + if (event.MiddleDown()) { + bSkip = false; + SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item); + } + if (event.RightDown()) { + bSkip = false; + SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item); + } + if (event.RightUp()) { + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MENU, 0); + nevent.SetPoint(p); + nevent.SetInt(m_curColumn); + SendEvent(0, item, &nevent); + } + + // if 2nd left click finishes on same item, will edit it + if (m_lastOnSame && event.LeftUp()) { + if ((item == m_curItem) && (m_curColumn != -1) && + (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) && + (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN)) + ){ + m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT); + bSkip = false; + } + m_lastOnSame = false; + } + } + + +// ---------- HANDLE DOUBLE-CLICKS ---------- + if (mayDoubleClick && event.LeftDClick()) { + + bSkip = false; + + // double clicking should not start editing the item label + m_editTimer->Stop(); + m_lastOnSame = false; + + // selection reset to that single item which was double-clicked + if (SelectItem(item, (wxTreeItemId*)NULL, true)) { // unselect others --return false if vetoed + + // selection change not vetoed, send activate event + if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) { + + // if the user code didn't process the activate event, + // handle it ourselves by toggling the item when it is + // double clicked + if (item && item->HasPlus()) Toggle(item); + } + } + } + + +// ---------- HANDLE DRAGGING ---------- +// NOTE: drag itself makes no change to selection + if (mayDrag) { // actually this is always true + + // CASE 1: we were dragging => continue, end, abort + if (m_isDragging) { + + // CASE 1.1: click aborts drag: + if (event.LeftDown() || event.MiddleDown() || event.RightDown()) { + + bSkip = false; + + // stop dragging + m_isDragStarted = m_isDragging = false; + if (HasCapture()) ReleaseMouse(); + RefreshSelected(); + + // CASE 1.2: still dragging + } else if (event.Dragging()) { + + ;; // nothing to do + + // CASE 1.3: dragging now ends normally + } else { + + bSkip = false; + + // stop dragging + m_isDragStarted = m_isDragging = false; + if (HasCapture()) ReleaseMouse(); + RefreshSelected(); + + // send drag end event + wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, 0); + event.SetPoint(p); + event.SetInt(m_curColumn); + SendEvent(0, item, &event); + } + + // CASE 2: not were not dragging => continue, start + } else if (event.Dragging()) { + + // We will really start dragging if we've moved beyond a few pixels + if (m_isDragStarted) { + const int tolerance = 3; + int dx = abs(p.x - m_dragStartPos.x); + int dy = abs(p.y - m_dragStartPos.y); + if (dx <= tolerance && dy <= tolerance) + return; + // determine drag start + } else { + m_dragStartPos = p; + m_dragCol = m_curColumn; + m_dragItem = item; + m_isDragStarted = true; + return; + } + + bSkip = false; + + // we are now dragging + m_isDragging = true; + RefreshSelected(); + CaptureMouse(); // TODO: usefulness unclear + + wxTreeEvent nevent(event.LeftIsDown() + ? wxEVT_COMMAND_TREE_BEGIN_DRAG + : wxEVT_COMMAND_TREE_BEGIN_RDRAG, 0); + nevent.SetPoint(p); + nevent.SetInt(m_dragCol); + nevent.Veto(); + SendEvent(0, m_dragItem, &nevent); + } + } + + + if (bSkip) event.Skip(); +} + + +void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) { + /* after all changes have been done to the tree control, + * we actually redraw the tree when everything is over */ + + if (!m_dirty) return; + + m_dirty = false; + + CalculatePositions(); + Refresh(); + AdjustMyScrollbars(); +} + +void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) { + // FIXME +#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) + wxScrolledWindow::OnScroll(event); +#else + HandleOnScroll( event ); +#endif + + if(event.GetOrientation() == wxHORIZONTAL) { + m_owner->GetHeaderWindow()->Refresh(); + m_owner->GetHeaderWindow()->Update(); + } +} + +void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) { + wxCoord text_w = 0; + wxCoord text_h = 0; + + dc.SetFont (GetItemFont (item)); + dc.GetTextExtent (item->GetText(m_main_column).size() > 0 + ? item->GetText (m_main_column) + : _T(" "), // blank to avoid zero height and no highlight width + &text_w, &text_h); + // restore normal font + dc.SetFont (m_normalFont); + + int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h; + if (max_h < 30) { // add 10% space if greater than 30 pixels + max_h += 2; // minimal 2 pixel space + }else{ + max_h += max_h / 10; // otherwise 10% space + } + + item->SetHeight (max_h); + if (max_h > m_lineHeight) m_lineHeight = max_h; + item->SetWidth(m_imgWidth + text_w+2); +} + +// ----------------------------------------------------------------------------- +void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc, + int level, int &y, int x_colstart) { + + // calculate position of vertical lines + int x = x_colstart + MARGIN; // start of column + if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root + if (HasButtons()) { + x += (m_btnWidth-m_btnWidth2); // half button space + }else{ + x += (m_indent-m_indent/2); + } + if (HasFlag(wxTR_HIDE_ROOT)) { + x += m_indent * (level-1); // indent but not level 1 + }else{ + x += m_indent * level; // indent according to level + } + + // a hidden root is not evaluated, but its children are always + if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse; + + CalculateSize( item, dc ); + + // set its position + item->SetX (x); + item->SetY (y); + y += GetLineHeight(item); + + // we don't need to calculate collapsed branches + if ( !item->IsExpanded() ) return; + +Recurse: + wxArrayTreeListItems& children = item->GetChildren(); + long n, count = (long)children.Count(); + ++level; + for (n = 0; n < count; ++n) { + CalculateLevel( children[n], dc, level, y, x_colstart ); // recurse + } +} + +void wxTreeListMainWindow::CalculatePositions() { + if ( !m_rootItem ) return; + + wxClientDC dc(this); + PrepareDC( dc ); + + dc.SetFont( m_normalFont ); + + dc.SetPen( m_dottedPen ); + //if(GetImageList() == NULL) + // m_lineHeight = (int)(dc.GetCharHeight() + 4); + + int y = 2; + int x_colstart = 0; + for (int i = 0; i < (int)GetMainColumn(); ++i) { + if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue; + x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i); + } + CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion +} + +void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) { + if (m_dirty) return; + + wxClientDC dc(this); + PrepareDC(dc); + + int cw = 0; + int ch = 0; + GetVirtualSize( &cw, &ch ); + + wxRect rect; + rect.x = dc.LogicalToDeviceX( 0 ); + rect.width = cw; + rect.y = dc.LogicalToDeviceY( item->GetY() - 2 ); + rect.height = ch; + + Refresh (true, &rect ); + AdjustMyScrollbars(); +} + +void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) { + if (m_dirty) return; + + wxClientDC dc(this); + PrepareDC( dc ); + + int cw = 0; + int ch = 0; + GetVirtualSize( &cw, &ch ); + + wxRect rect; + rect.x = dc.LogicalToDeviceX( 0 ); + rect.y = dc.LogicalToDeviceY( item->GetY() ); + rect.width = cw; + rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6; + + Refresh (true, &rect); +} + +void wxTreeListMainWindow::RefreshSelected() { + // TODO: this is awfully inefficient, we should keep the list of all + // selected items internally, should be much faster + if (m_rootItem) { + RefreshSelectedUnder (m_rootItem); + } +} + +void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) { + if (item->IsSelected()) { + RefreshLine (item); + } + + const wxArrayTreeListItems& children = item->GetChildren(); + long count = (long)children.GetCount(); + for (long n = 0; n < count; n++ ) { + RefreshSelectedUnder (children[n]); + } +} + +// ---------------------------------------------------------------------------- +// changing colours: we need to refresh the tree control +// ---------------------------------------------------------------------------- + +bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) { + if (!wxWindow::SetBackgroundColour(colour)) return false; + + Refresh(); + return true; +} + +bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) { + if (!wxWindow::SetForegroundColour(colour)) return false; + + Refresh(); + return true; +} + +void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, + const wxString& text) { + wxCHECK_RET (itemId.IsOk(), _T("invalid tree item")); + + wxClientDC dc (this); + wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem; + item->SetText (column, text); + CalculateSize (item, dc); + RefreshLine (item); +} + +wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, + int column) const { + wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") ); + + if( IsVirtual() ) return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column); + else return ((wxTreeListItem*) itemId.m_pItem)->GetText (column); +} + +wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, +int column) const { + wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") ); + return m_owner->OnGetItemText(item,column); +} + +void wxTreeListMainWindow::SetFocus() { + wxWindow::SetFocus(); +} + +wxFont wxTreeListMainWindow::GetItemFont (wxTreeListItem *item) { + wxTreeItemAttr *attr = item->GetAttributes(); + + if (attr && attr->HasFont()) { + return attr->GetFont(); + }else if (item->IsBold()) { + return m_boldFont; + }else{ + return m_normalFont; + } +} + +int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) { + if (!item) return 0; + + // determine item width + int w = 0, h = 0; + wxFont font = GetItemFont (item); + GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL); + w += 2*MARGIN; + + // calculate width + int width = w + 2*MARGIN; + if (column == GetMainColumn()) { + width += MARGIN; + if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT; + if (HasButtons()) width += m_btnWidth + LINEATROOT; + if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth; + + // count indent level + int level = 0; + wxTreeListItem *parent = item->GetItemParent(); + wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem; + while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) { + level++; + parent = parent->GetItemParent(); + } + if (level) width += level * GetIndent(); + } + + return width; +} + +int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) { + int maxWidth, h; + GetClientSize (&maxWidth, &h); + int width = 0; + + // get root if on item + if (!parent.IsOk()) parent = GetRootItem(); + + // add root width + if (!HasFlag(wxTR_HIDE_ROOT)) { + int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem); + if (width < w) width = w; + if (width > maxWidth) return maxWidth; + } + + wxTreeItemIdValue cookie = 0; + wxTreeItemId item = GetFirstChild (parent, cookie); + while (item.IsOk()) { + int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem); + if (width < w) width = w; + if (width > maxWidth) return maxWidth; + + // check the children of this item + if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) { + int w = GetBestColumnWidth (column, item); + if (width < w) width = w; + if (width > maxWidth) return maxWidth; + } + + // next sibling + item = GetNextChild (parent, cookie); + } + + return width; +} + + +bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) { +wxTreeEvent nevent (event_type, 0); + + if (event == NULL) { + event = &nevent; + event->SetInt (m_curColumn); // the mouse colum + } + + event->SetEventObject (m_owner); + event->SetId(m_owner->GetId()); + if (item) { +#if !wxCHECK_VERSION(2, 5, 0) + event->SetItem ((long)item); +#else + event->SetItem (item); +#endif + } + + return m_owner->GetEventHandler()->ProcessEvent (*event); +} + + +//----------------------------------------------------------------------------- +// wxTreeListCtrl +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl); + +BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl) + EVT_SIZE(wxTreeListCtrl::OnSize) +END_EVENT_TABLE(); + +bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, const wxValidator &validator, + const wxString& name) +{ + long main_style = style & ~(wxSIMPLE_BORDER|wxSUNKEN_BORDER|wxDOUBLE_BORDER| + wxRAISED_BORDER|wxSTATIC_BORDER); + main_style |= wxWANTS_CHARS ; + long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL); + + if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) { + return false; + } + m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size, + main_style, validator); + m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win, + wxPoint(0, 0), wxDefaultSize, + wxTAB_TRAVERSAL); + CalculateAndSetHeaderHeight(); + return true; +} + +void wxTreeListCtrl::CalculateAndSetHeaderHeight() +{ + if (m_header_win) { + + // we use 'g' to get the descent, too + int h; +#if wxCHECK_VERSION_FULL(2, 7, 0, 1) +#ifdef __WXMSW__ + h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2; +#else + h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win); +#endif +#else + int w, d; + m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d); + h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT; +#endif + + // only update if changed + if (h != m_headerHeight) { + m_headerHeight = h; + DoHeaderLayout(); + } + } +} + +void wxTreeListCtrl::DoHeaderLayout() +{ + int w, h; + GetClientSize(&w, &h); + if (m_header_win) { + m_header_win->SetSize (0, 0, w, m_headerHeight); + m_header_win->Refresh(); + } + if (m_main_win) { + m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight); + } +} + +void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + DoHeaderLayout(); +} + +size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); } + +unsigned int wxTreeListCtrl::GetIndent() const +{ return m_main_win->GetIndent(); } + +void wxTreeListCtrl::SetIndent(unsigned int indent) +{ m_main_win->SetIndent(indent); } + +unsigned int wxTreeListCtrl::GetLineSpacing() const +{ return m_main_win->GetLineSpacing(); } + +void wxTreeListCtrl::SetLineSpacing(unsigned int spacing) +{ m_main_win->SetLineSpacing(spacing); } + +wxImageList* wxTreeListCtrl::GetImageList() const +{ return m_main_win->GetImageList(); } + +wxImageList* wxTreeListCtrl::GetStateImageList() const +{ return m_main_win->GetStateImageList(); } + +wxImageList* wxTreeListCtrl::GetButtonsImageList() const +{ return m_main_win->GetButtonsImageList(); } + +void wxTreeListCtrl::SetImageList(wxImageList* imageList) +{ m_main_win->SetImageList(imageList); } + +void wxTreeListCtrl::SetStateImageList(wxImageList* imageList) +{ m_main_win->SetStateImageList(imageList); } + +void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList) +{ m_main_win->SetButtonsImageList(imageList); } + +void wxTreeListCtrl::AssignImageList(wxImageList* imageList) +{ m_main_win->AssignImageList(imageList); } + +void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList) +{ m_main_win->AssignStateImageList(imageList); } + +void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList) +{ m_main_win->AssignButtonsImageList(imageList); } + +wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const +{ return m_main_win->GetItemText (item, column); } + +int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column, + wxTreeItemIcon which) const +{ return m_main_win->GetItemImage(item, column, which); } + +wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const +{ return m_main_win->GetItemData(item); } + +bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const +{ return m_main_win->GetItemBold(item); } + +wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const +{ return m_main_win->GetItemTextColour(item); } + +wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) + const +{ return m_main_win->GetItemBackgroundColour(item); } + +wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const +{ return m_main_win->GetItemFont(item); } + + +void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, + const wxString& text) +{ m_main_win->SetItemText (item, column, text); } + +void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, + int column, + int image, + wxTreeItemIcon which) +{ m_main_win->SetItemImage(item, column, image, which); } + +void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, + wxTreeItemData* data) +{ m_main_win->SetItemData(item, data); } + +void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) +{ m_main_win->SetItemHasChildren(item, has); } + +void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, bool bold) +{ m_main_win->SetItemBold(item, bold); } + +void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, + const wxColour& colour) +{ m_main_win->SetItemTextColour(item, colour); } + +void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, + const wxColour& colour) +{ m_main_win->SetItemBackgroundColour(item, colour); } + +void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, + const wxFont& font) +{ m_main_win->SetItemFont(item, font); } + +bool wxTreeListCtrl::SetFont(const wxFont& font) +{ + if (m_header_win) { + m_header_win->SetFont(font); + CalculateAndSetHeaderHeight(); + m_header_win->Refresh(); + } + if (m_main_win) { + return m_main_win->SetFont(font); + }else{ + return false; + } +} + +void wxTreeListCtrl::SetWindowStyle(const long style) +{ + if(m_main_win) + m_main_win->SetWindowStyle(style); + m_windowStyle = style; + // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win +} + +long wxTreeListCtrl::GetWindowStyle() const +{ + long style = m_windowStyle; + if(m_main_win) + style |= m_main_win->GetWindowStyle(); + return style; +} + +bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const +{ return m_main_win->IsVisible(item, fullRow, within); } + +bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const +{ return m_main_win->HasChildren(item); } + +bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const +{ return m_main_win->IsExpanded(item); } + +bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const +{ return m_main_win->IsSelected(item); } + +bool wxTreeListCtrl::IsBold(const wxTreeItemId& item) const +{ return m_main_win->IsBold(item); } + +size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec) +{ return m_main_win->GetChildrenCount(item, rec); } + +wxTreeItemId wxTreeListCtrl::GetRootItem() const +{ return m_main_win->GetRootItem(); } + +wxTreeItemId wxTreeListCtrl::GetSelection() const +{ return m_main_win->GetSelection(); } + +size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const +{ return m_main_win->GetSelections(arr); } + +wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const +{ return m_main_win->GetItemParent(item); } + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item, + long& cookie) const +#else +wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +#endif +{ return m_main_win->GetFirstChild(item, cookie); } + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item, + long& cookie) const +#else +wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +#endif +{ return m_main_win->GetNextChild(item, cookie); } + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item, + long& cookie) const +#else +wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +#endif +{ return m_main_win->GetPrevChild(item, cookie); } + +#if !wxCHECK_VERSION(2, 5, 0) +wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item, + long& cookie) const +#else +wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +#endif +{ return m_main_win->GetLastChild(item, cookie); } + + +wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const +{ return m_main_win->GetNextSibling(item); } + +wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const +{ return m_main_win->GetPrevSibling(item); } + +wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const +{ return m_main_win->GetNext(item, true); } + +wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const +{ return m_main_win->GetPrev(item, true); } + +wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const +{ return m_main_win->GetFirstExpandedItem(); } + +wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const +{ return m_main_win->GetNextExpanded(item); } + +wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const +{ return m_main_win->GetPrevExpanded(item); } + +wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const +{ return GetFirstVisible(fullRow); } +wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const +{ return m_main_win->GetFirstVisible(fullRow, within); } + +wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const +{ return m_main_win->GetLastVisible(fullRow, within); } + +wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const +{ return m_main_win->GetNextVisible(item, fullRow, within); } + +wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const +{ return m_main_win->GetPrevVisible(item, fullRow, within); } + +wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image, + int selectedImage, wxTreeItemData* data) +{ return m_main_win->AddRoot (text, image, selectedImage, data); } + +wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ return m_main_win->PrependItem(parent, text, image, selectedImage, data); } + +wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent, + const wxTreeItemId& previous, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ + return m_main_win->InsertItem(parent, previous, text, image, + selectedImage, data); +} + +wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent, + size_t index, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ + return m_main_win->InsertItem(parent, index, text, image, + selectedImage, data); +} + +wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent, + const wxString& text, int image, + int selectedImage, + wxTreeItemData* data) +{ return m_main_win->AppendItem(parent, text, image, selectedImage, data); } + +void wxTreeListCtrl::Delete(const wxTreeItemId& item) +{ m_main_win->Delete(item); } + +void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item) +{ m_main_win->DeleteChildren(item); } + +void wxTreeListCtrl::DeleteRoot() +{ m_main_win->DeleteRoot(); } + +void wxTreeListCtrl::Expand(const wxTreeItemId& item) +{ m_main_win->Expand(item); } + +void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item) +{ m_main_win->ExpandAll(item); } + +void wxTreeListCtrl::Collapse(const wxTreeItemId& item) +{ m_main_win->Collapse(item); } + +void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item) +{ m_main_win->CollapseAndReset(item); } + +void wxTreeListCtrl::Toggle(const wxTreeItemId& item) +{ m_main_win->Toggle(item); } + +void wxTreeListCtrl::Unselect() +{ m_main_win->Unselect(); } + +void wxTreeListCtrl::UnselectAll() +{ m_main_win->UnselectAll(); } + +bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last, + bool unselect_others) +{ return m_main_win->SelectItem (item, last, unselect_others); } + +void wxTreeListCtrl::SelectAll() +{ m_main_win->SelectAll(); } + +void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item) +{ m_main_win->EnsureVisible(item); } + +void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item) +{ m_main_win->ScrollTo(item); } + +wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column) +{ + wxPoint p = m_main_win->ScreenToClient (ClientToScreen (pos)); + return m_main_win->HitTest (p, flags, column); +} + +bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect, + bool textOnly) const +{ return m_main_win->GetBoundingRect(item, rect, textOnly); } + +void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column) +{ m_main_win->EditLabel (item, column); } + +int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, + const wxTreeItemId& item2) +{ + // do the comparison here, and not delegate to m_main_win, in order + // to let the user override it + //return m_main_win->OnCompareItems(item1, item2); + return wxStrcmp(GetItemText(item1), GetItemText(item2)); +} + +void wxTreeListCtrl::SortChildren(const wxTreeItemId& item) +{ m_main_win->SortChildren(item); } + +wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, const wxString& str, int mode) +{ return m_main_win->FindItem (item, str, mode); } + +void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item) +{ m_main_win->SetDragItem (item); } + +bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour) +{ + if (!m_main_win) return false; + return m_main_win->SetBackgroundColour(colour); +} + +bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour) +{ + if (!m_main_win) return false; + return m_main_win->SetForegroundColour(colour); +} + +int wxTreeListCtrl::GetColumnCount() const +{ return m_main_win->GetColumnCount(); } + +void wxTreeListCtrl::SetColumnWidth(int column, int width) +{ + m_header_win->SetColumnWidth (column, width); + m_header_win->Refresh(); +} + +int wxTreeListCtrl::GetColumnWidth(int column) const +{ return m_header_win->GetColumnWidth(column); } + +void wxTreeListCtrl::SetMainColumn(int column) +{ m_main_win->SetMainColumn(column); } + +int wxTreeListCtrl::GetMainColumn() const +{ return m_main_win->GetMainColumn(); } + +void wxTreeListCtrl::SetColumnText(int column, const wxString& text) +{ + m_header_win->SetColumnText (column, text); + m_header_win->Refresh(); +} + +wxString wxTreeListCtrl::GetColumnText(int column) const +{ return m_header_win->GetColumnText(column); } + +void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo) +{ + m_header_win->AddColumn (colInfo); + DoHeaderLayout(); +} + +void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo) +{ + m_header_win->InsertColumn (before, colInfo); + m_header_win->Refresh(); +} + +void wxTreeListCtrl::RemoveColumn(int column) +{ + m_header_win->RemoveColumn (column); + m_header_win->Refresh(); +} + +void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo) +{ + m_header_win->SetColumn (column, colInfo); + m_header_win->Refresh(); +} + +const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const +{ return m_header_win->GetColumn(column); } + +wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) +{ return m_header_win->GetColumn(column); } + +void wxTreeListCtrl::SetColumnImage(int column, int image) +{ + m_header_win->SetColumn (column, GetColumn(column).SetImage(image)); + m_header_win->Refresh(); +} + +int wxTreeListCtrl::GetColumnImage(int column) const +{ + return m_header_win->GetColumn(column).GetImage(); +} + +void wxTreeListCtrl::SetColumnEditable(int column, bool shown) +{ + m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown)); +} + +void wxTreeListCtrl::SetColumnShown(int column, bool shown) +{ + wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") ); + m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown)); + m_header_win->Refresh(); +} + +bool wxTreeListCtrl::IsColumnEditable(int column) const +{ + return m_header_win->GetColumn(column).IsEditable(); +} + +bool wxTreeListCtrl::IsColumnShown(int column) const +{ + return m_header_win->GetColumn(column).IsShown(); +} + +void wxTreeListCtrl::SetColumnAlignment (int column, int flag) +{ + m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag)); + m_header_win->Refresh(); +} + +int wxTreeListCtrl::GetColumnAlignment(int column) const +{ + return m_header_win->GetColumn(column).GetAlignment(); +} + +void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect) +{ + m_main_win->Refresh (erase, rect); + m_header_win->Refresh (erase, rect); +} + +void wxTreeListCtrl::SetFocus() +{ m_main_win->SetFocus(); } + +wxSize wxTreeListCtrl::DoGetBestSize() const +{ + // something is better than nothing... + return wxSize (200,200); // but it should be specified values! FIXME +} + +wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const +{ + return wxEmptyString; +} + +void wxTreeListCtrl::SetToolTip(const wxString& tip) { + m_header_win->SetToolTip(tip); + m_main_win->SetToolTip(tip); +} +void wxTreeListCtrl::SetToolTip(wxToolTip *tip) { + m_header_win->SetToolTip(tip); + m_main_win->SetToolTip(tip); +} + +void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) { + m_main_win->SetItemToolTip(item, tip); +} diff --git a/src/xvaga01/treelistctrl.h b/src/xvaga01/treelistctrl.h new file mode 100644 index 000000000..4962a5387 --- /dev/null +++ b/src/xvaga01/treelistctrl.h @@ -0,0 +1,552 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: treelistctrl.h +// Purpose: wxTreeListCtrl class +// Author: Robert Roebling +// Maintainer: Otto Wyss +// Created: 01/02/97 +// RCS-ID: $Id: treelistctrl.h,v 1.1.2.1 2011-04-06 14:09:31 guy Exp $ +// Copyright: (c) 2004 Robert Roebling, Julian Smart, Alberto Griggio, +// Vadim Zeitlin, Otto Wyss +// Licence: wxWindows +///////////////////////////////////////////////////////////////////////////// + + +#ifndef TREELISTCTRL_H +#define TREELISTCTRL_H + +#if defined(__GNUG__) && !defined(__APPLE__) + #pragma interface "treelistctrl.h" +#endif +#include +#include // for wxListEvent + +class WXDLLEXPORT wxTreeListItem; +class WXDLLEXPORT wxTreeListHeaderWindow; +class WXDLLEXPORT wxTreeListMainWindow; + +#define wxTR_COLUMN_LINES 0x1000 // put border around items +#define wxTR_VIRTUAL 0x4000 // The application provides items text on demand. + +// Using this typedef removes an ambiguity when calling Remove() +#ifdef __WXMSW__ +#if !wxCHECK_VERSION(2, 5, 0) +typedef long wxTreeItemIdValue; +#else +typedef void *wxTreeItemIdValue; +#endif +#endif + +//----------------------------------------------------------------------------- +// wxTreeListColumnAttrs +//----------------------------------------------------------------------------- + +enum { + DEFAULT_COL_WIDTH = 100 +}; + +class /*WXDLLEXPORT*/ wxTreeListColumnInfo: public wxObject { + +public: + wxTreeListColumnInfo (const wxString &text = wxEmptyString, + int width = DEFAULT_COL_WIDTH, + int flag = wxALIGN_LEFT, + int image = -1, + bool shown = true, + bool edit = false) { + m_text = text; + m_width = width; + m_flag = flag; + m_image = image; + m_selected_image = -1; + m_shown = shown; + m_edit = edit; + } + + wxTreeListColumnInfo (const wxTreeListColumnInfo& other) { + m_text = other.m_text; + m_width = other.m_width; + m_flag = other.m_flag; + m_image = other.m_image; + m_selected_image = other.m_selected_image; + m_shown = other.m_shown; + m_edit = other.m_edit; + } + + ~wxTreeListColumnInfo() {} + + // get/set + wxString GetText() const { return m_text; } + wxTreeListColumnInfo& SetText (const wxString& text) { m_text = text; return *this; } + + int GetWidth() const { return m_width; } + wxTreeListColumnInfo& SetWidth (int width) { m_width = width; return *this; } + + int GetAlignment() const { return m_flag; } + wxTreeListColumnInfo& SetAlignment (int flag) { m_flag = flag; return *this; } + + int GetImage() const { return m_image; } + wxTreeListColumnInfo& SetImage (int image) { m_image = image; return *this; } + + int GetSelectedImage() const { return m_selected_image; } + wxTreeListColumnInfo& SetSelectedImage (int image) { m_selected_image = image; return *this; } + + bool IsEditable() const { return m_edit; } + wxTreeListColumnInfo& SetEditable (bool edit) + { m_edit = edit; return *this; } + + bool IsShown() const { return m_shown; } + wxTreeListColumnInfo& SetShown(bool shown) { m_shown = shown; return *this; } + +private: + wxString m_text; + int m_width; + int m_flag; + int m_image; + int m_selected_image; + bool m_shown; + bool m_edit; +}; + +//---------------------------------------------------------------------------- +// wxTreeListCtrl - the multicolumn tree control +//---------------------------------------------------------------------------- + +// modes for navigation +const int wxTL_MODE_NAV_FULLTREE = 0x0000; // default +const int wxTL_MODE_NAV_EXPANDED = 0x0001; +const int wxTL_MODE_NAV_VISIBLE = 0x0002; +const int wxTL_MODE_NAV_LEVEL = 0x0004; + +// modes for FindItem +const int wxTL_MODE_FIND_EXACT = 0x0000; // default +const int wxTL_MODE_FIND_PARTIAL = 0x0010; +const int wxTL_MODE_FIND_NOCASE = 0x0020; + +// additional flag for HitTest +const int wxTREE_HITTEST_ONITEMCOLUMN = 0x2000; +extern /*WXDLLEXPORT*/ const wxChar* wxTreeListCtrlNameStr; + + +class /*WXDLLEXPORT*/ wxTreeListCtrl : public wxControl +{ +friend class wxTreeListHeaderWindow; +friend class wxTreeListMainWindow; +friend class wxTreeListItem; +public: + // creation + // -------- + wxTreeListCtrl() + : m_header_win(0), m_main_win(0), m_headerHeight(0) + {} + + wxTreeListCtrl(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxTreeListCtrlNameStr ) + : m_header_win(0), m_main_win(0), m_headerHeight(0) + { + Create(parent, id, pos, size, style, validator, name); + } + + virtual ~wxTreeListCtrl() {} + + bool Create(wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxTR_DEFAULT_STYLE, + const wxValidator &validator = wxDefaultValidator, + const wxString& name = wxTreeListCtrlNameStr ); + + void Refresh(bool erase=TRUE, const wxRect* rect=NULL); + void SetFocus(); + // accessors + // --------- + + // get the total number of items in the control + size_t GetCount() const; + + // indent is the number of pixels the children are indented relative to + // the parents position. SetIndent() also redraws the control + // immediately. + unsigned int GetIndent() const; + void SetIndent(unsigned int indent); + + // line spacing is the space above and below the text on each line + unsigned int GetLineSpacing() const; + void SetLineSpacing(unsigned int spacing); + + // image list: these functions allow to associate an image list with + // the control and retrieve it. Note that when assigned with + // SetImageList, the control does _not_ delete + // the associated image list when it's deleted in order to allow image + // lists to be shared between different controls. If you use + // AssignImageList, the control _does_ delete the image list. + // + // The normal image list is for the icons which correspond to the + // normal tree item state (whether it is selected or not). + // Additionally, the application might choose to show a state icon + // which corresponds to an app-defined item state (for example, + // checked/unchecked) which are taken from the state image list. + wxImageList *GetImageList() const; + wxImageList *GetStateImageList() const; + wxImageList *GetButtonsImageList() const; + + void SetImageList(wxImageList *imageList); + void SetStateImageList(wxImageList *imageList); + void SetButtonsImageList(wxImageList *imageList); + void AssignImageList(wxImageList *imageList); + void AssignStateImageList(wxImageList *imageList); + void AssignButtonsImageList(wxImageList *imageList); + + void SetToolTip(const wxString& tip); + void SetToolTip (wxToolTip *tip); + void SetItemToolTip(const wxTreeItemId& item, const wxString &tip); + + // Functions to work with columns + + // adds a column + void AddColumn (const wxString& text, + int width = DEFAULT_COL_WIDTH, + int flag = wxALIGN_LEFT, + int image = -1, + bool shown = true, + bool edit = false) { + AddColumn (wxTreeListColumnInfo (text, width, flag, image, shown, edit)); + } + void AddColumn (const wxTreeListColumnInfo& colInfo); + + // inserts a column before the given one + void InsertColumn (int before, + const wxString& text, + int width = DEFAULT_COL_WIDTH, + int flag = wxALIGN_LEFT, + int image = -1, + bool shown = true, + bool edit = false) { + InsertColumn (before, + wxTreeListColumnInfo (text, width, flag, image, shown, edit)); + } + void InsertColumn (int before, const wxTreeListColumnInfo& colInfo); + + // deletes the given column - does not delete the corresponding column + void RemoveColumn (int column); + + // returns the number of columns in the ctrl + int GetColumnCount() const; + + // tells which column is the "main" one, i.e. the "threaded" one + void SetMainColumn (int column); + int GetMainColumn() const; + + void SetColumn (int column, const wxTreeListColumnInfo& colInfo); + wxTreeListColumnInfo& GetColumn (int column); + const wxTreeListColumnInfo& GetColumn (int column) const; + + void SetColumnText (int column, const wxString& text); + wxString GetColumnText (int column) const; + + void SetColumnWidth (int column, int width); + int GetColumnWidth (int column) const; + + void SetColumnAlignment (int column, int flag); + int GetColumnAlignment (int column) const; + + void SetColumnImage (int column, int image); + int GetColumnImage (int column) const; + + void SetColumnShown (int column, bool shown = true); + bool IsColumnShown (int column) const; + + void SetColumnEditable (int column, bool edit = true); + bool IsColumnEditable (int column) const; + + // Functions to work with items. + + // accessors + // --------- + + // retrieve item's label (of the main column) + wxString GetItemText (const wxTreeItemId& item) const + { return GetItemText (item, GetMainColumn()); } + // retrieves item's label of the given column + wxString GetItemText (const wxTreeItemId& item, int column) const; + + // get one of the images associated with the item (normal by default) + int GetItemImage (const wxTreeItemId& item, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return GetItemImage (item, GetMainColumn(), which); } + int GetItemImage (const wxTreeItemId& item, int column, + wxTreeItemIcon which = wxTreeItemIcon_Normal) const; + + // get the data associated with the item + wxTreeItemData *GetItemData (const wxTreeItemId& item) const; + + bool GetItemBold (const wxTreeItemId& item) const; + wxColour GetItemTextColour (const wxTreeItemId& item) const; + wxColour GetItemBackgroundColour (const wxTreeItemId& item) const; + wxFont GetItemFont (const wxTreeItemId& item) const; + + // modifiers + + // set item's label + void SetItemText (const wxTreeItemId& item, const wxString& text) + { SetItemText (item, GetMainColumn(), text); } + void SetItemText (const wxTreeItemId& item, int column, const wxString& text); + + // get one of the images associated with the item (normal by default) + void SetItemImage (const wxTreeItemId& item, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal) + { SetItemImage (item, GetMainColumn(), image, which); } + // the which parameter is ignored for all columns but the main one + void SetItemImage (const wxTreeItemId& item, int column, int image, + wxTreeItemIcon which = wxTreeItemIcon_Normal); + + // associate some data with the item + void SetItemData (const wxTreeItemId& item, wxTreeItemData *data); + + // force appearance of [+] button near the item. This is useful to + // allow the user to expand the items which don't have any children now + // - but instead add them only when needed, thus minimizing memory + // usage and loading time. + void SetItemHasChildren(const wxTreeItemId& item, bool has = true); + + // the item will be shown in bold + void SetItemBold (const wxTreeItemId& item, bool bold = true); + + // set the item's text colour + void SetItemTextColour (const wxTreeItemId& item, const wxColour& colour); + + // set the item's background colour + void SetItemBackgroundColour (const wxTreeItemId& item, const wxColour& colour); + + // set the item's font (should be of the same height for all items) + void SetItemFont (const wxTreeItemId& item, const wxFont& font); + + // set the window font + virtual bool SetFont ( const wxFont &font ); + + // set the styles. + void SetWindowStyle (const long styles); + long GetWindowStyle() const; + long GetWindowStyleFlag () const { return GetWindowStyle(); } + + // item status inquiries + // --------------------- + + // is the item visible (it might be outside the view or not expanded)? + bool IsVisible (const wxTreeItemId& item, bool fullRow = false, bool within = true) const; + // does the item has any children? + bool HasChildren (const wxTreeItemId& item) const; + // is the item expanded (only makes sense if HasChildren())? + bool IsExpanded (const wxTreeItemId& item) const; + // is this item currently selected (the same as has focus)? + bool IsSelected (const wxTreeItemId& item) const; + // is item text in bold font? + bool IsBold (const wxTreeItemId& item) const; + // does the layout include space for a button? + + // number of children + // ------------------ + + // if 'recursively' is FALSE, only immediate children count, otherwise + // the returned number is the number of all items in this branch + size_t GetChildrenCount (const wxTreeItemId& item, bool recursively = true); + + // navigation + // ---------- + + // wxTreeItemId.IsOk() will return FALSE if there is no such item + + // get the root tree item + wxTreeItemId GetRootItem() const; + + // get the item currently selected (may return NULL if no selection) + wxTreeItemId GetSelection() const; + + // get the items currently selected, return the number of such item + size_t GetSelections (wxArrayTreeItemIds&) const; + + // get the parent of this item (may return NULL if root) + wxTreeItemId GetItemParent (const wxTreeItemId& item) const; + + // for this enumeration function you must pass in a "cookie" parameter + // which is opaque for the application but is necessary for the library + // to make these functions reentrant (i.e. allow more than one + // enumeration on one and the same object simultaneously). Of course, + // the "cookie" passed to GetFirstChild() and GetNextChild() should be + // the same! + + // get child of this item +#if !wxCHECK_VERSION(2, 5, 0) + wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const; + wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const; +#else + wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; + wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const; +#endif + + // get sibling of this item + wxTreeItemId GetNextSibling(const wxTreeItemId& item) const; + wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const; + + // get item in the full tree (currently only for internal use) + wxTreeItemId GetNext(const wxTreeItemId& item) const; + wxTreeItemId GetPrev(const wxTreeItemId& item) const; + + // get expanded item, see IsExpanded() + wxTreeItemId GetFirstExpandedItem() const; + wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const; + wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const; + + // get visible item, see IsVisible() + wxTreeItemId GetFirstVisibleItem( bool fullRow = false) const; + wxTreeItemId GetFirstVisible( bool fullRow = false, bool within = true) const; + wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow = false, bool within = true) const; + wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow = false, bool within = true) const; + wxTreeItemId GetLastVisible ( bool fullRow = false, bool within = true) const; + + // operations + // ---------- + + // add the root node to the tree + wxTreeItemId AddRoot (const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the first child of the parent + wxTreeItemId PrependItem (const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item after a given one + wxTreeItemId InsertItem (const wxTreeItemId& parent, + const wxTreeItemId& idPrevious, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item before the one with the given index + wxTreeItemId InsertItem (const wxTreeItemId& parent, + size_t index, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // insert a new item in as the last child of the parent + wxTreeItemId AppendItem (const wxTreeItemId& parent, + const wxString& text, + int image = -1, int selectedImage = -1, + wxTreeItemData *data = NULL); + + // delete this item (except root) + children and associated data if any + void Delete (const wxTreeItemId& item); + // delete all children (but don't delete the item itself) + void DeleteChildren (const wxTreeItemId& item); + // delete the root and all its children from the tree + void DeleteRoot(); + + // expand this item + void Expand (const wxTreeItemId& item); + // expand this item and all subitems recursively + void ExpandAll (const wxTreeItemId& item); + // collapse the item without removing its children + void Collapse (const wxTreeItemId& item); + // collapse the item and remove all children + void CollapseAndReset(const wxTreeItemId& item); //? TODO ??? + // toggles the current state + void Toggle (const wxTreeItemId& item); + + // remove the selection from currently selected item (if any) + void Unselect(); + void UnselectAll(); + // select this item - return true if selection was allowed (no veto) + bool SelectItem (const wxTreeItemId& item, + const wxTreeItemId& last = (wxTreeItemId*)NULL, + bool unselect_others = true); + // select all items in the expanded tree + void SelectAll(); + // make sure this item is visible (expanding the parent item and/or + // scrolling to this item if necessary) + void EnsureVisible (const wxTreeItemId& item); + // scroll to this item (but don't expand its parent) + void ScrollTo (const wxTreeItemId& item); + + // The first function is more portable (because easier to implement + // on other platforms), but the second one returns some extra info. + wxTreeItemId HitTest (const wxPoint& point) + { int flags; int column; return HitTest (point, flags, column); } + wxTreeItemId HitTest (const wxPoint& point, int& flags) + { int column; return HitTest (point, flags, column); } + wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column); + + // get the bounding rectangle of the item (or of its label only) + bool GetBoundingRect (const wxTreeItemId& item, wxRect& rect, + bool textOnly = false) const; + + // Start editing the item label: this (temporarily) replaces the item + // with a one line edit control. The item will be selected if it hadn't + // been before. + void EditLabel (const wxTreeItemId& item) + { EditLabel (item, GetMainColumn()); } + // edit item's label of the given column + void EditLabel (const wxTreeItemId& item, int column); + + // virtual mode + virtual wxString OnGetItemText( wxTreeItemData* item, long column ) const; + + // sorting + // this function is called to compare 2 items and should return -1, 0 + // or +1 if the first item is less than, equal to or greater than the + // second one. The base class version performs alphabetic comparaison + // of item labels (GetText) + virtual int OnCompareItems (const wxTreeItemId& item1, const wxTreeItemId& item2); + // sort the children of this item using OnCompareItems + // NB: this function is not reentrant and not MT-safe (FIXME)! + void SortChildren(const wxTreeItemId& item); + + // searching + wxTreeItemId FindItem (const wxTreeItemId& item, const wxString& str, int mode = 0); + + // overridden base class virtuals + virtual bool SetBackgroundColour (const wxColour& colour); + virtual bool SetForegroundColour (const wxColour& colour); + + // drop over item + void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL); + + + virtual wxSize DoGetBestSize() const; + +protected: + // header window, responsible for column visualization and manipulation + wxTreeListHeaderWindow* GetHeaderWindow() const + { return m_header_win; } + wxTreeListHeaderWindow* m_header_win; // future cleanup: make private or remove GetHeaderWindow() + + // main window, the "true" tree ctrl + wxTreeListMainWindow* GetMainWindow() const + { return m_main_win; } + wxTreeListMainWindow* m_main_win; // future cleanup: make private or remove GetMainWindow() + + int GetHeaderHeight() const { return m_headerHeight; } + + void CalculateAndSetHeaderHeight(); + void DoHeaderLayout(); + void OnSize(wxSizeEvent& event); + +private: + int m_headerHeight; + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxTreeListCtrl) +}; + +#endif // TREELISTCTRL_H + diff --git a/src/xvaga01/wxinc.h b/src/xvaga01/wxinc.h new file mode 100644 index 000000000..c0fd60d92 --- /dev/null +++ b/src/xvaga01/wxinc.h @@ -0,0 +1,23 @@ +// Evito di mettere nei settaggi di tutti i progetti questa sequela di #define +#ifndef __WXINC_H__ +#define __WXINC_H__ + +#ifdef WIN32 +#define __WINDOWS__ +#define __WXMSW__ +#define __WIN95__ +#define __WIN32__ +#define WINVER 0x0500 +#define STRICT +#define WXUSINGDLL 1 +#include +#else +#define _FILE_OFFSET_BITS 64 +#define _LARGE_FILES +#define __WXGTK__ +#define GTK_NO_CHECK_CASTS +#define _IODBC +#include +#endif + +#endif diff --git a/src/xvaga01/xvaga.cpp b/src/xvaga01/xvaga.cpp new file mode 100644 index 000000000..75a7554ee --- /dev/null +++ b/src/xvaga01/xvaga.cpp @@ -0,0 +1,5041 @@ +#include "wxinc.h" + +#include "xvt.h" +#include "statbar.h" + +#include "agasys.h" +#include "fstrcmp.h" +#include "matche.h" +#include "xvtart.h" +#include "xvtwin.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +extern "C" +{ +#include "b64/cdecode.h" +#include "b64/cencode.h" +} + + +#include + +#if wxCHECK_VERSION(2,9,0) +#include +#else +#include +#endif + + +#ifdef __WXMSW__ +#include "oswin32.h" +#include "XFont.h" +#else +#include +#include +#include "oslinux.h" +#include +#endif + +#define XVT_ASSERT(test) _AssertBox((test), __FUNCTION__, __FILE__, __LINE__) + +wxWindow* _mouse_trapper = NULL; +RCT _startup_rect = { 0,0,0,0 }; +long _startup_style = 0; +wxString _startup_dir; +wxString _strDefaultStatbarText; +wxString _appl_name; +wxString _appl_version; +BOOLEAN _appl_already_running; +wxLocale* _locale = NULL; + +static XVT_ERRMSG_HANDLER _error_handler = NULL; +static int __oem = 0; + +const wxString& _GetAppTitle() +{ + if (_appl_name.IsEmpty()) + { + const wxFileName fn = __argv[0]; + _appl_name << "CAMPO: " << fn.GetName(); + } + return _appl_name; +} + +void _AssertBox(bool test, const char* func, const char* file, int line) +{ + if (!test) + { + bool display = (_error_handler == NULL) || (_error_handler(SEV_FATAL, NULL) == FALSE); + if (display) + { + wxString strMessage; + strMessage.Printf("Sorry, the application passed some invalid parameters to\n" + "function %s in file %s at line %d.", func, file, line); + xvt_dm_post_error(strMessage); + } + } +} + +/////////////////////////////////////////////////////////// +// XVT +/////////////////////////////////////////////////////////// + +void xvt_app_allow_quit(void) +{ + wxTheApp->ExitMainLoop(); // Già lo fa la destroy +} + +XVTDLL void xvt_app_pre_create(void) +{ + DIRECTORY dir; + xvt_fsys_get_default_dir(&dir); // Init Startup Directory + wxString strResPath = dir.path; strResPath += "/res"; + + _locale = new wxLocale(wxLANGUAGE_DEFAULT); // wxLANGUAGE_ITALIAN + _locale->AddCatalogLookupPathPrefix(strResPath); + _locale->AddCatalog("wxstd", wxLanguage(_locale->GetLanguage()), NULL); + + ::wxInitAllImageHandlers(); + xvtart_Init(); + +#ifdef __WXMSW__ + if (::wxDisplayDepth() >= 32 && wxTheApp->GetComCtl32Version() >= 600) + wxSystemOptions::SetOption(wxT("msw.remap"), 2); + else + wxSystemOptions::SetOption(wxT("msw.remap"), 0); +#endif +} + +void xvt_app_create(int WXUNUSED(argc), char** WXUNUSED(argv), unsigned long WXUNUSED(flags), + EVENT_HANDLER eh, XVT_CONFIG* config) +{ + _task_win_handler = eh; + _appl_name = config->appl_name; + + const wxString title = config->taskwin_title; + + wxPoint pos = wxDefaultPosition; + wxSize size = wxDefaultSize; + long style = wxDEFAULT_FRAME_STYLE; + + wxWindow* pParent = NULL; + +#ifdef __WXMSW__ + HWND hwndParent = (HWND)OsWin32_FindMenuContainer(); + if (hwndParent != NULL) + { + pParent = new wxWindow; + pParent->AssociateHandle(hwndParent); + const wxSize szWin = pParent->GetSize(); + const wxSize szCli = pParent->GetClientSize(); + xvt_rect_set(&_startup_rect, 0, 0, szWin.x, szWin.y); + style = wxSYSTEM_MENU; // Lo stile si riduce al minimo: niente cornici + if ((szWin.y - szCli.y) > 2) // Sposto la finestra in modo da coprire il menu del padre + _startup_rect.top -= xvt_vobj_get_attr(NULL_WIN, ATTR_MENU_HEIGHT); + } + else + { + char xmax[50]; + + xvt_sys_get_profile_string(xvt_fsys_get_campo_ini(), "Main", "MaxDim", "MAX", xmax, sizeof(xmax)); + + if (strcmp(xmax, "MAX") != 0) + { + char * ymax = strchr(xmax, 'x'); + + if (ymax == NULL) + ymax = strchr(xmax, 'X'); + if (ymax != NULL) + { + *ymax++ = '\0'; + + const wxRect rect = wxGetClientDisplayRect(); + int x = atoi(xmax); + int y = atoi(ymax); + + if (x >= 1024 && y >= 768) + { + pos = rect.GetPosition(); + size = rect.GetSize(); + + pos.x += (size.x - x) / 2; + pos.y += (size.y - y) / 2; + size.x = x; + size.y = y; + } + else + { + pos.x = 0; + pos.y = 0; + size.x = 0; + size.y = 0; + } + } + } + } +#endif + + if (_startup_rect.right > _startup_rect.left) + { + pos.x = _startup_rect.left; + pos.y = _startup_rect.top; + size.x = _startup_rect.right - _startup_rect.left; + size.y = _startup_rect.bottom - _startup_rect.top; + } + else + { +#ifdef __WXMSW__ + if (size.x <= 0 || size.y <= 0) + style |= wxMAXIMIZE; + else + style &= ~wxMAXIMIZE; +#else + style &= ~wxMAXIMIZE; + + const wxRect rect = wxGetClientDisplayRect(); + + pos = rect.GetPosition(); + size = rect.GetSize(); +#endif + } + + if (_startup_style & WSF_NO_TASKBAR) + style |= wxFRAME_NO_TASKBAR; + + _task_win = new TTaskWin(ICON_RSRC, title, pos, size, style); + _task_win->SetBackgroundStyle(wxBG_STYLE_CUSTOM); // Lo sfondo viene disegnato nella OnPaint + _nice_windows.Put((WINDOW)_task_win, _task_win); + + if (pParent != NULL) + { + _task_win->Reparent(pParent); + pParent->DissociateHandle(); + pParent = NULL; + } + + wxMenu* Menus[4] = { NULL }; + wxString Title[4]; + Title[0] = "&File"; + Menus[0] = new wxMenu; + Menus[0]->Append(M_FILE_PG_SETUP, "&Impostazione Stampante..."); + Menus[0]->Append(M_FILE_PRINT, "&Stampa"); + Menus[0]->Append(M_FILE_PREVIEW, "&Anteprima"); + Menus[0]->AppendSeparator(); + Menus[0]->Append(M_FILE_QUIT, "&Fine"); + Title[1] = "&Modifica"; + Menus[1] = new wxMenu; + Menus[1]->Append(M_EDIT_CUT, "&Taglia\tCtrl+X"); + Menus[1]->Append(M_EDIT_COPY, "&Copia\tCtrl+C"); + Menus[1]->Append(M_EDIT_PASTE, "&Incolla\tCtrl+V"); + Menus[1]->Append(M_EDIT_CLEAR, "&Elimina\tCanc"); + Title[2] = "&?"; + Menus[2] = new wxMenu; + Menus[2]->Append(M_HELP_CONTENTS, "&Sommario"); + Menus[2]->Append(M_HELP_ONCONTEXT, "&Aiuto contestuale"); + Menus[2]->AppendSeparator(); + Menus[2]->Append(M_HELP_VERSION, "Storia delle &modifiche"); + Menus[2]->Append(M_FILE_ABOUT, "&Informazioni"); + + wxMenuBar* pMenubar = new wxMenuBar(3, Menus, Title); + _task_win->SetMenuBar(pMenubar); + + if (style & wxMAXIMIZE) + _task_win->Maximize(); + _task_win->Show(); + _task_win->Raise(); + + wxApp* a = wxTheApp; + a->SetTopWindow(_task_win); + + EVENT e; memset(&e, 0, sizeof(e)); + e.type = E_CREATE; + long ret = _task_win_handler((WINDOW)_task_win, &e); + if (ret != 0) + { + // Simula main loop + xvt_app_process_pending_events(); + } + a->ExitMainLoop(); // Non entrare nel main loop di wxWidgets +} + +void xvt_app_destroy(void) +{ + wxTheApp->ExitMainLoop(); + if (_task_win != NULL) + _task_win->Destroy(); + + xvt_dm_speech_enable(0x00); + + xvt_sign_stop(); + + if (_locale != NULL) + { + delete _locale; + _locale = NULL; + } + +#ifdef __WXMSW__ + // Evita noiosa finestra d'errore che succede solo a PressColor + ::SetErrorMode(SEM_NOGPFAULTERRORBOX); +#endif +} + +DRAW_CTOOLS* xvt_app_get_default_ctools(DRAW_CTOOLS *ct) +{ + XVT_ASSERT(ct != NULL); + TDC dc(NULL); + memcpy(ct, &dc._dct, sizeof(DRAW_CTOOLS)); + return ct; +} + +void xvt_app_process_pending_events(void) +{ + wxApp* a = wxTheApp; // Memorizzo il risultato di wxGetInstance + if (a != nullptr) // Puo' succedere! + { + while (a->Pending()) + a->Dispatch(); + a->ProcessIdle(); // Necessario per wxAUI + a->Yield(true); // Non so se serva veramente + } +} + +/////////////////////////////////////////////////////////// +// Clipboard functions +/////////////////////////////////////////////////////////// + +static DATA_PTR ptrClipboardData = NULL; + +char* xvt_cb_alloc_data(long size) +{ + xvt_cb_free_data(); + if (size > 0) + ptrClipboardData = xvt_mem_zalloc(size+1); + return ptrClipboardData; +} + +BOOLEAN xvt_cb_close(void) +{ + wxTheClipboard->Close(); + wxTheClipboard->Flush(); + return TRUE; +} + +void xvt_cb_free_data(void) +{ + if (ptrClipboardData != NULL) + { + xvt_mem_free(ptrClipboardData); + ptrClipboardData = NULL; + } +} + +char* xvt_cb_get_data(CB_FORMAT cbfmt, char *name, long *sizep) +{ + if (xvt_cb_has_format(cbfmt, name)) + { + wxTextDataObject data; + wxTheClipboard->GetData(data); + *sizep = data.GetDataSize(); + if (*sizep > 0) + { + xvt_cb_alloc_data(*sizep); + memcpy(ptrClipboardData, data.GetText(), *sizep); + (*sizep)--; // Elimino lo '/0' finale che non piace a XI + return ptrClipboardData; + } + } + sizep = 0; + return NULL; +} + +BOOLEAN xvt_cb_has_format(CB_FORMAT fmt, char* WXUNUSED(name)) +{ + return (fmt == CB_TEXT) && wxTheClipboard->IsSupported(wxDF_TEXT); +} + +BOOLEAN xvt_cb_open(BOOLEAN WXUNUSED(writing)) +{ + return wxTheClipboard->Open(); +} + +BOOLEAN xvt_cb_put_data(CB_FORMAT cbfmt, char* WXUNUSED(name), long WXUNUSED(size), PICTURE WXUNUSED(pic)) +{ + BOOLEAN ok = cbfmt == CB_TEXT && ptrClipboardData != NULL; + if (ok) + wxTheClipboard->SetData(new wxTextDataObject(ptrClipboardData)); + return ok; +} + +/////////////////////////////////////////////////////////// +// Debug functions +/////////////////////////////////////////////////////////// + +void xvt_debug_printf(const char* fmt, ...) +{ +#ifndef NDEBUG + static FILE* f = NULL; + if (f == NULL) + f = fopen("trace.log", "w"); + if (f != NULL) + { + char msg[256]; + va_list argptr; + va_start(argptr,fmt); + vsprintf(msg,fmt,argptr); + va_end(argptr); + fprintf(f, "%s\n", msg); + fflush(f); + } +#endif +} + +/////////////////////////////////////////////////////////// +// Dongle functions +/////////////////////////////////////////////////////////// + +BOOLEAN xvt_dongle_hl_crypt(unsigned short* data) // Array di 4 words (8 bytes) +{ return FALSE; } + +BOOLEAN xvt_dongle_hl_login(unsigned short address, const unsigned char* label, const unsigned char* password) +{ return FALSE; } + +BOOLEAN xvt_dongle_hl_logout() +{ return FALSE; } + +BOOLEAN xvt_dongle_hl_read(unsigned short reg, unsigned short* data) +{ return FALSE; } + +BOOLEAN xvt_dongle_hl_read_block(unsigned char* data) +{ return FALSE; } + +BOOLEAN xvt_dongle_hl_write(unsigned short reg, unsigned short data) +{ return FALSE; } + +BOOLEAN xvt_dongle_sl_crypt(unsigned short* data) +{ return FALSE; } + +BOOLEAN xvt_dongle_sl_login(const unsigned char* label, const unsigned char* password) +{ return FALSE; } + +BOOLEAN xvt_dongle_sl_logout() +{ return FALSE; } + +BOOLEAN xvt_dongle_sl_read_block(unsigned short reg, unsigned short size, unsigned short* data) +{ return FALSE; } + +BOOLEAN xvt_dongle_sl_write_block(unsigned short reg, unsigned short size, const unsigned short* data) +{ return FALSE; } + +/////////////////////////////////////////////////////////// +// Font cache +/////////////////////////////////////////////////////////// + +WX_DECLARE_STRING_HASH_MAP(wxFont*, wxFontHashMap); + +class TFontCache +{ + wxFontHashMap* m_map; + +public: + wxFont& FindOrCreate(int pointSize, int family, int style, int weight, + bool underline, const wxString& face); + void Destroy(); + TFontCache() : m_map(NULL) { } + ~TFontCache() { Destroy(); } + +} XVT_FONT_CACHE; + +void TFontCache::Destroy() +{ + if (m_map) + { + m_map->clear(); +// delete m_map; // NON funziona ma non si capisce perche': PAZIENZA! + m_map = NULL; + } +} + +wxFont& TFontCache::FindOrCreate(int pointSize, int family, int style, int weight, + bool underline, const wxString& face) +{ + if (m_map == NULL) + m_map = new wxFontHashMap; + + wxString key; + key.Printf("%s_%d_%d_%d_%d", face, pointSize, style, weight, underline); + wxFont* pFont = (*m_map)[key]; + if (pFont == NULL) + { + pFont = new wxFont(pointSize, family, style, weight, underline, face); + pFont->SetPointSize(pointSize); // Colpo di classe indispensabile per i PDF :-) + (*m_map)[key] = pFont; + } + return *pFont; +} + + +/////////////////////////////////////////////////////////// +// Image handling +/////////////////////////////////////////////////////////// + +class TXVT_IMAGE : public wxImage +{ + DECLARE_DYNAMIC_CLASS(TXVT_IMAGE); + + int m_nDepth; + bool m_bDirty; + +#ifdef __WXMSW__ + HBITMAP m_bitmap; +#else + wxBitmap* m_bitmap; +#endif + +protected: + void Destroy(); + +public: + const wxImage& Image() const { return *this; } + wxImage& Image() { m_bDirty = true; return *this; } + +#ifdef __WXMSW__ + HBITMAP Bitmap(wxDC& dc); +#else + const wxBitmap& Bitmap(wxDC& dc); +#endif + COLOR GetPixel(int x, int y) const; + void SetPixel(int x, int y, COLOR color); + + TXVT_IMAGE() : m_bitmap(NULL), m_nDepth(0), m_bDirty(false) { } + ~TXVT_IMAGE(); +}; + +IMPLEMENT_DYNAMIC_CLASS(TXVT_IMAGE, wxImage); + +#define CAST_TIMAGE(xvtimg, img) TXVT_IMAGE* img = wxDynamicCast(xvtimg, TXVT_IMAGE); +#define CAST_IMAGE(xvtimg, img) const wxImage* img = wxDynamicCast(xvtimg, wxImage); + +// Chissa' perche' non esiste la GetRGB +COLOR TXVT_IMAGE::GetPixel(int x, int y) const +{ + if (IsTransparent(x, y)) + return XVT_MAKE_COLOR(GetMaskRed(), GetMaskGreen(), GetMaskBlue()); + + const long pos = XYToIndex(x, y) * 3; + unsigned char* data = GetData() + pos; + return XVT_MAKE_COLOR(data[0], data[1], data[2]); +} + +void TXVT_IMAGE::SetPixel(int x, int y, COLOR color) +{ + SetRGB(x, y, XVT_COLOR_GET_RED(color), XVT_COLOR_GET_GREEN(color), XVT_COLOR_GET_BLUE(color)); + m_bDirty = true; +} + +#ifdef __WXMSW__ + +HBITMAP TXVT_IMAGE::Bitmap(wxDC& dc) +{ + if (m_bDirty || m_bitmap == NULL || dc.GetDepth() != m_nDepth) + { + Destroy(); + m_nDepth = dc.GetDepth(); + m_bitmap = OsWin32_CreateBitmap(*this, dc); + m_bDirty = false; + } + return m_bitmap; +} + +#else + +const wxBitmap& TXVT_IMAGE::Bitmap(wxDC& dc) +{ + if (m_bDirty || m_bitmap == NULL || dc.GetDepth() != m_nDepth) + { + Destroy(); + m_nDepth = dc.GetDepth(); + m_bitmap = new wxBitmap(*this, m_nDepth); + m_bDirty = false; + } + return *m_bitmap; +} + +#endif + +void TXVT_IMAGE::Destroy() +{ + if (m_bitmap != NULL) +#ifdef __WXMSW__ + ::DeleteObject(m_bitmap); +#else + delete m_bitmap; +#endif + m_bitmap = NULL; +} + +TXVT_IMAGE::~TXVT_IMAGE() +{ + Destroy(); +} + +/////////////////////////////////////////////////////////// +// Font Handling +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TFontId, wxObject); + +void TFontId::Copy(const TFontId& rFont) +{ + m_strFace = rFont.m_strFace; + m_nSize = rFont.m_nSize; + m_wMask = rFont.m_wMask; + m_win = rFont.m_win; +} + +bool TFontId::IsEqual(const TFontId& rFont) const +{ + if (m_strFace != rFont.m_strFace) + return false; + if (m_nSize != rFont.m_nSize) + return false; + if (m_wMask != rFont.m_wMask) + return false; + return true; +} + +const char* TFontId::FaceName() const +{ + if (m_strFace.IsEmpty()) + return XVT_FFN_COURIER; + return m_strFace; +} + +int TFontId::Family() const +{ + if (m_strFace.IsEmpty() || m_strFace == XVT_FFN_COURIER) + return wxMODERN; + if (m_strFace == XVT_FFN_HELVETICA) + return wxSWISS; + if (m_strFace == XVT_FFN_TIMES) + return wxROMAN; + if (m_strFace == XVT_FFN_FIXED) + return wxMODERN; + if (m_strFace == XVT_FFN_SYSTEM) + return wxDEFAULT; + return wxSWISS; +} + +int TFontId::Style() const +{ + return (m_wMask & XVT_FS_ITALIC) ? wxITALIC : wxNORMAL; +} + +bool TFontId::Underline() const +{ + return (m_wMask & XVT_FS_UNDERLINE) != 0; +} + +int TFontId::Weight() const +{ + return (m_wMask & XVT_FS_BOLD) ? wxBOLD : wxNORMAL; +} + +const wxFont& TFontId::Font(wxDC* dc, WINDOW win) const +{ + int nSize = PointSize(); + if (win == PRINTER_WIN) + { + static wxDC* lastDC = NULL; + static wxSize lastPPI; + static double dPrintScale = 1.0; + const wxSize ppi = dc->GetPPI(); + if (dc != lastDC || ppi != lastPPI) + { +#ifdef __WXMSW__ + const char* const DEFAULT_FONT_NAME = "Courier New"; +#else + const char* const DEFAULT_FONT_NAME = "Courier"; +#endif + const int nTarget10 = 10 * ppi.x; // pixel in 10 pollici in larghezza + const int cpi10 = 10 * 120 / nSize; // caratteri stimati in 10 pollici + const wxString str('M', cpi10); // stringa campione per stimare la larghezza + int nMin = 1, nMax = nSize*16; // Limiti arbitrari + int nBest = 0; + while (nMin <= nMax) + { + const int nFontSize = (nMin+nMax)/2; + + wxFont courier(nFontSize, wxFIXED, wxNORMAL, wxNORMAL, false, DEFAULT_FONT_NAME); + dc->SetFont(courier); + int tw; dc->GetTextExtent(str, &tw, NULL); + if (tw <= nTarget10) + { + nMin = nFontSize+1; + nBest = nFontSize; + if (tw == nTarget10) + break; + } + else + nMax = nFontSize-1; + } + if (nBest == 0) + nBest = nMax; + +#ifdef __WXMSW__ + // Pezza per cercare di ovviare a dimensioni assurde calcolate dai sistemi Win * + // Praticamente succede che il Courier 70 sia piu' piccolo del Curier 60 + // Per cui una volta candidata una dimensione (nBest) tramite le righe precedenti + // cerco il primo font piu' piccolo che non sfondi + bool bPrevGood = true; + for (int i = 15; i > 0; i--) + { + const int nFontSize = nBest-i; + wxFont courier(nFontSize, wxFIXED, wxNORMAL, wxNORMAL, false, DEFAULT_FONT_NAME); + + dc->SetFont(courier); + int tw, th; dc->GetTextExtent(str, &tw, &th); + if (tw > nTarget10 && bPrevGood) + { + nBest = nFontSize-1; + break; + } + bPrevGood = tw <= nTarget10; + } +#endif + + dPrintScale = double(nBest) / double(nSize); +#ifdef LINUX + dPrintScale /= 10.0; // * wxPostScriptDC::GetResolution()) / 72.0); +#endif + lastDC = dc; + lastPPI = ppi; + } + nSize = (int)(nSize * dPrintScale + 0.5); + } + + const wxFont& ff1 = XVT_FONT_CACHE.FindOrCreate(nSize, Family(), Style(), Weight(), Underline(), FaceName()); + if (ff1.GetPointSize() > 0) + return ff1; + + XVT_FONT_CACHE.Destroy(); + const wxFont& ff2 = XVT_FONT_CACHE.FindOrCreate(nSize, Family(), Style(), Weight(), Underline(), FaceName()); + return ff2; +} + +void TFontId::Copy(const wxFont& rFont) +{ + m_strFace = rFont.GetFaceName(); + m_nSize = rFont.GetPointSize(); + m_wMask = XVT_FS_NONE; + if (rFont.GetUnderlined()) + m_wMask |= XVT_FS_UNDERLINE; + if (rFont.GetWeight() >= wxBOLD) + m_wMask |= XVT_FS_BOLD; + if (rFont.GetStyle() == wxITALIC) + m_wMask |= XVT_FS_ITALIC; + m_win = NULL_WIN; +} + +/////////////////////////////////////////////////////////// +// Drawable windows +/////////////////////////////////////////////////////////// + +void xvt_dwin_clear(WINDOW win, COLOR col) +{ + if (win != NULL_WIN && win != PRINTER_WIN) + { + CAST_DC(win, dc); + CAST_COLOR(col, colour); + wxBrush* brush = wxTheBrushList->FindOrCreateBrush(colour, wxSOLID); + dc.SetBackground(*brush); + dc.Clear(); + } +} + +void xvt_dwin_draw_arc(WINDOW win, const RCT* r, int sx, int sy, int ex, int ey) +{ + if (win != NULL_WIN && r != NULL) + { + CAST_DC(win, dc); + const wxRect rect = RCT2Rect(r); + const wxPoint c(rect.x+rect.width/2, rect.y+rect.height/2); + if (abs(rect.width - rect.height) < 2) + dc.DrawArc(sx, sy, ex, ey, c.x, c.y); + else + { + const double pi = acos(-1.0); + double sa = atan2(double(c.y-sy), double(sx-c.x)) * 180 / pi; if (sa < 0) sa += 360; + double ea = atan2(double(c.y-ey), double(ex-c.x)) * 180 / pi; while (ea < sa) ea += 360; + dc.DrawEllipticArc(rect.x, rect.y, rect.width, rect.height, sa, ea); + } + } +} + +void xvt_dwin_draw_checkmark(WINDOW win, const RCT* rctp) +{ + CAST_DC(win, dc); + const wxRect rct = RCT2Rect(rctp); + dc.DrawCheckMark(rct); +} + + +void xvt_dwin_draw_gradient_circular(WINDOW win, const RCT* r, COLOR col1, COLOR col2, const PNT* center) +{ + if (win != NULL_WIN && r != NULL) + { + CAST_DC(win, dc); + const wxRect rect = RCT2Rect(r); + CAST_COLOR(col1, color1); + CAST_COLOR(col2, color2); + + if (center != NULL) + dc.GradientFillConcentric(rect, color1, color2, wxPoint(center->h, center->v)); + else + dc.GradientFillConcentric(rect, color1, color2); + } +} + +void xvt_dwin_draw_gradient_linear(WINDOW win, const RCT* r, COLOR col1, COLOR col2, int angle) +{ + if (win != NULL_WIN && r != NULL) + { + CAST_DC(win, dc); + const wxRect rect = RCT2Rect(r); + CAST_COLOR(col1, color1); + CAST_COLOR(col2, color2); + + angle %= 360; + if (angle < 0) + angle += 360; + wxDirection dir = wxDOWN; + switch (angle / 90) + { + case 0: dir = wxRIGHT; break; + case 1: dir = wxUP; break; + case 2: dir = wxLEFT; break; + default: dir = wxDOWN; break; + } + + dc.GradientFillLinear(rect, color1, color2, dir); + } +} + +void xvt_dwin_draw_icon(WINDOW win, int x, int y, int rid) +{ + const wxIcon ico = xvtart_GetIconResource(rid); + if (ico.IsOk()) + { + CAST_DC(win, dc); + dc.DrawIcon(ico, x, y); + } +} + +void xvt_dwin_draw_icon_rect(WINDOW win, RCT* rct, int rid) +{ + const int w = xvt_rect_get_width(rct); + const int h = xvt_rect_get_height(rct); + const int s = min(w/16*16, h/16*16); + if (s > 0) + { + const wxIcon ico = xvtart_GetIconResource(rid, NULL, s); + if (ico.IsOk()) + { + CAST_DC(win, dc); + dc.DrawIcon(ico, rct->left+(w-ico.GetWidth())/2, rct->top+(h-ico.GetHeight())/2); + } + } +} + + + +static wxRect ComputeRect(const wxRect& rct, int h, int v, int k) +{ + const int sx = rct.x + h * rct.width / k; + const int ex = rct.x + (h+1) * rct.width / k; + const int sy = rct.y + v * rct.height / k; + const int ey = rct.y + (v+1) * rct.height / k; + return wxRect(sx, sy, ex-sx, ey-sy); +} + +static void DrawImageOnDC(wxDC& dc, TXVT_IMAGE* image, const wxRect& dst, const wxRect& src) +{ +#ifdef __WXMSW__ + if (!OsWin32_DrawBitmap(image->Bitmap(dc), dc, dst, src)) + { + const int k = 4; + for (int h = 0; h < k; h++) + { + for (int v = 0; v < k; v++) + { + const wxRect destin = ComputeRect(dst, h, v, k); + wxRect source = ComputeRect(src, h, v, k); + wxImage img = image->Image().GetSubImage(source); + source.x = source.y = 0; + wxBitmap bmp(img); + OsWin32_DrawBitmap((HBITMAP)bmp.GetHBITMAP(), dc, destin, source); + } + } + } +#else + const wxBitmap& bmp = image->Bitmap(); + const bool printing = is_printer_dc(&dc); + if (src.GetPosition() == wxPoint(0,0) && src.GetSize() == dst.GetSize() && bmp.Ok()) + dc.DrawBitmap(bmp, dst.GetX(), dst.GetY(), !printing); + else + { + wxImage img = image->Image().GetSubImage(src); + + if (dst.GetHeight() < src.GetHeight() || + dst.GetWidth() < src.GetWidth()) + img.Rescale(dst.GetWidth() * 4, dst.GetHeight() * 4); + img.Rescale(dst.GetWidth(), dst.GetHeight()); + wxBitmap bmp(img); + dc.DrawBitmap(bmp, dst.GetX(), dst.GetY(), !printing); + } +#endif +} + +void xvt_dwin_draw_image(WINDOW win, XVT_IMAGE img, const RCT* dest, const RCT* source) +{ + CAST_TIMAGE(img, image); + if (image != NULL) + { + CAST_DC(win, dc); + const wxRect src = RCT2Rect(source); + const wxRect dst = RCT2Rect(dest); + DrawImageOnDC(dc, image, dst, src); + } +} + +void xvt_dwin_draw_oval(WINDOW win, const RCT* rctp) +{ + CAST_DC(win, dc); + const wxRect rct = RCT2Rect(rctp); + dc.DrawEllipse(rct); +} + +void xvt_dwin_draw_pie(WINDOW win, const RCT *rctp, + int WXUNUSED(start_x), int WXUNUSED(start_y), int WXUNUSED(stop_x), int WXUNUSED(stop_y)) +{ + SORRY_BOX(); + xvt_dwin_draw_oval(win, rctp); +} + +void xvt_dwin_draw_polygon(WINDOW win, const PNT *lpnts, int npnts) +{ + if (lpnts != NULL && npnts > 1) + { + CAST_DC(win, dc); + wxPoint* pt = new wxPoint[npnts]; + for (int i = 0; i < npnts; i++) + { + pt[i].x = lpnts[i].h; + pt[i].y = lpnts[i].v; + } + dc.DrawPolygon(npnts, pt); + delete pt; + } +} + +void xvt_dwin_draw_polyline(WINDOW win, const PNT *lpnts, int npnts) +{ + if (win != NULL_WIN && lpnts != NULL && npnts > 1) // Occorrono almeno 2 punti + { + xvt_dwin_draw_set_pos(win, lpnts[0]); + for (int i = 1; i < npnts; i++) + xvt_dwin_draw_line(win, lpnts[i]); + } +} + +void xvt_dwin_draw_rect(WINDOW win, const RCT* rctp) +{ + CAST_DC(win, dc); + const wxRect rct = RCT2Rect(rctp); + dc.DrawRectangle(rct); +} + +void xvt_dwin_draw_roundrect(WINDOW win, const RCT *rctp, int oval_width, int oval_height) +{ + CAST_DC(win, dc); + const wxRect rct = RCT2Rect(rctp); + dc.DrawRoundedRectangle(rct, min(oval_width, oval_height)); +} + +void xvt_dwin_draw_dotted_rect(WINDOW win, RCT *rctp) +{ +#ifdef __WXMSW__ + CAST_DC(win, dc); + OsWin32_DrawDottedRect(dc.GetHDC(), rctp->left, rctp->top, rctp->right, rctp->bottom); +#else + DRAW_CTOOLS dct; + xvt_dwin_get_draw_ctools(win, &dct); + + CPEN pen; + pen.width = 1; + pen.pat = PAT_SOLID; + pen.style = P_DOT; + pen.color = dct.fore_color; + xvt_dwin_set_cpen(win, &pen); + + CBRUSH brush; + brush.color = dct.back_color; + brush.pat = PAT_HOLLOW; + xvt_dwin_set_cbrush(win, &brush); + xvt_dwin_draw_rect(win, rctp); + xvt_dwin_set_draw_ctools(win, &dct); +#endif +} + +void xvt_dwin_draw_set_pos(WINDOW win, PNT pnt) +{ + CAST_TDC(win, dc); + dc._pnt.x = pnt.h; + dc._pnt.y = pnt.v; +} + +// x refers to to the left of the text +// y refers to the baseline of the text +// s is the text +// len is the klenght of the text (-1 stands for all the null terminated text) +void xvt_dwin_draw_text(WINDOW win, int x, int y, const char *s, int len) +{ + if (s && *s && len != 0) + { + CAST_TDC(win, tdc); + RCT rct; + const bool noclip = !tdc.GetClippingBox(&rct); + if (noclip || x < rct.right) + { + wxString str(s); + if (len >= 0) + str.Truncate(len); + wxDC& dc = tdc.GetDC(); // Prima getto il DC ... + const int delta = tdc.GetFontDelta(); // ... poi faccio la GetFontDelta! +/* +#ifndef NDEBUG + // Disegna linee base del testo + int width = ::xvt_dwin_get_text_width(win, s, len); + int leading, ascent, descent; xvt_dwin_get_font_metrics(win, &leading, &ascent, &descent); + + dc.SetPen(*wxMEDIUM_GREY_PEN); + dc.DrawLine(x, y, x+width, y); + + dc.SetPen(*wxCYAN_PEN); + dc.DrawLine(x, y-ascent, x+width, y-ascent); + + dc.SetPen(*wxGREEN_PEN); + dc.DrawLine(x, y+descent, x+width, y+descent); + + if (leading > 0) + { + dc.SetPen(*wxRED_PEN); + dc.DrawLine(x, y+descent+leading, x+width, y+descent+leading); + } +#endif +*/ + dc.DrawText(str, x, y-delta); + } + } +} + +RCT* xvt_dwin_get_clip(WINDOW win, RCT* rct) +{ + CAST_TDC(win, dc); + dc.GetClippingBox(rct); + return rct; +} + +DRAW_CTOOLS* xvt_dwin_get_draw_ctools(WINDOW win, DRAW_CTOOLS* ctoolsp) +{ + CAST_TDC(win, dc); + memcpy(ctoolsp, &dc._dct, sizeof(DRAW_CTOOLS)); + return ctoolsp; +} + +XVT_FNTID xvt_dwin_get_font(WINDOW win) +{ + CAST_TDC(win, dc); + TFontId* pFont = new TFontId(dc._font); + return pFont; +} + +void xvt_dwin_get_font_metrics(WINDOW win, int *leadingp, int *ascentp, int *descentp) +{ + // Attenzione: non funziona la chiamate in cascata a xvt_font_get_metrics + CAST_DC(win, dc); + const wxString str = "Kpfx"; + int height, desc, lead; + dc.GetTextExtent(str, NULL, &height, &desc, &lead); + if (leadingp) + *leadingp = lead; + if (ascentp) + *ascentp = height-desc; + if (descentp) + *descentp = desc; +} + +long xvt_dwin_get_font_size_mapped(WINDOW win) +{ + CAST_WIN(win, dc); + const wxFont& font = dc.GetFont(); + int height = font.GetPointSize(); + return height; +} + +int xvt_dwin_get_text_width(WINDOW win, const char *s, int len) +{ + int width = 0; + if (s && *s && len != 0) + { + CAST_DC(win, dc); + + wxString str = s; + if (str.StartsWith("ABCDEFGH") || str.StartsWith("MMMMMMMM")) + { + const wxString emme('G', str.Length()); // Questa lettera cambia con le mode + str = emme; + } + if (len > 0) + str.Truncate(len); + int height = 0; + dc.GetTextExtent(str, &width, &height); + } + + return width; +} + +void xvt_dwin_invalidate_rect(WINDOW win, const RCT* rctp) +{ + if (win != NULL_WIN) + { + CAST_WIN(win, w); + if (rctp != NULL) + { + const wxRect rct = RCT2Rect(rctp); + w.Refresh(false, &rct); + } + else + w.Refresh(false); + } +} + +BOOLEAN xvt_dwin_is_update_needed(WINDOW win, const RCT* rctp) +{ + if (win != NULL_WIN && rctp != NULL) + { + if (win == PRINTER_WIN || win == SCREEN_WIN) + return TRUE; + CAST_WIN(win, w); // child windows and TASK_WIN + const wxRect rect1 = RCT2Rect(rctp); + const wxRect rect2 = w.GetUpdateClientRect(); + return rect1.Intersects(rect2); + } + return FALSE; +} + +void xvt_dwin_scroll_rect(WINDOW win, RCT *rctp, int dh, int dv) +{ + if (dh != 0 || dv != 0) + { + CAST_WIN(win, w); + if (rctp != NULL) + { + const wxRect rct = RCT2Rect(rctp); + if (!rct.IsEmpty()) +// w.ScrollWindow(dh, dv, &rct); // Metodo ortodosso ma impreciso di un pixel + w.Refresh(false, &rct); // Pezza "TEMPORANEA" per evitare artefatti + } + else + w.ScrollWindow(dh, dv); + } +} + +void xvt_dwin_set_back_color(WINDOW win, COLOR color) +{ + CAST_TDC(win, dc); + dc._dct.back_color = color; + dc.SetDirty(); +} + +void xvt_dwin_set_cbrush(WINDOW win, CBRUSH* cbrush) +{ + CAST_TDC(win, dc); + memcpy(&dc._dct.brush, cbrush, sizeof(CBRUSH)); + dc.SetDirty(); +} + +void xvt_dwin_set_clip(WINDOW win, const RCT* rctp) +{ + CAST_TDC(win, dc); + dc.SetClippingBox(rctp); + dc.SetDirty(); +} + +void xvt_dwin_set_cpen(WINDOW win, CPEN* cpen) +{ + CAST_TDC(win, dc); + memcpy(&dc._dct.pen, cpen, sizeof(CPEN)); + dc.SetDirty(); +} + +void xvt_dwin_set_draw_ctools(WINDOW win, DRAW_CTOOLS* xct) +{ + CAST_TDC(win, dc); + memcpy(&dc._dct, xct, sizeof(DRAW_CTOOLS)); + dc.SetDirty(); +} + +void xvt_dwin_set_draw_mode(WINDOW win, DRAW_MODE mode) +{ + CAST_TDC(win, dc); + dc._dct.mode = mode; + dc.SetDirty(); +} + +void xvt_dwin_set_font(WINDOW win, XVT_FNTID font_id) +{ + CAST_TDC(win, dc); + CAST_FONT(font_id, font); + if (dc._font != font) + { + dc._font = font; + dc.SetDirty(); + } +} + +void xvt_dwin_set_fore_color(WINDOW win, COLOR color) +{ + CAST_TDC(win, dc); + dc._dct.fore_color = color; + dc.SetDirty(); +} + +void xvt_dwin_set_std_cbrush(WINDOW win, long flag) +{ + CBRUSH brush; + brush.pat = PAT_SOLID; + switch (flag) + { + case TL_BRUSH_BLACK: brush.color = COLOR_BLACK; break; + case TL_BRUSH_WHITE: brush.color = COLOR_WHITE; break; + default: SORRY_BOX(); break; + } + xvt_dwin_set_cbrush(win, &brush); +} + +void xvt_dwin_set_std_cpen(WINDOW win, long flag) +{ + CPEN pen; memset(&pen, 0, sizeof(CPEN)); + pen.style = P_SOLID; + pen.pat = PAT_SOLID; + + switch(flag) + { + case TL_PEN_BLACK : pen.color = COLOR_BLACK; break; + case TL_PEN_DKGRAY: pen.color = COLOR_DKGRAY; break; + case TL_PEN_GRAY : pen.color = COLOR_GRAY; break; + case TL_PEN_LTGRAY: pen.color = COLOR_LTGRAY; break; + case TL_PEN_WHITE : pen.color = COLOR_WHITE; break; + case TL_PEN_HOLLOW: pen.pat = PAT_HOLLOW; break; + case TL_PEN_RUBBER: pen.pat = PAT_RUBBER; break; + default: SORRY_BOX(); break; + } + xvt_dwin_set_cpen(win, &pen); +} + +void xvt_dwin_draw_line(WINDOW win, PNT pnt) +{ + CAST_TDC(win, tdc); + const wxPoint to(pnt.h, pnt.v); + if (tdc._pnt != to) + { + wxDC& dc = tdc.GetDC(); + dc.DrawLine(tdc._pnt, to); +// dc.DrawPoint(to); // Non scommentare o cancellare: Un giorno capiro' il perche' servisse + } + tdc._pnt = to; +} + +void xvt_dwin_update(WINDOW win) +{ + CAST_WIN(win, w); + w.Update(); +} + +/////////////////////////////////////////////////////////// +// Debug functions +/////////////////////////////////////////////////////////// + +XVT_ERRSEV xvt_errmsg_get_sev_id(XVT_ERRMSG err) +{ + return (XVT_ERRSEV)err; +} + +/////////////////////////////////////////////////////////// +// Fonts +/////////////////////////////////////////////////////////// + +void xvt_font_copy(XVT_FNTID dest_font_id, XVT_FNTID src_font_id, XVT_FONT_ATTR_MASK mask) +{ + XVT_ASSERT(dest_font_id && src_font_id && mask == XVT_FA_ALL); + CAST_FONT(dest_font_id, dst); + CAST_FONT(src_font_id, src); + dst = src; +} + +XVT_FNTID xvt_font_create(void) +{ + TFontId* pFont = new TFontId; + return (XVT_FNTID)pFont; +} + +void xvt_font_deserialize(XVT_FNTID font_id, const char* buf) +{ + // 01\\Courier\\0\\10\\WIN01/-13/0/0/0/400/0/0/0/0/1/2/1/49/Courier + + CAST_FONT(font_id, font) + const char* s = strchr(buf, '/'); + if (s == NULL) + return; + const int nSize = atoi(s+1); + if (nSize > 0) + font.SetPointSize(nSize); + else + font.SetPointSize(-nSize * 10 / 13); + + // Ignore 4 fields + int i; + for (i = 0; i < 4; i++) + { + s = strchr(s+1, '/'); + if (s == NULL) + return; + } + s++; + const int nWeight = atoi(s); + if (nWeight >= 600) + font.SetMask(font.Mask() | XVT_FS_BOLD); + + s = strchr(s, '/'); + if (s == NULL) + return; + const int nItalic = atoi(s+1); + if (nItalic) + font.SetMask(font.Mask() | XVT_FS_ITALIC); + + // Ignore 8 fields + for (i = 0; i < 8; i++) + { + s = strchr(s+1, '/'); + if (s == NULL) + return; + } + + font.SetFaceName(s+1); + font.SetWin(NULL_WIN); +} + +void xvt_font_destroy(XVT_FNTID font_id) +{ + TFontId* fp = wxDynamicCast(font_id, TFontId); + if (fp != NULL) + delete fp; +} + +BOOLEAN xvt_font_get_family(XVT_FNTID font_id, char* buf, long max_buf) +{ + BOOLEAN ok = font_id != NULL && buf != NULL && max_buf > 0; + if (ok) + { + CAST_FONT(font_id, font); + wxStrncpy(buf, font.FaceName(), max_buf); + buf[max_buf-1] = '\0'; + } + return ok; +} + +BOOLEAN xvt_font_get_family_mapped(XVT_FNTID font_id, char* buf, long max_buf) +{ return xvt_font_get_family(font_id, buf, max_buf); } + +void xvt_font_get_metrics(XVT_FNTID font_id, int *leadingp, int *ascentp, int *descentp) +{ + CAST_FONT(font_id, font); + WINDOW win = font.Win(); + if (win != PRINTER_WIN) + win = TASK_WIN; // Non mi fido troppo della finestra su cui il font e' mappato + CAST_DC(win, dc); + + const wxString str = "Kpfx"; + int height = 0, desc = 0, lead = 0; + const wxFont& ff = font.Font(&dc, win); + dc.GetTextExtent(str, NULL, &height, &desc, &lead, (wxFont*)&ff); + if (height <= 0 || height > 64000) // Gestisce eventuali anomalie alla meno peggio + { + wxASSERT(false); + height = ff.GetPointSize(); + desc = height / 5; + lead = 0; + } + if (leadingp) + *leadingp = lead; + if (ascentp) + *ascentp = height-desc; //*ascentp = height-desc-lead; + if (descentp) + *descentp = desc; +} + +BOOLEAN xvt_font_get_native_desc(XVT_FNTID font_id, char *buf, long max_buf) +{ + const long len = xvt_font_serialize(font_id, buf, max_buf); + return len > 0 && len < max_buf; +} + +long xvt_font_get_size(XVT_FNTID font_id) +{ + CAST_FONT(font_id, font); + return font.PointSize(); +} + +XVT_FONT_STYLE_MASK xvt_font_get_style(XVT_FNTID font_id) +{ + CAST_FONT(font_id, font); + return font.Mask(); +} + +WINDOW xvt_font_get_win(XVT_FNTID font_id) +{ + CAST_FONT(font_id, font); + return font.Win(); +} + +BOOLEAN xvt_font_is_mapped(XVT_FNTID font_id) +{ + return xvt_font_get_win(font_id) != NULL_WIN; +} + +void xvt_font_map(XVT_FNTID font_id, WINDOW win) +{ + CAST_FONT(font_id, font); + font.SetWin(win); +} + +void xvt_font_map_using_default(XVT_FNTID font_id) +{ + xvt_font_map(font_id, TASK_WIN); +} + +void xvt_font_set_family(XVT_FNTID font_id, const char* family) +{ + CAST_FONT(font_id, font); + font.SetFaceName(family); +} + +void xvt_font_set_size(XVT_FNTID font_id, long size) +{ + CAST_FONT(font_id, font); + font.SetPointSize(size); +} + +void xvt_font_set_style(XVT_FNTID font_id, XVT_FONT_STYLE_MASK mask) +{ + CAST_FONT(font_id, font); + font.SetMask(mask); +} + +long xvt_font_serialize(XVT_FNTID font_id, char *buf, long max_buf) +{ + // 01\\Courier\\0\\10\\WIN01/-13/0/0/0/400/0/0/0/0/1/2/1/49/Courier + + CAST_FONT(font_id, font); + const char* name = font.FaceName(); + const int size = font.PointSize(); + const int italic = (font.Mask() & XVT_FS_ITALIC) != 0; + const int weight = (font.Mask() & XVT_FS_BOLD) ? 700 : 400; + + wxString str; + str.Printf("01\\%s\\0\\%d\\WIN01/%d/%d/0/0/%d/0/0/0/0/0/0/0/0/%s", + name, size, size, weight, italic, name); + if (buf != NULL && max_buf > 0) + { + wxStrncpy(buf, str, max_buf); + buf[max_buf-1] = '\0'; + } + return str.Len(); +} + +void xvt_font_unmap(XVT_FNTID font_id) +{ + CAST_FONT(font_id, font); + font.SetWin(NULL_WIN); +} + +/////////////////////////////////////////////////////////// +// File system +/////////////////////////////////////////////////////////// + +BOOLEAN xvt_fsys_build_pathname(char* mbs, const char* volname, const char* dirname, const char* leafroot, const char* leafext, const char* /* leafvers */) +{ +#ifdef __WXMSW__ + _makepath(mbs, volname, dirname, leafroot, leafext); +#else + *mbs = '\0'; + if (dirname && *dirname) + strcpy(mbs, dirname); + if (leafroot && *leafroot) + { + if (!wxEndsWithPathSeparator(mbs) && !wxIsPathSeparator(*leafroot)) + strcat(mbs, "/"); + strcat(mbs, leafroot); + } + if (leafext && *leafext) + { + if (*leafext != '.') + strcat(mbs, "."); + strcat(mbs, leafext); + } +#endif + return TRUE; +} + +BOOLEAN xvt_fsys_parse_pathname(const char* mbs, char* volname, char* dirname, char* leafroot, char* leafext, char* leafvers) +{ + wxString volume, path, file, ext; + wxFileName::SplitPath(mbs, &volume, &path, &file, &ext); + if (volname) + { + if (mbs[0] == mbs[1] && wxIsPathSeparator(mbs[0])) + { + volume.insert(size_t(0), size_t(2), wxFILE_SEP_PATH); // Mette due slash all'inizio + if (!wxIsPathSeparator(path[0])) + volume << wxFILE_SEP_PATH; // Accoda uno slash + path.insert(0, volume); + *volname = '\0'; + } + else + { + wxStrcpy(volname, volume); +#ifdef __WXMSW__ + if (volname[0] != '\0' && volname[1] == '\0') + wxStrcat(volname, ":"); +#endif + } + } + if (dirname) strcpy(dirname, path); + if (leafroot) strcpy(leafroot, file); + if (leafext) strcpy(leafext, ext); + if (leafvers) + { + wxFileName name(mbs); + wxDateTime t; + wxString strTime; + + name.GetTimes(nullptr, &t, nullptr); + strTime = t.Format(wxDefaultDateTimeFormat); + strcpy(leafvers, strTime); + } + return true; + } + +BOOLEAN xvt_fsys_convert_dir_to_str(DIRECTORY* dirp, char* path, int sz_path) +{ + BOOLEAN ok = dirp != NULL && path != NULL && sz_path > 0; + if (ok) + { + wxStrncpy(path, dirp->path, sz_path-1); + path[sz_path-1] = '\0'; + } + return ok; +} + +BOOLEAN xvt_fsys_convert_str_to_dir(const char *path, DIRECTORY *dirp) +{ + BOOLEAN ok = path != NULL && dirp != NULL; + if (ok) + { + const int sz = sizeof(dirp->path)-1; + wxStrncpy(dirp->path, path, sz); + dirp->path[sz] = '\0'; + } + return ok; +} + +BOOLEAN xvt_fsys_convert_fspec_to_str(const FILE_SPEC *fs, char *path, int sz_path) +{ + BOOLEAN ok = FALSE; + if (fs != NULL && path != NULL && sz_path > 0) + { + char mbs[_MAX_PATH]; + xvt_fsys_build_pathname(mbs, "", fs->dir.path, fs->name, fs->type, NULL); + wxStrncpy(path, mbs, sz_path); + ok = *path > ' '; + } + return ok; +} + +BOOLEAN xvt_fsys_convert_str_to_fspec(const char *mbs, FILE_SPEC *fs) +{ + BOOLEAN ok = FALSE; + if (fs != NULL) + { + memset(fs, 0, sizeof(FILE_SPEC)); + wxStrcpy(fs->creator, "CAMPO"); + if (mbs && *mbs) + { + char volume[_MAX_DRIVE], path[_MAX_PATH]; + xvt_fsys_parse_pathname(mbs, volume, path, fs->name, fs->type, NULL); + wxStrcpy(fs->dir.path, volume); + wxStrcat(fs->dir.path, path); + ok = fs->name[0] != '\0'; + } + } + return ok; +} + +wxString xvt_fsys_get_default_dir_name() +{ + if (_startup_dir.IsEmpty()) + _startup_dir = ::wxGetCwd(); + return _startup_dir; +} + +void xvt_fsys_get_default_dir(DIRECTORY *dirp) +{ + xvt_fsys_convert_str_to_dir(xvt_fsys_get_default_dir_name(), dirp); +} + +BOOLEAN xvt_fsys_get_dir(DIRECTORY *dirp) +{ + return xvt_fsys_convert_str_to_dir(xvt_fsys_get_default_dir_name(), dirp); +} + +BOOLEAN xvt_fsys_get_curr_dir(DIRECTORY *dirp) +{ + return xvt_fsys_convert_str_to_dir(::wxGetCwd(), dirp); +} + +void xvt_fsys_get_temp_dir(DIRECTORY *dirp) +{ + xvt_sys_get_profile_string(NULL, "Main", "Temp", "", dirp->path, sizeof(dirp->path)); + + wxString work_dirp(dirp->path); + + work_dirp.MakeUpper(); + + const int pos = work_dirp.Find("%STUDY"); + + if (pos >= 0) + { + char wrk[_MAX_PATH]; xvt_sys_get_profile_string(NULL, "Main", "Study", "", wrk, sizeof(wrk)); + + strcat_s(wrk, dirp->path + pos + 7); + dirp->path[pos] = '\0'; + strcat_s(dirp->path, wrk); + } + if (!*dirp->path) + wxStrcpy(dirp->path, wxFileName::GetTempDir()); +} + +static wxString get_disk_root(const char* path) +{ + wxString str; + if (path && *path) + { + str = path; + if (!wxEndsWithPathSeparator(str)) + str << wxFILE_SEP_PATH; + + wxChar drive[_MAX_DRIVE], dir[_MAX_DIR]; + xvt_fsys_parse_pathname(str,drive,dir,NULL,NULL,NULL); + + if (*drive) + str = drive; + else + str = dir; + + if (!wxEndsWithPathSeparator(str)) + str << wxFILE_SEP_PATH; + } + return str; +} + +// Il disco e' un floppy? +BOOLEAN xvt_fsys_is_floppy_drive(const char* path) +{ + BOOLEAN yes = xvt_fsys_is_removable_drive(path); + if (yes) + { + const unsigned long mb = xvt_fsys_get_disk_size(path, 'M'); // Dimensioni in Mb + yes = mb < 4; // E' un vero floppy solo se e' piu' piccolo di 4 Mb + } + return yes; +} + +// Il disco e' rimuovibile? (floppy / memory stick) +BOOLEAN xvt_fsys_is_removable_drive(const char* path) +{ + BOOLEAN yes = FALSE; + + if (path && *path) + { +#ifdef __WXMSW__ + const wxString strRoot = get_disk_root(path); + yes = ::GetDriveType(strRoot) == DRIVE_REMOVABLE; +#else + char dev[_MAX_PATH]; + OsLinux_GetFileSys(path, dev, NULL, NULL); + yes = strncmp(dev, "/dev/fd", 7) == 0; +#endif + } + return yes; +} + +BOOLEAN xvt_fsys_is_network_drive(const char* path) +{ + BOOLEAN yes = FALSE; + if (path && *path) + { + if (wxIsPathSeparator(path[0]) && wxIsPathSeparator(path[1])) + yes = TRUE; + else + { +#ifdef __WXMSW__ + const wxString strRoot = get_disk_root(path); + yes = ::GetDriveType(strRoot) == DRIVE_REMOTE; +#else + yes = OsLinux_IsNetworkDrive(path); +#endif + } + } + return yes; +} + +BOOLEAN xvt_fsys_is_fixed_drive(const char* path) +{ + BOOLEAN yes = FALSE; + if (path && *path) + { + if (!wxIsPathSeparator(path[0]) || !wxIsPathSeparator(path[1])) + { +#ifdef __WXMSW__ + const wxString strRoot = get_disk_root(path); + yes = ::GetDriveType(strRoot) == DRIVE_FIXED; +#else + yes = !(xvt_fsys_is_network_drive(path) || xvt_fsys_is_removable_drive(path)); +#endif + } + } + return yes; +} + +static unsigned long compute_disk_size(const char* path, bool tot, char unit) +{ + long nVal = 0; + if (path && *path) + { + const wxString strRoot = get_disk_root(path); + wxLongLong total = 0, unused = 0; + wxGetDiskSpace(strRoot, &total, &unused); + __int64 nBytes = tot ? total.ToDouble() : unused.ToDouble(); + + if (nBytes > 0) + { + switch (unit) + { + case 'K': nBytes >>= 10; break; // Kilobytes + case 'M': nBytes >>= 20; break; // Megabytes + case 'G': nBytes >>= 30; break; // Gigabytes + case 'T': nBytes >>= 40; break; // Terabytes + default : break; + } + const unsigned long nMax = (unsigned long)(~0L); + nVal = nBytes > nMax ? nMax : (unsigned long)nBytes; + } + } + return nVal; +} + +unsigned long xvt_fsys_get_disk_size(const char* path, char unit) +{ + return compute_disk_size(path, true, unit); +} + +unsigned long xvt_fsys_get_disk_free_space(const char* path, char unit) +{ + return compute_disk_size(path, false, unit); +} + +BOOLEAN xvt_fsys_test_disk_free_space(const char* path, unsigned long filesize) +{ + // Arrotonda per eccesso al Kilobyte + unsigned long kb = filesize/1024+4; + return kb <= xvt_fsys_get_disk_free_space(path, 'K'); +} + +// Usr friendly implementation +long xvt_fsys_file_attr(const char* path, long attr) +{ + long ret = 0; + if (path && *path && attr >= XVT_FILE_ATTR_MINIMUM && attr <= XVT_FILE_ATTR_MAXIMUM) + { + switch (attr) + { + case XVT_FILE_ATTR_EXIST: + ret = xvt_fsys_access(path, 0) == 0; + break; + case XVT_FILE_ATTR_READ: + ret = xvt_fsys_access(path, 1) == 0; + break; + case XVT_FILE_ATTR_WRITE: + ret = xvt_fsys_access(path, 2) == 0; + break; + case XVT_FILE_ATTR_DIRECTORY: + ret = ::wxDirExists(path); + break; + case XVT_FILE_ATTR_SIZE: + { + wxURL url(path); + wxString scheme = url.GetScheme(); + + if (scheme == "ftp" || scheme == "http") + { + SLIST files = xvt_fsys_list_files("", path, false); + const int count = xvt_slist_count(files); + + if (count > 0) + { + SLIST_ELT e = xvt_slist_get_first(files); + ret = e->data; + } + else + ret = -1L; + xvt_slist_destroy(files); + return ret; + } + const wxULongLong sz = wxFileName::GetSize(path); + ret = sz.GetHi() != 0 ? INT_MAX : sz.GetLo(); + } + break; + case XVT_FILE_ATTR_ATIME: + { + wxFileName name(path); + wxDateTime t; + + name.GetTimes(&t, nullptr, nullptr); + ret = t.GetTicks(); + } + break; + case XVT_FILE_ATTR_MTIME: + ret = ::wxFileModificationTime(path); + break; + case XVT_FILE_ATTR_CTIME: + { + wxFileName name(path); + wxDateTime t; + + name.GetTimes(nullptr, nullptr, &t); + ret = t.GetTicks(); + } + break; + default: break; + } + } + return ret; +} + +// Original XVT implementation +long xvt_fsys_get_file_attr(const FILE_SPEC* fs, long attr) +{ + char mbs[_MAX_PATH]; xvt_fsys_convert_fspec_to_str(fs, mbs, sizeof(mbs)); + return xvt_fsys_file_attr(mbs, attr); +} + +void xvt_fsys_set_file_time(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime) +{ +#ifdef __WXMSW__ + OsWin32_Set_FileTime(file, ctime, atime, mtime); +#else + Oslinux_Set_FileTime(file, ctime, atime, mtime); +#endif +} + +/////////////////////////////////////////////////////////// +// File system +/////////////////////////////////////////////////////////// + +static bool xvt_sys_ftp_passive_mode(const char* server) +{ + static char pasv = ' '; + if (pasv <= ' ') + { + char str[16] = ""; + xvt_sys_get_profile_string(xvt_fsys_get_campo_ini(), "Server", "ftp", "Passive", str, sizeof(str)); + pasv = toupper(str[0]); + } + return pasv != 'A'; +} + +SLIST xvt_fsys_list_files(const char *type, const char *pat, BOOLEAN dirs) +{ + wxBusyCursor hourglass; + + SLIST list = xvt_slist_create(); + + int flags = wxFILE | wxDIR; + if (dirs) + { + if (xvt_str_same(type, DIR_TYPE)) + flags = wxDIR; + } + else + flags = wxFILE; + + const wxURL url(pat); + if (url.GetScheme() == "ftp") + { + const wxString strHost = url.GetServer(); + const wxString strUser = url.GetUser(); + const wxString strPwd = url.GetPassword(); + const wxFileName fnPath = url.GetPath(); + const wxString fnDir = fnPath.GetPath(wxPATH_GET_VOLUME, wxPATH_UNIX); + const wxString fnName = fnPath.GetFullName(); + + wxFTP ftp; + + if (!strUser.IsEmpty()) + { + ftp.SetUser(strUser); + ftp.SetPassword(strPwd); + } + ftp.SetPassive(xvt_sys_ftp_passive_mode(strHost)); + + const bool bConnected = ftp.Connect(strHost); + if (bConnected && ftp.ChDir(fnDir)) + { + wxString RemotePath = pat; + RemotePath = RemotePath.BeforeLast('/'); + + wxArrayString files; + ftp.GetList(files, fnName, true); + + for (size_t i = 0; i < files.GetCount(); i++) + { + const int type = files[i][0] == 'd' ? wxDIR : wxFILE; + if (type & flags) // Entry type matches desired mask? + { + wxString f = RemotePath; f << '/' << files[i].AfterLast(' '); + wxString size = files[i].Mid(30); + xvt_slist_add_at_elt(list, NULL, f, type == wxFILE ? wxAtol(size) : -1L); + } + } + } + } + else //normale list_files + { + wxString ext; + if (flags == wxFILE) + wxSplitPath(pat, NULL, NULL, &ext); + + wxString f = ::wxFindFirstFile(pat, flags); + while (!f.IsEmpty()) + { + if (f.StartsWith(".\\") || f.StartsWith("./")) + f = f.Mid(2); + + bool bGood = true; + if (flags == wxFILE && ext.Len() >= 3) + bGood = wxStricmp(ext, f.AfterLast('.')) == 0; + if (bGood) + xvt_slist_add_at_elt(list, NULL, f, 0L); + f = ::wxFindNextFile(); + } + } + + return list; +} + +static wxString _strSavedir; + +void xvt_fsys_restore_dir() +{ + wxASSERT(!_strSavedir.IsEmpty()); + ::wxSetWorkingDirectory(_strSavedir); + _strSavedir = wxEmptyString; +} + +void xvt_fsys_save_dir() +{ + wxASSERT(_strSavedir.IsEmpty()); + _strSavedir = ::wxGetCwd(); +} + +BOOLEAN xvt_fsys_set_dir(const DIRECTORY *dirp) +{ + return ::wxSetWorkingDirectory(dirp->path); +} + +BOOLEAN xvt_fsys_fcopy(const char* orig, const char* dest) +{ + wxURL orig_url(orig); + + wxInputStream* input = nullptr; + const wxString ischeme = orig_url.GetScheme(); + + if (ischeme == "ftp") + { + wxFTP& ftp = *wxStaticCast(&orig_url.GetProtocol(), wxFTP); + const wxString strHost = orig_url.GetServer(); + const wxString strUser = orig_url.GetUser(); + const wxString strPwd = orig_url.GetPassword(); + const wxFileName fnPath = orig_url.GetPath(); + const wxString fnDir = fnPath.GetPath(wxPATH_GET_VOLUME, wxPATH_UNIX); + const wxString fnName = fnPath.GetFullName(); + + if (!strUser.IsEmpty()) + { + ftp.SetUser(strUser); + ftp.SetPassword(strPwd); + } + ftp.SetPassive(xvt_sys_ftp_passive_mode(strHost)); + + if (ftp.Connect(strHost) && ftp.SetBinary() && ftp.ChDir(fnDir)) + input = ftp.GetInputStream(fnName); + } + else + if (ischeme == "http") + return false; + /*{ + + const wxString strHost = orig_url.GetServer(); + const wxString strUser = orig_url.GetUser(); + const wxString strPwd = orig_url.GetPassword(); + const wxFileName fnPath = orig_url.GetPath(); + + wxHTTP http; + + if (!strUser.IsEmpty()) + { + http.SetUser(strUser); + http.SetPassword(strPwd); + } + http.SetHeader(_T("Content-type"), _T("application/x-www-form-urlencoded")); //remember to define “Content-type: application/x-www-form-urlencoded”, or remote server can’t get your posted data. + wxString PostData("postdata="); + + PostData << fnPath.GetFullPath(); + http.SetPostBuffer(PostData); //it’s the data to be posted + if (http.Connect(strHost)) + { + input = http.GetInputStream(_T("/getfile.php")); + if (input != nullptr && http.GetError() != wxPROTO_NOERR) + { + delete input; + input = nullptr; + } + } + }*/ + else + input = new wxFileInputStream(orig); + if (input == nullptr) + return false; + + wxURL dest_url(dest); + wxOutputStream* output = NULL; + const wxString scheme = dest_url.GetScheme(); + + if (scheme == "ftp") + { + wxFTP ftp; + const wxString strHost = dest_url.GetServer(); + const wxString strUser = dest_url.GetUser(); + const wxString strPwd = dest_url.GetPassword(); + const wxFileName fnPath = dest_url.GetPath(); + const wxString fnDir = fnPath.GetPath(wxPATH_GET_VOLUME, wxPATH_UNIX); + const wxString fnName = fnPath.GetFullName(); + + if (!strUser.IsEmpty()) + { + ftp.SetUser(strUser); + ftp.SetPassword(strPwd); + } + ftp.SetPassive(xvt_sys_ftp_passive_mode(strHost)); + + if (ftp.Connect(strHost) && ftp.SetBinary() && ftp.ChDir(fnDir)) + output = ftp.GetOutputStream(fnName); + } + else + if (scheme == "http") + return false; + /*{ + const wxString strHost = dest_url.GetServer(); + const wxString strUser = dest_url.GetUser(); + const wxString strPwd = dest_url.GetPassword(); + const wxFileName fnPath = dest_url.GetPath(); + wxHTTP http; + + if (!strUser.IsEmpty()) + { + http.SetUser(strUser); + http.SetPassword(strPwd); + } + http.SetHeader(_T("Content-type"), _T("application/x-www-form-urlencoded")); //remember to define “Content-type: application/x-www-form-urlencoded”, or remote server can’t get your posted data. + + wxString PostData("postdata="); + + PostData << fnPath.GetFullPath(); + http.SetPostBuffer(PostData); //it’s the data to be posted + if (http.Connect(strHost)) + { + output = http.GetResponse(); + if (output != nullptr) && http.GetError() == wxPROTO_NOERR; + { + wxDELETE(output); + output = nullptr; + } + } + } */ + else + output = new wxFileOutputStream(dest); + // } + + BOOLEAN ok = false; + + if (input != nullptr && output != nullptr) + { + input->Read(*output); + wxStreamError err = output->GetLastError(); + ok = (err == wxSTREAM_NO_ERROR); + output->Close(); + } + if (input != nullptr) + delete input; + if (output != nullptr && scheme != "ftp") + delete output; + return ok; +} + +/////////////////////////////////////////////////////////// +// Images +/////////////////////////////////////////////////////////// + +inline bool XVT_SAME_COLOR(COLOR col1, COLOR col2) { return (col1 & 0x00FFFFFF) == (col2 & 0x00FFFFFF); } + +void xvt_image_blur(XVT_IMAGE img, short radius) +{ + CAST_TIMAGE(img, image); + image->Blur(radius); +} + +XVT_IMAGE xvt_image_capture(WINDOW win, const RCT* src) +{ + wxRect r; + if (src == NULL) + { + RCT rct; xvt_vobj_get_client_rect(win, &rct); + r = RCT2Rect(&rct); + } + else + r = RCT2Rect(src); + + CAST_DC(win, wdc); + + wxBitmap bmp(r.GetWidth(), r.GetHeight()); + wxMemoryDC mdc(bmp); + mdc.Blit(wxPoint(0,0), r.GetSize(), &wdc, r.GetPosition()); + + TXVT_IMAGE* i = new TXVT_IMAGE; + i->Image() = bmp.ConvertToImage(); + + return (XVT_IMAGE)i; +} + +XVT_IMAGE xvt_image_create(XVT_IMAGE_FORMAT WXUNUSED(format), short width, short height, COLOR color) +{ + TXVT_IMAGE* i = new TXVT_IMAGE; + i->Image().Create(width, height); + if (color != COLOR_INVALID) + { + CAST_COLOR(color, rgb); +#if wxCHECK_VERSION(2,9,0) + if (rgb.Red() == rgb.Green() && rgb.Green() == rgb.Blue()) + i->Image().Clear(rgb.Red()); + else +#endif + { + const wxRect rct(0, 0, width, height); + i->Image().SetRGB(rct, rgb.Red(), rgb.Green(), rgb.Blue()); + } + } + return (XVT_IMAGE)i; +} + +void xvt_image_destroy(XVT_IMAGE img) +{ + CAST_TIMAGE(img, image); + if (image != NULL) + delete image; +} + +int xvt_image_find_clut_index(XVT_IMAGE img, COLOR rgb) +{ + CAST_IMAGE(img, image); + int i = -1; + if (image && image->Ok() && image->HasPalette()) + { + const wxPalette& pal = image->GetPalette(); + for (i = 255; i >= 0; i--) + { + unsigned char ri, gi, bi; + if (pal.GetRGB(i, &ri, &gi, &bi)) + { + const COLOR rgbi = XVT_MAKE_COLOR(ri, gi, bi); + if ((rgbi & 0x00FFFFFF) == (rgb & 0x00FFFFFF)) + break; + } + } + } + return i; +} + +COLOR xvt_image_get_clut(XVT_IMAGE img, short index) +{ + CAST_IMAGE(img, image); + if (image && image->Ok() && image->HasPalette()) + { + const wxPalette& pal = image->GetPalette(); + unsigned char r, g, b; + if (pal.GetRGB(index, &r, &g, &b)) + return XVT_MAKE_COLOR(r, g, b); + } + return COLOR_INVALID; +} + +void xvt_image_get_dimensions(XVT_IMAGE image, short* width, short* height) +{ + *width = *height = 0; + + CAST_IMAGE(image, img); + if (img != NULL && img->Ok()) + { + *width = img->GetWidth(); + *height = img->GetHeight(); + } +} + +XVT_IMAGE_FORMAT xvt_image_get_format(XVT_IMAGE image) +{ + CAST_IMAGE(image, img); + if (img != NULL && img->Ok()) + return img->HasPalette() ? XVT_IMAGE_CL8 : XVT_IMAGE_RGB; + return XVT_IMAGE_NONE; +} + +short xvt_image_get_ncolors(XVT_IMAGE image) +{ + int n = 0; + if (xvt_image_get_format(image) == XVT_IMAGE_CL8) + { + CAST_IMAGE(image, i); + const wxPalette& pal = i->GetPalette(); + unsigned char r, g, b; + for (n = 16; n < 256; n++) + { + if (!pal.GetRGB(n, &r, &g, &b)) + break; + } + } + return n; +} + +COLOR xvt_image_get_pixel(XVT_IMAGE image, short x, short y) +{ + CAST_TIMAGE(image, i); + if (i != NULL && i->Ok()) + return i->GetPixel(x, y); + return COLOR_INVALID; +} + +XVT_IMAGE xvt_image_read(const char* filenamep) +{ + TXVT_IMAGE* i = NULL; +#ifdef __WXMSW__ + const wxString name = filenamep; +#else + wxString name; + if (isalpha(filenamep[0u])) + { + name = _startup_dir; + name += "/"; + } + name += filenamep; +#endif + if (::wxFileExists(name)) + { + i = new TXVT_IMAGE; + i->LoadFile(name); + if (!i->Ok()) + { + delete i; + i = NULL; + } + } + return (XVT_IMAGE)i; +} + +XVT_IMAGE xvt_image_read_bmp(const char *filenamep) +{ + return xvt_image_read(filenamep); // Very clever! +} + +void xvt_image_set_clut(XVT_IMAGE image, short index, COLOR color) +{ + CAST_TIMAGE(image, i); + if (i != NULL && i->Ok() && i->HasPalette()) + { + CAST_COLOR(color, c); + + wxImage& bmp = i->Image(); // Set dirty! + + const COLOR old_trans = XVT_MAKE_COLOR(bmp.GetMaskRed(), bmp.GetMaskGreen(), bmp.GetMaskBlue()); + const int idx = xvt_image_find_clut_index(image, old_trans); + if (idx == index) + bmp.SetMaskColour(c.Red(), c.Green(), c.Blue()); + + const wxPalette& pal = bmp.GetPalette(); + unsigned char ri, gi, bi; + pal.GetRGB(index, &ri, &gi, &bi); + const COLOR old_color = XVT_MAKE_COLOR(ri, gi, bi); + + const int w = bmp.GetWidth(); + const int h = bmp.GetHeight(); + for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) + { + const COLOR rgb = i->GetPixel(x, y); + if (XVT_SAME_COLOR(rgb, old_color)) + i->SetPixel(x, y, color); + } + } +} + +void xvt_image_replace_color(XVT_IMAGE image, COLOR old_color, COLOR new_color) +{ + CAST_TIMAGE(image, i); + if (i != NULL && i->Ok()) + { + if (i->HasPalette()) + { + int index = -1; + while (true) + { + const int idx = xvt_image_find_clut_index(image, old_color); + if (idx > index) + { + xvt_image_set_clut(image, idx, new_color); + index = idx; + } + else + break; + } + } + else + { + wxImage& bmp = i->Image(); // Set dirty! + + const COLOR old_trans = XVT_MAKE_COLOR(bmp.GetMaskRed(), bmp.GetMaskGreen(), bmp.GetMaskBlue()); + + const int w = bmp.GetWidth(); + const int h = bmp.GetHeight(); + for (int y = 0; y < h; y++) for (int x = 0; x < w; x++) + { + const COLOR rgb = i->GetPixel(x, y); + if (XVT_SAME_COLOR(rgb, old_color)) + i->SetPixel(x, y, new_color); + } + // Imposto la nuova trasparenza se cambiata + if (XVT_SAME_COLOR(old_trans, old_color)) + bmp.SetMaskColour(XVT_COLOR_GET_RED(new_color), XVT_COLOR_GET_GREEN(new_color), XVT_COLOR_GET_BLUE(new_color)); + } + } +} + + +void xvt_image_set_ncolors(XVT_IMAGE WXUNUSED(image), short WXUNUSED(ncolors)) +{ +// SORRY_BOX(); +} + +void xvt_image_set_pixel(XVT_IMAGE image, short x, short y, COLOR color) +{ + CAST_TIMAGE(image, i); + if (i != NULL && i->Ok()) + i->SetPixel(x, y, color); +} + +void xvt_image_transfer(XVT_IMAGE dstimage, XVT_IMAGE srcimage, RCT *dstrctp, RCT *srcrctp) +{ + CAST_TIMAGE(dstimage, dst); + CAST_TIMAGE(srcimage, src); + if (dst != NULL && src != NULL) + { + const wxRect rctDst = RCT2Rect(dstrctp); + const wxRect rctSrc = RCT2Rect(srcrctp); + + const wxRect rctDstI(0, 0, dst->GetWidth(), dst->GetHeight()); + const wxRect rctSrcI(0, 0, src->GetWidth(), src->GetHeight()); + + if (rctDst.GetSize() == rctSrc.GetSize() && + rctDstI.Contains(rctDst) && rctSrcI.Contains(rctSrc) && + src->HasAlpha() == dst->HasAlpha()) + { + const int nPixelSize = src->HasAlpha() ? 4 : 3; + const int nRowSize = nPixelSize * src->GetWidth(); +#ifndef NDEBUG + #pragma omp parallel for +#endif + for (int y = 0; y < rctSrc.height; y++) + { + unsigned char* rgbSrc = src->Image().GetData() + (rctSrc.y+y)*nRowSize + rctSrc.x * nPixelSize; + unsigned char* rgbDst = dst->Image().GetData() + (rctDst.y+y)*nRowSize + rctDst.x * nPixelSize; + memcpy(rgbDst, rgbSrc, nPixelSize * rctSrc.width); + } + } + else + { + wxMemoryDC dc; + wxBitmap bmp(*dst); + dc.SelectObject(bmp); + DrawImageOnDC(dc, src, rctDst, rctSrc); + dst->Image() = bmp.ConvertToImage(); + dc.SelectObject(wxNullBitmap); + } + } +} + +BOOLEAN xvt_image_filter(XVT_IMAGE image, IMAGE_FILTER filter, void* param) +{ + CAST_TIMAGE(image, img); + BOOLEAN ok = img != NULL && img->Ok(); + if (ok) + { + const short w = img->GetWidth(); + const short h = img->GetHeight(); + ok = w > 0 && h > 0; + if (ok) + { + const int nPixelSize = img->HasAlpha() ? 4 : 3; + const int nRowSize = nPixelSize * img->GetWidth(); + for (short y = 0; y < h; y++) + { + unsigned char* rgb = img->Image().GetData() + nRowSize*y; + for (short x = 0; x < w; x++, rgb += nPixelSize) + filter(x, y, rgb, param); + } + } + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Memory management +/////////////////////////////////////////////////////////// + +DATA_PTR xvt_mem_alloc(size_t size) +{ + DATA_PTR ptr = (DATA_PTR)malloc(size); + return ptr; +} + +void xvt_mem_free(DATA_PTR p) +{ free(p); } + +DATA_PTR xvt_mem_realloc(DATA_PTR p, size_t size) +{ return (DATA_PTR)realloc(p, size); } + +DATA_PTR xvt_mem_rep(DATA_PTR dst, DATA_PTR src, unsigned int srclen, long reps) +{ + XVT_ASSERT(dst != NULL || src != NULL); + + if (srclen == 1) + memset(dst, *src, reps); + else + { + for (long i = 0; i < reps; i++) + memcpy(dst + i*srclen, src, srclen); + } + return dst; +} + +DATA_PTR xvt_mem_zalloc(size_t size) +{ + DATA_PTR ptr = xvt_mem_alloc(size); + memset(ptr, 0, size); + return ptr; +} + +/////////////////////////////////////////////////////////// +// Menu management +/////////////////////////////////////////////////////////// + +static int xvt_menu_count(const MENU_ITEM* m) +{ + int n = 0; + if (m != NULL) + for (n = 0; m[n].tag != 0; n++); + return n; +} + +// Funzione inventata +MENU_ITEM* xvt_menu_duplicate_tree(const MENU_ITEM* m) +{ + MENU_ITEM* TheMenu = NULL; + if (m != NULL && m->tag != 0) + { + const int n = xvt_menu_count(m)+1; + TheMenu = (MENU_ITEM*)xvt_mem_zalloc(sizeof(MENU_ITEM)*n); + memcpy(TheMenu, m, n*sizeof(MENU_ITEM)); + for (int i = 0; i < n; i++) + { + MENU_ITEM* mi = &TheMenu[i]; + mi->text = xvt_str_duplicate(mi->text); + mi->child = xvt_menu_duplicate_tree(mi->child); + } + } + return TheMenu; +} + +MENU_ITEM* xvt_menu_get_tree(WINDOW win) +{ + MENU_ITEM* m = NULL; + if (win == TASK_WIN) + { + TTaskWin* w = wxStaticCast((wxObject*)win, TTaskWin); + m = xvt_menu_duplicate_tree(w->GetMenuTree()); + } + else + { + CAST_TWIN(win, w); + m = xvt_menu_duplicate_tree(w.GetMenuTree()); + } + return m; +} + +BOOLEAN xvt_menu_popup(const MENU_ITEM *menu_p, WINDOW win, PNT pos, + XVT_POPUP_ALIGNMENT /* alignment */, MENU_TAG /* item */) +{ + wxMenu menu; + for (const MENU_ITEM* mi = menu_p; mi != NULL && mi->tag != 0; mi++) + { + if (mi->separator || mi->text == NULL) + menu.AppendSeparator(); + else + { + wxMenuItem* item = NULL; + if (mi->checkable) + { + item = menu.AppendCheckItem(mi->tag, mi->text); + item->Check(mi->checked); + } + else + item = menu.Append(mi->tag, mi->text); + // Operazioni fattibili solo dopo la menu.Append(), non prima! + item->Enable(mi->enabled); + } + } + + wxPoint mp = wxDefaultPosition; + if (pos.h >= 0 && pos.v >= 0) + { + mp.x = pos.h; + mp.y = pos.v; + } + + CAST_WIN(win, w); + return w.PopupMenu(&menu, mp); +} + +static void TranslateMenu(wxMenu* pMenu, TRANSLATE_CALLBACK tc) +{ + wxMenuItemList& list = pMenu->GetMenuItems(); + for (unsigned i = 0; i < list.GetCount(); i++) + { + wxMenuItem* mi = list[i]; + if (!mi->IsSeparator()) + { + const char* ita = mi->GetText(); + const char* eng = tc(ita); + mi->SetText(eng); + wxMenu* pMenu = mi->GetSubMenu(); + if (pMenu != NULL) + TranslateMenu(pMenu, tc); + } + } +} + +void xvt_menu_translate_tree(WINDOW win, TRANSLATE_CALLBACK tc) +{ + if (win == TASK_WIN) + { + wxMenuBar* pMenuBar = _task_win->GetMenuBar(); + if (pMenuBar != NULL) + { + for (int m = pMenuBar->GetMenuCount()-1; m >= 0; m--) + { + const wxString ita = pMenuBar->GetLabelTop(m); + const char* eng = tc(ita); + pMenuBar->SetLabelTop(m, eng); + + wxMenu* pMenu = pMenuBar->GetMenu(m); + TranslateMenu(pMenu, tc); + } + } + } +} + +void xvt_menu_set_font_sel(WINDOW win, XVT_FNTID WXUNUSED(font_id)) +{ + XVT_ASSERT(win == TASK_WIN); +} + +static wxMenuItem* GetXvtMenuItem(WINDOW win, MENU_TAG tag) +{ + wxMenuItem* item = NULL; + wxFrame* pFrame = wxDynamicCast((wxObject*)win, wxFrame); + if (pFrame != NULL) + { + wxMenuBar* bar = pFrame->GetMenuBar(); + if (bar != NULL) + item = bar->FindItem(tag); + } + return item; +} + +void xvt_menu_set_item_checked(WINDOW win, MENU_TAG tag, BOOLEAN check) +{ + wxMenuItem* item = GetXvtMenuItem(win, tag); + if (item) + item->Check(check != 0); +} + +void xvt_menu_set_item_enabled(WINDOW win, MENU_TAG tag, BOOLEAN enable) +{ + wxMenuItem* item = GetXvtMenuItem(win, tag); + if (item) + item->Enable(enable != 0); +} + +void xvt_menu_set_item_title(WINDOW win, MENU_TAG tag, const char* text) +{ + wxMenuItem* item = GetXvtMenuItem(win, tag); + if (item) + item->SetText(text); +} + +void xvt_menu_set_tree(WINDOW win, MENU_ITEM* tree) +{ + if (win == TASK_WIN) + { + TTaskWin* w = wxStaticCast((wxObject*)win, TTaskWin); //occhio + w->SetMenuTree(tree); + } + else + { + CAST_TWIN(win, w); + w.SetMenuTree(tree); + } +} + +void xvt_menu_update(WINDOW /*win*/) +{ + wxMenuBar* bar = _task_win != NULL ? _task_win->GetMenuBar() : NULL; + if (bar) + bar->Refresh(); +} + +/////////////////////////////////////////////////////////// +// Palette management +/////////////////////////////////////////////////////////// + +short xvt_palet_add_colors(XVT_PALETTE WXUNUSED(palet), COLOR* WXUNUSED(colorsp), short numcolors) { return numcolors; } +short xvt_palet_add_colors_from_image(XVT_PALETTE WXUNUSED(palet), XVT_IMAGE image) { return xvt_image_get_ncolors(image); } +XVT_PALETTE xvt_palet_create(XVT_PALETTE_TYPE WXUNUSED(type), XVT_PALETTE_ATTR WXUNUSED(reserved)) { return NULL; } +void xvt_palet_destroy(XVT_PALETTE WXUNUSED(palet)) { SORRY_BOX(); } +short xvt_palet_get_colors(XVT_PALETTE WXUNUSED(palet), COLOR* WXUNUSED(colorsp), short WXUNUSED(maxcolors)) { return 0; } +short xvt_palet_get_ncolors(XVT_PALETTE WXUNUSED(palet)) { return 0; } +int xvt_palet_get_tolerance(XVT_PALETTE WXUNUSED(p)) { return 0; } +void xvt_palet_set_tolerance(XVT_PALETTE WXUNUSED(p), int WXUNUSED(t)) { SORRY_BOX(); } + +/////////////////////////////////////////////////////////// +// Rectangles +/////////////////////////////////////////////////////////// +int xvt_rect_get_height(const RCT *rctp) +{ + return rctp ? abs(rctp->bottom - rctp->top) : 0; + // 3.1 return rctp ? rctp->bottom - rctp->top : 0; +} + +int xvt_rect_get_width(const RCT *rctp) +{ + return rctp ? abs(rctp->right - rctp->left) : 0; + // 3.1 return rctp ? rctp->right - rctp->left : 0; +} + +BOOLEAN xvt_rect_has_point(const RCT *rctp, PNT pnt) +{ + const wxRect rct = RCT2Rect(rctp); + return rct.Contains(pnt.h, pnt.v); +} + +BOOLEAN xvt_rect_intersect(RCT *drctp, const RCT *rctp1, const RCT *rctp2) +{ + const wxRect rect1 = RCT2Rect(rctp1); + const wxRect rect2 = RCT2Rect(rctp2); + const BOOLEAN yes = rect1.Intersects(rect2); + if (drctp) + { + if (yes) + { + /* + drctp->left = max(rect1.x, rect2.x); + drctp->top = max(rect1.y, rect2.y); + drctp->right = min(rect1.GetRight(), rect2.GetRight())+1; + drctp->bottom = min(rect1.GetBottom(), rect2.GetBottom())+1; + */ + const wxRect rect0 = rect1.Intersect(rect2); + Rect2RCT(rect0, drctp); + } + else + { + // drctp->left = drctp->right = rect1.x; + // drctp->top = drctp->bottom = rect1.y; + xvt_rect_set_null(drctp); + } + } + return yes; +} + +BOOLEAN xvt_rect_is_empty(const RCT* rct) +{ + return rct == NULL || (rct->left==rct->right && rct->top==rct->bottom); +} + +void xvt_rect_offset(RCT *rctp, short dh, short dv) +{ + XVT_ASSERT(rctp != NULL); + rctp->left += dh; + rctp->top += dv; + rctp->right += dh; + rctp->bottom += dv; +} + +void xvt_rect_set(RCT *rctp, short left, short top, short right, short bottom) +{ + XVT_ASSERT(rctp != NULL); + rctp->left = left; + rctp->top = top; + rctp->right = right; + rctp->bottom = bottom; +} + +void xvt_rect_set_empty(RCT *rctp) +{ + XVT_ASSERT(rctp != NULL); + rctp->right = rctp->left; + rctp->bottom = rctp->top; +} + +void xvt_rect_set_null(RCT* rctp) +{ + XVT_ASSERT(rctp != NULL); + memset(rctp, 0, sizeof(RCT)); +} + +BOOLEAN xvt_rect_set_pos(RCT *rctp, PNT pos) +{ + BOOLEAN ok = rctp != NULL; + if (ok) + { + const short w = rctp->right-rctp->left; + const short h = rctp->bottom-rctp->top; + xvt_rect_set(rctp, pos.h, pos.v, pos.h + w, pos.v + h); + } + return ok; +} + +void xvt_rect_deflate(RCT *rctp, short ix, short iy) +{ + if (rctp != NULL) + { + rctp->left += ix; rctp->right -= ix; + rctp->top += iy; rctp->bottom -= iy; + } +} + +void xvt_rect_inflate(RCT *rctp, short ix, short iy) +{ + if (rctp != NULL) + { + rctp->left -= ix; rctp->right += ix; + rctp->top -= iy; rctp->bottom += iy; + } +} + +/////////////////////////////////////////////////////////// +// Resource management +/////////////////////////////////////////////////////////// + +void xvt_res_free_menu_tree(MENU_ITEM* tree) +{ + XVT_ASSERT(tree != NULL); + if (tree != NULL) + { + for (MENU_ITEM* item = tree; item->tag != 0; item++) + { + if (item->text) + xvt_mem_free(item->text); + if (item->child != NULL) + xvt_res_free_menu_tree(item->child); + } + xvt_mem_free((DATA_PTR)tree); + } +} + +XVT_FNTID xvt_res_get_font(int rid) +{ + XVT_FNTID f = xvt_font_create(); + if (rid <= 0) + { + CAST_FONT(f, font); + font.Copy(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + } + return f; +} + +XVT_IMAGE xvt_res_get_icon(int rid) +{ + XVT_IMAGE img = NULL; + const wxIcon icon = xvtart_GetIconResource(rid); + if (icon.IsOk()) + { + int w = icon.GetWidth(); if (w <= 0) w = 32; + int h = icon.GetHeight(); if (h <= 0) h = 32; + wxBitmap bmp(w, h, icon.GetDepth()); + { + wxMemoryDC dc(bmp); + dc.SetBackground(*wxWHITE_BRUSH); + dc.Clear(); + dc.DrawIcon(icon, 0, 0); + } + XVT_IMAGE_FORMAT xif = bmp.GetDepth()>8 ? XVT_IMAGE_RGB : XVT_IMAGE_CL8; + img = xvt_image_create(xif, w, h, 0); + ((TXVT_IMAGE*)img)->Image() = bmp.ConvertToImage(); + } + return img; +} + +XVT_IMAGE xvt_res_get_image(int rid) +{ + const wxString strFileName = xvtart_GetResourceName("Image", rid); + const bool ok = !strFileName.IsEmpty(); +#ifndef NDEBUG + if (!ok) + { + wxString msg; + msg << "Can't find image code " << rid << " in resource.ini"; + xvt_dm_post_note(msg); + } +#endif + return ok ? xvt_image_read(strFileName) : NULL; +} + +static int SplitString(const wxString& str, wxArrayString& a) +{ + const char* s = str; + char* comma = ""; + a.Clear(); + while (comma) + { + comma = (char*)strchr(s, ','); + if (comma) + { + *comma = '\0'; + a.Add(s); + *comma = ','; + s = comma+1; + } + else + a.Add(s); + } + return a.GetCount(); +} + +static void FillMenuItem(const wxString& strValue, MENU_ITEM* mi) +{ + wxArrayString a; + const int n = SplitString(strValue, a); + mi->tag = n > 0 ? atoi(a[0]) : 0; + if (mi->tag > 0) + { + const wxString& str = a[1]; + const int accelera = str.Find('&'); + if (accelera >= 0) + mi->mkey = str[accelera+1]; + mi->text = xvt_str_duplicate(str); + mi->enabled = n < 3 || (a[2].Find('D')<0); + mi->checkable = n >= 3 && (a[2].Find('C')>=0); + mi->checked = n >= 3 && (a[2].Find('c')>=0); + } + else + { + mi->tag = -1; + mi->separator = TRUE; + } +} + +MENU_ITEM* xvt_res_get_menu(int rid) +{ + wxFileConfig ini("", "", xvtart_GetResourceIni()); + + const int MAX_MENU = 16; + MENU_ITEM* TheMenu = (MENU_ITEM*)xvt_mem_zalloc(sizeof(MENU_ITEM)*MAX_MENU); + + wxString strName; + if (rid >= 10000 && rid < 10100) + { + wxFileName::SplitPath(wxTheApp->argv[0], NULL, &strName, NULL); + strName.MakeUpper(); + strName.Printf("/Menu_%s-%X", (const char*)strName.Left(3), (rid-1)%16); + } + else + strName.Printf("/Menu_%d", rid); + ini.SetPath(strName); + + wxString strItem; + for (int i = 0; i < MAX_MENU; i++) + { + MENU_ITEM* mi = &TheMenu[i]; + strItem.Printf("Item_%02d", i); + if (ini.Read(strItem, &strName)) + { + FillMenuItem(strName, mi); + mi = mi->child = (MENU_ITEM*)xvt_mem_zalloc(sizeof(MENU_ITEM)*MAX_MENU); + + for (int j = 0; j < MAX_MENU; j++, mi++) + { + strItem.Printf("Item_%02d_%02d", i, j); + if (ini.Read(strItem, &strName)) + FillMenuItem(strName, mi); + else + break; + } + } + else + break; + } + if (TheMenu->tag == 0) + { + XVT_ASSERT(false); // Menu not found + xvt_res_free_menu_tree(TheMenu); + TheMenu = NULL; + } + + return TheMenu; +} + +char* xvt_res_get_str(int rid, char *s, int sz_s) +{ + XVT_ASSERT(s != NULL && sz_s > 0); + const wxString str = xvtart_GetResourceName("String", rid); + wxStrncpy(s, str, sz_s); + s[sz_s-1] = '\0'; + return s; +} + +/////////////////////////////////////////////////////////// +// Scroll bars +/////////////////////////////////////////////////////////// + +#define CAST_GAUGE(win, pb) wxGauge& pb = *wxStaticCast((wxObject*)win, wxGauge); +#define CAST_SLIDER(win, sc) wxSlider& sc = *wxStaticCast((wxObject*)win, wxSlider); +#define CAST_SCROLL(win, sb) wxScrollBar& sb = *wxStaticCast((wxObject*)win, wxScrollBar); +#define CAST_SCROLL_TYPE(t, dir) const int dir = t == HSCROLL ? wxHORIZONTAL : wxVERTICAL; + +int xvt_sbar_get_pos(WINDOW win, SCROLL_TYPE t) +{ + int pos = 0; + switch (t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + pos = w.GetScrollPos(dir); + } + break; + case HVGAUGE: + { + CAST_GAUGE(win, g); + pos = g.GetValue(); + } + break; + case HVSLIDER: + { + CAST_SLIDER(win, g); + pos = g.GetValue(); + } + break; + default: + { + CAST_SCROLL(win, sb); + pos = sb.GetThumbPosition(); + } + break; + } + return pos; +} + +int xvt_sbar_get_proportion(WINDOW win, SCROLL_TYPE t) +{ + int p = 1; + switch (t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + p = w.GetScrollThumb(dir); + } + break; + case HVSLIDER: + { + CAST_SLIDER(win, sc); + p = sc.GetPageSize(); + } + break; + default: + { + CAST_SCROLL(win, sb); + p = sb.GetThumbSize(); + } + break; + } + return p; +} + +void xvt_sbar_get_range(WINDOW win, SCROLL_TYPE t, int *minp, int *maxp) +{ + wxASSERT(minp && maxp); + *minp = 0; + switch (t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + *maxp = w.GetScrollRange(dir); + } + break; + case HVGAUGE: + { + CAST_GAUGE(win, g); + *maxp = g.GetRange(); + } + break; + default: + { + CAST_SCROLL(win, sb); + *maxp = sb.GetRange(); + } + break; + } +} + +void xvt_sbar_set_pos(WINDOW win, SCROLL_TYPE t, int pos) +{ + switch(t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + w.SetScrollPos(dir, pos); + } + break; + case HVGAUGE: + { + CAST_GAUGE(win, g); + if (g.GetRange() <= 1) + g.Pulse(); + else + g.SetValue(pos); + } + break; + case HVSLIDER: + { + CAST_SLIDER(win, g); + g.SetValue(pos); + } + break; + default: + { + CAST_SCROLL(win, sb); + const int range = sb.GetRange(); + const int size = sb.GetThumbSize(); + sb.SetScrollbar(pos, size, range, size); + } + break; + } +} + +void xvt_sbar_set_proportion(WINDOW win, SCROLL_TYPE t, int proportion) +{ + switch (t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + const int pos = w.GetScrollPos(dir); + const int range = w.GetScrollRange(dir); + w.SetScrollbar(dir, pos, proportion, range); + } + break; + case HVSLIDER: + { + CAST_SLIDER(win, sc); + sc.SetPageSize(proportion); + sc.SetTickFreq(sc.GetMax()/proportion, 0); + } + break; + default: + { + CAST_SCROLL(win, sb); + const int pos = sb.GetThumbPosition(); + const int range = sb.GetRange(); + sb.SetScrollbar(pos, proportion, range, proportion); + } + break; + } +} + +void xvt_sbar_set_range(WINDOW win, SCROLL_TYPE t, int min, int max) +{ + XVT_ASSERT(min == 0 && max >= min); + switch (t) + { + case HSCROLL: + case VSCROLL: + { + CAST_WIN(win, w); + CAST_SCROLL_TYPE(t, dir); + const int pos = w.GetScrollPos(dir); + const int size = w.GetScrollThumb(dir); + w.SetScrollbar(dir, pos, size, max); + } + break; + case HVGAUGE: + { + CAST_GAUGE(win, g); + g.SetRange(max); + if (max > 1) + g.SetDeterminateMode(); + else + g.SetIndeterminateMode(); + } + break; + case HVSLIDER: + { + CAST_SLIDER(win, g); + g.SetRange(min, max); + } + break; + default: + { + CAST_SCROLL(win, sb); + const int pos = sb.GetThumbPosition(); + const int size = sb.GetThumbSize(); + sb.SetScrollbar(pos, size, max, size); + } + break; + } +} + + +/////////////////////////////////////////////////////////// +// Window manager +/////////////////////////////////////////////////////////// + +void xvt_scr_beep(void) +{ + xvt_sys_beep(0); +} + +WINDOW xvt_scr_get_focus_topwin(void) +{ + wxWindow* w = _task_win->FindFocus(); + while (w != NULL && w->IsKindOf(CLASSINFO(wxControl))) + w = w->GetParent(); + return (WINDOW)w; +} + +WINDOW xvt_scr_get_focus_vobj(void) +{ + return (WINDOW)_task_win->FindFocus(); +} + +SLIST xvt_scr_list_wins() +{ + SLIST list = xvt_slist_create(); + _nice_windows.BeginFind(); + for (wxHashTable::Node* node = _nice_windows.Next(); node; node = _nice_windows.Next()) + { + wxWindow* pWin = wxDynamicCast(node->GetData(), wxWindow); + if (pWin != NULL) + { + const char* title = pWin->GetLabel(); + xvt_slist_add_at_elt(list, NULL, title, (long)pWin); + } + } + return list; +} + +void xvt_scr_set_busy_cursor() +{ + wxBeginBusyCursor(); +} + +void xvt_scr_reset_busy_cursor() +{ + wxEndBusyCursor(); +} + +void xvt_scr_set_focus_vobj(WINDOW win) +{ + CAST_WIN(win, w); + w.SetFocus(); +} + +/////////////////////////////////////////////////////////// +// String lists +/////////////////////////////////////////////////////////// + +BOOLEAN xvt_slist_add_at_elt(SLIST list, SLIST_ELT e, const char *sx, long data) +{ + const BOOLEAN ok = list != NULL; + if (ok) + { + SLIST_ELT item = new SLIST_ITEM; + item->str = xvt_str_duplicate(sx); + item->data = data; + item->next = NULL; + + SLIST_ELT last = NULL; +// if (e != NULL) // Add at head by default (else at tail) +// { + for (SLIST_ELT i = list->head; i; i = (SLIST_ELT)i->next) + { + last = i; + if (i == e) + break; + } +// } + if (last == NULL) + { + item->next = list->head; + list->head = item; + } + else + { + item->next = last->next; + last->next = item; + } + list->count++; + } + return ok; +} + +int xvt_slist_count(SLIST list) +{ + return list != NULL ? list->count : 0; +} + +SLIST xvt_slist_create() +{ + SLIST list = new xvtList; + list->head = NULL; + list->count = 0; + return list; +} + +void xvt_slist_destroy(SLIST list) +{ + if (list != NULL) + { + SLIST_ELT obj = list->head; + while (obj != NULL) + { + SLIST_ELT tokill = obj; + xvt_mem_free(tokill->str); + obj = (SLIST_ELT)tokill->next; + delete tokill; + } + delete list; + } +} + +char* xvt_slist_get(SLIST list, SLIST_ELT e, long* datap) +{ + if (list != NULL && e != NULL) + { + if (datap != NULL) + *datap = e->data; + return e->str; + } + return NULL; +} + +long* xvt_slist_get_data(SLIST_ELT elt) +{ + return elt != NULL ? &elt->data : NULL; +} + +SLIST_ELT xvt_slist_get_first(SLIST list) +{ + return list != NULL ? list->head : NULL; +} + +SLIST_ELT xvt_slist_get_next(SLIST list, SLIST_ELT item) +{ + return (SLIST_ELT)(list != NULL && item != NULL ? item->next : NULL); +} + +SLIST_ELT xvt_slist_find_str(SLIST list, const char* str) // Cerca una stringa all'interno di una SLIST +{ + SLIST_ELT e = NULL; + for (e = xvt_slist_get_first(list); e; e = xvt_slist_get_next(list, e)) + { + const char* val = xvt_slist_get(list, e, NULL); + if (xvt_str_compare_ignoring_case(str, val) == 0) + break; + } + return e; +} + +/////////////////////////////////////////////////////////// +// XVT Strings??? +/////////////////////////////////////////////////////////// + +int xvt_str_compare_ignoring_case(const char* s1, const char* s2) +{ + return s1 && s2 ? wxStricmp(s1, s2) : -883; +} + +BOOLEAN xvt_str_same(const char* s1, const char* s2) +{ + return s1 && s2 && wxStricmp(s1, s2) == 0; +} + +char * xvt_str_exec_dir() +{ + wxString dir = xvt_fsys_get_default_dir_name(); + + return xvt_str_duplicate(dir); +} + +char* xvt_str_duplicate(const char* str) +{ + return str ? wxStrdup(str) : NULL; // bleah! +} + +char* xvt_str_number_format(char* str, int size) +{ +#ifdef __WXMSW__ + OsWin32_NumberFormat(str, size); +#else + wxString txt; + for (const char* s = str; *s; s++) + { + if (isdigit(*s)) + txt << *s; + else + { + if (*s == '.') + txt << ','; + } + } + wxStrncpy(str, txt, size); +#endif + return str; +} + +static const char* const ENCRYPTION_KEY = "QSECOFR-"; + +int xvt_str_encode(const char* text, char* cipher, int mode) +{ + int i = 0; + switch (mode) + { + case 1: // BASE64 + break; + default: // AGA + for (i = 0; text[i]; i++) + cipher[i] = text[i] + (i < 8 ? ENCRYPTION_KEY[i] : text[i - 8]); + cipher[i] = '\0'; + break; + } + return i; +} + +int xvt_str_decode(const char* cipher, char* text, int mode) +{ + int i = 0; + switch (mode) + { + case 1: // BASE64 + break; + default: // AGA + for (i = 0; cipher[i]; i++) + text[i] = cipher[i] - (i < 8 ? ENCRYPTION_KEY[i] : text[i - 8]); + text[i] = '\0'; + break; + } + return i; +} + +size_t xvt_str_base64_len(size_t len) +{ + return 4 * ((len + 2) / 3) + 1; +} + +#define BUFFERSIZE 65536 + +int xvt_str_base64_encode(const char *name, char *cypher) +{ + base64_encodestate state; + ifstream input(name, ios::binary); + int res = 0; + unsigned char plaintext[BUFFERSIZE]; + char code[2 * BUFFERSIZE]; + int plainlength; + int codelength; + + base64_init_encodestate(&state); + do + { + input.read((char *) plaintext, BUFFERSIZE); + plainlength = input.gcount(); + codelength = base64_encode_block(plaintext, plainlength, code, &state); + for (int i = 0; i < codelength; i++) + cypher[res++] = code[i]; + } while (input.good() && plainlength > 0); + + codelength = base64_encode_blockend(code, &state); + for (int i = 0; i < codelength; i++) + cypher[res++] = code[i]; + cypher[res] = '\0'; + base64_init_encodestate(&state); + return res; +} + +int xvt_str_base64_decode(const char *cypher, long len, unsigned char *text) +{ + base64_decodestate state; + + base64_init_decodestate(&state); + + int res = base64_decode_block(cypher, len, text, &state); + base64_init_decodestate(&state); + text[res + 1] = '\0'; + return res; +} + +BOOLEAN xvt_str_match(const char* mbs, const char *pat, BOOLEAN case_sensitive) +{ +/* + // Attualmente la wxString::Matches funziona solo con * e ? :-( + wxString text = mbs; + wxString pattern = pat; + if (!case_sensitive) + { + text.MakeUpper(); + pattern.MakeUpper(); + } + return text.Matches(pattern); +*/ + + // Uso la vecchia funzione implementata anticamente in agalib + if (case_sensitive) + return match(pat, mbs); + + wxString text = mbs; text.MakeUpper(); + wxString pattern = pat; pattern.MakeUpper(); + return match(pattern, text); +} + +void xvt_str_make_upper(char* str) +{ + wxString s(str); + s.MakeUpper(); + wxStrcpy(str, s); +} + +void xvt_str_make_lower(char* str) +{ + wxString s(str); + s.MakeLower(); + wxStrcpy(str, s); +} + +double xvt_str_fuzzy_compare (const char* s1, const char* s2) +{ + return fstrcmp(s1, s2); +} + +double xvt_str_fuzzy_compare_ignoring_case (const char* s1, const char* s2) +{ + wxString str1(s1); str1.MakeUpper(); + wxString str2(s2); str2.MakeUpper(); + return fstrcmp(str1, str2); +} + +BOOLEAN xvt_chr_is_digit(int c) +{ + return (c <= 255) && wxIsdigit(c); +} + +BOOLEAN xvt_chr_is_alpha(int c) +{ + return (c <= 255) && wxIsalpha(c); +} + +BOOLEAN xvt_chr_is_alnum(int c) +{ + return (c <= 255) && wxIsalnum(c); +} + +int xvt_net_get_status() +{ + wxDialUpManager* dum = nullptr; + int nStatus = 0; + //stoppa il log di wxWidgets per non avere segnalazioni di errori incomprensibili! + const bool bLogEnabled = wxLog::EnableLogging(false); + + if (dum == nullptr) + dum = wxDialUpManager::Create(); + if (dum != nullptr) + { + if (dum->IsOk() && dum->IsOnline()) + { + nStatus = 0x1; // 1 = Online + + if (dum->IsAlwaysOnline()) + { + nStatus |= 0x2; // 2 = Always Online + wxIPV4address addr; + if (addr.Hostname("www.google.com")) + nStatus |= 0x4; // 4 = Connected to web + } + } + // delete dum; + // dum = nullptr; + } + wxLog::EnableLogging(bLogEnabled); + return nStatus; +} + +/////////////////////////////////////////////////////////// +// XVT system calls (added by Guy) +/////////////////////////////////////////////////////////// + +void xvt_sys_beep(int severity) +{ +#ifdef __WXMSW__ + OsWin32_Beep(severity); +#else + wxBell(); +#endif +} + +BOOLEAN xvt_sys_get_host_name(char* name, int maxlen) +{ + wxString str = wxGetHostName(); + wxStrncpy(name, str, maxlen); + name[maxlen-1] = '\0'; + return *name > '\0'; +} + +BOOLEAN xvt_sys_get_user_name(char* name, int maxlen) +{ + wxString str = wxGetUserId(); + wxStrncpy(name, str, maxlen); + name[maxlen-1] = '\0'; + return *name > '\0'; +} + +/////////////////////////////////////////////////////////// +// TIconizeTaskThread +/////////////////////////////////////////////////////////// +static bool __bChildRunning = false; + +class TIconizeTaskThread : public wxThread +{ +protected: + virtual ExitCode Entry(); +public: + TIconizeTaskThread(); +}; + +wxThread::ExitCode TIconizeTaskThread::Entry() +{ + ::wxMilliSleep(500); + if (__bChildRunning) // Il programma e' ancora attivo + _task_win->Iconize(); + return 0; +} + +TIconizeTaskThread::TIconizeTaskThread() +{ + Create(); + SetPriority(WXTHREAD_MIN_PRIORITY); + Run(); +} + +/////////////////////////////////////////////////////////// +// Process processing +/////////////////////////////////////////////////////////// + +const char * xvt_sys_command() +{ + return OsWin32_CommandLine(); +} + + +long xvt_sys_execute(const char* cmdline, BOOLEAN sync, BOOLEAN iconizetask) +{ + long exitcode = 0; + wxString cmd(cmdline); + +#ifdef LINUX + if (isalpha(cmd[0u])) + cmd = "./" + cmd; +#endif + + if (sync) + { + if (iconizetask) + { + wxEnableTopLevelWindows(FALSE); + + TIconizeTaskThread* it = new TIconizeTaskThread(); // No need to delete + if (it != NULL) + { + __bChildRunning = true; + exitcode = wxExecute(cmd, wxEXEC_SYNC); + __bChildRunning = false; + + if (_task_win->IsIconized()) + _task_win->Restore(); + wxEnableTopLevelWindows(TRUE); + } + } + else + exitcode = wxExecute(cmd, wxEXEC_SYNC); // Valutare wxEXEC_NODISABLE + if (!_task_win->IsIconized()) + _task_win->Raise(); + } + else + { + // Qui iconizetask significa nascondi processo a task_win + if (_task_win != NULL && _task_win_handler != NULL && !iconizetask) + { + wxProcess* p = new wxProcess(_task_win->GetEventHandler(), wxID_ANY); + exitcode = wxExecute(cmd, wxEXEC_ASYNC, p); + if (exitcode > 0) + { + XVT_EVENT e(E_PROCESS); + e.v.process.msg_id = E_CREATE; + e.v.process.pid = exitcode; + _task_win_handler((WINDOW)_task_win, &e); + } + else + delete p; + } + else + exitcode = wxExecute(cmd, wxEXEC_ASYNC); + } + + return exitcode; +} + +BOOLEAN xvt_sys_kill(long pid) +{ + BOOLEAN bKilled = wxProcess::Kill(pid, wxSIGTERM, wxKILL_CHILDREN) == wxKILL_OK; + if (!bKilled) + bKilled = wxProcess::Kill(pid, wxSIGKILL, wxKILL_CHILDREN) == wxKILL_OK; + if (bKilled && _task_win != NULL && _task_win_handler != NULL) + { + XVT_EVENT e(E_PROCESS); + e.v.process.msg_id = E_DESTROY; + e.v.process.pid = pid; + _task_win_handler((WINDOW)_task_win, &e); + } + return bKilled; +} + +long xvt_sys_execute_in_window(const char* cmdline, WINDOW win) +{ + const long inst = xvt_sys_execute(cmdline, FALSE, FALSE); + if (inst > 0 && win != NULL_WIN) + { + CAST_WIN(win, w); +#ifdef __WXMSW__ + OsWin32_PlaceProcessInWindow(inst, "", (unsigned int)w.GetHandle()); +#else + OsLinux_PlaceProcessInWindow(inst, "", w.GetHandle()); +#endif + } + return inst; +} + +long xvt_sys_close_children(WINDOW win) +{ + long c = 0; +#ifdef __WXMSW__ + CAST_WIN(win, w); + c = OsWin32_CloseChildren((unsigned int)w.GetHandle()); +#endif + return c; +} + +BOOLEAN xvt_sys_goto_url(const char* url, const char* action) +{ +#ifdef __WXMSW__ + if (action && *action && !xvt_str_same(action, "open")) + return OsWin32_GotoUrl(url, action); +#endif + return wxLaunchDefaultBrowser(url); +} + +int xvt_sys_dongle_server_running() +{ + int s = 0; + if (OsWin32_ProcessModule("Authoriz.exe")) + s |= 1; + return s; +} + +#define OEM_INI wxString(_startup_dir+wxT("/setup/oem.ini")) + +void xvt_sys_set_oem(int oem) +{ + __oem = oem; +} + +long xvt_sys_get_oem_int(const char* name, long defval) +{ + if (__oem >= 0) + { + if (wxStricmp(name, wxT("OEM")) != 0) + { + wxString strPara; strPara.Printf(wxT("OEM_%d"), __oem); + defval = xvt_sys_get_profile_int(OEM_INI, strPara, name, defval); + } + else + return __oem; + } + return defval; +} + +int xvt_sys_get_oem_string(const char* name, const char* defval, char* value, int maxsize) +{ + if (__oem >= 0) + { + if (wxStricmp(name, wxT("OEM")) != 0) + { + wxString strPara; strPara.Printf(wxT("OEM_%d"), __oem); + return xvt_sys_get_profile_string(OEM_INI, strPara, name, defval, value, maxsize); + } + else + { + wxString str; str.Printf("%d", __oem); + wxStrncpy(value, str, maxsize); + return 1; + } + } + return 0; +} + +int xvt_sys_get_profile_string(const char* file, const char* paragraph, const char* name, + const char* defval, char* value, int maxsize) +{ + if (file == NULL || *file == '\0') + file = xvt_fsys_get_campo_ini(); + +/* + if (!(paragraph && *paragraph) && wxStricmp(file, "ssa.ini") == 0) + { + if (xvt_fsys_file_exists(file)) + { + wxTextFile ssa; + ssa.Open(file); + for (wxString str = ssa.GetFirstLine(); !ssa.Eof(); str = ssa.GetNextLine()) + { + str.Trim(false); + if (str.StartsWith(name)) + { + str = str.AfterFirst('='); + str.Trim(true); str.Trim(false); + wxStrncpy(value, str, maxsize-1); + return str.Len(); + } + } + } + wxStrncpy(value, defval, maxsize-1); + return wxStrlen(defval); + } +*/ + + if (!(paragraph && *paragraph)) + paragraph = "Main"; + +#ifdef __WXMSW__ + int len = ::GetPrivateProfileString(paragraph, name, defval, value, maxsize, file); +#else + wxFileConfig ini("", "", file, "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH); + + wxString path; + path << "/" << paragraph; + ini.SetPath(path); + + int len = 0; + wxString val; + if (!ini.Read(name, &val)) + val = defval; + + len = val.Length(); + if (value) + { + wxStrncpy(value, val, maxsize); + value[maxsize-1] = '\0'; + } +#endif + + return len; +} + +long xvt_sys_get_profile_int(const char* file, const char* paragraph, const char* name, long defval) +{ + char defstr[16] = { 0 }, str[16] = { 0 }; + long value = defval; + if (defval != 0) + wxSprintf(defstr, "%ld", defval); + if (xvt_sys_get_profile_string(file, paragraph, name, defstr, str, sizeof(str))) + value = atol(str); + return value; +} + +BOOLEAN xvt_sys_set_profile_int(const char* file, const char* paragraph, const char* name, long value) +{ + char str[16] = { 0 }; wxSprintf(str, "%ld", value); + return xvt_sys_set_profile_string(file, paragraph, name, str); +} + +BOOLEAN xvt_sys_set_profile_string(const char* file, const char* paragraph, const char* name, const char* value) +{ + if (file == NULL || *file == '\0') + file = xvt_fsys_get_campo_ini(); + + if (paragraph == NULL || *paragraph == '\0') + paragraph = "Main"; + +#ifdef __WXMSW__ + return ::WritePrivateProfileString(paragraph, name, value, file) > 0; +#else + wxFileConfig ini("", "", file, "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH); + ini.SetUmask(0x0); + + wxString path; + path << "/" << paragraph; + ini.SetPath(path); + + return ini.Write(name, value); +#endif +} + +XVTDLL BOOLEAN xvt_sys_remove_profile_string(const char* file, const char* paragraph, const char* name) +{ + if (file == NULL || *file == '\0') + file = xvt_fsys_get_campo_ini(); + + if (paragraph == NULL || *paragraph == '\0') + paragraph = "Main"; + +#ifdef __WXMSW__ + return ::WritePrivateProfileString(paragraph, name, nullptr, file) > 0; +#else + wxFileConfig ini("", "", file, "", wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH); + ini.SetUmask(0x0); + + wxString path; + path << "/" << paragraph; + ini.SetPath(path); + + return ini.DeleteEntry(name); +#endif +} + +BOOLEAN xvt_sys_find_editor(const char* file, char* editor) +{ + BOOLEAN ok = FALSE; + +#ifdef __WXMSW__ + const wxString e = OsWin32_File2App(file); +#else + const wxString e = OsLinux_File2App(file); +#endif + ok = !e.IsEmpty(); + if (ok && editor != NULL) + wxStrncpy(editor, e, _MAX_PATH); + + return ok; +} + + +int xvt_sys_get_session_id() +{ +#ifdef __WXMSW__ + return OsWin32_GetSessionId(); +#else + return OsLinux_GetSessionId(); +#endif +} + +unsigned long xvt_sys_get_free_memory() +{ + const wxMemorySize sz = ::wxGetFreeMemory(); + return sz.GetHi() ? -1 : sz.GetLo(); +} + +unsigned long xvt_sys_get_free_memory_kb() +{ + const wxMemorySize sz = ::wxGetFreeMemory() / 1024; // Arrotondo per difetto + return sz.GetHi() ? -1 : sz.GetLo(); +} + +int xvt_sys_get_os_version() +{ + int os = 0; +#ifdef __WXMSW__ + int nVersion = 0; + ::GetWinVer(NULL, 0, &nVersion); // Implemented in XFont.cpp, not a Win32 API + switch (nVersion) + { + case 101: + case 102: os = XVT_WS_WIN_NT; break; + case 103: os = XVT_WS_WIN_2000; break; + case 104: os = XVT_WS_WIN_XP; break; + case 105: os = XVT_WS_WIN_2003; break; + case 106: os = XVT_WS_WIN_VISTA; break; + case 107: os = XVT_WS_WIN_2008; break; + case 108: os = XVT_WS_WIN_2008R2; break; + case 109: os = XVT_WS_WIN_7; break; + case 110: os = XVT_WS_WIN_2012; break; + case 111: os = XVT_WS_WIN_8; break; + default : os = XVT_WS_WIN_10; break; + } +#endif + + return os; +} + +BOOLEAN xvt_sys_is_pda() +{ + wxSize sz; + if (_task_win == NULL) + { + sz.x = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); + sz.y = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); + } + else + sz = _task_win->GetSize(); + return max(sz.x,sz.y) <= 640; +} + +int xvt_sys_get_version(char* os_version, char* ptk_version, int maxsize) +{ + const int version = xvt_sys_get_os_version(); + if (os_version && maxsize >= 8) + { +#ifdef __WXMSW__ + if (version >= XVT_WS_WIN_VISTA) // wxWidgets non sa descrivere i moderni sistemi Microsoft + ::GetWinVer(os_version, maxsize, NULL); // wxWidgets non sa descrivere i moderni sistemi Microsoft + else +#endif + + wxStrncpy(os_version, wxGetOsDescription(), maxsize); + } + if (ptk_version && maxsize >= 8) + wxStrncpy(ptk_version, wxVERSION_STRING, maxsize); + return version; +} + +void xvt_sys_sleep(unsigned long msec) +{ + ::wxMilliSleep(msec); +} + +/////////////////////////////////////////////////////////// +// XVT system calls +/////////////////////////////////////////////////////////// + +XVTDLL BOOLEAN xvt_sys_get_env(const char* varname, char* value, int max_size) +{ + const wxString strName(varname); + wxString strValue; + const bool ok = wxGetEnv(strName, &strValue); + if (ok) + wxStrncpy(value, strValue, max_size); + return ok; +} + +void xvt_sys_search_env(const char * filename, const char * varname, char * pathname) +{ +#ifdef __WXMSW__ + _searchenv(filename, varname, pathname); +#else + const char * value = wxGetEnv(varname); + if (value) + { + char path_list[4096]; + strcpy(path_list, value); + for (const char* s = path_list; *s; ) + { + char* s1 = strchr(s, ';'); + if (s1 != NULL) + *s1 = '\0'; + xvt_fsys_build_pathname(pathname, NULL, s, filename, NULL, NULL); + if (xvt_fsys_file_exists(pathname)) + break; + if (s1 != NULL) + s = s1 + 1; + else + break; + } + } + else + *pathname = '\0'; +#endif +} + +BOOLEAN xvt_sys_set_env(const char* varname, const char* value) +{ + const wxString strName(varname); + return value != NULL ? wxSetEnv(strName, value) : wxUnsetEnv(strName); +} + +// BOOLEAN o int? Adso! +int xvt_fsys_access(const char *pathname, int mode) +{ + const wxURL url(pathname); + const wxString scheme = url.GetScheme(); + + if (scheme == "ftp" || scheme == "http") + { + if (mode & 4) + return ENOEXEC; + if (mode & 2 && scheme == "http") + return EACCES; + + if (scheme == "ftp") + { + const wxFileName fnPath = url.GetPath(); + const wxString fnDir = fnPath.GetPath(wxPATH_GET_VOLUME, wxPATH_UNIX); + const wxString fnName = fnPath.GetFullName(); + if (fnName.IsEmpty()) // Test for directory existence + { + const wxString strHost = url.GetServer(); + const wxString strUser = url.GetUser(); + const wxString strPwd = url.GetPassword(); + wxFTP ftp; + if (!strUser.IsEmpty()) + { + ftp.SetUser(strUser); + ftp.SetPassword(strPwd); + } + ftp.SetPassive(xvt_sys_ftp_passive_mode(strHost)); + return ftp.Connect(strHost) && ftp.ChDir(fnDir) ? 0 : EACCES; + } + } + SLIST files = xvt_fsys_list_files("", pathname, true); + const int count = xvt_slist_count(files); + + xvt_slist_destroy(files); + return count > 0 ? 0 : ENOENT; + } + return wxAccess(pathname, mode) == -1 ? errno : 0; +} + +BOOLEAN xvt_fsys_dir_exists(const char *pathname) +{ + return wxDirExists(pathname); +} + +BOOLEAN xvt_fsys_file_exists(const char *pathname) +{ + int err = xvt_fsys_access(pathname, 0); + // Ritorno true se non ho trovato errori o non ho l'accesso al file (potrebbe essere anche bloccato) + return err == 0 || err == EACCES; +} + +BOOLEAN xvt_fsys_mkdir(const char *pathname) +{ + // Crea l'intero albero di cartelle senza dare errori se esistono gia' + return wxFileName::Mkdir(pathname, 0777, wxPATH_MKDIR_FULL); +} + +BOOLEAN xvt_fsys_rmdir(const char *pathname) +{ + if (!wxDirExists(pathname)) + return TRUE; + return wxRmdir(pathname); +} + +BOOLEAN xvt_fsys_remove_file(const char *pathname) +{ + wxURL url(pathname); + wxString scheme = url.GetScheme(); + + if (scheme == "ftp") + { + wxFTP ftp; + const wxString strHost = url.GetServer(); + const wxString strUser = url.GetUser(); + const wxString strPwd = url.GetPassword(); + const wxFileName fnPath = url.GetPath(); + const wxString fnDir = fnPath.GetPath(wxPATH_GET_VOLUME, wxPATH_UNIX); + const wxString fnName = fnPath.GetFullName(); + + if (!strUser.IsEmpty()) + { + ftp.SetUser(strUser); + ftp.SetPassword(strPwd); + } + ftp.SetPassive(xvt_sys_ftp_passive_mode(strHost)); + + if (ftp.Connect(strHost)) + if (ftp.ChDir(fnDir)) + return ftp.RmFile(fnName); + return false; + } + else + if (scheme == "http") + return false; + return wxRemoveFile(pathname); +} + +BOOLEAN xvt_fsys_rename_file(const char *src_pathname, const char *dst_pathname) +{ + return wxRenameFile(src_pathname, dst_pathname); +} + +BOOLEAN xvt_fsys_fupdate(const char* src, const char* dst) // Aggiorna il file dst se più vecchio di src +{ + bool ok = false; + if (xvt_fsys_file_exists(src)) + { + const long tsrc = xvt_fsys_file_attr(src, XVT_FILE_ATTR_MTIME); + if (tsrc > 0) + { + long tdst = 0; + if (xvt_fsys_file_exists(dst)) + tdst = xvt_fsys_file_attr(dst, XVT_FILE_ATTR_MTIME); + if (tsrc > tdst) + ok = xvt_fsys_fcopy(src, dst) != 0; + } + } + + return ok; +} + +/////////////////////////////////////////////////////////// +// Timers +/////////////////////////////////////////////////////////// + +struct tm* xvt_time_now() +{ return wxDateTime::GetTmNow(); } + +long xvt_timer_create(WINDOW win, long interval) +{ + CAST_TWIN(win, w); + if (w._timer == NULL) + w._timer = new wxTimer(&w, TIMER_ID); + w._timer->Start(interval); + return win; +} + +void xvt_timer_destroy(long id) +{ + if (id > 0L) + { + CAST_TWIN(id, w); + wxTimer*& t = w._timer; + if (t != NULL) + { + t->Stop(); + delete t; + t = NULL; + } + } +} + +/////////////////////////////////////////////////////////// +// Visual objects +/////////////////////////////////////////////////////////// + +static wxWindow* SafeCastWin(WINDOW win) +{ + wxWindow* w = wxDynamicCast(_nice_windows.Get(win), wxWindow); + if (w != NULL) + { + wxASSERT(win == (WINDOW)w); + const TwxWindow* tw = wxDynamicCast(w, TwxWindow); + if (tw != NULL && tw->InDestroy()) + w = NULL; + } + return w; +} + +void xvt_vobj_destroy(WINDOW win) +{ + wxWindow* w = SafeCastWin(win); + if (w != NULL) + { + xvt_win_set_caret_visible(win, FALSE); + w->Destroy(); // same as delete w + _nice_windows.Delete(win); // Elimina "di nuovo" dalla lista delle finestre attive + } else + if (win == PRINTER_WIN) + GetTDCMapper().DestroyTDC(win); +} + +static long xvt_vobj_get_metric(WINDOW win, wxSystemMetric data) +{ + wxWindow* w = wxDynamicCast((wxObject*)win, wxWindow); + if (w == NULL) w = _task_win; + long ret = wxSystemSettings::GetMetric(data, w); + return ret; +} + +long xvt_vobj_get_attr(WINDOW win, long data) +{ + long ret = 0L; + + switch(data) + { + case ATTR_APP_CTL_COLORS: + { + XVT_COLOR_COMPONENT* xcc = (XVT_COLOR_COMPONENT*)xvt_mem_zalloc(sizeof(XVT_COLOR_COMPONENT)*16); + if (win != NULL_WIN && win != SCREEN_WIN) + { + TTaskWin* tw = wxDynamicCast(_task_win, TTaskWin); + if (tw != NULL) + { + const XVT_COLOR_COMPONENT* tcc = tw->GetCtlColors(); + int c = 0; + for (c = 0; c < 15 && tcc[c].type != XVT_COLOR_NULL; c++); + memcpy(xcc, tcc, (c+1)*sizeof(XVT_COLOR_COMPONENT)); + return long(xcc); + } + } + // XVT components + xcc[0].type = XVT_COLOR_FOREGROUND; + xcc[0].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT)); + xcc[1].type = XVT_COLOR_BACKGROUND; + xcc[1].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + xcc[2].type = XVT_COLOR_BLEND; + xcc[2].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT)); + xcc[3].type = XVT_COLOR_BORDER; + xcc[3].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + xcc[4].type = XVT_COLOR_SELECT; + xcc[4].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); + xcc[5].type = XVT_COLOR_HIGHLIGHT; + xcc[5].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); + xcc[6].type = XVT_COLOR_TROUGH; + xcc[6].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + // AGA components + xcc[7].type = XVT_COLOR_CAPTIONLT; + xcc[7].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION)); + xcc[8].type = XVT_COLOR_CAPTIONDK; + xcc[8].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_INACTIVECAPTION)); + xcc[9].type = XVT_COLOR_CAPTIONTEXT; + xcc[9].color = MAKE_XVT_COLOR(wxSystemSettings::GetColour(wxSYS_COLOUR_CAPTIONTEXT)); + + // Ensure last (NULL) component + xcc[15].type = XVT_COLOR_NULL; + xcc[15].color = 0; + ret = (long)xcc; + } + break; + case ATTR_APPL_VERSION_STRING: + ret = (long)(const char*)_appl_version; + break; + case ATTR_APPL_VERSION_YEAR: + if (_appl_version.IsEmpty()) + ret = 2151; + else + ret = wxAtoi(_appl_version.Left(4)); + break; + case ATTR_APPL_ALREADY_RUNNING: + ret = _appl_already_running; + break; + case ATTR_DOCFRAME_WIDTH: + case ATTR_FRAME_WIDTH: + ret = xvt_vobj_get_metric(win, wxSYS_FRAMESIZE_X); + break; + case ATTR_DOCFRAME_HEIGHT: + case ATTR_FRAME_HEIGHT: + ret = xvt_vobj_get_metric(win, wxSYS_FRAMESIZE_Y); + break; + case ATTR_MENU_HEIGHT: + ret = xvt_vobj_get_metric(win, wxSYS_MENU_Y); + break; + case ATTR_TITLE_HEIGHT: + ret = xvt_vobj_get_metric(win, wxSYS_CAPTION_Y); + break; + case ATTR_CTL_VERT_SBAR_WIDTH: + ret = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + break; + case ATTR_CTL_HORZ_SBAR_HEIGHT: + ret = wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); + break; + case ATTR_DISPLAY_TYPE: + switch (::wxDisplayDepth()) // Test ormai ridicolo? + { + case 1: ret = XVT_DISPLAY_MONO; break; // Ridicolissimo :-) + case 4: ret = XVT_DISPLAY_COLOR_16; break; + case 8: ret = XVT_DISPLAY_COLOR_256; break; + default: ret = XVT_DISPLAY_DIRECT_COLOR; break; + } + break; + case ATTR_ERRMSG_HANDLER: + ret = (long)_error_handler; + break; + case ATTR_NATIVE_GRAPHIC_CONTEXT: + SORRY_BOX(); // Obsoleto e non piu' usato + break; + case ATTR_NATIVE_WINDOW: + { + const wxWindow* w = SafeCastWin(win); + if (w != NULL) + ret = (long)w->GetHandle(); + } + break; + case ATTR_PRINTER_HEIGHT: + xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, NULL, &ret, NULL, NULL, NULL); + break; + case ATTR_PRINTER_HRES: + xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, NULL, NULL, NULL, NULL, &ret); + break; + case ATTR_PRINTER_VRES: + xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, NULL, NULL, NULL, &ret, NULL); + break; + case ATTR_PRINTER_WIDTH: + xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, NULL, NULL, &ret, NULL, NULL); + break; + case ATTR_SCREEN_HEIGHT: + ret = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); + break; + case ATTR_SCREEN_WIDTH: + ret = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); + break; + case ATTR_SCREEN_WINDOW: + ret = 882L; // Scelta arbitraria ma accettabile + break; + case ATTR_SPEECH_MODE: + ret = xvt_dm_speech_enabled(); + break; + case ATTR_TASK_WINDOW: + ret = long(_task_win); + break; + case ATTR_PRINTER_WINDOW: + ret = 883L; // Scelta arbitraria ma accettabile + break; + case ATTR_WIN_INSTANCE: + ret = 0; + break; + case ATTR_WIN_OPENFILENAME_HOOK: + ret = 0; + break; + case ATTR_WIN_PM_DRAWABLE_TWIN: + ret = TRUE; + break; + case ATTR_WIN_PM_TWIN_STARTUP_STYLE: + ret = _startup_style; + break; + case ATTR_ICON_WIDTH: + ret = xvt_vobj_get_metric(win, wxSYS_ICON_X); + break; + case ATTR_ICON_HEIGHT: + ret = xvt_vobj_get_metric(win, wxSYS_ICON_Y); + break; + default: + SORRY_BOX(); + break; + } + return ret; +} + +RCT* xvt_vobj_get_client_rect(WINDOW win, RCT *rctp) +{ + XVT_ASSERT(rctp != NULL); + int l = 0, h = 0; + switch (win) + { + case NULL_WIN: + l = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); + h = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); + break; + case 882: // SCREEN_WIN + l = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); + h = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) - 32; // Puerile tentativo di escludere la task bar + break; + case PRINTER_WIN: + l = 4600; h = 6800; // circa A4 size at 600 DPI + break; + default: + { + CAST_WIN(win, w); + w.GetClientSize(&l, &h); + } + break; + } + xvt_rect_set(rctp, 0, 0, l, h); + return rctp; +} + +long xvt_vobj_get_data(WINDOW win) +{ + const TwxWindow* w = wxDynamicCast(SafeCastWin(win), TwxWindow); + return w != NULL ? w->_app_data : 0L; +} + +RCT* xvt_vobj_get_outer_rect(WINDOW win, RCT *rctp) +{ + if (win != NULL_WIN) + { + if (win == SCREEN_WIN) + { + const short sx = wxSystemSettings::GetMetric(wxSYS_SCREEN_X); + const short sy = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y); + xvt_rect_set(rctp, 0, 0, sx, sy); + } + else + { + CAST_WIN(win, w); + const wxRect rct = w.GetRect(); + Rect2RCT(rct, rctp); + } + } + else + xvt_rect_set_null(rctp); + + return rctp; +} + +XVT_PALETTE xvt_vobj_get_palet(WINDOW WXUNUSED(win)) +{ return NULL; } + +WINDOW xvt_vobj_get_parent(WINDOW win) +{ + if (win == NULL_WIN || win == TASK_WIN || win == SCREEN_WIN) + return NULL_WIN; + CAST_WIN(win, w); + return (WINDOW)w.GetParent(); +} + +char* xvt_vobj_get_title(WINDOW win, char *title, int sz_title) +{ + if (win == NULL_WIN) + return NULL; + CAST_WIN(win, w); + wxStrncpy(title, w.GetLabel(), sz_title); + title[sz_title-1] = '\0'; + return title; +} + +BOOLEAN xvt_vobj_is_focusable(WINDOW win) +{ + BOOLEAN ok = win != NULL_WIN && win != PRINTER_WIN && + win != TASK_WIN && win != SCREEN_WIN && + xvt_vobj_is_valid(win); + if (ok) + { + CAST_WIN(win, w); + ok = w.IsEnabled() && w.IsShownOnScreen(); + } + return ok; +} + +BOOLEAN xvt_vobj_is_valid(WINDOW win) +{ + return win != NULL_WIN && SafeCastWin(win) != NULL; +} + +void xvt_vobj_maximize(WINDOW win) +{ + XVT_ASSERT(win != NULL_WIN && _task_win != NULL); + if (win == TASK_WIN) + _task_win->Maximize(); + else + { + CAST_WIN(win, w); + + wxWindow* parent = w.GetParent(); + + if (parent == NULL) + parent = _task_win; + int width, height; + parent->GetClientSize(&width, &height); + w.SetSize(0, 0, width, height); + } +} + +void xvt_vobj_minimize(WINDOW win) +{ + wxFrame* pMain = wxDynamicCast((wxObject*)win, wxFrame); + + if (pMain != nullptr) + pMain->Iconize(!pMain->IsIconized()); + else + SORRY_BOX(); + +} + +BOOLEAN xvt_vobj_maximized(WINDOW win) +{ + wxFrame* pMain = wxDynamicCast((wxObject*)win, wxFrame); + BOOLEAN maximized = true; + + if (pMain != nullptr) + maximized = !pMain->IsIconized(); + return maximized != 0; +} + +void xvt_vobj_hide(WINDOW win) +{ + wxFrame * pMain = wxDynamicCast((wxObject*)win, wxFrame); + + if (pMain != nullptr) + pMain->Hide(); + else + { + wxWindow * pWin = wxDynamicCast((wxObject*)win, wxWindow); + + if (pWin != nullptr) + pWin->Hide(); + else + SORRY_BOX(); + } +} + +void xvt_vobj_show(WINDOW win) +{ + wxFrame* pMain = wxDynamicCast((wxObject*)win, wxFrame); + + if (pMain != nullptr) + { + if (!pMain->IsShown()) + pMain->Show(); + } + else + { + wxWindow * pWin = wxDynamicCast((wxObject*)win, wxWindow); + + if (pWin != nullptr) + { + if (!pWin->IsShown()) + pWin->Show(); + } + else + SORRY_BOX(); + } +} + +BOOLEAN xvt_vobj_shown(WINDOW win) +{ + wxFrame* pMain = wxDynamicCast((wxObject*)win, wxFrame); + BOOLEAN shown = true; + + if (pMain != nullptr) + shown = pMain->IsShown(); + else + { + wxWindow * pWin = wxDynamicCast((wxObject*)win, wxWindow); + + if (pWin != nullptr) + shown = pWin->IsShown(); + } + return shown != 0; +} + +void xvt_vobj_move(WINDOW win, const RCT* rctp) +{ + CAST_WIN(win, w); + const wxRect rct = RCT2Rect(rctp); + w.Move(rct.x, rct.y); + w.SetClientSize(rct.width, rct.height); +} + +void xvt_vobj_raise(WINDOW win) +{ + CAST_WIN(win, w); + w.Raise(); +} + +static void SetArtistColor(WINDOW win, int id, long rgb) +{ + CAST_WIN(win, w); + const wxAuiManager* pMgr = wxAuiManager::GetManager(&w); + wxAuiDockArt* pArt = (pMgr != NULL) ? pMgr->GetArtProvider() : NULL; + if (pArt != NULL) + { + CAST_COLOR(rgb, col); + pArt->SetColour(id, col); + if (id == wxAUI_DOCKART_BACKGROUND_COLOUR) + { + } + } +} + +void xvt_vobj_set_attr(WINDOW win, long data, long value) +{ + switch (data) + { + case ATTR_APP_CTL_COLORS: + if (win == TASK_WIN) + { + TTaskWin* tw = wxDynamicCast(_task_win, TTaskWin); + if (tw != NULL) + tw->SetCtlColors((XVT_COLOR_COMPONENT*)value); + } + break; + case ATTR_APPL_VERSION_STRING: _appl_version = (const char*)value; break; + case ATTR_APPL_ALREADY_RUNNING: _appl_already_running = value != 0; break; + case ATTR_BACK_COLOR: SetArtistColor(win, wxAUI_DOCKART_BACKGROUND_COLOUR, value); break; + case ATTR_ERRMSG_HANDLER: _error_handler = (XVT_ERRMSG_HANDLER)value; break; + case ATTR_EVENT_HOOK: SORRY_BOX(); break; // TBI?: Native events hook! + case ATTR_WIN_PM_DRAWABLE_TWIN: break; // Ignored: Always TRUE + case ATTR_WIN_PM_TWIN_STARTUP_RCT: _startup_rect = *(RCT*)value; break; + case ATTR_WIN_PM_TWIN_STARTUP_STYLE: _startup_style = value; break; + case ATTR_SPEECH_MODE: xvt_dm_speech_enable(value); break; + default: SORRY_BOX(); break; + } +} + +void xvt_vobj_set_data(WINDOW win, long app_data) +{ + CAST_TWIN(win, w); + w._app_data = app_data; +} + +void xvt_vobj_set_enabled(WINDOW win, BOOLEAN enabled) +{ + CAST_WIN(win, w); + w.Enable(enabled != 0); +} + +void xvt_vobj_set_palet(WINDOW WXUNUSED(win), XVT_PALETTE WXUNUSED(palet)) +{ + // Do not implement! +} + +void xvt_vobj_set_title(WINDOW win, const char* title) +{ + CAST_WIN(win, w); + w.SetLabel(title); +} + +void xvt_vobj_set_visible(WINDOW win, BOOLEAN show) +{ + CAST_WIN(win, w); + w.Show(show != 0); +} + +void xvt_vobj_translate_points(WINDOW from_win, WINDOW to_win, PNT *pntp, int npnts) +{ + XVT_ASSERT(from_win != NULL_WIN && to_win != NULL_WIN); + XVT_ASSERT(pntp != NULL && npnts > 0); + CAST_WIN(from_win, w1); + CAST_WIN(to_win, w2); + for (int i = 0; i < npnts; i++) + { + int x = pntp[i].h; + int y = pntp[i].v; + w1.ClientToScreen(&x, &y); + w2.ScreenToClient(&x, &y); + pntp[i].h = x; + pntp[i].v = y; + } +} + +/////////////////////////////////////////////////////////// +// Real windows +/////////////////////////////////////////////////////////// + +WINDOW xvt_win_create(WIN_TYPE wtype, const RCT* rct_p, const char* title, int menu_rid, WINDOW parent, long win_flags, + EVENT_MASK WXUNUSED(mask), EVENT_HANDLER eh, long app_data) +{ + const wxRect rct = RCT2Rect(rct_p); + const wxString caption = title; + + long style = wxCLIP_SIBLINGS | wxCLIP_CHILDREN | wxWANTS_CHARS; + if (win_flags & WSF_VSCROLL) + style |= wxVSCROLL; + if (win_flags & WSF_HSCROLL) + style |= wxHSCROLL; + + TwxWindow* w = NULL; + switch (wtype) + { + case W_DOC: + style |= wxSYSTEM_MENU; // Questo flag in realta' viene interpretato come wxCAPTION + if (win_flags & WSF_CLOSE) + style |= wxCLOSE_BOX; + break; + case W_PLAIN: + // style |= wxBORDER; // Non attivare MAI il bordo! + if (win_flags & WSF_TRANSPARENT) + style |= wxTRANSPARENT_WINDOW; + break; + default: + SORRY_BOX(); break; + } + if (parent == SCREEN_WIN) + parent = NULL; + w = new TwxWindow((wxWindow*)parent, -1, caption, rct.GetPosition(), rct.GetSize(), style); + + w->_type = wtype; + w->_app_data = app_data; + w->SetBackgroundStyle(wxBG_STYLE_CUSTOM); // Lo sfondo viene disegnato nella OnPaint + +#ifdef __WXMSW__ + OsWin32_SetCaptionStyle(w->GetHWND(), style); +#else + OsLinux_SetCaptionStyle(w, style); +#endif + + if (menu_rid > 0 && menu_rid != 8000) // 8000 = NULL_MENU_RID + { + MENU_ITEM* mi = xvt_res_get_menu(menu_rid); + if (mi) + { + w->SetMenuTree(mi); + xvt_res_free_menu_tree(mi); + } + } + + if (style & wxHSCROLL) + w->SetScrollbar(wxHORIZONTAL, 0, 1, 100); + if (style & wxVSCROLL) + w->SetScrollbar(wxVERTICAL, 0, 1, 100); + + if (win_flags & WSF_DISABLED) + w->Disable(); + else + w->Enable(); + + if (win_flags & WSF_INVISIBLE) + w->Hide(); + else + w->Show(); // Non dovrebbe mai succedere nel nostro caso + + // Accetta messaggi solo da ora! + w->_eh = eh; + + EVENT e; memset(&e, 0, sizeof(e)); + e.type = E_CREATE; // Serve a poco, ma fa' lo stesso + eh((WINDOW)w, &e); + + xvt_vobj_move((WINDOW)w, rct_p); // Forza la giusta dimensione della client area + + return (WINDOW)w; +} + +long xvt_win_dispatch_event(WINDOW win, EVENT* event_p) +{ + XVT_ASSERT(win != NULL_WIN && event_p != NULL); + + if (win == (WINDOW)_task_win) + return _task_win_handler(win, event_p); + + CAST_TWIN(win, w); + return w._eh(win, event_p); +} + +BOOLEAN xvt_win_enum_wins(WINDOW parent_win, XVT_ENUM_CHILDREN func, long data, unsigned long /*reserved*/) +{ + CAST_WIN(parent_win, w) + wxWindowList& list = w.GetChildren(); + const BOOLEAN ok = list.GetCount() > 0; + if (ok && func != NULL) + { + for (wxWindowList::iterator i = list.begin(); i != list.end(); ++i) + { + wxWindow* tw = wxDynamicCast(*i, wxWindow); + if (tw != NULL) + { + if (!func((WINDOW)tw, data)) + break; + } + } + } + return ok; +} + +long xvt_win_get_children_count(WINDOW parent_win) +{ + long nCount = 0; + if (parent_win != NULL_WIN) + { + CAST_WIN(parent_win, w) +#ifdef __WXMSW__ + nCount = OsWin32_GetChildrenCount((unsigned int)w.GetHandle()); +#else + nCount = w.GetChildren().GetCount(); +#endif + } + return nCount; + } + +void xvt_win_post_event(WINDOW win, EVENT* event_p) +{ + // Per ora e' garantito che funzioni solo con la task window + CAST_WIN(win, w); + switch (event_p->type) + { + case E_COMMAND: + { + wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, event_p->v.cmd.tag); + e.SetEventObject(&w); + wxPostEvent(&w, e); + } + break; + default: + SORRY_BOX(); + break; + } +} + +void xvt_win_release_pointer(void) +{ + if (_mouse_trapper != NULL) + { + // cap SHOULD be equal to _mouse_trapper :-) + wxWindow* cap = wxWindow::GetCapture(); + if (cap != NULL) + cap->ReleaseMouse(); + _mouse_trapper = NULL; + } +} + +void xvt_win_set_cursor(WINDOW win, CURSOR cursor) +{ + if (xvt_vobj_is_valid(win)) // Ignore setting cursor on invalid windows + { + CAST_WIN(win, w); + wxCursor cur; + switch (cursor) + { + case CURSOR_ARROW: cur = *wxSTANDARD_CURSOR; break; + case CURSOR_CROCE: cur = *wxCROSS_CURSOR; break; + case CURSOR_WAIT : cur = *wxHOURGLASS_CURSOR; break; + default: cur = xvtart_GetCursorResource(cursor); break; // Always succeeds + } + w.SetCursor(cur); + } +} + +void xvt_win_set_handler(WINDOW win, EVENT_HANDLER eh) +{ + if (win == (WINDOW)_task_win) + { + _task_win_handler = eh; + } + else + { + CAST_TWIN(win, w); + w._eh = eh; + } +} + +void xvt_win_trap_pointer(WINDOW win) +{ + CAST_WIN(win, w); + xvt_win_release_pointer(); + w.CaptureMouse(); + _mouse_trapper = &w; +} + +BOOLEAN xvt_win_is_taskbar_visible() +{ +#ifdef __WXMSW__ + return OsWin32_IsdTaskbarVisible(); +#else + return OsLinux_IsdTaskbarVisible(); +#endif +} + +/////////////////////////////////////////////////////////// +// Status bar +/////////////////////////////////////////////////////////// + +static wxStatusBar* WIN2StatBar(WINDOW win) +{ + wxStatusBar* pStatusBar = NULL; + if (win == NULL_WIN || win == TASK_WIN) + pStatusBar = _task_win->GetStatusBar(); + else + pStatusBar = wxDynamicCast((wxObject*)win, wxStatusBar); + return pStatusBar; +} + +const char* statbar_set_title(WINDOW win, const char* text) +{ + wxStatusBar* pStatusBar = WIN2StatBar(win); + if (pStatusBar != NULL) + { + if (text == NULL) + text = _strDefaultStatbarText; + wxStringTokenizer tok(text, "\t", wxTOKEN_RET_EMPTY); + for (int t = 0; tok.HasMoreTokens(); t++) + { + const wxString strMsg = tok.GetNextToken(); + pStatusBar->SetStatusText(strMsg, t); + if (t == 0) + pStatusBar->SetToolTip(strMsg); + } + } + return text; +} + +const char* statbar_set_default_title(WINDOW win, const char *text) +{ + _strDefaultStatbarText = text; + return statbar_set_title(win, text); +} + +XVT_FNTID statbar_set_fontid(WINDOW win, XVT_FNTID font_id) +{ + wxStatusBar* pStatBar = WIN2StatBar(win); + if (pStatBar != NULL && font_id != NULL) + { + CAST_FONT(font_id, font); + pStatBar->SetFont(font.Font(NULL, win)); + } + return font_id; +} + +XVT_FNTID statbar_get_fontid(WINDOW win, XVT_FNTID font_id) +{ + wxStatusBar* pStatBar = WIN2StatBar(win); + if (pStatBar != NULL && font_id != NULL) + { + CAST_FONT(font_id, font); + font.Copy(pStatBar->GetFont()); + } + return font_id; +} + +WINDOW statbar_create(int cid, int WXUNUSED(left), int WXUNUSED(top), int WXUNUSED(right), int WXUNUSED(bottom), + int WXUNUSED(prop_count), char** WXUNUSED(prop_list), WINDOW parent_win, + int WXUNUSED(parent_rid), long WXUNUSED(parent_flags), char* WXUNUSED(parent_class)) +{ + wxStatusBar* pStatusBar = NULL; + wxFrame* w = wxDynamicCast(SafeCastWin(parent_win), wxFrame); + if (w != NULL) + { + const int nStyle = 0; // not wxST_SIZEGRIP + pStatusBar = w->CreateStatusBar(3, nStyle, cid); + if (pStatusBar != NULL) + { + const int widths[4] = { -4, -2, -2, 0 }; + pStatusBar->SetStatusWidths(3, widths); + } + } + return (WINDOW)pStatusBar; +} + +BOOLEAN statbar_destroy(WINDOW win) +{ + wxStatusBar* pStatusBar = WIN2StatBar(win); + if (pStatusBar != NULL) + { + if (_task_win->GetStatusBar() == pStatusBar) + _task_win->SetStatusBar(NULL); + pStatusBar->Destroy(); + } + return pStatusBar != NULL; +} + +BOOLEAN xvt_url_valid(const char * url) +{ + if (url && *url) + { + wxURL u(url); + + return u.IsOk(); + } + return FALSE; +} + +BOOLEAN xvt_url_get(const char * url, const char * path, const char *outfile) +{ + if (xvt_url_valid(url)) + { + wxURL u(url); + wxInputStream * in = u.GetInputStream(); + wxString file(outfile); + wxFileOutputStream out(file); + + in->Read(out); + return TRUE; + } + return FALSE; +} + +int xvt_dongle_crypt(unsigned short* data) +{ + if (data == nullptr) + return -EACCES; + + data[0] ^= 0xDEAD; + data[1] ^= 0xBEEF; + data[2] ^= 0xDEAD; + data[3] ^= 0xBEEF; + return 0; +} \ No newline at end of file diff --git a/src/xvaga01/xvapp.cpp b/src/xvaga01/xvapp.cpp new file mode 100644 index 000000000..39f9d21a5 --- /dev/null +++ b/src/xvaga01/xvapp.cpp @@ -0,0 +1,284 @@ +#include "../xvaga/wxinc.h" + +#include "xvt.h" + +#include +#include + +#ifdef false +#ifdef __WXMSW__ +#include +#include +#include + +static FILE * f = nullptr; + +void print_stack_element(STACKFRAME frame) +{ + //------------------------------------------------------------------ + // Declare an image help symbol structure to hold symbol info and + // name up to 256 chars This struct is of variable lenght though so + // it must be declared as a raw byte buffer. + //------------------------------------------------------------------ + + static char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 255]; + + memset(symbolBuffer, 0, sizeof(IMAGEHLP_SYMBOL) + 255); + + // Cast it to a symbol struct: + + IMAGEHLP_SYMBOL * symbol = (IMAGEHLP_SYMBOL*)symbolBuffer; + + // Need to set the first two fields of this symbol before obtaining name info: + + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL) + 255; + symbol->MaxNameLength = 254; + + // The displacement from the beginning of the symbol is stored here: pretty useless + + unsigned displacement = 0; + + // Get the symbol information from the address of the instruction pointer register: + + if (SymGetSymFromAddr(GetCurrentProcess(), // Process to get symbol information for + frame.AddrPC.Offset, // Address to get symbol for: instruction pointer register + (DWORD*)& displacement, // Displacement from the beginning of the symbol: whats this for ? + symbol)) // Where to save the symbol + { + // Add the name of the function to the function list: + + fprintf(f, "0x%08x %s\n", frame.AddrPC.Offset, symbol->Name); + } + else + { + // Print an unknown location: + + // functionNames.push_back("unknown location"); + + fprintf(f, "0x%08x\n", frame.AddrPC.Offset); + } +} + +void windows_print_stacktrace(CONTEXT* context) +{ + SymInitialize(GetCurrentProcess(), 0, true); + + STACKFRAME frame = { 0 }; + + /* setup initial stack frame */ + frame.AddrPC.Offset = context->Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + + while (StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &frame, + context, 0, SymFunctionTableAccess, SymGetModuleBase, 0)) + print_stack_element(frame); + SymCleanup(GetCurrentProcess()); +} + +LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo) +{ + fopen_s(&f, "stack.log", xvt_fsys_file_exists("stack.log") != 0 ? "a+tc" : "wtc"); + if (f != nullptr) + { + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + fprintf(f, "Error: EXCEPTION_ACCESS_VIOLATION"); + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + fprintf(f, "Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); + break; + case EXCEPTION_BREAKPOINT: + fprintf(f, "Error: EXCEPTION_BREAKPOINT"); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + fprintf(f, "Error: EXCEPTION_DATATYPE_MISALIGNMENT"); + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + fprintf(f, "Error: EXCEPTION_FLT_DENORMAL_OPERAND"); + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + fprintf(f, "Error: EXCEPTION_FLT_DIVIDE_BY_ZERO"); + break; + case EXCEPTION_FLT_INEXACT_RESULT: + fprintf(f, "Error: EXCEPTION_FLT_INEXACT_RESULT"); + break; + case EXCEPTION_FLT_INVALID_OPERATION: + fprintf(f, "Error: EXCEPTION_FLT_INVALID_OPERATION"); + break; + case EXCEPTION_FLT_OVERFLOW: + fprintf(f, "Error: EXCEPTION_FLT_OVERFLOW"); + break; + case EXCEPTION_FLT_STACK_CHECK: + fprintf(f, "Error: EXCEPTION_FLT_STACK_CHECK"); + break; + case EXCEPTION_FLT_UNDERFLOW: + fprintf(f, "Error: EXCEPTION_FLT_UNDERFLOW"); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + fprintf(f, "Error: EXCEPTION_ILLEGAL_INSTRUCTION"); + break; + case EXCEPTION_IN_PAGE_ERROR: + fprintf(f, "Error: EXCEPTION_IN_PAGE_ERROR"); + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + fprintf(f, "Error: EXCEPTION_INT_DIVIDE_BY_ZERO"); + break; + case EXCEPTION_INT_OVERFLOW: + fprintf(f, "Error: EXCEPTION_INT_OVERFLOW"); + break; + case EXCEPTION_INVALID_DISPOSITION: + fprintf(f, "Error: EXCEPTION_INVALID_DISPOSITION"); + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + fprintf(f, "Error: EXCEPTION_NONCONTINUABLE_EXCEPTION"); + break; + case EXCEPTION_PRIV_INSTRUCTION: + fprintf(f, "Error: EXCEPTION_PRIV_INSTRUCTION"); + break; + case EXCEPTION_SINGLE_STEP: + fprintf(f, "Error: EXCEPTION_SINGLE_STEP"); + break; + case EXCEPTION_STACK_OVERFLOW: + fprintf(f, "Error: EXCEPTION_STACK_OVERFLOW"); + break; + default: + return EXCEPTION_EXECUTE_HANDLER; // per ora non mi interessa; + break; + } + /* If this is a stack overflow then we can't walk the stack, so just show + where the error happened */ + if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) + windows_print_stacktrace(ExceptionInfo->ContextRecord); + else + { + STACKFRAME frame = { 0 }; + + frame.AddrPC.Offset = ExceptionInfo->ContextRecord->Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + print_stack_element(frame); + } + fflush(f); + } + return EXCEPTION_EXECUTE_HANDLER; +} + +static BOOL PreventSetUnhandledExceptionFilter() +{ + HMODULE hKernelbase = LoadLibrary(_T("KernelBase.dll")); + HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); + if (hKernel32 == nullptr) return false; + void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); + if (pOrgEntry == nullptr) return false; + +#ifdef _M_IX86 + // Code for x86: + // 33 C0 xor eax,eax + // C2 04 00 ret 4 + unsigned char szExecute[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; +#elif _M_X64 + // 33 C0 xor eax,eax + // C3 ret + unsigned char szExecute[] = { 0x33, 0xC0, 0xC3 }; +#else +#error "The following code only works for x86 and x64!" +#endif + + SIZE_T bytesWritten = 0; + BOOL bRet = WriteProcessMemory(GetCurrentProcess(), + pOrgEntry, szExecute, sizeof(szExecute), &bytesWritten); + return bRet; +} + +void OSWin32_set_signal_handler() +{ + AddVectoredExceptionHandler(1L, windows_exception_handler); +// SetUnhandledExceptionFilter(windows_exception_handler); + PreventSetUnhandledExceptionFilter(); +} + +#else +void OSLinux_set_signal_handler() +{ +} +#endif +#endif + +extern int xvt_main(int argc, char** argv); + +class TMainApp : public wxApp +{ + wxSingleInstanceChecker* m_sic; + +protected: + virtual bool OnInit(); + virtual int OnExit(); + void OnTimer(wxTimerEvent& evt); +// void OnUnhandledException(); + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(TMainApp); +}; + +IMPLEMENT_DYNAMIC_CLASS(TMainApp, wxApp) + +IMPLEMENT_APP(TMainApp) + +#define TIMER_ID 883 + +BEGIN_EVENT_TABLE(TMainApp, wxApp) + EVT_TIMER(TIMER_ID, TMainApp::OnTimer) +END_EVENT_TABLE() + +void TMainApp::OnTimer(wxTimerEvent& evt) +{ + xvt_app_pre_create(); + xvt_main(argc, argv); +} + +bool TMainApp::OnInit() +{ +#ifdef false +#ifdef __WXMSW__ + OSWin32_set_signal_handler(); +#else + OSLinux_set_signal_handler(); +#endif +#endif + + wxFileName strWrk = argv[0]; + + //const wxString strApp = strWrk.GetName().Lower(); + strWrk.MakeAbsolute(); + wxString strApp = strWrk.GetFullPath().Lower(); + strApp.Replace("\\", "_"); strApp.Replace("/", "_"); strApp.Replace(":", "_"); + m_sic = new wxSingleInstanceChecker(strApp); + xvt_vobj_set_attr(NULL_WIN, ATTR_APPL_ALREADY_RUNNING, m_sic->IsAnotherRunning()); + + // Non eseguo direttamente xvt_main per dar modo al main event loop di partire + wxTimerEvent evt(TIMER_ID); + AddPendingEvent(evt); + return true; +} + +/*void TMainApp::OnUnhandledException() +{ + windows_exception_handler(nullptr); +} +*/ + +int TMainApp::OnExit() +{ + delete m_sic; + m_sic = NULL; + + return wxApp::OnExit(); +} diff --git a/src/xvaga01/xvt.h b/src/xvaga01/xvt.h new file mode 100644 index 000000000..4538be0ab --- /dev/null +++ b/src/xvaga01/xvt.h @@ -0,0 +1,634 @@ +#ifndef XVT_INCL_XVT +#define XVT_INCL_XVT + +#if defined(WIN32)&&(_MSC_VER > 1300) + #define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#ifdef XVT_INCL_NATIVE +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#define WIN32_EXTRA_LEAN +#define STRICT +#include +#endif +#endif + +#ifdef WIN32 + #ifdef XVAGADLL + #define XVTDLL __declspec(dllexport) + #else + #define XVTDLL __declspec(dllimport) + #endif +#else + #define XVTDLL +#endif + +#include +#include +#include +#include +#include + +#include "xvt_env.h" +#include "xvt_defs.h" +#include "xvt_help.h" +#include "xvt_menu.h" +#include "xvt_type.h" +#include "xvt_vers.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define XVT_DESKTOP_DIR 0 +#define XVT_DOCUMENTS_DIR 1 +#define XVT_EXEC_DIR 2 +#define XVT_INSTALL_DIR 3 +#define XVT_TEMP_DIR 4 + + +#define MAX_TASKS 1024 + +XVTDLL void xvt_app_allow_quit(void); +XVTDLL void xvt_app_pre_create(void); +XVTDLL void xvt_app_create(int argc, char **argv, unsigned long flags, EVENT_HANDLER eh, XVT_CONFIG *config); +XVTDLL void xvt_app_destroy(void); +XVTDLL BOOLEAN xvt_app_escape(int esc_code, PRINT_RCD*, long* ph, long* pw, long* pvr, long* phr); +XVTDLL DRAW_CTOOLS* xvt_app_get_default_ctools(DRAW_CTOOLS* ct); +XVTDLL void xvt_app_process_pending_events(void); + +XVTDLL char* xvt_cb_alloc_data(long size); +XVTDLL BOOLEAN xvt_cb_close(void); +XVTDLL void xvt_cb_free_data(void); +XVTDLL char* xvt_cb_get_data(CB_FORMAT cbfmt, char *name, long *sizep); +XVTDLL BOOLEAN xvt_cb_has_format(CB_FORMAT fmt, char *name); +XVTDLL BOOLEAN xvt_cb_open(BOOLEAN writing); +XVTDLL BOOLEAN xvt_cb_put_data(CB_FORMAT cbfmt, char *name, long size, PICTURE pic); + +XVTDLL void xvt_ctl_check_radio_button(WINDOW Win, WINDOW* Wins, int NbrWindows); +XVTDLL WINDOW xvt_ctl_create_def(WIN_DEF *win_def_p, WINDOW parent_win, long app_data); +XVTDLL void xvt_ctl_set_checked(WINDOW Win, BOOLEAN Check); +XVTDLL void xvt_ctl_set_colors(WINDOW win, const XVT_COLOR_COMPONENT* colors, XVT_COLOR_ACTION action); +XVTDLL void xvt_ctl_set_texture(WINDOW win, XVT_IMAGE img); + +XVTDLL void xvt_debug_printf(const char* fmt, ...); + +XVTDLL void xvt_dm_popup_message(const char *fmt); +XVTDLL void xvt_dm_popup_warning(const char *fmt); +XVTDLL void xvt_dm_popup_error(const char *fmt); + +XVTDLL WINDOW xvt_dm_progress_create(WINDOW parent, const char* msg, long total, BOOLEAN cancellable); +XVTDLL BOOLEAN xvt_dm_progress_set_status(WINDOW prog, long current, long total); +XVTDLL void xvt_dm_progress_set_text(WINDOW prog, const char* msg); +XVTDLL void xvt_dm_progress_destroy(WINDOW prog); + +XVTDLL void xvt_dm_post_about_box(void); +XVTDLL ASK_RESPONSE xvt_dm_post_ask(const char* Btn1, const char*Btn2, const char* Btn3, const char* xin_buffer); +XVTDLL unsigned int xvt_dm_post_date_sel(WINDOW win, const RCT* ownrct, unsigned int ansidate); // Added by guy +XVTDLL BOOLEAN xvt_dm_post_color_sel(COLOR* color, unsigned long reserved); +XVTDLL void xvt_dm_post_error(const char *fmt); +XVTDLL void xvt_dm_post_fatal_exit(const char *fmt); +XVTDLL FL_STATUS xvt_dm_post_file_open(FILE_SPEC *fsp, const char *msg); +XVTDLL FL_STATUS xvt_dm_post_file_save(FILE_SPEC *fsp, const char *msg); +XVTDLL FL_STATUS xvt_dm_post_dir_sel(DIRECTORY *dir); // Added by Luca +XVTDLL BOOLEAN xvt_dm_post_font_sel(WINDOW win, XVT_FNTID font_id, PRINT_RCD *precp, unsigned long reserved); +XVTDLL void xvt_dm_post_message(const char *fmt); +XVTDLL void xvt_dm_post_note(const char *fmt); +XVTDLL BOOLEAN xvt_dm_post_page_setup(PRINT_RCD *precp); +XVTDLL char* xvt_dm_post_string_prompt(const char* message, char* response, int response_len); +XVTDLL void xvt_dm_post_warning(const char *fmt); +XVTDLL BOOLEAN xvt_dm_post_speech(const char* text, int priority, BOOLEAN async); // 0 = Error, 1 = Warning, 2 Message, ... + +XVTDLL void xvt_dm_speech_enable(int mode); +XVTDLL int xvt_dm_speech_enabled(void); + +// Dongle support by Sirio +/* +XVTDLL int xvt_dongle_sa_crypt(unsigned short* data); +XVTDLL int xvt_dongle_sa_login(const char* module); +XVTDLL int xvt_dongle_sa_logout(const char* module); +XVTDLL int xvt_dongle_sa_test(const char* module); +*/ + +// Dongle support +XVTDLL int xvt_dongle_crypt(unsigned short* data); + +// Dongle software support +XVTDLL BOOLEAN xvt_dongle_sw_encode_decode(unsigned char* data, unsigned long serial, int len); +XVTDLL int xvt_dongle_sw_crypt(unsigned short* data); +XVTDLL BOOLEAN xvt_get_secret(const char* addresses); + +XVTDLL void xvt_dwin_clear(WINDOW win, COLOR col); +XVTDLL void xvt_dwin_draw_arc(WINDOW win, const RCT* r, int sx, int sy, int ex, int ey); +XVTDLL void xvt_dwin_draw_checkmark(WINDOW win, const RCT* rctp); +XVTDLL void xvt_dwin_draw_icon(WINDOW win, int x, int y, int rid); +XVTDLL void xvt_dwin_draw_icon_rect(WINDOW win, RCT* rct, int rid); +XVTDLL void xvt_dwin_draw_gradient_circular(WINDOW win, const RCT* r, COLOR col1, COLOR col2, const PNT* center); // Added by AGA +XVTDLL void xvt_dwin_draw_gradient_linear(WINDOW win, const RCT* r, COLOR col1, COLOR col2, int angle); // Added by AGA +XVTDLL void xvt_dwin_draw_image_on_pdf(WINDOW win, const char* name, const RCT* dest); // Added by AGA +XVTDLL void xvt_dwin_draw_image(WINDOW win, XVT_IMAGE image, const RCT* dest, const RCT* source); +XVTDLL void xvt_dwin_draw_line(WINDOW win, PNT pnt); +XVTDLL void xvt_dwin_draw_oval(WINDOW Win, const RCT* r); +XVTDLL void xvt_dwin_draw_pie(WINDOW win, const RCT *rctp, int start_x, int start_y, int stop_x, int stop_y); +XVTDLL void xvt_dwin_draw_polygon(WINDOW win, const PNT *lpnts, int npnts); +XVTDLL void xvt_dwin_draw_polyline(WINDOW win, const PNT *lpnts, int npnts); +XVTDLL void xvt_dwin_draw_rect(WINDOW win, const RCT *rctp); +XVTDLL void xvt_dwin_draw_roundrect(WINDOW win, const RCT *rctp, int oval_width, int oval_height); +XVTDLL void xvt_dwin_draw_dotted_rect(WINDOW win, RCT *rctp); // Added by Guy +XVTDLL void xvt_dwin_draw_tool(WINDOW win, int x, int y, int rid, int size); // Added by Guy +XVTDLL void xvt_dwin_draw_set_pos(WINDOW win, PNT pnt); +XVTDLL void xvt_dwin_draw_text(WINDOW win, int x, int y, const char *s, int len); +XVTDLL RCT* xvt_dwin_get_clip(WINDOW win, RCT* rct); +XVTDLL DRAW_CTOOLS* xvt_dwin_get_draw_ctools(WINDOW win, DRAW_CTOOLS *ctoolsp); +XVTDLL XVT_FNTID xvt_dwin_get_font(WINDOW win); +XVTDLL void xvt_dwin_get_font_metrics(WINDOW win, int *leadingp, int *ascentp, int *descentp); +XVTDLL long xvt_dwin_get_font_size_mapped(WINDOW win); +XVTDLL int xvt_dwin_get_text_width(WINDOW win, const char *s, int len); +XVTDLL void xvt_dwin_invalidate_rect(WINDOW win, const RCT *rctp); +XVTDLL BOOLEAN xvt_dwin_is_update_needed(WINDOW Win, const RCT* rctp); +XVTDLL void xvt_dwin_scroll_rect(WINDOW win, RCT *rctp, int dh, int dv); +XVTDLL void xvt_dwin_set_back_color(WINDOW win, COLOR color); +XVTDLL void xvt_dwin_set_cbrush(WINDOW win, CBRUSH* cbrush); +XVTDLL void xvt_dwin_set_clip(WINDOW win, const RCT* rct); +XVTDLL void xvt_dwin_set_cpen(WINDOW win, CPEN* cpen); +XVTDLL void xvt_dwin_set_draw_ctools(WINDOW win, DRAW_CTOOLS* xct); +XVTDLL void xvt_dwin_set_draw_mode(WINDOW win, DRAW_MODE mode); +XVTDLL void xvt_dwin_set_font(WINDOW win, XVT_FNTID font_id); +XVTDLL void xvt_dwin_set_fore_color(WINDOW win, COLOR color); +XVTDLL void xvt_dwin_set_std_cbrush(WINDOW win, long flag); +XVTDLL void xvt_dwin_set_std_cpen(WINDOW win, long flag); +XVTDLL void xvt_dwin_update(WINDOW win); + +XVTDLL XVT_ERRSEV xvt_errmsg_get_sev_id(XVT_ERRMSG err); + +XVTDLL long xvt_fmap_get_family_sizes(PRINT_RCD *precp, char *family, long *size_array, BOOLEAN *scalable, long max_sizes); +XVTDLL long xvt_fmap_get_families(PRINT_RCD *precp, char **family_array, long max_families); + +XVTDLL void xvt_font_copy(XVT_FNTID dest_font_id, XVT_FNTID src_font_id, XVT_FONT_ATTR_MASK mask); +XVTDLL XVT_FNTID xvt_font_create(void); +XVTDLL void xvt_font_deserialize(XVT_FNTID font_id, const char *buf); +XVTDLL void xvt_font_destroy(XVT_FNTID font_id); +XVTDLL BOOLEAN xvt_font_get_family(XVT_FNTID font_id, char* buf, long max_buf); +XVTDLL BOOLEAN xvt_font_get_family_mapped(XVT_FNTID font_id, char* buf, long max_buf); +XVTDLL void xvt_font_get_metrics(XVT_FNTID font_id, int *leadingp, int *ascentp, int *descentp); +XVTDLL BOOLEAN xvt_font_get_native_desc(XVT_FNTID font_id, char *buf, long max_buf); +XVTDLL long xvt_font_get_size(XVT_FNTID font_id); +XVTDLL XVT_FONT_STYLE_MASK xvt_font_get_style(XVT_FNTID font_id); +XVTDLL WINDOW xvt_font_get_win(XVT_FNTID font_id); +XVTDLL BOOLEAN xvt_font_is_mapped(XVT_FNTID font_id); +XVTDLL void xvt_font_map(XVT_FNTID font_id, WINDOW font_win ); +XVTDLL void xvt_font_map_using_default(XVT_FNTID font_id); +XVTDLL void xvt_font_set_family(XVT_FNTID font_id, const char* family); +XVTDLL void xvt_font_set_size(XVT_FNTID font_id, long size); +XVTDLL void xvt_font_set_style(XVT_FNTID font_id, XVT_FONT_STYLE_MASK mask); +XVTDLL long xvt_font_serialize(XVT_FNTID font_id, char *buf, long max_buf); +XVTDLL void xvt_font_unmap(XVT_FNTID font_id); + +XVTDLL BOOLEAN xvt_fsys_build_pathname(char *mbs, const char *volname, const char *dirname, const char *leafroot, const char *leafext, const char *leafvers); +XVTDLL BOOLEAN xvt_fsys_convert_dir_to_str(DIRECTORY *dirp, char *path, int sz_path); +XVTDLL BOOLEAN xvt_fsys_convert_str_to_dir(const char *path, DIRECTORY *dirp); +XVTDLL BOOLEAN xvt_fsys_convert_fspec_to_str(const FILE_SPEC *fs, char *path, int sz_path); +XVTDLL BOOLEAN xvt_fsys_convert_str_to_fspec(const char *mbs, FILE_SPEC *fs); + +XVTDLL BOOLEAN xvt_fsys_get_dir(DIRECTORY* dirp); // da eliminare nella 13 +XVTDLL BOOLEAN xvt_fsys_get_curr_dir(DIRECTORY* dirp); +XVTDLL void xvt_fsys_get_default_dir(DIRECTORY* dirp); +XVTDLL void xvt_fsys_get_temp_dir(DIRECTORY* dirp); +XVTDLL SLIST xvt_fsys_list_files(const char *type, const char *pat, BOOLEAN dirs); +XVTDLL BOOLEAN xvt_fsys_parse_pathname (const char *mbs, char *volname, char *dirname, char *leafroot, char *leafext, char *leafvers); +XVTDLL void xvt_fsys_restore_dir(); +XVTDLL void xvt_fsys_save_dir(); +XVTDLL BOOLEAN xvt_fsys_set_dir(const DIRECTORY* dirp); +XVTDLL long xvt_fsys_get_file_attr(const FILE_SPEC *fs, long attr); +XVTDLL void xvt_fsys_set_file_time(const char * file, struct tm * ctime, struct tm * atime, struct tm * mtime); +XVTDLL BOOLEAN xvt_fsys_fcopy(const char* orig, const char* dest); + +// Added by Guy +XVTDLL unsigned long xvt_fsys_get_disk_size(const char* path, char unit); +XVTDLL unsigned long xvt_fsys_get_disk_free_space(const char* path, char unit); +XVTDLL BOOLEAN xvt_fsys_is_floppy_drive(const char* path); +XVTDLL BOOLEAN xvt_fsys_is_removable_drive(const char* path); +XVTDLL BOOLEAN xvt_fsys_is_network_drive(const char* path); +XVTDLL BOOLEAN xvt_fsys_is_fixed_drive(const char* path); +XVTDLL BOOLEAN xvt_fsys_test_disk_free_space(const char* path, unsigned long filesize); +XVTDLL BOOLEAN xvt_fsys_mkdir(const char *pathname); +XVTDLL BOOLEAN xvt_fsys_rmdir(const char *pathname); +XVTDLL BOOLEAN xvt_fsys_remove_file(const char *pathname); +XVTDLL BOOLEAN xvt_fsys_rename_file(const char *src_pathname, const char *dst_pathname); +XVTDLL int xvt_fsys_access(const char *pathname, int mode); +XVTDLL BOOLEAN xvt_fsys_dir_exists(const char *pathname); +XVTDLL BOOLEAN xvt_fsys_file_exists(const char *pathname); +XVTDLL int xvt_fsys_get_campo_stp_value(const char* name, char* value, int valsize); +XVTDLL const char* xvt_fsys_get_home_dir(); +XVTDLL const char* xvt_fsys_get_campo_ini(); +XVTDLL long xvt_fsys_file_attr(const char* pathname, long attr); +XVTDLL BOOLEAN xvt_fsys_file_md5(const char* path, char* outstr32); + +XVTDLL int xvt_fsys_files_copy (const char* src, SLIST names, const char* dst); +XVTDLL int xvt_fsys_files_move (const char* src, SLIST names, const char* dst); +XVTDLL int xvt_fsys_files_remove(const char* src, SLIST names); +XVTDLL void xvt_fsys_get_sys_dir(int what_dir, char * dir); + +XVTDLL void xvt_help_close_helpfile(XVT_HELP_INFO hi); +XVTDLL XVT_HELP_INFO xvt_help_open_helpfile(FILE_SPEC *fs, unsigned long flags); +XVTDLL BOOLEAN xvt_help_process_event(XVT_HELP_INFO hi, WINDOW win, EVENT *ev); + +XVTDLL BOOLEAN xvt_html_set_url(WINDOW win, const char* url); + +XVTDLL void xvt_image_blur(XVT_IMAGE image, short radius); +XVTDLL XVT_IMAGE xvt_image_capture(WINDOW win, const RCT* rct); +XVTDLL XVT_IMAGE xvt_image_create(XVT_IMAGE_FORMAT format, short width, short height, COLOR color); +XVTDLL void xvt_image_destroy(XVT_IMAGE image); +XVTDLL int xvt_image_find_clut_index(XVT_IMAGE image, COLOR color); +XVTDLL COLOR xvt_image_get_clut(XVT_IMAGE image, short index); +XVTDLL void xvt_image_get_dimensions(XVT_IMAGE image, short *width, short *height); +XVTDLL XVT_IMAGE_FORMAT xvt_image_get_format(XVT_IMAGE image); +XVTDLL short xvt_image_get_ncolors(XVT_IMAGE image); +XVTDLL COLOR xvt_image_get_pixel(XVT_IMAGE image, short x, short y); +XVTDLL XVT_IMAGE xvt_image_read(const char *filenamep); +XVTDLL XVT_IMAGE xvt_image_read_bmp(const char *filenamep); +XVTDLL void xvt_image_replace_color(XVT_IMAGE image, COLOR old_color, COLOR new_color); +XVTDLL void xvt_image_set_clut(XVT_IMAGE image, short index, COLOR color); +XVTDLL void xvt_image_set_ncolors(XVT_IMAGE image, short ncolors); +XVTDLL void xvt_image_set_pixel(XVT_IMAGE image, short x, short y, COLOR color); +XVTDLL void xvt_image_transfer(XVT_IMAGE dstimage, XVT_IMAGE srcimage, RCT *dstrctp, RCT *srcrctp); + +typedef XVT_CALLCONV_TYPEDEF(void, IMAGE_FILTER, (short x, short y, unsigned char* rgba, void* jolly)); +XVTDLL BOOLEAN xvt_image_filter(XVT_IMAGE image, IMAGE_FILTER filter, void* param); + +XVTDLL int xvt_list_add_item(WINDOW win, short icon, const char* text, int flags); +XVTDLL BOOLEAN xvt_list_add(WINDOW win, int index, const char* text); +XVTDLL BOOLEAN xvt_list_clear(WINDOW win); +XVTDLL int xvt_list_get_sel_index(WINDOW win); +XVTDLL BOOLEAN xvt_list_set_sel(WINDOW win, int index, BOOLEAN select); +XVTDLL int xvt_list_count(WINDOW win); +XVTDLL MENU_TAG xvt_list_popup(WINDOW parent, const RCT* ownrct, const MENU_ITEM* menu, const XVT_COLOR_COMPONENT* colors, MENU_TAG first); + +XVTDLL DATA_PTR xvt_mem_alloc(size_t size); +XVTDLL void xvt_mem_free(DATA_PTR p); +XVTDLL DATA_PTR xvt_mem_realloc(DATA_PTR p, size_t size); +XVTDLL DATA_PTR xvt_mem_rep(DATA_PTR dst, DATA_PTR src, unsigned int srclen, long reps); +XVTDLL DATA_PTR xvt_mem_zalloc(size_t size); + +XVTDLL MENU_ITEM* xvt_menu_get_tree(WINDOW win); +XVTDLL BOOLEAN xvt_menu_popup(const MENU_ITEM *menu_p, WINDOW win, PNT pos, XVT_POPUP_ALIGNMENT alignment, MENU_TAG item); +XVTDLL void xvt_menu_set_font_sel(WINDOW win, XVT_FNTID font_id); +XVTDLL void xvt_menu_set_item_checked(WINDOW win, MENU_TAG tag, BOOLEAN check); +XVTDLL void xvt_menu_set_item_enabled(WINDOW win, MENU_TAG tag, BOOLEAN enable); +XVTDLL void xvt_menu_set_item_title(WINDOW win, MENU_TAG tag, const char* text); +XVTDLL void xvt_menu_set_tree(WINDOW win, MENU_ITEM* tree); +XVTDLL void xvt_menu_update(WINDOW win); +XVTDLL MENU_ITEM* xvt_menu_duplicate_tree(const MENU_ITEM* m); + +XVTDLL short xvt_notebk_add_page(WINDOW notebk, WINDOW page, const char* title, XVT_IMAGE img, short page_no); +XVTDLL short xvt_notebk_get_front_page(WINDOW notebk); +XVTDLL short xvt_notebk_get_num_tabs(WINDOW notebk); +XVTDLL WINDOW xvt_notebk_get_page(WINDOW notebk, short page_no); +XVTDLL char* xvt_notebk_get_tab_title(WINDOW notebk, short page_no, char* title, int sz_title); +XVTDLL void xvt_notebk_set_front_page(WINDOW notebk, short page_no); +XVTDLL void xvt_notebk_set_tab_icon(WINDOW notebk, short page_no, int rid); +XVTDLL void xvt_notebk_set_tab_image(WINDOW notebk, short page_no, XVT_IMAGE img); +XVTDLL void xvt_notebk_set_tab_title(WINDOW notebk, short page_no, const char* title); +XVTDLL void xvt_notebk_set_page_title(WINDOW notebk, short page_no, const char* title); +XVTDLL void xvt_notebk_rem_page(WINDOW notebk, short page_no); +XVTDLL void xvt_notebk_rem_tab(WINDOW notebk, short tab_no); + +XVTDLL char * xvt_GUID(); + +// Added by Guy +typedef const char* TRANSLATE_CALLBACK(const char* ita); +XVTDLL void xvt_menu_translate_tree(WINDOW win, TRANSLATE_CALLBACK tc); + +XVTDLL short xvt_palet_add_colors(XVT_PALETTE palet, COLOR *colorsp, short numcolors); +XVTDLL short xvt_palet_add_colors_from_image(XVT_PALETTE palet, XVT_IMAGE image); +XVTDLL XVT_PALETTE xvt_palet_create(XVT_PALETTE_TYPE type, XVT_PALETTE_ATTR reserved); +XVTDLL void xvt_palet_destroy(XVT_PALETTE palet); +XVTDLL short xvt_palet_get_colors(XVT_PALETTE palet, COLOR *colorsp, short maxcolors); +XVTDLL short xvt_palet_get_ncolors(XVT_PALETTE palet); +XVTDLL int xvt_palet_get_tolerance(XVT_PALETTE p); +XVTDLL void xvt_palet_set_tolerance(XVT_PALETTE p, int t); + +XVTDLL void xvt_print_close(void); +XVTDLL BOOLEAN xvt_print_close_page(PRINT_RCD *precp); +XVTDLL PRINT_RCD* xvt_print_create(int *sizep); +XVTDLL PRINT_RCD* xvt_print_create_by_name(int* sizep, const char* name); // Added by Aga +XVTDLL int xvt_print_get_name(const PRINT_RCD *precp, char* name, int sz_s); // Added by Aga +XVTDLL int xvt_print_set_name(PRINT_RCD* precp, const char* name); // Added by Aga +XVTDLL WINDOW xvt_print_create_win(PRINT_RCD *precp, const char* title); + +XVTDLL void xvt_print_destroy(PRINT_RCD *precp); +XVTDLL RCT* xvt_print_get_next_band(void); +XVTDLL BOOLEAN xvt_print_is_valid(const PRINT_RCD *precp); +XVTDLL BOOLEAN xvt_print_open(void); +XVTDLL BOOLEAN xvt_print_start_thread (BOOLEAN (* print_fcn)(long), long data); +XVTDLL BOOLEAN xvt_print_open_page(PRINT_RCD *precp); +// Added XVAGA +XVTDLL SLIST xvt_print_list_devices(); +XVTDLL BOOLEAN xvt_print_set_default_device(const char* name); +XVTDLL BOOLEAN xvt_print_get_default_device(char* name, int namesize); +XVTDLL BOOLEAN xvt_print_suspend_thread(); +XVTDLL BOOLEAN xvt_print_restart_thread(); +XVTDLL BOOLEAN xvt_print_is_pdf(const PRINT_RCD* precp); +XVTDLL BOOLEAN xvt_print_pdf_version(char* version, int size); + +XVTDLL void xvt_rect_deflate(RCT *rctp, short ix, short iy); +XVTDLL int xvt_rect_get_height(const RCT *rctp); +XVTDLL int xvt_rect_get_width(const RCT *rctp); +XVTDLL BOOLEAN xvt_rect_has_point(const RCT *rctp, PNT pnt); +XVTDLL void xvt_rect_inflate(RCT *rctp, short ix, short iy); +XVTDLL BOOLEAN xvt_rect_intersect(RCT *drctp, const RCT *rctp1, const RCT *rctp2); +XVTDLL BOOLEAN xvt_rect_is_empty(const RCT *rctp); +XVTDLL void xvt_rect_offset(RCT *rctp, short dh, short dv); +XVTDLL void xvt_rect_set(RCT *rctp, short left, short top, short right, short bottom); +XVTDLL void xvt_rect_set_empty(RCT *rctp); +XVTDLL void xvt_rect_set_null(RCT* rctp); +XVTDLL BOOLEAN xvt_rect_set_pos(RCT *rctp, PNT pos); + +XVTDLL void xvt_res_free_menu_tree(MENU_ITEM* tree); +XVTDLL XVT_FNTID xvt_res_get_font(int rid); +XVTDLL XVT_IMAGE xvt_res_get_icon(int rid); +XVTDLL XVT_IMAGE xvt_res_get_image(int rid); +XVTDLL MENU_ITEM* xvt_res_get_menu(int rid); +XVTDLL char* xvt_res_get_str(int rid, char *s, int sz_s); + +XVTDLL int xvt_sbar_get_pos(WINDOW win, SCROLL_TYPE t); +XVTDLL int xvt_sbar_get_proportion(WINDOW win, SCROLL_TYPE t); +XVTDLL void xvt_sbar_get_range(WINDOW win, SCROLL_TYPE t, int *minp, int *maxp); +XVTDLL void xvt_sbar_set_pos(WINDOW win, SCROLL_TYPE t, int pos); +XVTDLL void xvt_sbar_set_proportion(WINDOW win, SCROLL_TYPE t, int proportion); +XVTDLL void xvt_sbar_set_range(WINDOW win, SCROLL_TYPE t, int min, int max); + +XVTDLL void xvt_scr_beep(void); +XVTDLL WINDOW xvt_scr_get_focus_topwin(void); +XVTDLL WINDOW xvt_scr_get_focus_vobj(void); +XVTDLL SLIST xvt_scr_list_wins(); +XVTDLL void xvt_scr_reset_busy_cursor(); +XVTDLL void xvt_scr_set_busy_cursor(); +XVTDLL void xvt_scr_set_focus_vobj(WINDOW win); + +XVTDLL BOOLEAN xvt_slist_add_at_elt(SLIST x, SLIST_ELT e, const char *sx, long data); +XVTDLL int xvt_slist_count(SLIST x); +XVTDLL SLIST xvt_slist_create(); +XVTDLL void xvt_slist_destroy(SLIST list); +XVTDLL char* xvt_slist_get(SLIST x, SLIST_ELT e, long *datap); +XVTDLL long* xvt_slist_get_data(SLIST_ELT elt); +XVTDLL SLIST_ELT xvt_slist_get_first(SLIST list); +XVTDLL SLIST_ELT xvt_slist_get_next(SLIST list, SLIST_ELT item); + +XVTDLL SLIST_ELT xvt_slist_find_str(SLIST list, const char* str); // Cerca una stringa all'interno di una SLIST +XVTDLL BOOLEAN xvt_fsys_fupdate(const char* src, const char* dst); // Aggiorna il file dst se più vecchio di src + +XVTDLL int xvt_str_compare_ignoring_case (const char* s1, const char* s2); +XVTDLL int xvt_str_encode(const char* text, char* cypher, int mode); +XVTDLL int xvt_str_decode(const char* cypher, char* text, int mode); +XVTDLL int xvt_str_base64_encode(const char *name, char *cypher); +XVTDLL int xvt_str_base64_decode(const char *cypher, long len, unsigned char *text); +XVTDLL size_t xvt_str_base64_len(size_t len); +XVTDLL char* xvt_str_duplicate(const char* str); +XVTDLL BOOLEAN xvt_str_match(const char* str, const char* pat, BOOLEAN case_sensitive); +XVTDLL double xvt_str_fuzzy_compare (const char* s1, const char* s2); +XVTDLL double xvt_str_fuzzy_compare_ignoring_case(const char* s1, const char* s2); +XVTDLL void xvt_str_make_upper(char* str); +XVTDLL void xvt_str_make_lower(char* str); +XVTDLL BOOLEAN xvt_str_md5(const char* instr, char* outstr32); +XVTDLL char* xvt_str_number_format(char* str, int size); +XVTDLL BOOLEAN xvt_str_same(const char* s1, const char* s2); +XVTDLL char * xvt_str_exec_dir(); + +XVTDLL XVT_TREEVIEW_NODE xvt_treeview_add_child_node(WINDOW win, + XVT_TREEVIEW_NODE parent, XVT_TREEVIEW_NODE_TYPE type, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + const char* string, XVT_TREEVIEW_CALLBACK callback, const char* data); +XVTDLL WINDOW xvt_treeview_create(WINDOW parent_win, + RCT * rct_p, char * title, long ctl_flags, long app_data, int ctl_id, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + long attrs, int line_height); +XVTDLL void xvt_treeview_destroy_node(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL BOOLEAN xvt_treeview_enable_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN on); +XVTDLL BOOLEAN xvt_treeview_expand_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN recurse); +XVTDLL XVT_TREEVIEW_NODE xvt_treeview_find_node_string(WINDOW win, const char* text); +XVTDLL XVT_TREEVIEW_NODE xvt_treeview_get_child_node(WINDOW win, XVT_TREEVIEW_NODE parent_node, int position); +XVTDLL const char* xvt_treeview_get_node_data(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL XVT_TREEVIEW_NODE xvt_treeview_get_root_node(WINDOW win); +XVTDLL XVT_TREEVIEW_NODE xvt_treeview_get_selected_node(WINDOW win); +XVTDLL SLIST xvt_treeview_get_selected_list(WINDOW win); +XVTDLL BOOLEAN xvt_treeview_remove_child_node(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL BOOLEAN xvt_treeview_remove_node_children(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL void xvt_treeview_resume(WINDOW win); +XVTDLL void xvt_treeview_select_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN sel); +XVTDLL void xvt_treeview_set_node_bold(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN bold); +XVTDLL void xvt_treeview_set_node_images(WINDOW win, XVT_TREEVIEW_NODE node, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image); +XVTDLL void xvt_treeview_set_node_string(WINDOW win, XVT_TREEVIEW_NODE node, const char* text); +XVTDLL void xvt_treeview_suspend(WINDOW win); + +XVTDLL BOOLEAN xvt_chr_is_digit(int c); +XVTDLL BOOLEAN xvt_chr_is_alpha(int c); +XVTDLL BOOLEAN xvt_chr_is_alnum(int c); + +// System calls by XVAGA +XVTDLL void xvt_sys_beep(int severity); +XVTDLL long xvt_sys_close_children(WINDOW win); +XVTDLL long xvt_sys_execute(const char* cmdline, BOOLEAN sync, BOOLEAN iconizetask); +XVTDLL long xvt_sys_execute_in_window(const char* cmdline, WINDOW win); +XVTDLL BOOLEAN xvt_sys_kill(long pid); +XVTDLL const char * xvt_sys_command(); + +typedef XVT_CALLCONV_TYPEDEF(int, XVT_MULTITHREAD_CALLBACK, (void* pCaller, void* pData, int i, int tot) ); +XVTDLL BOOLEAN xvt_sys_multithread(XVT_MULTITHREAD_CALLBACK callback, void* pCaller, void* pData, int tot, const char* msg); + +XVTDLL BOOLEAN xvt_sys_get_host_name(char* name, int maxlen); +XVTDLL BOOLEAN xvt_sys_get_user_name(char* name, int maxlen); +XVTDLL BOOLEAN xvt_sys_goto_url(const char* url, const char* action); +XVTDLL int xvt_sys_dongle_server_running(); +XVTDLL BOOLEAN xvt_sys_find_editor(const char* file, char* editor); +XVTDLL BOOLEAN xvt_sys_get_env(const char* varname, char* value, int max_size); +XVTDLL void xvt_sys_set_oem(int oem); +XVTDLL long xvt_sys_get_oem_int(const char* name, long defval); +XVTDLL int xvt_sys_get_oem_string(const char* name, const char* defval, char* value, int maxsize); + +XVTDLL long xvt_sys_get_profile_int(const char* file, const char* paragraph, const char* name, long defval); +XVTDLL int xvt_sys_get_profile_string(const char* file, const char* paragraph, const char* name, + const char* defval, char* value, int maxsize); +XVTDLL BOOLEAN xvt_sys_set_profile_int(const char* file, const char* paragraph, const char* name, long value); +XVTDLL BOOLEAN xvt_sys_set_profile_string(const char* file, const char* paragraph, const char* name, const char* value); +XVTDLL BOOLEAN xvt_sys_remove_profile_string(const char* file, const char* paragraph, const char* name); + +XVTDLL int xvt_sys_get_session_id(); +XVTDLL unsigned long xvt_sys_get_free_memory(); +XVTDLL unsigned long xvt_sys_get_free_memory_kb(); +XVTDLL int xvt_sys_get_os_version(); +XVTDLL BOOLEAN xvt_sys_is_pda(); +XVTDLL int xvt_sys_get_version(char* os_version, char* ptk_version, int maxsize); +XVTDLL unsigned int xvt_sys_load_icon(const char* file); +XVTDLL void xvt_sys_sleep(unsigned long msec); + +XVTDLL void xvt_sys_search_env(const char* filename, const char* varname, char* pathname); +XVTDLL BOOLEAN xvt_sys_set_env(const char* varname, const char* value); +XVTDLL void xvt_sys_sorry_box(const char* func, const char* file, int line); +XVTDLL void xvt_sys_deprecated_box(const char* oldfunc, const char* file, const char* newfunc); + +XVTDLL struct tm* xvt_time_now(); +XVTDLL long xvt_timer_create(WINDOW win, long interval); +XVTDLL void xvt_timer_destroy(long id); + +XVTDLL WINDOW xvt_trayicon_create(WINDOW owner, short icon, const char* tooltip); +XVTDLL void xvt_trayicon_destroy(WINDOW tray); + +XVTDLL void xvt_vobj_destroy(WINDOW win); +XVTDLL long xvt_vobj_get_attr(WINDOW win, long data); +XVTDLL RCT* xvt_vobj_get_client_rect(WINDOW win, RCT *rctp); +XVTDLL long xvt_vobj_get_data(WINDOW win); +XVTDLL RCT* xvt_vobj_get_outer_rect(WINDOW win, RCT *rctp); +XVTDLL XVT_PALETTE xvt_vobj_get_palet(WINDOW win); +XVTDLL WINDOW xvt_vobj_get_parent(WINDOW win); +XVTDLL char* xvt_vobj_get_title(WINDOW win, char *title, int sz_title); +XVTDLL WIN_TYPE xvt_vobj_get_type(WINDOW win); +XVTDLL BOOLEAN xvt_vobj_is_focusable(WINDOW win); +XVTDLL BOOLEAN xvt_vobj_is_valid(WINDOW win); +XVTDLL void xvt_vobj_maximize(WINDOW win); // Added by XVAGA +XVTDLL void xvt_vobj_minimize(WINDOW win); // Added by XVAGA +XVTDLL BOOLEAN xvt_vobj_maximized(WINDOW win); // Added by XVAGA +XVTDLL void xvt_vobj_hide(WINDOW win); // Added by XVAGA +XVTDLL void xvt_vobj_show(WINDOW win); // Added by XVAGA +XVTDLL BOOLEAN xvt_vobj_shown(WINDOW win); // Added by XVAGA +XVTDLL void xvt_vobj_move(WINDOW win, const RCT* rctp); +XVTDLL void xvt_vobj_raise(WINDOW win); +XVTDLL void xvt_vobj_set_attr(WINDOW win, long data, long value); +XVTDLL void xvt_vobj_set_data(WINDOW win, long AppData); +XVTDLL void xvt_vobj_set_enabled(WINDOW win, BOOLEAN enabled); +XVTDLL void xvt_vobj_set_palet(WINDOW win, XVT_PALETTE palet); +XVTDLL void xvt_vobj_set_title(WINDOW win, const char* title); +XVTDLL void xvt_vobj_set_visible(WINDOW win, BOOLEAN show); +XVTDLL void xvt_vobj_translate_points(WINDOW from_win, WINDOW to_win, PNT *pntp, int npnts); +XVTDLL WINDOW xvt_win_create(WIN_TYPE wtype, const RCT* rct_p, const char* title, int menu_rid, WINDOW parent_win, long win_flags, EVENT_MASK mask, EVENT_HANDLER eh, long app_data); +XVTDLL long xvt_win_dispatch_event(WINDOW win, EVENT* event_p); +XVTDLL BOOLEAN xvt_win_enum_wins(WINDOW parent_win, XVT_ENUM_CHILDREN func, long data, unsigned long reserved); +XVTDLL long xvt_win_get_children_count(WINDOW parent_win); +XVTDLL void xvt_win_post_event(WINDOW win, EVENT* event_p); // Added by XVAGA +XVTDLL void xvt_win_release_pointer(void); +XVTDLL void xvt_win_set_caret_size(WINDOW win, int width, int height); +XVTDLL void xvt_win_set_caret_pos(WINDOW win, PNT p); +XVTDLL void xvt_win_set_caret_visible(WINDOW win, BOOLEAN on); +XVTDLL void xvt_win_set_cursor(WINDOW win, CURSOR Cursor); +XVTDLL void xvt_win_set_handler(WINDOW win, EVENT_HANDLER eh); +XVTDLL void xvt_win_trap_pointer(WINDOW win); +XVTDLL BOOLEAN xvt_win_is_taskbar_visible(); + +// Added by XVAGA + +#ifndef UNDEF_TASK +XVTDLL const char ** xvt_task_get_list(int & ntasks); +XVTDLL int xvt_task_get_instances(const char * task); +#endif + +XVTDLL BOOLEAN xvt_pane_add(WINDOW parent, WINDOW pane, const char* name, int dock, int flags); +XVTDLL BOOLEAN xvt_pane_change_flags(WINDOW pane, int set, int reset); +XVTDLL BOOLEAN xvt_pane_detach(WINDOW pane); +XVTDLL BOOLEAN xvt_pane_manager_load_perspective(WINDOW win, const char* str); +XVTDLL int xvt_pane_manager_save_perspective(WINDOW win, char* str, int max_size); +XVTDLL BOOLEAN xvt_pane_set_size_range(WINDOW pane, int min_size, int best_size, int max_size); +XVTDLL BOOLEAN xvt_pane_set_title(WINDOW pane, const char* title); + +XVTDLL BOOLEAN xvt_sign_file(const char* input_file, char* output_file); +XVTDLL BOOLEAN xvt_sign_start(); +XVTDLL BOOLEAN xvt_sign_stop(); +XVTDLL BOOLEAN xvt_sign_test(const char* input_file); + +typedef int ODBC_CALLBACK(void*, int, char**, char**); +XVTDLL XVT_ODBC xvt_odbc_get_connection(const char* dsn, const char* usr, const char* pwd, const char* dir); +XVTDLL BOOLEAN xvt_odbc_free_connection(XVT_ODBC handle); +XVTDLL ULONG xvt_odbc_execute(XVT_ODBC handle, const char* sql, ODBC_CALLBACK cb, void* jolly); +XVTDLL BOOLEAN xvt_odbc_driver(XVT_ODBC handle, char* str, int max_size); +XVTDLL BOOLEAN xvt_odbc_log_file(XVT_ODBC handle, const char* str); + +XVTDLL BOOLEAN xvt_sql_begin(XVT_SQLDB handle); +XVTDLL BOOLEAN xvt_sql_close(XVT_SQLDB handle); +XVTDLL BOOLEAN xvt_sql_commit(XVT_SQLDB handle); +XVTDLL BOOLEAN xvt_sql_driver(XVT_SQLDB handle, char* str, int max_size); +XVTDLL ULONG xvt_sql_execute(XVT_SQLDB handle, const char* sql, ODBC_CALLBACK cb, void* jolly); +XVTDLL SLIST xvt_sql_list_fields(XVT_SQLDB handle, const char* table); +XVTDLL SLIST xvt_sql_list_tables(XVT_SQLDB handle); +XVTDLL const char * xvt_sql_field_type(XVT_SQLDB handle, const char* table, const char* field); +XVTDLL XVT_SQLDB xvt_sql_open(const char* dsn, const char* usr, const char* pwd, const char* dir); +XVTDLL BOOLEAN xvt_sql_rollback(XVT_SQLDB handle); +XVTDLL BOOLEAN xvt_sql_table_exists(XVT_SQLDB handle, const char* name); + + +typedef BOOLEAN PROP_CALLBACK(WINDOW win, XVT_TREEVIEW_NODE node, void* app_data); +XVTDLL XVT_TREEVIEW_NODE xvt_prop_add(WINDOW win, const char* type, const char* name, const char* value, const char* label); +XVTDLL XVT_TREEVIEW_NODE xvt_prop_current(WINDOW win); +XVTDLL XVT_TREEVIEW_NODE xvt_prop_find(WINDOW win, const char* name); +XVTDLL void xvt_prop_fit_columns(WINDOW win); +XVTDLL BOOLEAN xvt_prop_for_each(WINDOW win, PROP_CALLBACK pcb, void* jolly); +XVTDLL int xvt_prop_get_data(WINDOW win, XVT_TREEVIEW_NODE node, char* value, int maxlen); +XVTDLL int xvt_prop_get_string(WINDOW win, XVT_TREEVIEW_NODE node, char* label, int maxlen); +XVTDLL int xvt_prop_get_type(WINDOW win, XVT_TREEVIEW_NODE node, char* type, int maxlen); +XVTDLL BOOLEAN xvt_prop_remove(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL BOOLEAN xvt_prop_restart(WINDOW win); +XVTDLL BOOLEAN xvt_prop_set_data(WINDOW win, XVT_TREEVIEW_NODE node, const char* value); +XVTDLL BOOLEAN xvt_prop_set_read_only(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN ro); +XVTDLL BOOLEAN xvt_prop_suspend(WINDOW win); + +XVTDLL XVT_TREEVIEW_NODE xvt_treelist_add_child_node(WINDOW win, + XVT_TREEVIEW_NODE parent, XVT_TREEVIEW_NODE_TYPE type, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + const char* string, XVT_TREEVIEW_CALLBACK callback, const char* data); +XVTDLL WINDOW xvt_treelist_create(WINDOW parent_win, + RCT * rct_p, char * title, long ctl_flags, long app_data, int ctl_id, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + long attrs, int line_height); +XVTDLL void xvt_treelist_destroy_node(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL BOOLEAN xvt_treelist_enable_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN on); +XVTDLL BOOLEAN xvt_treelist_expand_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN recurse); +XVTDLL XVT_TREEVIEW_NODE xvt_treelist_find_node_string(WINDOW win, const char* text); +XVTDLL XVT_TREEVIEW_NODE xvt_treelist_get_child_node(WINDOW win, XVT_TREEVIEW_NODE parent_node, int position); +XVTDLL const char* xvt_treelist_get_node_data(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL XVT_TREEVIEW_NODE xvt_treelist_get_root_node(WINDOW win); +XVTDLL XVT_TREEVIEW_NODE xvt_treelist_get_selected_node(WINDOW win); +XVTDLL SLIST xvt_treelist_get_selected_list(WINDOW win); +XVTDLL BOOLEAN xvt_treelist_remove_child_node(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL BOOLEAN xvt_treelist_remove_node_children(WINDOW win, XVT_TREEVIEW_NODE node); +XVTDLL void xvt_treelist_resume(WINDOW win); +XVTDLL void xvt_treelist_select_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN sel); +XVTDLL void xvt_treelist_set_node_bold(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN bold); +XVTDLL void xvt_treelist_set_node_images(WINDOW win, XVT_TREEVIEW_NODE node, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image); +XVTDLL void xvt_treelist_set_node_string(WINDOW win, XVT_TREEVIEW_NODE node, const char* text); +XVTDLL void xvt_treelist_suspend(WINDOW win); + +XVTDLL BOOLEAN xvt_url_valid(const char * url); +XVTDLL BOOLEAN xvt_url_get(const char * url, const char * path, const char * outfile); + +XVTDLL void xvt_set_mail_params(const char * smtp, const char * port, const char * user, const char * pass, const char * from); +// Send email using normal methods + + // flags 0x1=UI; 0x2=Receipt +XVTDLL BOOLEAN xvt_mail_send(const char* to, const char* cc, const char* ccn, const char* subject, + const char* msg, const char* attach, short flags); +// Send email using Microsoft Powershell +XVTDLL BOOLEAN xvt_powermail_send(const char* to, const char* cc, const char* ccn, + const char* subject, const char* msg, const char* attach, short flags, const char* usr); // 0x1=UI; 0x2=Receipt +XVTDLL BOOLEAN xvt_wx_mail_send(const char* to, const char* cc, const char* ccn, const char* subject, + const char* msg, const char* attach, short flags); +XVTDLL short xvt_mail_installed(); + +XVTDLL void xvt_btn_set_images(WINDOW win, XVT_IMAGE up, XVT_IMAGE down); +XVTDLL int xvt_net_get_status(); + +XVTDLL int xvt_xslt_transform(const char * infile, const char * stylefile, const char * outfile); // Added by AGA + +#ifdef __cplusplus +} +#endif + +#define SORRY_BOX() xvt_sys_sorry_box(__FUNCTION__, __FILE__, __LINE__) + +#ifdef NDEBUG +#define DEPRECATED_BOX(newfunc) +#else +#define DEPRECATED_BOX(newfunc) xvt_sys_deprecated_box(__FUNCTION__, __FILE__, newfunc) +#endif + +#endif diff --git a/src/xvaga01/xvt_defs.h b/src/xvaga01/xvt_defs.h new file mode 100644 index 000000000..d24841c4d --- /dev/null +++ b/src/xvaga01/xvt_defs.h @@ -0,0 +1,538 @@ +/**************************************************************************** + * + * Copyright 1987-1996 XVT Software. All rights reserved. + * May be used only in accordance with a valid Source Code License + * Agreement with XVT Software. + * + * $RCSfile: xvt_defs.h,v $ + * $Revision: 1.11.2.2 $ + * + * Purpose: Global XVT macro definitions. + * + ****************************************************************************/ + +#ifndef XVT_INCL_DEFS +#define XVT_INCL_DEFS + +/*--------------------------------------------------------------------------- + Resource ID constants +---------------------------------------------------------------------------*/ +/* DECLINING usage: Do not rely on MENU_BAR_RID, as support for it may + * be discontinued in a future release */ +#define MENU_BAR_RID 9001 /* ID for default menubar resource */ +#define ICON_RSRC 9012 +#define DB_ABOUT 9050 +#define DB_ASK 9051 +#define DB_ERROR 9052 +#define DB_NOTE 9053 +#define DB_OPEN 9054 +#define DB_ABORT 9055 +#define DB_SAVE 9056 +#define DB_HELPTOPICS 9057 +#define DB_HELPTEXT 9058 +#define DB_RESPONSE 9059 +#define DB_WARNING 9060 +#define DB_FONTSEL 9061 +/* Number 9062 reserved for XVT/Mac FontSize dialog */ +#define STR_HELPTYPE 40000 /* string resource for help file-type */ + +/* Define the beginning of the common code and K layer string resources */ +/* The maximum reserved string res ID is 32767 */ +#define XVT_STRING_RES_BASE 30000 +#define XVTV_STRING_RES_BASE XVT_STRING_RES_BASE + 1300 + +/*--------------------------------------------------------------------------- + Standard dialog pushbutton control IDs +---------------------------------------------------------------------------*/ +#define DLG_OK 1 /* default button was clicked */ +#define DLG_YES DLG_OK /* synonym */ +#define DLG_CANCEL 2 /* cancel button was clicked */ +#define DLG_OUTLINE 3 /* ID of userItem on Mac (internal use) */ +#define DLG_NO 4 /* other button was clicked */ + +/*--------------------------------------------------------------------------- + Colors +---------------------------------------------------------------------------*/ +#ifndef COLOR_RED +#define COLOR_RED 0x01FF0000L +#endif +#ifndef COLOR_GREEN +#define COLOR_GREEN 0x0200FF00L +#endif +#ifndef COLOR_BLUE +#define COLOR_BLUE 0x030000FFL +#endif +#ifndef COLOR_CYAN +#define COLOR_CYAN 0x0400FFFFL +#endif +#ifndef COLOR_MAGENTA +#define COLOR_MAGENTA 0x05FF00FFL +#endif +#ifndef COLOR_YELLOW +#define COLOR_YELLOW 0x06FFFF00L +#endif +#ifndef COLOR_BLACK +#define COLOR_BLACK 0x07000000L +#endif +#ifndef COLOR_DKGRAY +#define COLOR_DKGRAY 0x08404040L +#endif +#ifndef COLOR_GRAY +#define COLOR_GRAY 0x09808080L +#endif +#ifndef COLOR_LTGRAY +#define COLOR_LTGRAY 0x0AC0C0C0L +#endif +#ifndef COLOR_WHITE +#define COLOR_WHITE 0x0BFFFFFFL +#endif + +#define COLOR_INVALID ((COLOR)~0) + +/*--------------------------------------------------------------------------- + String and Character Constants +---------------------------------------------------------------------------*/ +#define XVT_MAX_MB_SIZE XVTK_MAX_MB_SIZE + + +/*--------------------------------------------------------------------------- + Key codes +---------------------------------------------------------------------------*/ +#define K_DEL 127 /* delete (same as ASCII) */ +#define K_UP 301 /* up arrow */ +#define K_DOWN 302 /* down arrow */ +#define K_RIGHT 303 /* right arrow */ +#define K_LEFT 304 /* left arrow */ +#define K_PREV 305 /* previous screen */ +#define K_NEXT 306 /* next screen */ +#define K_LHOME 307 /* line home */ +#define K_LEND 308 /* line end */ +#define K_HOME 309 /* home */ +#define K_END 310 /* end */ +#define K_INS 312 /* insert */ +#define K_WLEFT 313 /* word left */ +#define K_WRIGHT 314 /* word right */ +#define K_BTAB 315 /* back tab */ +#define K_HELP 316 /* help */ +#define K_CLEAR 317 /* clear */ +#define K_KP0 318 /* keypad '0' */ +#define K_KP1 319 +#define K_KP2 320 +#define K_KP3 321 +#define K_KP4 322 +#define K_KP5 323 +#define K_KP6 324 +#define K_KP7 325 +#define K_KP8 326 +#define K_KP9 327 /* keypad '9' */ +#define K_COPY 328 /* copy */ +#define K_CUT 329 /* cut */ +#define K_PASTE 330 /* paste */ +#define K_F1 331 /* function key 1 */ +#define K_F2 332 +#define K_F3 333 +#define K_F4 334 +#define K_F5 335 +#define K_F6 336 +#define K_F7 337 +#define K_F8 338 +#define K_F9 339 +#define K_F10 340 +#define K_F11 341 +#define K_F12 342 +#define K_F13 343 +#define K_F14 344 +#define K_F15 345 /* function key 15 */ +#define K_F16 346 +#define K_F17 347 +#define K_F18 348 +#define K_F19 349 +#define K_F20 350 +#define K_F21 351 +#define K_F22 352 +#define K_F23 353 +#define K_F24 354 + +#define K_KPMULT 372 /* keypad '*' */ +#define K_KPSUB 373 /* keypad '-' */ +#define K_KPADD 374 /* keypad '+' */ +#define K_KPDIV 375 /* keypad '/' */ +#define K_KPDOT 376 /* keypad '.' */ +#define K_KPEQ 377 /* keypad '=' */ + +/*--------------------------------------------------------------------------- + Text edit module +---------------------------------------------------------------------------*/ +#define TX_READONLY 0x0001 /* text is not editable */ +#define TX_WRAP 0x0002 /* wrap text to margin */ +#define TX_AUTOVSCROLL 0x0004 /* autoscroll vertically */ +#define TX_AUTOHSCROLL 0x0008 /* autoscroll horizontally */ +#define TX_BORDER 0x0010 /* rectangular border */ +#define TX_VSCROLLBAR 0x0020 /* vertical scroll bar */ +#define TX_HSCROLLBAR 0x0040 /* horizontal scroll bar */ +#define TX_ONEPAR 0x0080 /* one paragraph only (no \r) */ +#define TX_NOCOPY 0x0100 /* no copy allowed */ +#define TX_NOCUT 0x0200 /* no cut allowed */ +#define TX_NOPASTE 0x0400 /* no paste allowed */ +#define TX_NOMENU 0x0800 /* no edit menu changes */ +#define TX_ENABLECLEAR 0x1000 /* leave CLEAR enabled always */ +#define TX_OVERTYPE 0x2000 /* overtype mode */ +#define TX_DISABLED 0x4000 +#define TX_INVISIBLE 0x8000 + +/*--------------------------------------------------------------------------- + Cursors +---------------------------------------------------------------------------*/ +#define CURSOR_ARROW 0 /* arrow */ +#define CURSOR_IBEAM 1 /* I-beam */ +#define CURSOR_CROCE 2 /* cross hair (was CURSOR_CROSS)*/ +#define CURSOR_PLUS 3 /* plus sign (fatter than cross hair) */ +#define CURSOR_WAIT 4 /* waiting symbol (e.g., hourglass) */ +#define CURSOR_HELP 5 /* help system */ +#define CURSOR_USER 11 /* user defined shape (>= 11) */ + +/*--------------------------------------------------------------------------- + Event masks +---------------------------------------------------------------------------*/ + +#define EM_NONE ((EVENT_MASK)0L) +#define EM_ALL ((EVENT_MASK)~0L) +#define EM_CREATE ((EVENT_MASK)(1L << E_CREATE)) +#define EM_DESTROY ((EVENT_MASK)(1L << E_DESTROY)) +#define EM_FOCUS ((EVENT_MASK)(1L << E_FOCUS)) +#define EM_SIZE ((EVENT_MASK)(1L << E_SIZE)) +#define EM_UPDATE ((EVENT_MASK)(1L << E_UPDATE)) +#define EM_CLOSE ((EVENT_MASK)(1L << E_CLOSE)) +#define EM_MOUSE_DOWN ((EVENT_MASK)(1L << E_MOUSE_DOWN)) +#define EM_MOUSE_UP ((EVENT_MASK)(1L << E_MOUSE_UP)) +#define EM_MOUSE_MOVE ((EVENT_MASK)(1L << E_MOUSE_MOVE)) +#define EM_MOUSE_DBL ((EVENT_MASK)(1L << E_MOUSE_DBL)) +#define EM_CHAR ((EVENT_MASK)(1L << E_CHAR)) +#define EM_VSCROLL ((EVENT_MASK)(1L << E_VSCROLL)) +#define EM_HSCROLL ((EVENT_MASK)(1L << E_HSCROLL)) +#define EM_COMMAND ((EVENT_MASK)(1L << E_COMMAND)) +#define EM_FONT ((EVENT_MASK)(1L << E_FONT)) +#define EM_CONTROL ((EVENT_MASK)(1L << E_CONTROL)) +#define EM_TIMER ((EVENT_MASK)(1L << E_TIMER)) +#define EM_QUIT ((EVENT_MASK)(1L << E_QUIT)) +#define EM_HELP ((EVENT_MASK)(1L << E_HELP)) +#define EM_USER ((EVENT_MASK)(1L << E_USER)) +#define EM_CXO ((EVENT_MASK)(1L << E_CXO)) + +/*--------------------------------------------------------------------------- + XVT escape code value ranges +---------------------------------------------------------------------------*/ +#define XVT_ESC_COMMON_BASE 8000 +#define XVT_ESC_INTERNAL_BASE 30000 + +/*--------------------------------------------------------------------------- + Control, window, and dialog creation flags +---------------------------------------------------------------------------*/ +#define CTL_FLAG_DISABLED 0x00000001L +#define CTL_FLAG_CHECKED 0x00000004L +#define CTL_FLAG_DEFAULT 0x00000008L +#define CTL_FLAG_INVISIBLE 0x00000010L +#define CTL_FLAG_GROUP 0x00000020L +#define CTL_FLAG_MAC_MULTILINE 0x00000080L /* opt3 */ +#define CTL_FLAG_MAC_WORDWRAP 0x00000100L /* opt4 */ +#define CTL_FLAG_READONLY 0x00000200L +#define CTL_FLAG_MULTIPLE 0x00000400L +#define CTL_FLAG_MAC_GENEVA9 0x00000800L /* was opt1 */ +#define CTL_FLAG_PM_SYSICON 0x00000800L +#define CTL_FLAG_MAC_MONACO9 0x00001000L /* was opt2 */ +#define CTL_FLAG_NATIVE_JUST 0x0L /* default */ +#define CTL_FLAG_LEFT_JUST 0x00002000L /* left text */ +#define CTL_FLAG_CENTER_JUST 0x00004000L /* centered text */ +#define CTL_FLAG_RIGHT_JUST 0x00008000L /* right justified text */ +#define CTL_FLAG_PASSWORD 0x00010000L +/* Notebk specific flags */ +#define CTL_FLAG_TAB_SQUARE 0x00000000L /* default */ +#define CTL_FLAG_TAB_ROUND 0x00020000L +#define CTL_FLAG_TAB_DEFAULT 0x00000000L /* default */ +#define CTL_FLAG_TAB_BOTTOM 0x00100000L +#define CTL_FLAG_TAB_LEFT 0x00200000L +#define CTL_FLAG_TAB_RIGHT 0x00400000L +#define CTL_FLAG_TAB_TOP 0x00800000L + +#define WSF_NONE 0x00000000L +#define WSF_SIZE 0x00000001L /* is user sizeable */ +#define WSF_CLOSE 0x00000002L /* is user closeable */ +#define WSF_HSCROLL 0x00000004L /* has horz. scrolbar outside client area */ +#define WSF_VSCROLL 0x00000008L /* has vert. scrolbar outside client area */ +#define WSF_DECORATED 0x0000000FL /* all of above four flags */ +#define WSF_INVISIBLE 0x00000010L /* is initially invisible */ +#define WSF_DISABLED 0x00000020L /* is initially disabled */ +#define WSF_FLOATING 0x00000040L /* is floating */ +#define WSF_ICONIZABLE 0x00000080L +#define WSF_ICONIZED 0x00000100L /* is initially iconized */ +#define WSF_SIZEONLY 0x00000200L /* lacks border rectangles (Mac only) */ +#define WSF_NO_MENUBAR 0x00000800L /* has no menu bar of its own */ +#define WSF_MAXIMIZED 0x00001000L /* initially maximized */ +#define WSF_PLACE_EXACT 0x00002000L /* do not auto-place */ +#define WSF_DEFER_MODAL 0x00008000L /* defer modal state for W_MODAL windows */ +#define WSF_TRANSPARENT 0x00010000L /* trasparent */ +#define WSF_NO_TASKBAR 0x00020000L /* No task bar icon */ + +#define DLG_FLAG_DISABLED 0x00000001L +#define DLG_FLAG_INVISIBLE 0x00000002L + +/*--------------------------------------------------------------------------- + Standard tool constants +---------------------------------------------------------------------------*/ +#define TL_PEN_BLACK 1L +#define TL_PEN_HOLLOW 2L +#define TL_PEN_RUBBER 3L +#define TL_PEN_WHITE 4L +#define TL_PEN_DKGRAY 5L +#define TL_PEN_GRAY 6L +#define TL_PEN_LTGRAY 7L + +#define TL_BRUSH_BLACK 0L +#define TL_BRUSH_WHITE 1L + +/*--------------------------------------------------------------------------- + Font support +---------------------------------------------------------------------------*/ +/* Font style */ +#define XVT_FS_NONE 0L +#define XVT_FS_BOLD (1L<<0) +#define XVT_FS_ITALIC (1L<<1) +#define XVT_FS_UNDERLINE (1L<<4) +#define XVT_FS_OUTLINE (1L<<5) +#define XVT_FS_SHADOW (1L<<6) +#define XVT_FS_INVERSE (1L<<7) +#define XVT_FS_BLINK (1L<<8) +#define XVT_FS_STRIKEOUT (1L<<9) +#define XVT_FS_USER1 (1L<<15) +#define XVT_FS_USER2 (1L<<16) +#define XVT_FS_USER3 (1L<<17) +#define XVT_FS_USER4 (1L<<18) +#define XVT_FS_USER5 (1L<<19) +#define XVT_FS_WILDCARD (1L<<25) + +/* Font attribute type */ +#define XVT_FA_FAMILY (XVT_FONT_ATTR_MASK)(1L<<0) +#define XVT_FA_SIZE (XVT_FONT_ATTR_MASK)(1L<<1) +#define XVT_FA_STYLE (XVT_FONT_ATTR_MASK)(1L<<2) +#define XVT_FA_NATIVE (XVT_FONT_ATTR_MASK)(1L<<3) +#define XVT_FA_APP_DATA (XVT_FONT_ATTR_MASK)(1L<<4) +#define XVT_FA_WIN (XVT_FONT_ATTR_MASK)(1L<<5) +#define XVT_FA_ALL (XVT_FONT_ATTR_MASK)~(0L) + +/* Guaranteed support for these font families */ +#ifdef WIN32 +#define XVT_FFN_TIMES "Times New Roman" +#define XVT_FFN_HELVETICA "Arial" +#define XVT_FFN_COURIER "Courier New" +#define XVT_FFN_FIXED "Courier New" +#define XVT_FFN_SYSTEM "system" +#else +#define XVT_FFN_TIMES "times" +#define XVT_FFN_HELVETICA "helvetica" +#define XVT_FFN_COURIER "courier" +#define XVT_FFN_FIXED "fixed" +#define XVT_FFN_SYSTEM "system" +#endif + +/* Convenience macro for identifying a NULL font id */ +#define NULL_FNTID ((XVT_FNTID)NULL) + + +/*--------------------------------------------------------------------------- + COLOR macros +---------------------------------------------------------------------------*/ + +/* allocated nbr of entries in image->v.cl8.clut */ + +#define XVT_CLUT_SIZE 256 +#define XVT_PALETTE_SIZE 256 + +/* macros for COLOR values */ +#define XVT_MAKE_COLOR(r,g,b) ((COLOR)((((ULONG)(r)&0xFF) << 16) | \ + (((ULONG)(g)&0xFF) << 8) | \ + (((ULONG)(b)&0xFF)))) +#define XVT_COLOR_GET_RED(color) ((unsigned char)(((color) >> 16) & 0xFF)) +#define XVT_COLOR_GET_GREEN(color) ((unsigned char)(((color) >> 8) & 0xFF)) +#define XVT_COLOR_GET_BLUE(color) ((unsigned char)((color) & 0xFF)) + +/*--------------------------------------------------------------------------- + File attributes +---------------------------------------------------------------------------*/ +/* definitions for attributes used in the xvt_fsys_*_file_attr calls */ + +#define XVT_FILE_ATTR_MINIMUM 1L + +#define XVT_FILE_ATTR_EXIST 1L +#define XVT_FILE_ATTR_READ 2L +#define XVT_FILE_ATTR_WRITE 3L +#define XVT_FILE_ATTR_EXECUTE 4L +#define XVT_FILE_ATTR_DIRECTORY 5L +#define XVT_FILE_ATTR_NUMLINKS 6L +#define XVT_FILE_ATTR_SIZE 7L +#define XVT_FILE_ATTR_ATIME 8L +#define XVT_FILE_ATTR_MTIME 9L +#define XVT_FILE_ATTR_CTIME 10L +#define XVT_FILE_ATTR_CREATORSTR 11L +#define XVT_FILE_ATTR_DIRSTR 12L +#define XVT_FILE_ATTR_FILESTR 13L +#define XVT_FILE_ATTR_TYPESTR 14L + +#define XVT_FILE_ATTR_MAXIMUM 14L + +/*--------------------------------------------------------------------------- + Miscellaneous +---------------------------------------------------------------------------*/ +#define XVT_TIMER_ERROR (-1L) +#define XVT_MAX_WINDOW_RECT ((RCT *)NULL) +#define DIR_TYPE "/\1\2\3" /* used with list_files */ +#ifndef NULL +#define NULL 0L +#endif +#define NULL_WIN ((WINDOW)NULL) +#define NULL_PICTURE ((PICTURE)NULL) +#define NULL_PIXMAP ((XVT_PIXMAP)NULL) +#define NULL_PALETTE ((XVT_PALETTE)NULL) +#define NULL_IMAGE ((XVT_IMAGE)NULL) +#define NULL_TID ((XVT_HELP_TID)NULL) +#define NULL_TXEDIT NULL_WIN +#define BAD_TXEDIT NULL_TXEDIT + +#define TASK_WIN ((WINDOW)xvt_vobj_get_attr(NULL_WIN, ATTR_TASK_WINDOW)) +#define SCREEN_WIN ((WINDOW)xvt_vobj_get_attr(NULL_WIN, ATTR_SCREEN_WINDOW)) +//#define PRINTER_WIN ((WINDOW)xvt_vobj_get_attr(NULL_WIN, ATTR_PRINTER_WINDOW)) // Guy optimization +#define PRINTER_WIN 883L + +#define PTR_LONG(p) ((long)(char *)(p)) + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif +#ifndef min +#define min(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#define XVT_MAKE_VERSION(major, minor, patch) ((major)*10000L + (minor)*100L + (patch)) + +/*--------------------------------------------------------------------------- + Attribute definitions for get/set_value() + Note that non-portable constants are defined by the platform header. +---------------------------------------------------------------------------*/ +#define ATTR_BASE 0 +/* system config attributes */ +#define ATTR_BACK_COLOR (ATTR_BASE + 100) +#define ATTR_HAVE_COLOR (ATTR_BASE + 101) +#define ATTR_HAVE_MOUSE (ATTR_BASE + 102) +#define ATTR_NUM_TIMERS (ATTR_BASE + 103) +#define ATTR_XVT_CONFIG (ATTR_BASE + 104) +#define ATTR_DISPLAY_TYPE (ATTR_BASE + 105) + +/* Object size attributes */ +#define ATTR_CTL_BUTTON_HEIGHT (ATTR_BASE + 200) +#define ATTR_CTL_CHECKBOX_HEIGHT (ATTR_BASE + 201) +#define ATTR_CTL_EDIT_TEXT_HEIGHT (ATTR_BASE + 202) +#define ATTR_CTL_HORZ_SBAR_HEIGHT (ATTR_BASE + 203) +#define ATTR_CTL_VERT_SBAR_WIDTH (ATTR_BASE + 204) +#define ATTR_CTL_RADIOBUTTON_HEIGHT (ATTR_BASE + 205) +#define ATTR_CTL_STATIC_TEXT_HEIGHT (ATTR_BASE + 206) +#define ATTR_ICON_WIDTH (ATTR_BASE + 207) +#define ATTR_ICON_HEIGHT (ATTR_BASE + 208) + +/* Predefined windows */ +#define ATTR_SCREEN_WINDOW (ATTR_BASE + 300) +#define ATTR_TASK_WINDOW (ATTR_BASE + 301) +#define ATTR_PRINTER_WINDOW (ATTR_BASE + 302) + +/* System metric attributes */ +#define ATTR_SCREEN_HEIGHT (ATTR_BASE + 400) +#define ATTR_SCREEN_WIDTH (ATTR_BASE + 401) +#define ATTR_SCREEN_HRES (ATTR_BASE + 402) +#define ATTR_SCREEN_VRES (ATTR_BASE + 403) +#define ATTR_PRINTER_HEIGHT (ATTR_BASE + 404) +#define ATTR_PRINTER_WIDTH (ATTR_BASE + 405) +#define ATTR_PRINTER_HRES (ATTR_BASE + 406) +#define ATTR_PRINTER_VRES (ATTR_BASE + 407) +#define ATTR_DOC_STAGGER_HORZ (ATTR_BASE + 408) +#define ATTR_DOC_STAGGER_VERT (ATTR_BASE + 409) + +/* Window metric attributes */ +#define ATTR_DOCFRAME_WIDTH (ATTR_BASE + 500) +#define ATTR_DOCFRAME_HEIGHT (ATTR_BASE + 501) +#define ATTR_FRAME_WIDTH (ATTR_BASE + 502) +#define ATTR_FRAME_HEIGHT (ATTR_BASE + 503) +#define ATTR_DBLFRAME_WIDTH (ATTR_BASE + 504) +#define ATTR_DBLFRAME_HEIGHT (ATTR_BASE + 505) +#define ATTR_MENU_HEIGHT (ATTR_BASE + 506) +#define ATTR_TITLE_HEIGHT (ATTR_BASE + 507) + +/* Window attributes */ +#define ATTR_NATIVE_GRAPHIC_CONTEXT (ATTR_BASE + 601) +#define ATTR_NATIVE_WINDOW (ATTR_BASE + 602) +#define ATTR_PROPAGATE_NAV_CHARS (ATTR_BASE + 603) + +/* Misc attributes */ +#define ATTR_DEBUG_FILENAME (ATTR_BASE + 700) +#define ATTR_MALLOC_ERR_HANDLER (ATTR_BASE + 701) /* DECLINING */ +#define ATTR_KEY_HOOK (ATTR_BASE + 702) +#define ATTR_EVENT_HOOK (ATTR_BASE + 703) +#define ATTR_SUPPRESS_UPDATE_CHECK (ATTR_BASE + 704) +#define ATTR_FATAL_ERR_HANDLER (ATTR_BASE + 705) /* DECLINING */ +#define ATTR_ERRMSG_HANDLER (ATTR_BASE + 706) +#define ATTR_MEMORY_MANAGER (ATTR_BASE + 707) +#define ATTR_DEFAULT_PALETTE_TYPE (ATTR_BASE + 708) +#define ATTR_ERRMSG_FILENAME (ATTR_BASE + 709) +#define ATTR_HELP_HOOK (ATTR_BASE + 710) +#define ATTR_HELP_CONTEXT (ATTR_BASE + 711) +#define ATTR_COLLATE_HOOK (ATTR_BASE + 712) +#define ATTR_MULTIBYTE_AWARE (ATTR_BASE + 713) +#define ATTR_RESOURCE_FILENAME (ATTR_BASE + 714) +#define ATTR_APP_CTL_COLORS (ATTR_BASE + 715) +#define ATTR_APPL_NAME_RID (ATTR_BASE + 716) +#define ATTR_TASKWIN_TITLE_RID (ATTR_BASE + 717) +#define ATTR_R40_TXEDIT_BEHAVIOR (ATTR_BASE + 718) +#define ATTR_APP_CTL_FONT_RID (ATTR_BASE + 719) +#define ATTR_SPEECH_MODE (ATTR_BASE + 720) /* Added by Guy */ +#define ATTR_APPL_VERSION_STRING (ATTR_BASE + 721) /* Added by Guy */ +#define ATTR_APPL_ALREADY_RUNNING (ATTR_BASE + 722) /* Added by Guy */ +#define ATTR_APPL_VERSION_YEAR (ATTR_BASE + 723) /* Added by Guy */ + +/* Font attributes */ +#define ATTR_FONT_MAPPER (ATTR_BASE + 800) +#define ATTR_FONT_DIALOG (ATTR_BASE + 801) +#define ATTR_FONT_CACHE_SIZE (ATTR_BASE + 802) + +/*--------------------------------------------------------------------------- + Values for the "modifier" field of the E_CHAR event. +---------------------------------------------------------------------------*/ +#define XVT_MOD_KEY_NONE 0L +#define XVT_MOD_KEY_SHIFT (1L<<1) +#define XVT_MOD_KEY_CTL (1L<<2) +#define XVT_MOD_KEY_ALT (1L<<3) +#define XVT_MOD_KEY_LSHIFT (1L<<4) +#define XVT_MOD_KEY_RSHIFT (1L<<5) +#define XVT_MOD_KEY_CMD (1L<<6) +#define XVT_MOD_KEY_OPTION (1L<<7) +#define XVT_MOD_KEY_COMPOSE (1L<<8) +#define XVT_MOD_KEY_LALT (1L<<9) +#define XVT_MOD_KEY_RALT (1L<<10) +#define XVT_MOD_KEY_ALTGRAF (1L<<11) + + +/*--------------------------------------------------------------------------- + Values for the type XVT_COLOR_TYPE. +---------------------------------------------------------------------------*/ +#define XVT_COLOR_NULL (XVT_COLOR_TYPE)(0L) +#define XVT_COLOR_FOREGROUND (XVT_COLOR_TYPE)(1L<<1) +#define XVT_COLOR_BACKGROUND (XVT_COLOR_TYPE)(1L<<2) +#define XVT_COLOR_BLEND (XVT_COLOR_TYPE)(1L<<3) +#define XVT_COLOR_HIGHLIGHT (XVT_COLOR_TYPE)(1L<<4) +#define XVT_COLOR_BORDER (XVT_COLOR_TYPE)(1L<<5) +#define XVT_COLOR_TROUGH (XVT_COLOR_TYPE)(1L<<6) +#define XVT_COLOR_SELECT (XVT_COLOR_TYPE)(1L<<7) +// Added by XVAGA +#define XVT_COLOR_CAPTIONLT (XVT_COLOR_TYPE)(1L<<8) +#define XVT_COLOR_CAPTIONDK (XVT_COLOR_TYPE)(1L<<9) +#define XVT_COLOR_CAPTIONTEXT (XVT_COLOR_TYPE)(1L<<10) + +#define XVT_PDF_PRINTER_NAME "***AGAPDF***" + +#endif /* XVT_INCL_DEFS */ \ No newline at end of file diff --git a/src/xvaga01/xvt_env.h b/src/xvaga01/xvt_env.h new file mode 100644 index 000000000..76759e7ff --- /dev/null +++ b/src/xvaga01/xvt_env.h @@ -0,0 +1,77 @@ +#define XVT_CC_ENUM_END 127 + +#define XVT_OS_WIN32 400 +#define XVT_OS_LINUX 595 + +#ifdef WIN32 +#define XVT_OS XVT_OS_WIN32 +#else +#define XVT_OS XVT_OS_LINUX +#endif + +#define XVT_WS_LINUX 107 +#define XVT_WS_WIN_95 301 +#define XVT_WS_WIN_98 302 +#define XVT_WS_WIN_ME 303 +#define XVT_WS_WIN_NT 304 +#define XVT_WS_WIN_2000 305 +#define XVT_WS_WIN_XP 306 +#define XVT_WS_WIN_2003 307 +#define XVT_WS_WIN_VISTA 308 +#define XVT_WS_WIN_2008 309 +#define XVT_WS_WIN_2008R2 310 +#define XVT_WS_WIN_7 311 +#define XVT_WS_WIN_2012 312 +#define XVT_WS_WIN_8 313 +#define XVT_WS_WIN_10 314 + +#define XVT_WS_UNKNOWN 0 +#define MACWS 100 /* Apple Macintosh */ +#define PMWS 200 /* IBM OS/2 PM */ +#define WIN32WS 300 /* MS Windows 3.1 for NT */ +#define WIN16WS 400 /* MS Windows 3.x for Win16 */ +#define WMWS 450 /* Character */ +#define MTFWS 500 /* Motif */ +#define XOLWS 501 /* Open Look */ +#define WXGTKWS 107 +#define NTWS WIN32WS /* for compatibility with docs */ +#define WINWS WIN16WS /* for compatibility with docs */ + +#if defined(WIN32) + #define XVTWS WIN32WS +#elif defined(LINUX) + #define XVTWS WXGTKWS +#else + #define XVTWS XVT_WS_UNKNOWN +#endif + +#define ATTR_WIN_BASE 10000 +#define ATTR_WIN_CMD_LINE (ATTR_WIN_BASE + 0) +#define ATTR_WIN_INSTANCE (ATTR_WIN_BASE + 1) +#define ATTR_WIN_PREV_INSTANCE (ATTR_WIN_BASE + 2) +#define ATTR_WIN_MDI (ATTR_WIN_BASE + 3) +#define ATTR_WIN_FCN_PRINT_INIT (ATTR_WIN_BASE + 4) +#define ATTR_WIN_PM_CLASS_ICON (ATTR_WIN_BASE + 5) +#define ATTR_WIN_PM_DRAWABLE_TWIN (ATTR_WIN_BASE + 6) +#define ATTR_WIN_PM_SPECIAL_1ST_DOC (ATTR_WIN_BASE + 7) +#define ATTR_WIN_PM_NO_TWIN (ATTR_WIN_BASE + 8) +#define ATTR_WIN_PM_TWIN_STARTUP_DATA (ATTR_WIN_BASE + 9) +#define ATTR_WIN_PM_TWIN_STARTUP_MASK (ATTR_WIN_BASE + 10) +#define ATTR_WIN_PM_TWIN_STARTUP_RCT (ATTR_WIN_BASE + 11) +#define ATTR_WIN_PM_TWIN_STARTUP_STYLE (ATTR_WIN_BASE + 12) +#define ATTR_WIN_OPENFILENAME_HOOK (ATTR_WIN_BASE + 13) +#define ATTR_WIN_POPUP_DETACHED (ATTR_WIN_BASE + 14) +#define main xvt_main + +/**************************************************************************** +* Define Prototyping Information +****************************************************************************/ + +#define XVT_CC_ARGL(al__) ( +#define XVT_CC_ARG(t__,a__) t__ a__, +#define XVT_CC_LARG(t__,a__) t__ a__) +#define XVT_CC_ARGS(al__) al__ +#define XVT_CC_NOARGS() (void) + +/* Default to no linkage conventions in callback typedef */ +#define XVT_CALLCONV_TYPEDEF(ret, func, args) ret (*func)XVT_CC_ARGS(args) diff --git a/src/xvaga01/xvt_help.h b/src/xvaga01/xvt_help.h new file mode 100644 index 000000000..6b9acdba1 --- /dev/null +++ b/src/xvaga01/xvt_help.h @@ -0,0 +1,280 @@ +/**************************************************************************** + * + * Copyright 1987-1996 XVT Software. All rights reserved. + * May be used only in accordance with a valid Source Code License + * Agreement with XVT Software. + * + * $RCSfile: xvt_help.h,v $ + * $Revision: 1.1 $ + * + * Purpose: XVT help subsystem macros and types. + * + ****************************************************************************/ + +#ifndef XVT_INCL_HELP +#define XVT_INCL_HELP + + +/* +* Help Versions +*/ +#define XVT_HELP_VERSION_MAJOR 4 +#define XVT_HELP_VERSION_MINOR 57 +#define XVT_HELP_VERSION_PATCH 0 +#define XVT_HELP_VERSION XVT_MAKE_VERSION(XVT_HELP_VERSION_MAJOR,XVT_HELP_VERSION_MINOR,XVT_HELP_VERSION_PATCH) + + + +/* +* Types +*/ + +typedef struct s_xvt_help_info {long* fake;} *XVT_HELP_INFO; +#define NULL_HELP_INFO (XVT_HELP_INFO)0 + + +typedef enum e_xvt_help_flavor +{ + XVT_HELP_FLAVOR_NONE, + XVT_HELP_FLAVOR_NTVSRV, + XVT_HELP_FLAVOR_NTVBND, + XVT_HELP_FLAVOR_PORTSRV, + XVT_HELP_FLAVOR_PORTBND +} XVT_HELP_FLAVOR; + + + +/* +* Help System Flags. +*/ + +/* for xvt_help_open_helpfile */ +#define HSF_INDEX_ON_DISK 0x001L /* Default value is in-memory */ +#define HSF_NO_TOPIC_WARNING 0x002L /* No warning for missing topics */ +#define HSF_NO_HELPMENU_ASSOC 0x004L /* Don't associate topics to helpmenu */ +#define HSF_APPNAME_TITLE 0x008L /* show APPNAME in title */ +#define HSF_NO_BEEP_MODAL 0x010L /* don't beep for help on modal dialog*/ + +/* internal use, only */ +#define HSF_EXIT_ON_CLOSE 0x020L /* exit when topic window closes */ + +/* for customization */ +#define HSF_USER 0x040L + +/* +* Reserved help topic IDs +*/ +#define XVT_TPC_BASE 32000 +#define XVT_TPC_HELPONHELP (XVT_TPC_BASE + 0) +#define XVT_TPC_INDEX (XVT_TPC_BASE + 1) +#define XVT_TPC_TUTORIAL (XVT_TPC_BASE + 2) +#define XVT_TPC_BASICSKILLS (XVT_TPC_BASE + 3) +#define XVT_TPC_PROCEDURES (XVT_TPC_BASE + 4) +#define XVT_TPC_KEYBOARD (XVT_TPC_BASE + 5) +#define XVT_TPC_CONTENTS (XVT_TPC_BASE + 6) +#define XVT_TPC_ABOUT (XVT_TPC_BASE + 7) +#define XVT_TPC_COMMANDS (XVT_TPC_BASE + 8) +#define XVT_TPC_GLOSSARY (XVT_TPC_BASE + 9) +#define XVT_TPC_ABOUTHELP (XVT_TPC_BASE + 10) + +/* Motif specific */ +#define XVT_TPC_ONHELP XVT_TPC_HELPONHELP +#define XVT_TPC_ONKEYS XVT_TPC_KEYBOARD +#define XVT_TPC_ONVERSION XVT_TPC_ABOUT + +/* Other help menu item topics */ +#define XVT_TPC_ONCONTEXT (XVT_TPC_BASE + 20) +#define XVT_TPC_SEARCH (XVT_TPC_BASE + 21) +#define XVT_TPC_ONWINDOW (XVT_TPC_BASE + 22) +#define XVT_TPC_OBJCLICK (XVT_TPC_BASE + 23) + +/* predefined dialog topics */ +#define XVT_TPC_FILE_OPEN (XVT_TPC_BASE + 30) +#define XVT_TPC_FILE_SAVE (XVT_TPC_BASE + 40) +#define XVT_TPC_ASK (XVT_TPC_BASE + 50) +#define XVT_TPC_NOTE (XVT_TPC_BASE + 60) +#define XVT_TPC_ERROR (XVT_TPC_BASE + 70) +#define XVT_TPC_WARNING (XVT_TPC_BASE + 80) +#define XVT_TPC_STRING_PROMPT (XVT_TPC_BASE + 90) +#define XVT_TPC_FONT_SEL (XVT_TPC_BASE + 100) +#define XVT_TPC_PAGE_SETUP (XVT_TPC_BASE + 110) +#define XVT_TPC_MESSAGE (XVT_TPC_BASE + 120) +#define XVT_TPC_FATAL (XVT_TPC_BASE + 130) + +/* maximum predefined topic */ +#define XVT_TPC_MAX (XVT_TPC_BASE + 130) + + +/* +* Resource-related macros. +*/ + + +/* +* Help Menu Tags +*/ + +#define TagBASE M_HELP +#define M_HELP_HELPMENU (TagBASE + 0) +#define M_HELP_ONCONTEXT (TagBASE + 1) +#define M_HELP_HELPONHELP (TagBASE + 2) +#define M_HELP_ONWINDOW (TagBASE + 3) +#define M_HELP_KEYBOARD (TagBASE + 4) +#define M_HELP_INDEX (TagBASE + 5) +#define M_HELP_TUTORIAL (TagBASE + 6) +#define M_HELP_SEARCH (TagBASE + 7) +#define M_HELP_OBJCLICK (TagBASE + 8) +#define M_HELP_VERSION (TagBASE + 9) +#define M_HELP_GOTO (TagBASE + 10) +#define M_HELP_GLOSSARY (TagBASE + 11) +#define M_HELP_CONTENTS (TagBASE + 12) +/* internal use -- highest help tag */ +#define M_HELP_LAST (TagBASE + 12) + + +#ifndef NO_HELP_RESOURCES + +/* +* Help menu text strings. +* +* (Because of the Mac, these are numbered using even values.) +*/ +#define HELP_STR_BASE XVTV_STRING_RES_BASE +#define TextHELPMENU (HELP_STR_BASE + 0) +#define TextONWINDOW (HELP_STR_BASE + 2) +#define TextHELPONHELP (HELP_STR_BASE + 4) +#define TextKEYBOARD (HELP_STR_BASE + 6) +#define TextINDEX (HELP_STR_BASE + 8) +#define TextCONTENTS (HELP_STR_BASE + 10) +#define TextTUTORIAL (HELP_STR_BASE + 12) +#define TextVERSION (HELP_STR_BASE + 14) +#define TextSEARCH (HELP_STR_BASE + 16) +#define TextONCONTEXT (HELP_STR_BASE + 18) +#define TextOBJCLICK (HELP_STR_BASE + 20) + +/* Topic menubar navigate strings */ +#define TextNAV_SEARCH (HELP_STR_BASE + 22) +#define TextNAV_GOTO (HELP_STR_BASE + 24) +#define TextNAV_MARK (HELP_STR_BASE + 26) +#define TextNAV_BACKLINK (HELP_STR_BASE + 28) +#define TextNAV_FORWLINK (HELP_STR_BASE + 30) +#define TextNAV_PREVPAGE (HELP_STR_BASE + 32) +#define TextNAV_NEXTPAGE (HELP_STR_BASE + 34) + +/* General strings */ +#define TextCLIP_ERR (HELP_STR_BASE + 36) +#define TextMEM_ERR (HELP_STR_BASE + 38) +#define TextCLIP_PUT_ERR (HELP_STR_BASE + 40) +#define TextPRINT_ERR (HELP_STR_BASE + 42) +#define TextPRINT_OK (HELP_STR_BASE + 44) +#define TextCLIP_OK (HELP_STR_BASE + 46) +#define TextTHREAD_INFO (HELP_STR_BASE + 48) +#define TextMARKED_INFO (HELP_STR_BASE + 50) + +/* Copy selection window */ +#define TextCOPYPART_NONE (HELP_STR_BASE + 52) + +/* Some labels */ +#define TextMARK (HELP_STR_BASE + 54) +#define TextUNMARK (HELP_STR_BASE + 56) + +/* hyper link & hot link attribute strings */ +#define TextHYPERLINK (HELP_STR_BASE + 60) +#define TextHOTLINK (HELP_STR_BASE + 62) + + +/* + * Define the local resource file constants + */ +/* Window, dialog identifiers */ +#define HELP_RES_BASE 29500 +#define TOPIC_WIN_RID (HELP_RES_BASE + 0) +#define GOTO_DLG_RID (HELP_RES_BASE + 3) +#define SEARCH_DLG_RID (HELP_RES_BASE + 4) +#define TOPIC_SELCOPY_RID (HELP_RES_BASE + 5) +#define HELPVIEW_ABOUT_RID (HELP_RES_BASE + 6) + +/* Topic window menubar */ +#define TOPICWIN_MENUBAR (HELP_RES_BASE + 10) +#define MHELP_FILE (HELP_RES_BASE + 11) +#define MHELP_FILE_PRINT_SETUP (HELP_RES_BASE + 12) +#define MHELP_FILE_PRINT (HELP_RES_BASE + 13) +#define MHELP_FILE_EXIT (HELP_RES_BASE + 14) +#define MHELP_EDIT (HELP_RES_BASE + 15) +#define MHELP_EDIT_COPY M_EDIT_COPY /* (HELP_RES_BASE + 16) */ +#define MHELP_EDIT_AS_WRAPPED (HELP_RES_BASE + 17) +#define MHELP_NAV (HELP_RES_BASE + 18) +#define MHELP_NAV_SEARCH (HELP_RES_BASE + 19) +#define MHELP_NAV_GOTO (HELP_RES_BASE + 20) +#define MHELP_NAV_MARK (HELP_RES_BASE + 21) +#define MHELP_NAV_BACKLINK (HELP_RES_BASE + 22) +#define MHELP_NAV_FORWLINK (HELP_RES_BASE + 23) +#define MHELP_NAV_PREVPAGE (HELP_RES_BASE + 24) +#define MHELP_NAV_NEXTPAGE (HELP_RES_BASE + 25) +#define MHELP_HELP (HELP_RES_BASE + 26) +#define MHELP_HELP_ONHELP M_HELP_HELPONHELP +#define MHELP_HELP_ABOUT (HELP_RES_BASE + 27) +#define MHELP_EDIT_COPYPART (HELP_RES_BASE + 28) + +/* Topic specific control identifiers */ +#define TOPIC_SEARCH (HELP_RES_BASE + 30) +#define TOPIC_BOOKMARK (HELP_RES_BASE + 31) +#define TOPIC_GOTO (HELP_RES_BASE + 32) +#define TOPIC_BACKLINK (HELP_RES_BASE + 33) +#define TOPIC_FORWLINK (HELP_RES_BASE + 34) +#define TOPIC_VSCROLL (HELP_RES_BASE + 35) +#define TOPIC_INFOGROUP (HELP_RES_BASE + 36) +#define TOPIC_INFOLBL (HELP_RES_BASE + 37) +#define TOPIC_CLIENTW (HELP_RES_BASE + 38) +#define TOPIC_PREVPAGE (HELP_RES_BASE + 39) +#define TOPIC_NEXTPAGE (HELP_RES_BASE + 40) + +/* Shared identifiers */ +#define CLIENT_AREA (HELP_RES_BASE + 50) + +/* Search dialog ids */ +#define SEARCH_BY_TOPICNAME (HELP_RES_BASE + 60) +#define SEARCH_BY_KEYWORD (HELP_RES_BASE + 61) +#define SEARCH_SELECT_LIST (HELP_RES_BASE + 62) +#define SEARCH_MATCH_LIST (HELP_RES_BASE + 63) +#define SEARCH_GOTO_MATCH (HELP_RES_BASE + 64) +#define SEARCH_CANCEL DLG_CANCEL +#define SEARCH_RADIO_LBL (HELP_RES_BASE + 66) +#define SEARCH_ITEMS_LBL (HELP_RES_BASE + 67) +#define SEARCH_MATCH_LBL (HELP_RES_BASE + 68) + +/* Goto dialog ids */ +#define GOTO_CONTENTS M_HELP_CONTENTS +#define GOTO_INDEX M_HELP_INDEX +#define GOTO_CONTENTS M_HELP_CONTENTS +#define GOTO_GLOSSARY M_HELP_GLOSSARY +#define GOTO_KEYBOARD M_HELP_KEYBOARD +#define GOTO_BOOKMARK_LIST (HELP_RES_BASE + 70) +#define GOTO_BOOKMARK_BTN (HELP_RES_BASE + 71) +#define GOTO_CANCEL DLG_CANCEL +#define GOTO_GROUP (HELP_RES_BASE + 73) +#define GOTO_BOOK_LBL (HELP_RES_BASE + 74) + +/* Popup window sample definition */ +#define POPUP_WIN_RID (HELP_RES_BASE + 80) + +/* Topic selection copy menubar */ +#define EDITSEL_MENUBAR (HELP_RES_BASE + 90) +#define MHELP_TSE_EDIT (HELP_RES_BASE + 91) +#define MHELP_TSE_EDIT_COPY /* (HELP_RES_BASE + 92) */ M_EDIT_COPY +#define MHELP_TSE_HELP (HELP_RES_BASE + 93) +#define MHELP_TSE_HELP_ONHELP M_HELP_HELPONHELP +#define MHELP_TSE_HELP_ABOUT (HELP_RES_BASE + 94) + +/* Other RID for selection copy window */ +#define TOPIC_SELCOPY_WIN_TX (HELP_RES_BASE + 100) +#define TOPIC_SELCOPY_WIN_LBL (HELP_RES_BASE + 101) + +/* RID's for viewer about box */ +#define XHV_STATIC_1 (HELP_RES_BASE + 110) +#define XHV_STATIC_2 (HELP_RES_BASE + 111) + +#endif /* NO_HELP_RESOURCES */ + +#endif /* XVT_INCL_HELP */ + diff --git a/src/xvaga01/xvt_menu.h b/src/xvaga01/xvt_menu.h new file mode 100644 index 000000000..ceb4fa4f1 --- /dev/null +++ b/src/xvaga01/xvt_menu.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * + * Copyright 1987-1996 XVT Software. All rights reserved. + * May be used only in accordance with a valid Source Code License + * Agreement with XVT Software. + * + * $RCSfile: xvt_menu.h,v $ + * $Revision: 1.2.6.1 $ + * + * Purpose: XVT menu subsystem definitions. + * + ****************************************************************************/ + +#ifndef XVT_INCL_XVT_MENU +#define XVT_INCL_XVT_MENU + +#define MAX_MENU_TAG 31999 /* max allowable application menu tag */ + +#define M_FILE 32000 +#define M_FILE_NEW (M_FILE+1) +#define M_FILE_OPEN (M_FILE+2) +#define M_FILE_CLOSE (M_FILE+3) +#define M_FILE_SAVE (M_FILE+4) +#define M_FILE_SAVE_AS (M_FILE+5) +#define M_FILE_REVERT (M_FILE+6) +#define M_FILE_PG_SETUP (M_FILE+7) +#define M_FILE_PRINT (M_FILE+8) +#define M_FILE_QUIT (M_FILE+9) +#define M_FILE_ABOUT (M_FILE+10) +#define M_FILE_PREVIEW (M_FILE+11) + +#define M_EDIT 32025 +#define M_EDIT_UNDO (M_EDIT+1) +#define M_EDIT_CUT (M_EDIT+2) +#define M_EDIT_COPY (M_EDIT+3) +#define M_EDIT_PASTE (M_EDIT+4) +#define M_EDIT_CLEAR (M_EDIT+5) +#define M_EDIT_SEL_ALL (M_EDIT+6) +#define M_EDIT_CLIPBOARD (M_EDIT+7) + +#define M_FONT 32050 /* needs range of 300 for Mac */ +#define M_STYLE 32350 +#define M_HELP 32450 /* reserve about 50 for Help */ +#define M_DEFAULT_SEPARATOR 32765 /* indicates no tag value set */ +#define FONT_MENU_TAG 32766 /* magic cookie */ +/* XVT/Mac reserves 32767 */ + +#endif /* XVT_INCL_XVT_MENU */ diff --git a/src/xvaga01/xvt_sql.cpp b/src/xvaga01/xvt_sql.cpp new file mode 100644 index 000000000..6950bb6bd --- /dev/null +++ b/src/xvaga01/xvt_sql.cpp @@ -0,0 +1,417 @@ +#include "wxinc.h" +#include "xvt.h" + +#include "../wxSqlite3/wxSqlite3.h" + +class XVT_SQLDataBase +{ +public: + virtual bool Open(const char* dsn, const char* usr, const char* pwd, const char* dir) = 0; + virtual bool Close() = 0 { return false; } + virtual bool IsOk() const = 0 { return false; } + virtual ULONG Execute(const char* sql, ODBC_CALLBACK cb, void* jolly) = 0; + virtual SLIST ListFields(const char* table) const = 0; + virtual SLIST ListTables() const = 0; + virtual wxString FindField(const char* strTable, const char* strField) const = 0; + virtual bool TableExists(const char* name) const; + + virtual bool Begin() const { return false; } + virtual bool Commit() const { return false; } + virtual bool Rollback() const { return false; } + + virtual ~XVT_SQLDataBase() { Close(); } +}; + +bool XVT_SQLDataBase::TableExists(const char* name) const +{ + bool yes = false; + SLIST list = ListTables(); + for (SLIST_ELT e = xvt_slist_get_first(list); e != NULL && !yes; e = xvt_slist_get_next(list, e)) + { + const char* table = xvt_slist_get(list, e, NULL); + yes = xvt_str_same(name, table) != 0; + } + xvt_slist_destroy(list); + + return yes; +} + +class XVT_SQLDB_SQLite3 : public XVT_SQLDataBase +{ + wxSQLite3Database* m_pDB; + +protected: + virtual bool Open(const char* dsn, const char* usr, const char* pwd, const char* dir); + virtual bool Close(); + virtual bool IsOk() const { return m_pDB != NULL && m_pDB->IsOpen(); } + virtual ULONG Execute(const char* sql, ODBC_CALLBACK cb, void* jolly); + virtual SLIST ListFields(const char* table) const; + virtual SLIST ListTables() const; + virtual wxString FindField(const char* strTable, const char* strField) const; + + virtual bool TableExists(const char* name) const; + +public: + virtual bool Begin() const; + virtual bool Commit() const; + virtual bool Rollback() const; + + XVT_SQLDB_SQLite3() : m_pDB(NULL) {} +}; + +bool XVT_SQLDB_SQLite3::Open(const char* dsn, const char*, const char*, const char*) +{ + Close(); + m_pDB = new wxSQLite3Database; + if (dsn == NULL || *dsn <= ' ') + dsn = ":memory:"; + try + { + m_pDB->Open(dsn); + } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage()); + return false; + } + + return true; +} + +bool XVT_SQLDB_SQLite3::Close() +{ + if (IsOk()) + { + delete m_pDB; + m_pDB = NULL; + } + return true; +} + +bool XVT_SQLDB_SQLite3::Begin() const +{ + bool bDone = IsOk(); + if (bDone) + { + try { m_pDB->Begin(); } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage()); + bDone = false; + } + } + return bDone; +} + +bool XVT_SQLDB_SQLite3::Commit() const +{ + bool bDone = IsOk(); + if (bDone) + { + try { m_pDB->Commit(); } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage()); + bDone = false; + } + } + return bDone; +} + +bool XVT_SQLDB_SQLite3::Rollback() const +{ + bool bDone = IsOk(); + if (bDone) + { + try { m_pDB->Rollback(); } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage()); + bDone = false; + } + } + return bDone; +} + +ULONG XVT_SQLDB_SQLite3::Execute(const char* sql, ODBC_CALLBACK cb, void* jolly) +{ + ULONG nRows = 0; + if (!IsOk()) + return nRows; + + if (cb != NULL) // Ho una vera callback? + { + try + { + wxSQLite3ResultSet rs = m_pDB->ExecuteQuery(sql); + short numcols = rs.GetColumnCount(); + + if (numcols > 0) + { + wxArrayString aNames, aValues; + + const short nMaxCols = 256; + char* values[nMaxCols]; // Lista dei valori del record corrente + memset(values, 0, sizeof(values)); + + char* names[2*nMaxCols]; // Lista dei nomi dei campi e dei tipi + memset(names, 0, sizeof(names)); + + if (numcols > nMaxCols) + numcols = nMaxCols; + + short c; + for (c = 0; c < numcols; c++) + { + aNames.Add(rs.GetColumnName(c)); + names[c] = (char*)(const char*)aNames[c]; + switch (rs.GetColumnType(c)) + { + case WXSQLITE_INTEGER: + case WXSQLITE_FLOAT: + names[c+numcols] = "NUMERIC"; break; + default: + names[c+numcols] = "VARCHAR"; break; + } + } + + while (rs.NextRow()) + { + aValues.Empty(); + for (c = 0; c < numcols; c++) + { + aValues.Add(rs.GetAsString(c)); + values[c] = (char*)(const char*)aValues[c]; + } + if (cb(jolly, numcols, values, names) != 0) + break; + nRows++; + } + } + } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage() + "\n" + sql); + } + } + else + nRows = m_pDB->ExecuteUpdate(sql); + + return nRows; +} + +SLIST XVT_SQLDB_SQLite3::ListTables() const +{ + wxASSERT(m_pDB != NULL); + SLIST list = xvt_slist_create(); + const wxString strQuery = wxT("SELECT name FROM sqlite_master WHERE type = 'table'"); + try + { + wxSQLite3ResultSet rs = m_pDB->ExecuteQuery(strQuery); + while (rs.NextRow()) + xvt_slist_add_at_elt(list, NULL, rs.GetAsString(0), 0L); + } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage() + "\n" + strQuery); + } + return list; +} + +SLIST XVT_SQLDB_SQLite3::ListFields(const char* strTable) const +{ + SLIST list = NULL; + if (TableExists(strTable)) + { + list = xvt_slist_create(); + wxString strQuery; strQuery << "PRAGMA table_info(" << (const char*)strTable << ");"; + try + { + wxSQLite3ResultSet rs = m_pDB->ExecuteQuery(strQuery); + while (rs.NextRow()) + { + const wxString strField = rs.GetAsString(1); + const wxString strType = rs.GetAsString(2); + if (strType == "INTEGER") + xvt_slist_add_at_elt(list, NULL, strField, 2L); // intfld + if (strType == "NUMERIC") + xvt_slist_add_at_elt(list, NULL, strField, 5L); // realfld + else + xvt_slist_add_at_elt(list, NULL, strField, 1L); // alfafld + } + } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage() + "\n" + strQuery); + } + } + return list; +} + +wxString XVT_SQLDB_SQLite3::FindField(const char* strTable, const char* strField) const +{ + wxString strType; + + if (TableExists(strTable)) + { + wxString strQuery; strQuery << "PRAGMA table_info(" << (const char*)strTable << ");"; + try + { + wxSQLite3ResultSet rs = m_pDB->ExecuteQuery(strQuery); + while (rs.NextRow()) + { + const wxString strFieldFound = rs.GetAsString(1); + + if (strFieldFound == strField) + strType = rs.GetAsString(2); + } + } + catch (wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage() + "\n" + strQuery); + } + } + return strType; +} + +bool XVT_SQLDB_SQLite3::TableExists(const char* name) const +{ + return m_pDB != NULL && name && *name && m_pDB->TableExists(name); +} + +/////////////////////////////////////////////////////////// +// xvt_sql_... +/////////////////////////////////////////////////////////// + +XVT_SQLDB xvt_sql_open(const char* dsn, const char* usr, const char* pwd, const char* dir) +{ + XVT_SQLDataBase* db = new XVT_SQLDB_SQLite3; + db->Open(dsn, usr, pwd, dir); + return (XVT_SQLDB)db; +} + +BOOLEAN xvt_sql_close(XVT_SQLDB handle) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db != NULL) + delete db; + } + return ok; +} + +BOOLEAN xvt_sql_begin(XVT_SQLDB handle) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db != NULL) + ok = db->Begin(); + } + return ok; +} + +BOOLEAN xvt_sql_commit(XVT_SQLDB handle) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db != NULL) + ok = db->Commit(); + } + return ok; +} + +BOOLEAN xvt_sql_rollback(XVT_SQLDB handle) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db != NULL) + ok = db->Rollback(); + } + return ok; +} + +ULONG xvt_sql_execute(XVT_SQLDB handle, const char* sql, ODBC_CALLBACK cb, void* jolly) +{ + ULONG n = 0; + if (handle && sql && *sql) + { + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db->IsOk()) + { + try + { + n = db->Execute(sql, cb, jolly); + } + catch(wxSQLite3Exception& e) + { + xvt_dm_post_error(e.GetMessage() + "\n" + sql); + n = ~0; + } + } + } + return n; +} + +SLIST xvt_sql_list_fields(XVT_SQLDB handle, const char* table) +{ + SLIST list = NULL; + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (table && *table && db != NULL && db->IsOk()) + list = db->ListFields(table); + return list; +} + +SLIST xvt_sql_list_tables(XVT_SQLDB handle) +{ + SLIST list = NULL; + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db != NULL && db->IsOk()) + list = db->ListTables(); + return list; +} + +XVTDLL const char * xvt_sql_field_type(XVT_SQLDB handle, const char* table, const char* field) +{ + XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + static wxString strType; + + strType = ""; + if (db != NULL && db->IsOk()) + strType = db->FindField(table, field); + + return strType; +} + + +BOOLEAN xvt_sql_table_exists(XVT_SQLDB handle, const char* name) +{ + BOOLEAN yes = FALSE; + if (handle && name && *name) + { + const XVT_SQLDataBase* db = (XVT_SQLDataBase*)handle; + if (db->IsOk()) + yes = db->TableExists(name); + } + return yes; +} + + +BOOLEAN xvt_sql_driver(XVT_SQLDB handle, char* str, int max_size) +{ + if (str != NULL && max_size > 8) + { + if (handle != NULL) + wxStrncpy(str, "SQLite 3", max_size); + else + wxStrncpy(str, "ODBC 2.0", max_size); + } + return handle != NULL; +} diff --git a/src/xvaga01/xvt_ssa.cpp b/src/xvaga01/xvt_ssa.cpp new file mode 100644 index 000000000..1ff170e76 --- /dev/null +++ b/src/xvaga01/xvt_ssa.cpp @@ -0,0 +1,226 @@ +#include "wxinc.h" +#include "xvt.h" + +#include "wx/filename.h" + +#include "../ssa/h/ssadll.h" +#include "../ssa/h/ssaerr.h" + +#include + +/////////////////////////////////////////////////////////// +// TSSA_Pinger +/////////////////////////////////////////////////////////// + +class TSSA_Pinger : public wxTimer +{ + int m_nSerNo; + bool m_bRemote; + wxString m_strModule; + wxString _id, _ini; + +protected: + virtual void Notify(); + + bool IsRemote() const { return m_bRemote; } + bool IsMenu() const; + + bool IsFreeModule(const wxString& mod) const; + int AddRef(const wxString& m, int nDelta = +1); + int DecRef(const wxString& m) { return AddRef(m, -1); } + + wxString NormalizedModule(const char* m) const; + bool LoginProduct(); + bool LogoutProduct(); + +public: + int Login(const char* module); + int Serial() const { return m_nSerNo; } + int Logout(const char* module); + TSSA_Pinger(); +}; + +static TSSA_Pinger* _ssa_timer = NULL; +static const char* const _ssa_product = "CAMPO"; + +bool TSSA_Pinger::IsMenu() const +{ + const wxFileName argv0 = __argv[0]; + return argv0.GetName().IsSameAs("ba0", false); +} + +void TSSA_Pinger::Notify() +{ SSA_Ping(_id); } + +bool TSSA_Pinger::LoginProduct() +{ + bool bLoggedIn = IsRemote() && !IsMenu(); + if (!bLoggedIn) + { + const int err = SSA_Login(_id, _ssa_product); + bLoggedIn = err == 0; + } + if (bLoggedIn && m_nSerNo < 0) + m_nSerNo = SSA_NumeroSerie(_ssa_product); + + if (bLoggedIn && IsRemote() && IsMenu()) + ::WritePrivateProfileSection(_ssa_product, "\0\0", _ini); // Azzera tutti i conteggi dei moduli + + return bLoggedIn; +} + +bool TSSA_Pinger::LogoutProduct() +{ + m_nSerNo = SSA_UTENTE_NON_LOGGATO; + if (IsRemote() && !IsMenu()) + return true; + int err = SSA_Logout(_id, _ssa_product); + return err == 0; +} + +wxString TSSA_Pinger::NormalizedModule(const char* m) const +{ + wxString module; + if (m && *m) + { + module = m; + module.Trim(); + module.MakeLower(); + module.Truncate(2); + } + return module; +} + +int TSSA_Pinger::AddRef(const wxString& module, int nDelta) +{ + int nCount = xvt_sys_get_profile_int(_ini, _ssa_product, module, 0); + nCount += nDelta; + if (nCount < 0) nCount = 0; + xvt_sys_set_profile_int(_ini, _ssa_product, module, nCount); + return nCount; +} + +bool TSSA_Pinger::IsFreeModule(const wxString& mod) const +{ return mod.IsEmpty() || mod=="ba" || mod=="pd" || mod=="ps"; } + +int TSSA_Pinger::Login(const char* mod) +{ + if (mod == NULL || *mod <= ' ') + return LoginProduct() ? Serial() : SSA_UTENTE_NON_LOGGATO; + + const wxString module = NormalizedModule(mod); + if (IsFreeModule(module)) // Base o personalizzazione + return 0; + + if (IsRemote() && AddRef(module) > 1) + return 0; + + int err = SSA_ApriModulo(_id, module); + if (err == SSA_UTENTE_NON_LOGGATO) // ritenta! + { + LoginProduct(); + err = SSA_ApriModulo(_id, module); + } + if (err != 0 && *module >= 'a') + err = SSA_ApriModulo(_id, module.Upper()); + + if (IsRemote() && err != 0) + DecRef(module); + + if (err == 0) + m_strModule = module; + + return err; +} + +int TSSA_Pinger::Logout(const char* mod) +{ + const wxString module = mod == NULL ? m_strModule : NormalizedModule(mod); + int err= 0; + bool cm = !IsFreeModule(module); + if (cm) + { + if (IsRemote()) + cm = DecRef(module) <= 0; + if (cm) + err = SSA_ChiudiModulo(_id, module); + } + if (err == 0) + LogoutProduct(); + return err; +} + +TSSA_Pinger::TSSA_Pinger() +{ + wxFileName ini = xvt_fsys_get_campo_ini(); + ini.SetName("ssacount"); ini.MakeAbsolute(); + _ini = ini.GetFullPath(); + + const int sess = xvt_sys_get_session_id(); + char user[64], host[64]; + xvt_sys_get_user_name(user, sizeof(user)); + xvt_sys_get_host_name(host, sizeof(host)); + _id.Printf("%s@%s:%d", user, host, sess); + + char ssaagent[128] = { 0 }; + const int len = xvt_sys_get_profile_string("ssa.ini", "", "SSA-PORT", "", ssaagent, sizeof(ssaagent)); + m_bRemote = len > 8; + m_nSerNo = -1; +} + +/////////////////////////////////////////////////////////// +// xvt_dongle_sa_... +/////////////////////////////////////////////////////////// + +int xvt_dongle_sa_login(const char* module) +{ + if (_ssa_timer == nullptr) + _ssa_timer = new TSSA_Pinger; + return _ssa_timer->Login(module); +} + +int xvt_dongle_sa_crypt(unsigned short* data) +{ + if (_ssa_timer == nullptr) + return SSA_UTENTE_NON_LOGGATO; + if (data == nullptr) + return -EACCES; + + data[0] ^= 0xDEAD; + data[1] ^= 0xBEEF; + data[2] ^= 0xDEAD; + data[3] ^= 0xBEEF; + return 0; +} + +int xvt_dongle_sa_logout(const char* module) +{ + int err = SSA_UTENTE_NON_LOGGATO; + if (_ssa_timer != NULL) + err = _ssa_timer->Logout(module); // logout + return err; +} + +int xvt_dongle_sa_test(const char* module) +{ + int err = SSA_PROD_NOTFOUND; + if (module && *module && *module != '?') + { + wxString p = _ssa_product; + wxString m = module; + + const int dot = m.Find('.'); + if (dot > 0) + { + p = m.Left(dot); + m = m.Mid(dot+1); + } + err = SSA_VerificaModulo(p, m); + if (err <= SSA_MOD_NOTFOUND && m[0] >= 'a') + { + m.MakeUpper(); + err = SSA_VerificaModulo(p, m); + } + } + return err; +} diff --git a/src/xvaga01/xvt_sw.cpp b/src/xvaga01/xvt_sw.cpp new file mode 100644 index 000000000..f13d61ab2 --- /dev/null +++ b/src/xvaga01/xvt_sw.cpp @@ -0,0 +1,68 @@ +#include "wxinc.h" +#include "xvt.h" +#include + +#ifdef __WXMSW__ +#include "oswin32.h" +#else +#include +#include "oslinux.h" +#endif + +XVTDLL int xvt_dongle_sw_crypt(unsigned short* data) +{ + if (data == NULL) + return -EACCES; + char chiaro[80], cifrato[80]; + sprintf(chiaro, "%04x%04x%04x%04x", data[0], data[1], data[2], data[3]); + xvt_str_md5(chiaro, cifrato); + _strupr(cifrato); + data[0] = cifrato[0] * 0xFF + cifrato[1]; + data[1] = cifrato[2] * 0xFF + cifrato[3]; + data[2] = cifrato[4] * 0xFF + cifrato[5]; + data[3] = cifrato[6] * 0xFF + cifrato[7]; + + data[0] ^= data[2]; + data[1] ^= data[2]; + data[2] ^= data[1]; + data[3] ^= data[2]; + return 0; +} + +XVTDLL BOOLEAN xvt_dongle_sw_encode_decode(unsigned char* data, unsigned long serial, int len) +{ + const int size = sizeof(serial); + unsigned char s[size]; + + for (int i = 0; i < len;) + { + s[1] = (unsigned char)((serial + i) / 0xFFFFFF); + s[2] = (unsigned char)(((serial + i) - s[1] * 0xFFFFFF) / 0xFFFF); + s[0] = (unsigned char)(((serial + i) - s[2] * 0xFFFF) / 0xFF); + s[3] = (unsigned char)((serial + i) - s[0] * 0xFF); + ((unsigned char *) data)[i++] ^= s[0]; + ((unsigned char *) data)[i++] ^= s[1]; + ((unsigned char *) data)[i++] ^= s[2]; + ((unsigned char *) data)[i++] ^= s[3]; + } + return true; +} + +XVTDLL BOOLEAN xvt_get_secret(const char* addresses) +{ + int retval = 0; + +#ifdef __WXMSW__ + retval = OsWin32_get_MAC_adresses((char *)addresses); +#else + retval = OsLinux_get_MAC_adresses((char *)addresses); +#endif + if (retval != 0) + { + wxString strMessage; + + strMessage.Printf("Error callng GetAdaptersInfo %d" , retval); + xvt_dm_post_error(strMessage); + } + return retval == NOERROR; +} \ No newline at end of file diff --git a/src/xvaga01/xvt_type.h b/src/xvaga01/xvt_type.h new file mode 100644 index 000000000..db3d9f36f --- /dev/null +++ b/src/xvaga01/xvt_type.h @@ -0,0 +1,484 @@ +#ifndef BOOLEAN +#define BOOLEAN short +#endif +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#ifdef LINUX +#define _MAX_PATH 512 +#define _MAX_EXT 6 +#define _MAX_DRIVE 6 +#define _MAX_DIR 512 +#define _MAX_FNAME 512 +#endif + +typedef unsigned long WINDOW; +typedef unsigned int UNIT_TYPE; +typedef unsigned long ULONG; +typedef unsigned long XVT_ERRMSG; +typedef unsigned long XVT_ODBC; +typedef unsigned long XVT_SQLDB; +typedef unsigned long XVT_SQLSTMT; + +typedef wchar_t XVT_WCHAR; +typedef short MENU_TAG; +typedef short CURSOR; +typedef char* DATA_PTR; + +#define EOL_SEQ "\015\012" + +typedef struct +{ + short top, left, bottom, right; +} RCT; + +typedef long XVT_HELP_TID; +typedef unsigned long COLOR; +typedef unsigned long XVT_COLOR_TYPE; +typedef unsigned long XVT_FONT_ATTR_MASK; +typedef unsigned long XVT_FONT_STYLE_MASK; +typedef long PICTURE; +typedef void* XVT_IMAGE; + +typedef enum { +XVT_IMAGE_NONE, +XVT_IMAGE_CL8, +XVT_IMAGE_RGB, +XVT_IMAGE_MONO, +} XVT_IMAGE_FORMAT; + +#define XVT_FNTID void* +typedef void* XVT_PALETTE; +typedef unsigned long XVT_PALETTE_ATTR; + +#define XVT_ESC_GET_PRINTER_INFO 883 +#define XVT_ESC_SET_PRINTER_INFO 884 + +typedef enum e_display_type { + XVT_DISPLAY_MONO, /* monochromatic display */ + XVT_DISPLAY_GRAY_16, /* 16-entry grayscale */ + XVT_DISPLAY_GRAY_256, /* 256-entry grayscale */ + XVT_DISPLAY_COLOR_16, /* 16-entry color */ + XVT_DISPLAY_COLOR_256, /* 256-entry color */ + XVT_DISPLAY_DIRECT_COLOR, /* full color capabilities */ +} XVT_DISPLAY_TYPE; + +typedef enum { + +XVT_PALETTE_NONE, +XVT_PALETTE_STOCK, +XVT_PALETTE_CURRENT, +XVT_PALETTE_CUBE16, +XVT_PALETTE_CUBE256, +XVT_PALETTE_USER +} XVT_PALETTE_TYPE; + +typedef enum { /* response from ask fcn */ + RESP_DEFAULT, /* default button */ + RESP_2, /* second button */ + RESP_3, /* third button */ +} ASK_RESPONSE; + +typedef enum { /* result from file open & save dialogs */ + FL_BAD, /* error occurred */ + FL_CANCEL, /* cancel button clicked */ + FL_OK, /* OK button clicked */ +} FL_STATUS; + +typedef struct +{ + char path[_MAX_DIR]; +} DIRECTORY; + +typedef struct s_mitem { + +MENU_TAG tag; /* menu tag */ +char *text; /* text to appear in menu */ +short mkey; /* mnemonic */ +unsigned enabled: 1; /* enabled? */ +unsigned checked: 1; /* checked? */ +unsigned checkable: 1; /* checkable? */ +unsigned separator: 1; /* separator? */ +struct s_mitem *child; /* pointer to submenu */ +} MENU_ITEM; + +typedef enum e_popup_alignment { +XVT_POPUP_CENTER, +XVT_POPUP_LEFT_ALIGN, +XVT_POPUP_RIGHT_ALIGN, +XVT_POPUP_OVER_ITEM +} XVT_POPUP_ALIGNMENT; + +#define SZ_FNAME _MAX_FNAME +#define SZ_EXT 6 + +typedef struct { /* file specification */ +DIRECTORY dir; /* directory */ +char type[SZ_EXT]; /* file type/extension */ +char name[SZ_FNAME]; /* filename */ +char creator[6]; /* file creator */ +} FILE_SPEC; + +typedef struct +{ + void* pr; +} PRINT_RCD; + +typedef struct +{ + short v, h; +} PNT; + +typedef struct { char* str; long data; void* next; } SLIST_ITEM; +typedef SLIST_ITEM* SLIST_ELT; + +typedef struct { SLIST_ELT head; long count; } xvtList; +typedef xvtList* SLIST; + +typedef enum { /* drawing (transfer) mode */ +M_COPY, +M_OR, +M_XOR, +M_CLEAR, +M_NOT_COPY, +M_NOT_OR, +M_NOT_XOR, +M_NOT_CLEAR +} DRAW_MODE; + +typedef enum e_pen_style { /* pen style */ +P_SOLID, /* solid */ +P_DOT, /* dotted line */ +P_DASH /* dashed line */ +} PEN_STYLE; + +typedef enum { +PAT_NONE, /* no pattern */ +PAT_HOLLOW, /* hollow */ +PAT_SOLID, /* solid fill */ +PAT_HORZ, /* horizontal lines */ +PAT_VERT, /* vertical lines */ +PAT_FDIAG, /* diagonal lines -- top-left to bottom-right */ +PAT_BDIAG, /* diagonal lines -- top-right to bottom-left */ +PAT_CROSS, /* horizontal and vertical crossing lines */ +PAT_DIAGCROSS, /* diagonal crossing lines */ +PAT_RUBBER, /* rubber banding */ +PAT_SPECIAL +} PAT_STYLE; + +typedef struct { /* color pen tool */ +short width; /* width */ +PAT_STYLE pat; /* pattern */ +PEN_STYLE style; /* style */ +COLOR color; /* color */ +} CPEN; + +typedef struct +{ + PAT_STYLE pat; + COLOR color; +} CBRUSH; + +typedef struct { /* color drawing tools */ +CPEN pen; /* color pen */ +CBRUSH brush; /* color brush */ +DRAW_MODE mode; /* drawing mode */ +COLOR fore_color; /* foreground color */ +COLOR back_color; /* background color */ +BOOLEAN opaque_text; /* is text opaque*/ +} DRAW_CTOOLS; + +typedef enum { /* scrollbar activity */ +SC_NONE, /* nowhere (ignore) */ +SC_LINE_UP, /* one line up */ +SC_LINE_DOWN, /* one line down */ +SC_PAGE_UP, /* previous page */ +SC_PAGE_DOWN, /* next page */ +SC_THUMB, /* thumb repositioning */ +SC_THUMBTRACK /* thumb tracking */ +} SCROLL_CONTROL; + +typedef enum { /* type of window */ + +W_NONE, /* marker for end of WIN_DEF array */ +W_DOC, /* document window */ +W_PLAIN, /* window with plain border */ +W_DBL, /* window with double border */ +W_PRINT, /* XVT internal use only */ +W_TASK, /* task window */ +W_SCREEN, /* screen window */ +W_NO_BORDER, /* no border */ +W_PIXMAP, /* pixmap */ +W_MODAL, /* modal window */ +WD_MODAL, /* modal dialog */ +WD_MODELESS, /* modeless dialog */ +WC_PUSHBUTTON, /* button control */ +WC_RADIOBUTTON, /* radio button control */ +WC_CHECKBOX, /* check box control */ +WC_HSCROLL, /* horizontal scrollbar control */ +WC_VSCROLL, /* vertical scrollbar control */ +//WC_EDIT, /* edit control */ commentato perche' rompe le scatole +WC_TEXT, /* static text control */ +WC_LBOX, /* list box control */ +WC_LISTBUTTON, /* button with list */ +WC_CHECKBUTTON, /* check button control */ +WC_LISTEDIT, /* edit with field list */ +WC_GROUPBOX, /* group box */ +WC_TEXTEDIT, /* text edit object */ +WC_ICON, /* icon control */ +WO_TE, /* text edit */ +WC_HGAUGE, /* horizontal progress bar */ +WC_VGAUGE, /* vertical progress bar */ +WC_NOTEBK, /* notebook control */ +WC_HTML, /* HTML control */ +WC_TREE, /* tree view */ +WC_OUTLOOKBAR, /* Barra di Outlook */ +WC_HSLIDER, /* horizontal slider control */ +WC_VSLIDER, /* vertical slider control */ +WC_POPUP, /* list of listedit control or popup menu */ +WC_PROPGRID, /* property grid */ +WC_MVC, /* model view controller */ +WC_TREELIST, /* tree list */ +WC_METROBAR, /* Barra di Metro */ +} WIN_TYPE; + +typedef enum { +SEV_NONE, +SEV_WARNING, +SEV_ERROR, +SEV_FATAL, +} XVT_ERRSEV; + +typedef enum { /* type of scrollbar */ + +HSCROLL, /* horizontal */ +VSCROLL, /* vertical */ +HVSCROLL, /* either */ +HVGAUGE, /* progress bar */ +HVSLIDER, /* slider */ + +} SCROLL_TYPE; + +/* Treeview - Types */ + +typedef void * XVT_TREEVIEW_NODE; + +typedef enum e_treeview_node_type { + XVT_TREEVIEW_NODE_TERMINAL, /* leaf - no children */ + XVT_TREEVIEW_NODE_NONTERMINAL, /* branch - may have children */ + XVT_ENUM_DUMMY26 = XVT_CC_ENUM_END +} XVT_TREEVIEW_NODE_TYPE; + +typedef XVT_CALLCONV_TYPEDEF( BOOLEAN, XVT_TREEVIEW_CALLBACK, + (WINDOW ctl_win, XVT_TREEVIEW_NODE node) ); + +typedef struct s_ctlinfo { + +WIN_TYPE type; +WINDOW win; +union { + +struct s_scroll { + +SCROLL_CONTROL what; +short pos; + +} scroll; +struct s_edit { + +BOOLEAN focus_change; +BOOLEAN active; + +} edit; +struct s_lbox { + +BOOLEAN dbl_click; + +} lbox; +struct s_listedit { + +BOOLEAN focus_change; +BOOLEAN active; + +} listedit; +struct s_notebk { + + WINDOW page; + short page_new; + short page_old; + +} notebk; +struct s_html { + + int reserved; /* Reserved...no usage yet.*/ + +} html; +struct s_treeview { + + XVT_TREEVIEW_NODE node; /* Node */ + BOOLEAN sgl_click; /* Single click */ + BOOLEAN dbl_click; /* Double click */ + BOOLEAN expanded; /* Node was expanded */ + BOOLEAN collapsed; /* Node was collapsed */ + +} treeview; + +} v; + +} CONTROL_INFO; + +typedef struct s_xvt_color_component { +XVT_COLOR_TYPE type; /* color component being defined */ +COLOR color; /* RGB color value */ +} XVT_COLOR_COMPONENT; + +typedef enum s_xvt_color_action { +XVT_COLOR_ACTION_SET,/* set the colors */ +XVT_COLOR_ACTION_UNSET/* unset the colors */ +} XVT_COLOR_ACTION; + +typedef struct s_win_def { + WIN_TYPE wtype; /* WC_* or WO_* type */ + RCT rct; + char *text; + UNIT_TYPE units; + XVT_COLOR_COMPONENT * ctlcolors; + union { + struct s_win_def_win { /* WINDOW's */ + short int menu_rid; /* menu resource id */ + MENU_ITEM *menu_p; /* pointer to menu tree */ + long flags; /* WSF_* flags */ + XVT_FNTID ctl_font_id; /* control font id */ + } win; + struct s_win_def_dlg { /* DIALOG's */ + long flags; /* WSF_* flags */ + XVT_FNTID ctl_font_id; /* control font id */ + } dlg; + struct s_win_def_ctl { /* CONTROL's */ + short int ctrl_id; + short int icon_id; /* for icons only */ + long flags; /* CTL_* flags */ + XVT_FNTID font_id; /* logical font */ + } ctl; + struct s_win_def_tx { /* text edit objects */ + unsigned short attrib; /* TX_* flags */ + XVT_FNTID font_id; /* logical font */ + short margin; /* right margin */ + short limit; /* max chars */ + short int tx_id; /* text ID */ + } tx; + } v; +} WIN_DEF; + +typedef enum { +E_CREATE, /* creation */ +E_DESTROY, /* destruction */ +E_FOCUS, /* window focus gain/loss */ +E_SIZE, /* resize */ +E_UPDATE, /* update */ +E_CLOSE, /* close window request */ +E_MOUSE_DOWN, /* mouse down */ +E_MOUSE_UP, /* mouse up */ +E_MOUSE_MOVE, /* mouse move */ +E_MOUSE_DBL, /* mouse double click */ +E_CHAR, /* character typed */ +E_VSCROLL, /* vert. window scrollbar activity */ +E_HSCROLL, /* horz. window scrollbar activity */ +E_COMMAND, /* menu command */ +E_FONT, /* font menu selection */ +E_CONTROL, /* control activity */ +E_TIMER, /* timer */ +E_QUIT, /* application shutdown request */ +E_HELP, /* help invoked */ +E_USER, /* user defined */ +E_CXO, /* cxo event */ +E_PROCESS, /* child process terminated */ +} EVENT_TYPE; + + +typedef struct s_event { + EVENT_TYPE type; + union _v { + struct s_mouse { /* E_MOUSE_DOWN, E_MOUSE_UP, E_MOUSE_MOVE, E_MOUSE_DBL */ + PNT where; /* location of event (window relative) */ + BOOLEAN shift; /* shift key down? */ + BOOLEAN control; /* control or option key down? */ + short button; /* button number */ + } mouse; + struct s_char { /* E_CHAR */ + XVT_WCHAR ch; /* wide character */ + BOOLEAN shift; /* shift key down? */ + BOOLEAN control; /* control or option key down? */ + BOOLEAN virtual_key; /* ch contains virtual key or not? */ + unsigned long modifiers; /* bit field of key modifiers */ + } chr; + BOOLEAN active; /* E_FOCUS: activation? (vs. deactivation) */ + BOOLEAN query; /* E_QUIT: query only? (app calls quit_OK) */ + struct s_scroll_info { /* E_VSCROLL, E_HSCROLL */ + SCROLL_CONTROL what; /* site of activity */ + short pos; /* thumb position, if SC_THUMB */ + } scroll; + struct s_cmd { /* E_COMMAND */ + MENU_TAG tag; /* menu item tag */ + BOOLEAN shift; /* shift key? */ + BOOLEAN control; /* control or option key? */ + } cmd; + struct s_size { /* E_SIZE */ + short height; /* new height */ + short width; /* new width */ + } size; + struct s_efont { /* E_FONT */ + XVT_FNTID font_id; /* R4 font id of selected font */ + } font; + struct s_ctl { /* E_CONTROL */ + short id; /* control's ID */ + CONTROL_INFO ci; /* control info */ + } ctl; + struct s_update { /* E_UPDATE */ + RCT rct; /* update rectangle */ + } update; + struct s_timer { /* E_TIMER */ + long id; /* timer ID */ + } timer; + struct s_user { /* E_USER */ + long id; /* application ID */ + void *ptr; /* application pointer */ + } user; + struct s_help { /* E_HELP */ + WINDOW obj; /* help for control, window, dialog */ + MENU_TAG tag; /* help for menu item */ + XVT_HELP_TID tid; /* predefined help topic */ + } help; + struct s_cxo { /* E_CXO */ + long msg_id; /* CXO message id - Unique to each CXO */ + void * ptr; /* message data pointer */ + } cxo; + struct s_process { /* E_PROCESS */ + long pid; /* PID of started/terminated process */ + int msg_id; /* 0=started; 1=stopped */ + int exit_code; + } process; + } v; +} EVENT, *EVENT_PTR; + +typedef unsigned long EVENT_MASK; +typedef long (* EVENT_HANDLER) (WINDOW win, EVENT *ep); +typedef BOOLEAN (* XVT_ERRMSG_HANDLER) (XVT_ERRMSG err, DATA_PTR context); +typedef BOOLEAN (* XVT_ENUM_CHILDREN)(WINDOW child, long data); + +typedef enum { /* std. clipboard format */ +CB_TEXT, /* ASCII text */ +CB_PICT, /* encapsulated picture */ +CB_APPL /* app's own (must have name) */ +} CB_FORMAT; + +typedef struct s_xvt_config +{ + short menu_bar_ID; /* task menubar ResID */ + short about_box_ID; /* default aboutbox ResID */ + const char* base_appl_name; /* application's "filename" */ + const char* appl_name; /* application's name */ + const char* taskwin_title; /* title for task window */ +} XVT_CONFIG; diff --git a/src/xvaga01/xvt_vers.h b/src/xvaga01/xvt_vers.h new file mode 100644 index 000000000..534900fe7 --- /dev/null +++ b/src/xvaga01/xvt_vers.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * + * Copyright (c) 1989 - 2002 Providence Software Solutions, Inc. All rights reserved. + * May be used only in accordance with a valid Source Code License + * Agreement with Providence Software Solutions, Inc. + * + * $RCSfile: xvt_vers.h,v $ + * $Revision: 1.1 $ + * + * Purpose: XVT PTK version definitions. + * + ****************************************************************************/ + +#ifndef XVT_INCL_VERS +#define XVT_INCL_VERS + +#define XVT_PTK_VERSION_MAJOR 5 +#define XVT_PTK_VERSION_MINOR 6 +#define XVT_PTK_VERSION_PATCH 1 + +#define XVT_PTK_VERSION (XVT_MAKE_VERSION(XVT_PTK_VERSION_MAJOR,XVT_PTK_VERSION_MINOR,XVT_PTK_VERSION_PATCH)) + +#define XVT_CHECK_VERSION(vma,vmi,vpa) XVT_PTK_VERSION>=XVT_MAKE_VERSION(vma,vmi,vpa) + +#endif /* XVT_INCL_VERS */ diff --git a/src/xvaga01/xvtart.cpp b/src/xvaga01/xvtart.cpp new file mode 100644 index 000000000..3f579f3c2 --- /dev/null +++ b/src/xvaga01/xvtart.cpp @@ -0,0 +1,496 @@ +#include "wxinc.h" + +#include "xvt.h" +#include "xvtart.h" + +#ifdef __WXMSW__ +#include "oswin32.h" +#else +#include "oslinux.h" +#endif + +#include +#include +#include + +wxString xvtart_GetResourceIni() +{ + DIRECTORY dir; xvt_fsys_get_default_dir(&dir); + wxString str = dir.path; + str += "/res/resource.ini"; + return str; +} + +wxString xvtart_GetResourceName(const char* type, int rid) +{ + wxString strName(type); strName << "s"; + wxString strKey; strKey.Printf("%d", rid); + + DIRECTORY dir; xvt_fsys_get_default_dir(&dir); + wxString startup_dir = dir.path; + + if ((rid == ICON_RSRC || rid == 0) && strName == "Icons") + { + int i = 1; + switch (xvt_sys_get_os_version()) + { + case XVT_WS_WIN_2000: + case XVT_WS_WIN_2003: i = 0; break; // Cerco prima l'icona a 256 colori + default : i = 1; break; // Cerco solo l'icona in RGBA + } + for (; i < 2; i++) + { + const char* const oem_var = i == 0 ? "Icon256" : "Icon"; + char name[MAX_PATH]; + + if (xvt_sys_get_oem_string(oem_var, "", name, sizeof(name))) + { + wxFileName fname(startup_dir + "/setup/" + name); + if (fname.FileExists()) + { + fname.Normalize(); + strName = fname.GetFullPath().Lower(); + return strName; + } + } + } + } + + wxString val; + char* buff = val.GetWriteBuf(MAX_PATH); + xvt_sys_get_profile_string(xvtart_GetResourceIni(), strName, strKey, "", buff, MAX_PATH); + val.UngetWriteBuf(); + + if (!val.IsEmpty()) + { + strName = startup_dir; + strName += "/custom/"; + strName += val; + + if (!wxFileExists(strName)) + { + const int oem = xvt_sys_get_oem_int("OEM", 0); + + if (oem > 0) + { + char oemstr[MAX_PATH]; + + strName = startup_dir; + strName += "/res/OEM_"; + sprintf(oemstr, "%02d", oem); + strName += oemstr; + strName += "/"; + strName += val; + } + if (!wxFileExists(strName)) + { + strName = startup_dir; + strName += "/res/"; + strName += val; + } + } + + wxFileName fname(strName); + fname.Normalize(); + strName = fname.GetFullPath().Lower(); + } + else + strName.Empty(); + + return strName; +} + +/////////////////////////////////////////////////////////// +// TArtProvider +/////////////////////////////////////////////////////////// + +class TArtProvider : public wxArtProvider +{ + +#if !wxCHECK_VERSION(2,9,0) + WX_DECLARE_STRING_HASH_MAP(wxIconBundle, TIconBundleHashTable); + TIconBundleHashTable m_hmBundles; + + WX_DECLARE_STRING_HASH_MAP(unsigned, TIconIdHashTable); + TIconIdHashTable m_hmIds; +#endif + +protected: + virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size); + virtual wxIconBundle CreateIconBundle(const wxArtID& id, const wxArtClient& client); + +public: +#if !wxCHECK_VERSION(2,9,0) + wxIconBundle GetIconBundle(const wxArtID& id, const wxArtClient& client); + wxIcon GetIcon(const wxArtID& id, const wxArtClient& client = wxART_OTHER, const wxSize& size = wxDefaultSize); + wxSize GetNativeSizeHint(const wxArtClient& client); +#endif + unsigned int GetIconBundleNumber(const wxArtID& id); +}; + +TArtProvider* _TheArtProvider = NULL; + +void xvtart_Init() +{ + if (_TheArtProvider == NULL) + _TheArtProvider = new TArtProvider; + wxArtProvider::Push(_TheArtProvider); +} + +wxBitmap TArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size) +{ + wxString strName; + + long tool = -1; + if (id.StartsWith(wxT("wxART"))) + { + if (id == wxART_ERROR) tool = 201; else + if (id == wxART_HELP) tool = 163; else + if (id == wxART_INFORMATION) tool = 162; else + if (id == wxART_MISSING_IMAGE) tool = 100; else + if (id == wxART_NEW) tool = 105; else + if (id == wxART_QUESTION) tool = 202; else + if (id == wxART_QUIT) tool = 114; else + if (id == wxART_WARNING) tool = 203; else + ; + } + else + id.ToLong(&tool); + + if (tool > 0) + { + strName = xvtart_GetResourceName("Tool", tool); + if (strName.IsEmpty() || !::wxFileExists(strName)) + strName = xvtart_GetResourceName("Tool", 100); // Default empty icon + } + else + strName = id; + + if (!strName.IsEmpty() && ::wxFileExists(strName)) + { + if (strName.EndsWith(".ico")) + { + const wxIcon ico = GetIcon(strName, client, size); + return wxBitmap(ico); + } + else + { + int sx = size.x, sy = size.y; + if (sx <= 0 || sy <= 0) + { + const wxSize sz = GetNativeSizeHint(client); + if (sx <= 0) sx = sz.x; + if (sy <= 0) sy = sz.y; + } + wxImage img(strName, wxBITMAP_TYPE_ANY); + img.Rescale(sx, sy, wxIMAGE_QUALITY_HIGH); + return wxBitmap(img); + } + } + + return wxNullBitmap; +} + +wxIconBundle TArtProvider::CreateIconBundle(const wxArtID& id, const wxArtClient& WXUNUSED(client)) +{ + wxString strName = id; + + long nIco = -1; + if (id.StartsWith(wxT("wxART"))) + { + if (id == wxART_EXECUTABLE_FILE) nIco = ICON_RSRC; else + ; + } + else + id.ToLong(&nIco); + + if (nIco > 0) + strName = xvtart_GetResourceName("Icon", nIco); + + wxIconBundle ib; + bool bFound = false; + if (::wxFileExists(strName)) + { + const bool bLog = wxLog::EnableLogging(false); // Evita segnalazione di errore di formato icona + if (strName.EndsWith(wxT(".ico"))) + { + ib.AddIcon(strName, wxBITMAP_TYPE_ICO); + bFound = true; + } + else + { + ib.AddIcon(OsWin32_LoadIcon(strName)); + bFound = true; + } + wxLog::EnableLogging(bLog); + + for (wxCoord s = 16; s <= 48; s += 16) + { + const wxIcon smico = ib.GetIcon(s); + if (smico.GetWidth() != s) + { + wxBitmap bmpbig(ib.GetIcon()); + wxImage img = bmpbig.ConvertToImage(); + img.Rescale(s, s, wxIMAGE_QUALITY_HIGH); + wxBitmap bmpsmall(img); + wxIcon icosmall; icosmall.CopyFromBitmap(bmpsmall); + ib.AddIcon(icosmall); + } + } + } + else + { + if (!strName.IsEmpty()) // Getione caso strName=".ext" + { + ib.AddIcon(OsWin32_LoadIcon(strName)); + bFound = true; + } + } + + if (!bFound && nIco == ICON_RSRC) + { + strName.Printf("%d", ICON_RSRC); // id puo' essere wxART_EXECUTABLE_FILE + ib.AddIcon(wxIcon(strName, wxBITMAP_TYPE_ICO_RESOURCE)); + } + + return ib; +} + +#if !wxCHECK_VERSION(2,9,0) + +wxSize TArtProvider::GetNativeSizeHint(const wxArtClient& client) +{ + int ix = 32, iy = 32; + + if (client == wxART_FRAME_ICON) + { + const int x = wxSystemSettings::GetMetric(wxSYS_SMALLICON_X); + const int y = wxSystemSettings::GetMetric(wxSYS_SMALLICON_Y); + if (x > 0 && y > 0) + { ix = x; iy = y; } + else + { ix /= 2; iy /= 2; } + } + else + { + const int x = wxSystemSettings::GetMetric(wxSYS_ICON_X); + const int y = wxSystemSettings::GetMetric(wxSYS_ICON_Y); + if (x > 0 && y > 0) + { ix = x; iy = y; } + if (client == wxART_MESSAGE_BOX) + { ix *= 2; iy *= 2; } + } + + return wxSize(ix,iy); +} + +wxIconBundle TArtProvider::GetIconBundle(const wxArtID& id, const wxArtClient& client) +{ + TIconBundleHashTable::iterator it = m_hmBundles.find(id); + if (it == m_hmBundles.end()) + { + const wxIconBundle b = CreateIconBundle(id, client); + m_hmBundles[id] = b; + + unsigned long uid = 0; + if (!id.ToULong(&uid)) + { + wxString numid; numid.Printf(wxT("%lu"), GetIconBundleNumber(id)); + m_hmBundles[numid] = b; + } + + return b; + } + return it->second; +} + +wxIcon TArtProvider::GetIcon(const wxArtID& id, const wxArtClient& client, const wxSize& size) +{ + wxIconBundle bundle = GetIconBundle(id, client); + const wxSize sz = size == wxDefaultSize ? GetNativeSizeHint(client) : size; + wxIcon ico = bundle.GetIcon(sz); + if (ico.IsOk() && sz.x != ico.GetWidth()) // Should never happen :-) + { + wxBitmap bmpbig(bundle.GetIcon()); + wxImage img = bmpbig.ConvertToImage(); + img.Rescale(sz.x, sz.y, wxIMAGE_QUALITY_HIGH); + wxBitmap bmpsmall(img); + wxIcon icosmall; icosmall.CopyFromBitmap(bmpsmall); + ico = icosmall; + bundle.AddIcon(ico); + } + return ico; +} + +// Metodo fichissimo per assegnare un identificatore univoco alle icone chiamate per nome del file.* +unsigned int TArtProvider::GetIconBundleNumber(const wxArtID& id) +{ + unsigned int num = m_hmIds[id]; + if (num == 0) + { + num = 60000+m_hmIds.size(); + m_hmIds[id] = num; + } + return num; +} + +#endif + +/////////////////////////////////////////////////////////// +// xvt_sys_load_icon +/////////////////////////////////////////////////////////// + +const wxBitmap xvtart_GetToolResource(int nIcon, int nDesiredSize) +{ + if (nDesiredSize < 16) nDesiredSize = 16; else + if (nDesiredSize > 128) nDesiredSize = 128; + wxArtID id; id.Printf("%d", nIcon); + return wxArtProvider::GetBitmap(id, wxART_TOOLBAR, wxSize(nDesiredSize, nDesiredSize)); +} + +const wxIcon xvtart_GetIconResource(int nIcon, const char* client, const int size) +{ + wxASSERT(_TheArtProvider != NULL); + + if (nIcon <= 0) + nIcon = ICON_RSRC; + + wxArtID id; id.Printf("%d", nIcon); + wxArtClient cl = client && * client ? client : wxART_OTHER; + wxSize sz(size, size); + return _TheArtProvider->GetIcon(id, cl, sz); +} + +unsigned int xvt_sys_load_icon(const char* file) +{ + wxASSERT(_TheArtProvider != NULL); + const wxArtID id = file; + const wxIcon ico = _TheArtProvider->GetIcon(id); + return ico.IsOk() ? _TheArtProvider->GetIconBundleNumber(id) : ICON_RSRC; +} + +WX_DECLARE_HASH_MAP(int, wxCursor, wxIntegerHash, wxIntegerEqual, TCursorHashTable); + +const wxCursor xvtart_GetCursorResource(int rid) +{ + static TCursorHashTable _nice_cursors; + wxCursor cursor = _nice_cursors[rid]; + + if (!cursor.IsOk()) + { + switch (rid) + { + case CURSOR_CROCE: cursor = wxCURSOR_CROSS; break; + case CURSOR_IBEAM: cursor = wxCURSOR_IBEAM; break; + default: + { + const wxString strName = xvtart_GetResourceName("Cursor", rid); + if (::wxFileExists(strName)) + { + if (strName.Find(".ico") > 0) + cursor = wxCursor(strName, wxBITMAP_TYPE_ICO); + else + cursor = wxCursor(strName, wxBITMAP_TYPE_CUR); + } + } + break; + } + if (!cursor.IsOk()) + { + wxFAIL_MSG(_("Invalid cursor")); + cursor = *wxSTANDARD_CURSOR; + } + + _nice_cursors[rid] = cursor; + } + return cursor; +} + +/////////////////////////////////////////////////////////// +// TAuiManager +/////////////////////////////////////////////////////////// + +/* +class TAuiManager : public wxAuiManager +{ +public: + static bool DrawBackground(wxDC& dc, wxWindow* window, int orientation, const wxRect &rect); + static bool BaseColours(wxColour& base, wxColour& light, wxColour& dark, wxColour& text); + TAuiManager(); +}; + +bool TAuiManager::BaseColours(wxColour& base, wxColour& light, wxColour& dark, wxColour& text) +{ + const wxSize sz(256,256); + wxBitmap bmp = wxArtProvider::GetBitmap(wxArtID(wxT("Skin")), wxART_OTHER, sz); + if (bmp.IsOk()) + { + wxColourBase::ChannelType ldark = 255, llight = 0; + dark = *wxWHITE; + light = *wxBLACK; + + wxNativePixelData data(bmp); + const int dim = data.GetHeight(); + wxNativePixelData::Iterator p(data); + double r = 0, g = 0, b = 0; + for (int i = 0; i < dim; i++) + { + p.MoveTo(data, i, i); + r += p.Red(); + g += p.Green(); + b += p.Blue(); + + const wxColour col(p.Red(), p.Green(), p.Blue()); + const wxColourBase::ChannelType lcol = Luma(col); + if (lcol < ldark) + { + dark = col; + ldark = lcol; + } + if (lcol > llight) + { + light = col; + llight = lcol; + } + } + r /= dim; g /= dim; b /= dim; + + base = wxColour(r, g, b); + const wxColourBase::ChannelType lbase = Luma(base); + if (lbase - ldark < 40) + dark = ModulatedColor(dark, -(40 - lbase + ldark)); + + if (llight - lbase < 40) + light = ModulatedColor(light, +(40 - llight + lbase)); + + text = ContrastingColor(base); + } + return bmp.IsOk(); +} + +bool TAuiManager::DrawBackground(wxDC& dc, wxWindow* WXUNUSED(window), + int WXUNUSED(orientation), const wxRect &rect) +{ + const wxBitmap bmp = wxArtProvider::GetBitmap(wxArtID(wxT("Skin")), wxART_OTHER, wxSize(256,256)); + if (bmp.IsOk()) + { + const wxSize szBm = bmp.GetSize(); + for (wxCoord y = rect.y; y < rect.GetBottom(); y += szBm.y) + { + for (wxCoord x = rect.x; x < rect.GetRight(); x += szBm.x) + dc.DrawBitmap(bmp, x, y); + } + } + return bmp.IsOk(); +} + +TAuiManager::TAuiManager() +{ + SetArtProvider(new TDockArt); +} +*/ + +wxAuiManager* xvtart_CreateManager(wxWindow* win) +{ + return new wxAuiManager(win); // will be TAUIManager +} diff --git a/src/xvaga01/xvtart.h b/src/xvaga01/xvtart.h new file mode 100644 index 000000000..eeeecab4a --- /dev/null +++ b/src/xvaga01/xvtart.h @@ -0,0 +1,17 @@ +#ifndef __XVTART_H__ +#define __XVTART_H__ + +#ifndef _WX_FRAMEMANAGER_H_ +class wxAuiManager; +#endif + +const wxCursor xvtart_GetCursorResource(int rid); +const wxIcon xvtart_GetIconResource(int rid, const char* client = NULL, int size = -1); +wxString xvtart_GetResourceIni(); +wxString xvtart_GetResourceName(const char* type, int rid); +const wxBitmap xvtart_GetToolResource(int rid, int size); + +void xvtart_Init(); +wxAuiManager* xvtart_CreateManager(wxWindow* win); + +#endif \ No newline at end of file diff --git a/src/xvaga01/xvtctl.cpp b/src/xvaga01/xvtctl.cpp new file mode 100644 index 000000000..d3a885a0a --- /dev/null +++ b/src/xvaga01/xvtctl.cpp @@ -0,0 +1,3873 @@ +#include "wxinc.h" +#include "xvt.h" +#include "xvtart.h" +#include "xvtwin.h" +#include "statbar.h" +#include "treelistctrl.h" + +#ifdef __WXMSW__ +#include "oswin32.h" +#include "XFont.h" +#else +#include +#include +#include "oslinux.h" +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////// + +static wxBitmap Image2Bitmap(XVT_IMAGE image, int maxx, int maxy, BOOLEAN trans) +{ + if (image == nullptr || !((wxImage*)image)->IsOk()) + return wxNullBitmap; + + wxImage img = *(wxImage*)image; + + int w = img.GetWidth(), h = img.GetHeight(); + if (w > maxx || h > maxy) + { + const double mx = (maxx / 2) * 2, my = (maxy / 2) * 2; + const double rx = mx / w, ry = my / h; + const double r = rx < ry ? rx : ry; + w = int(w * r); h = int(h * r); + img.Rescale(w, h, wxIMAGE_QUALITY_HIGH); + } + + if (trans && !img.HasMask()) + { + const int r = img.GetRed(0,0); + const int g = img.GetGreen(0,0); + const int b = img.GetBlue(0,0); + img.SetMask(); + img.SetMaskColour(r, g, b); + } + return wxBitmap(img); +} + +static int RoundToIcon(int nSize) +{ + nSize = (nSize/16) * 16; + if (nSize < 16) + nSize = 16; else + if (nSize > 128) + nSize = 128; + return nSize; +} + +void Image2Colors(const wxImage& img, wxColour& mean, wxColour& dark, wxColour& light) +{ + dark = *wxWHITE; + mean = *wxLIGHT_GREY; + light = *wxBLACK; + double r=0, g=0, b=0; + + const int h = min(img.GetWidth(), img.GetHeight()); + for (int i = 0; i < h; i++) + { + const wxColourBase::ChannelType cr = img.GetRed(i,i); + const wxColourBase::ChannelType cg = img.GetGreen(i,i); + const wxColourBase::ChannelType cb = img.GetBlue(i,i); + r += cr; g += cg; b += cb; + } + r/=h; g/=h; b/=h; + mean = wxColour(r, g, b); + dark = wxColour(r*0.8, g*0.8, b*0.8); + light = wxColour(min(r*1.2,255), min(g*1.2,255), min(b*1.2,255)); +} + + +static wxAuiDockArt* FindArtist(wxWindow* pWindow) +{ + wxAuiDockArt* pArtist = nullptr; + const wxAuiManager* pManager = wxAuiManager::GetManager(pWindow); + if (pManager != nullptr) + pArtist = pManager->GetArtProvider(); + return pArtist; +} + +/////////////////////////////////////////////////////////// +// Controls functions +/////////////////////////////////////////////////////////// + +class TwxScrollBar : public wxScrollBar +{ +protected: + virtual bool AcceptsFocus() const { return false; } // Altrimenti mette il flag wxTAB_TRAVERSAL + +public: + TwxScrollBar(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style) + { Create(parent, id, pos, size, style); } +}; + +class TwxNoteBook : public wxAuiNotebook +{ + enum { BOOK_ICO_SIZE = 16 }; + bool m_bSuspended; + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(TwxNoteBook) + +protected: + virtual bool SetBackgroundColour(const wxColour& col); + virtual bool SetForegroundColour(const wxColour& col); + + void OnChar(wxKeyEvent& evt); + void OnPageChanging(wxAuiNotebookEvent& e); + void OnPageChanged(wxAuiNotebookEvent& e); + long Flags2Style(long flags) const; + + TwxNoteBook() {} + +public: + int ChangeSelection(size_t tab_no); // wxNotebook had it! + void SetTabImage(size_t tab_no, XVT_IMAGE img); + + short AddTab(wxWindow* pPage, const wxString text, XVT_IMAGE img = nullptr, short idx = -1); + TwxNoteBook(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style); + ~TwxNoteBook(); +}; + +WX_DECLARE_VOIDPTR_HASH_MAP(int, XVT_IMAGE_Map); + +class TwxTreeCtrl : public wxTreeCtrl +{ + XVT_IMAGE_Map m_img; + wxColour m_clrSelFore, m_clrSelBack, m_clrDisFore; + int m_nFrozen; + +private: + int img2int(XVT_IMAGE img); // Store img into internal image list + void OnClick(wxTreeEvent& evt, bool bDouble); + +protected: + DECLARE_EVENT_TABLE(); + void OnExpanding(wxTreeEvent& e); // Called when node is about to be expanded + void OnCollapsed(wxTreeEvent& e); // Called when node is collapsed + void OnSelected(wxTreeEvent& e); // Calls OnClick(e, false) + void OnActivated(wxTreeEvent& e); // Calls OnClick(e, true) + void OnRightDown(wxMouseEvent& e); + + virtual wxColour GetItemTextColour(const wxTreeItemId& id) const; + virtual wxColour GetItemBackgroundColour(const wxTreeItemId& id) const; + +public: + void SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image); + void SetColors(const XVT_COLOR_COMPONENT* colors); + void Suspend(); + void Resume(); + void Enable(const wxTreeItemId& id, bool on); + TwxTreeCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size); +}; + +class TwxTreeListCtrl : public wxTreeListCtrl +{ + XVT_IMAGE_Map m_img; + wxColour m_clrSelFore, m_clrSelBack, m_clrDisFore; + int m_nFrozen; + +private: + int img2int(XVT_IMAGE img); // Store img into internal image list + +protected: + DECLARE_EVENT_TABLE(); + void OnExpanding(wxTreeEvent& e); // Called when node is about to be expanded + void OnExpanded(wxTreeEvent& e); // Called when node has been expanded + void OnCollapsed(wxTreeEvent& e); // Called when node has been collapsed + void OnSelChanged(wxTreeEvent& e); // Called when node has been selected + +public: + void SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image); + void SetColors(const XVT_COLOR_COMPONENT* colors); + void Suspend(); + void Resume(); + void Enable(const wxTreeItemId& id, bool on); + TwxTreeListCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, bool multisel); +}; + +struct TwxOutlookItem +{ + wxString m_strText; + short m_nIconId; + int m_nFlags; +}; + +class TwxOutlookBar : public wxVListBox +{ + DECLARE_DYNAMIC_CLASS(TwxOutlookBar); + + enum { MAX_ITEMS = 32 }; + TwxOutlookItem m_item[MAX_ITEMS]; + int m_nHovering; + + DECLARE_EVENT_TABLE() + TwxOutlookBar() {} + +protected: + virtual void OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const; + virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const; + virtual wxCoord OnMeasureItem(size_t n) const; + virtual void OnMouseMove(wxMouseEvent& e); + virtual void OnMouseLeave(wxMouseEvent& e); + virtual void OnSelected(wxCommandEvent& e); + +public: + int Add(short nIconId, const wxString strText, int nFlags); + + TwxOutlookBar(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style); + ~TwxOutlookBar(); +}; + +class TwxMetroBar : public wxWindow +{ + DECLARE_DYNAMIC_CLASS(TwxMetroBar); + + enum { MAX_ITEMS = 32 }; + TwxOutlookItem m_item[MAX_ITEMS]; + int m_nItems, m_nCurr, m_nHover; + int m_nRows, m_nCols, m_nWidth, m_nHeight; + wxColour m_rgbBorder, m_rgbSelectFore; + + DECLARE_EVENT_TABLE() + TwxMetroBar() {} + +protected: + void OnPaint(wxPaintEvent& e); + void OnMouseDown(wxMouseEvent& e); + void OnMouseMove(wxMouseEvent& e); + void OnMouseLeave(wxMouseEvent& e); + void OnResize(wxSizeEvent& e); + wxRect GetRect(int i) const; + void DrawCell(wxDC& dc, int i) const; + int HitTest(const wxPoint& pt) const; + +public: + void Clear() { m_nItems = 0; } + void SetSelection(int i, bool sel) { if (sel) m_nCurr = (i >= 0 && i < m_nItems) ? i : 0; } + int GetSelection() const { return m_nCurr; } + int Add(short nIconId, const wxString strText, int nFlags); + int GetItemCount() const { return m_nItems; } + void SetSelectForeColor(const wxColour& rgb) { m_rgbSelectFore = rgb; } + void SetBorderColor(const wxColour& rgb) { m_rgbBorder = rgb; } + TwxMetroBar(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style); +}; + +class TwxPopUp : public wxVListBox +{ + DECLARE_DYNAMIC_CLASS(TwxPopUp); + + wxArrayString m_menu; + int m_nHovering; + wxCoord m_nRowHeight; + wxColour m_clrBack, m_clrFore; + + DECLARE_EVENT_TABLE() + void NotifySelection(); + TwxPopUp() { wxFAIL; } + +protected: + virtual void OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const; + virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const; + virtual wxCoord OnMeasureItem(size_t n) const; + virtual void OnMouseMove(wxMouseEvent& e); + virtual void OnKillFocus(wxFocusEvent& e); + virtual void OnSelected(wxCommandEvent& e); + virtual void OnKeyDown(wxKeyEvent& e); + virtual void OnLeftDown(wxMouseEvent& e); + +public: + int Add(const wxString str); + void SetSelectForeColor(const wxColour& rgb) { m_clrFore = rgb; } + void SetSelectBackColor(const wxColour& rgb) { m_clrBack= rgb; } + TwxPopUp(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size); +}; + +class TwxPropertyGrid : public wxPropertyGrid +{ + DECLARE_EVENT_TABLE() +protected: + void OnPropertyChanged(wxPropertyGridEvent& evt); +public: + void SetColors(const XVT_COLOR_COMPONENT* colors); + TwxPropertyGrid(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style); +}; + +WINDOW xvt_ctl_create_def(WIN_DEF* win_def_p, WINDOW parent_win, long app_data) +{ + wxASSERT(win_def_p != nullptr); + const wxRect rct = RCT2Rect(&win_def_p->rct); + wxWindow* pParent = wxStaticCast((wxObject*)parent_win, wxWindow); + const wxWindowID id = win_def_p->v.ctl.ctrl_id; + + WINDOW win = NULL_WIN; + switch (win_def_p->wtype) + { + case WC_HSCROLL: /* horizontal scrollbar control */ + case WC_VSCROLL: /* vertical scrollbar control */ + { + long style = win_def_p->wtype == WC_HSCROLL ? wxSB_HORIZONTAL : wxSB_VERTICAL; + style |= wxCLIP_SIBLINGS; + TwxScrollBar* sb = new TwxScrollBar(pParent, id, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)sb; + } + break; + case WC_HGAUGE: /* horizontal progress bar control */ + case WC_VGAUGE: /* vertical progress bar control */ + { + const long style = (win_def_p->wtype == WC_HGAUGE) ? wxGA_HORIZONTAL : wxGA_VERTICAL; + wxGauge* pg = new wxGauge(pParent, id, app_data, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)pg; + } + break; + case WC_HSLIDER: /* horizontal slider control */ + case WC_VSLIDER: /* vertical slider control */ + { + const long style = win_def_p->wtype == WC_HSLIDER ? wxSL_HORIZONTAL : wxSL_VERTICAL; + wxSlider* sc = new wxSlider(pParent, id, 0, 0, app_data, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)sc; + } + break; + case WC_PUSHBUTTON: /* bottone normale */ + { + wxButton* pb = nullptr; + if (win_def_p->text && *win_def_p->text) // Bottone normale con label + pb = new wxButton(pParent, id, win_def_p->text, rct.GetPosition(), rct.GetSize()); + else + pb = new wxBitmapButton(pParent, id, wxNullBitmap, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)pb; + } + break; + case WC_CHECKBOX: /* check box */ + { + long style = wxCHK_2STATE | wxCLIP_SIBLINGS; + if (win_def_p->wtype == CTL_FLAG_RIGHT_JUST) + style |= wxALIGN_RIGHT; + wxCheckBox* cb = new wxCheckBox(pParent, id, win_def_p->text, + rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)cb; + } + break; + case WC_RADIOBUTTON: /* radio button */ + { + const long style = wxRB_SINGLE | wxCLIP_SIBLINGS; + wxRadioButton* rb = new wxRadioButton(pParent, id, win_def_p->text, + rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)rb; + } + break; + case WC_NOTEBK: + { + TwxNoteBook* nb = new TwxNoteBook(pParent, id, rct.GetPosition(), rct.GetSize(), win_def_p->v.ctl.flags); + win = (WINDOW)nb; + } + break; + case WC_HTML: + { + wxHtmlWindow* hw = new wxHtmlWindow(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)hw; + } + break; + case WC_TREE: + { + TwxTreeCtrl* tv = new TwxTreeCtrl(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)tv; + } + break; + case WC_LBOX: + { + wxListBox* tlb = new wxListBox(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)tlb; + } + break; + case WC_OUTLOOKBAR: + { + long style = 0; + TwxOutlookBar* tob = new TwxOutlookBar(pParent, id, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)tob; + } + break; + case WC_METROBAR: + { + long style = 0; + TwxMetroBar* tmb = new TwxMetroBar(pParent, id, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)tmb; + } + break; + case WC_POPUP: + { + TwxPopUp* tpu = new TwxPopUp(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)tpu; + } + break; + case WC_PROPGRID: + { + long flags = wxPG_BOLD_MODIFIED | wxPG_SPLITTER_AUTO_CENTER | wxPG_DESCRIPTION | wxPG_TOOLTIPS; + TwxPropertyGrid* pg = new TwxPropertyGrid(pParent, id, rct.GetPosition(), rct.GetSize(), flags); + win = (WINDOW)pg; + } + break; + case WC_TREELIST: + { + const bool multisel = (win_def_p->v.ctl.flags & CTL_FLAG_MULTIPLE) != 0; + TwxTreeListCtrl* tv = new TwxTreeListCtrl(pParent, id, rct.GetPosition(), rct.GetSize(), multisel); + win = (WINDOW)tv; + } + break; + default: + SORRY_BOX(); break; + } + + if (win != NULL_WIN) + { + wxWindow& w = *wxStaticCast((wxObject*)win, wxWindow); + const long flags = win_def_p->v.ctl.flags; + if (flags & CTL_FLAG_INVISIBLE) w.Hide(); + if (flags & CTL_FLAG_DISABLED) w.Disable(); + + XVT_FNTID font_id = win_def_p->v.ctl.font_id; + const bool bDestroyFont = font_id == nullptr; + if (bDestroyFont) + font_id = xvt_dwin_get_font(parent_win); + if (font_id != nullptr) + { + const wxFont& font = wxStaticCast(font_id, TFontId)->Font(nullptr, win); + w.SetFont(font); + if (bDestroyFont) + xvt_font_destroy(font_id); + } + xvt_ctl_set_colors(win, win_def_p->ctlcolors, XVT_COLOR_ACTION_SET); + } + + return win; +} + +void xvt_ctl_check_radio_button(WINDOW win, WINDOW* wins, int NbrWindows) +{ + wxASSERT(wins != NULL_WIN && NbrWindows >= 2); + for (int i = 0; i < NbrWindows; i++) + { + wxRadioButton* rb = wxDynamicCast((wxObject*)wins[i], wxRadioButton); + if (rb != nullptr) + rb->SetValue(win == wins[i]); + } +} + +void xvt_ctl_set_checked(WINDOW win, BOOLEAN bCheck) +{ + wxCheckBox* cb = wxDynamicCast((wxObject*)win, wxCheckBox); + if (cb != nullptr) + cb->SetValue(bCheck != 0); +} + +void xvt_ctl_set_colors(WINDOW win, const XVT_COLOR_COMPONENT* colors, XVT_COLOR_ACTION action) +{ + // Non posso usare wxControl in quanto certi controlli derivano da wxWindow + wxWindow* w = wxDynamicCast((wxObject*)win, wxWindow); + if (w != nullptr && colors != nullptr) + { + if (action == XVT_COLOR_ACTION_SET) + { + switch (xvt_vobj_get_type(win)) + { + case WC_TREE : wxStaticCast(w, TwxTreeCtrl)->SetColors(colors); return; + case WC_PROPGRID: wxStaticCast(w, TwxPropertyGrid)->SetColors(colors); return; + case WC_TREELIST: wxStaticCast(w, TwxTreeListCtrl)->SetColors(colors); return; + default: break;; + } + for (int i = 0; colors[i].type; i++) + { + CAST_COLOR(colors[i].color, rgb); + switch(colors[i].type) + { + case XVT_COLOR_BACKGROUND: w->SetOwnBackgroundColour(rgb); break; + case XVT_COLOR_FOREGROUND: w->SetOwnForegroundColour(rgb); break; + case XVT_COLOR_HIGHLIGHT: + { + TwxPopUp* tpu = wxDynamicCast(w, TwxPopUp); + if (tpu != nullptr) + tpu->SetSelectForeColor(rgb); + else + { + TwxMetroBar* tmb = wxDynamicCast(w, TwxMetroBar); + if (tmb != nullptr) + tmb->SetSelectForeColor(rgb); + } + } + break; + case XVT_COLOR_SELECT: + { + TwxPopUp* tpu = wxDynamicCast(w, TwxPopUp); + if (tpu != nullptr) + tpu->SetSelectBackColor(rgb); + } + break; + case XVT_COLOR_BLEND: + if (!w->IsKindOf(CLASSINFO(wxButton))) + w->SetOwnBackgroundColour(rgb); + break; + case XVT_COLOR_BORDER: + { + TwxMetroBar* tmb = wxDynamicCast(w, TwxMetroBar); + if (tmb != nullptr) + tmb->SetBorderColor(rgb); + } + break; + default: + break; + } + } + } + else + { + // ??? + } + } +} + +/////////////////////////////////////////////////////////// +// Buttons +/////////////////////////////////////////////////////////// + +void xvt_btn_set_images(WINDOW win, XVT_IMAGE up, XVT_IMAGE down) +{ + if (win != NULL_WIN && up != nullptr) + { + wxBitmapButton* pb = wxDynamicCast((wxObject*)win, wxBitmapButton); + if (pb != nullptr) + { + int mx, my; pb->GetSize(&mx, &my); + wxBitmap bmpUp = Image2Bitmap(up, mx, my, true); + if (bmpUp.Ok()) + { + pb->SetBitmapLabel(bmpUp); + const wxImage imgGay = ((wxImage*)up)->ConvertToGreyscale(); + wxBitmap bmpGay(imgGay); + pb->SetBitmapDisabled(bmpGay); + } + if (down != nullptr) + { + wxBitmap bmpDown = Image2Bitmap(down, mx, my, true); + if (bmpDown.Ok()) + pb->SetBitmapSelected(bmpDown); + } + else + { + if (bmpUp.Ok()) + pb->SetBitmapSelected(bmpUp); + } + } + } +} + +/////////////////////////////////////////////////////////// +// Pane interface +/////////////////////////////////////////////////////////// + +static wxAuiManager* FindPaneManager(WINDOW win) +{ + wxAuiManager* pManager = nullptr; + if (win != NULL_WIN) + { + wxWindow* pwin = wxStaticCast((wxObject*)win, wxWindow); + pManager = wxAuiManager::GetManager(pwin); + } + return pManager; +} + +static wxAuiPaneInfo* LockPane(WINDOW win) +{ + wxAuiManager* pManager = FindPaneManager(win); + if (pManager != nullptr) + { + wxAuiPaneInfo& pane = pManager->GetPane((wxWindow*)win); + if (pane.IsOk()) + return &pane; + } + return nullptr; +} + +static void UnlockPane(WINDOW win) +{ + wxAuiManager* pManager = FindPaneManager(win); + if (pManager != nullptr) + pManager->Update(); +} + +const char ** xvt_task_get_list(int & ntasks) +{ + static const char ** __list = (const char **) malloc((MAX_TASKS + 1) * sizeof(const char *)); + static int __ntasks = 0; + + for (int i = 0; i < __ntasks; i++) + { + delete(__list[i]); + __list[i] = nullptr; + } + + #ifdef __WXMSW__ + __ntasks = OsWin32_TaskList((const char **) __list); + #else + __ntasks = OsLinux_TaskList((const char **)__list); + #endif + ntasks = __ntasks; + return __list; +} + +int xvt_task_get_instances(const char * task) +{ + int ntasks = 0; + const char ** list = xvt_task_get_list(ntasks); + int i = 0; + int instances = 0; + + for (const char * t = list[i]; i < ntasks; t = list[++i]) + { + if (strcmp(t, task) == 0) + instances++; + } + return instances; +} + +BOOLEAN xvt_pane_add(WINDOW win, WINDOW pane, const char* name, int dock, int flags) +{ + BOOLEAN done = false; + if (win != NULL_WIN && pane != NULL_WIN && name && *name) + { + TwxWindow* owner = wxStaticCast((wxObject*)win, TwxWindow); + wxWindow* child = wxStaticCast((wxObject*)pane, wxWindow); + done = owner->AddPane(child, name, dock, flags); + } + return done; +} + +BOOLEAN xvt_pane_set_title(WINDOW win, const char* title) +{ + wxAuiPaneInfo* pane = LockPane(win); + if (pane != nullptr) + { + pane->Caption(title); + UnlockPane(win); + } + return pane != nullptr; +} + +XVTDLL BOOLEAN xvt_pane_change_flags(WINDOW win, int set, int rst) +{ + wxAuiPaneInfo* pane = LockPane(win); + if (pane != nullptr && (set || rst)) + { + if (set) pane->SetFlag(set, true); + if (rst) pane->SetFlag(rst, false); + UnlockPane(win); + } + return pane != nullptr; +} + +XVTDLL BOOLEAN xvt_pane_detach(WINDOW win) +{ + BOOLEAN ok = false; + wxAuiManager* pManager = FindPaneManager(win); + if (pManager != nullptr) + { + ok = pManager->DetachPane((wxWindow*)win); + pManager->Update(); + } + return ok; +} + +XVTDLL BOOLEAN xvt_pane_manager_load_perspective(WINDOW win, const char* perspective) +{ + BOOLEAN ok = false; + if (perspective && *perspective) + { + wxAuiManager* pManager = FindPaneManager(win); + if (pManager != nullptr) + { + const wxString str = perspective; + ok = pManager->LoadPerspective(str, true); + } + } + return ok; +} + +XVTDLL int xvt_pane_manager_save_perspective(WINDOW win, char* perspective, int max_size) +{ + int nSize = 0; + wxAuiManager* pManager = FindPaneManager(win); + if (pManager != nullptr) + { + const wxString str = pManager->SavePerspective(); + nSize = str.Len()+1; + if (perspective != nullptr && max_size > 0) + wxStrncpy(perspective, str, max_size); + } + return nSize; +} + +XVTDLL BOOLEAN xvt_pane_set_size_range(WINDOW win, int min_size, int best_size, int max_size) +{ + BOOLEAN ok = false; + wxAuiPaneInfo* pane = LockPane(win); + if (pane != nullptr) + { + if (min_size > 0 || max_size > 0) + { + if (best_size <= 0) + { + if (min_size > 0) + best_size = max_size > 0 ? (min_size+max_size) / 2 : min_size; + else + best_size = max_size; + } + wxSize szMin(-1, -1), szBst(-1, -1), szMax(-1, -1); + if (pane->IsTopDockable() || pane->IsBottomDockable()) + { + szMin.y = min_size; + szBst.y = best_size; + szMax.y = max_size; + } + else + { + szMin.x = min_size; + szBst.x = best_size; + szMax.x = max_size; + } + pane->MinSize(szMin); + pane->BestSize(szBst); + pane->MaxSize(szMax); + } + pane->Resizable(min_size != max_size); + pane->DockFixed(min_size == max_size); + UnlockPane(win); + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Notebook interface +/////////////////////////////////////////////////////////// + +class TwxAuiDefaultTabArt : public wxAuiDefaultTabArt +{ + wxColour m_fore_colour; + bool m_metro_style; + +protected: + virtual void DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& pane, + const wxRect& in_rect, int close_button_state, + wxRect* out_tab_rect, wxRect* out_button_rect, int* x_extent); + virtual void DrawBackground(wxDC& dc, wxWindow* wnd, const wxRect& rect); + +public: + void SetBackgroundColour(const wxColor& colour) { m_base_colour = colour; } + void SetForegroundColour(const wxColor& colour) { m_fore_colour = colour; } + void SetMetroStyle(bool ms) { m_metro_style = ms; } + virtual wxAuiTabArt* Clone(); +}; + +void TwxAuiDefaultTabArt::DrawBackground(wxDC& dc, wxWindow* wnd, const wxRect& rect) +{ + if (m_metro_style) + { + // dc.SetBackground(m_base_colour); dc.Clear(); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(m_base_colour); + dc.DrawRectangle(rect); + } + else + wxAuiDefaultTabArt::DrawBackground(dc, wnd, rect); +} + +void TwxAuiDefaultTabArt::DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& pane, + const wxRect& in_rect, int close_button_state, + wxRect* out_tab_rect, wxRect* out_button_rect, int* x_extent) +{ + dc.SetTextForeground(m_fore_colour); + wxAuiDefaultTabArt::DrawTab(dc, wnd, pane, in_rect, close_button_state, + out_tab_rect, out_button_rect, x_extent); +} + + +wxAuiTabArt* TwxAuiDefaultTabArt::Clone() +{ + TwxAuiDefaultTabArt* art = new TwxAuiDefaultTabArt(); + + // Copy'n'paste from aui/auibook.cpp + art->SetNormalFont(m_normal_font); + art->SetSelectedFont(m_selected_font); + art->SetMeasuringFont(m_measuring_font); + + // My own addition + art->m_base_colour = m_base_colour; + art->m_fore_colour = m_fore_colour; + art->SetMetroStyle(m_metro_style); + + return art; +} + +IMPLEMENT_DYNAMIC_CLASS(TwxNoteBook, wxAuiNotebook) + +#define CAST_NOTEBOOK(win, nb) TwxNoteBook& nb = *wxStaticCast((wxObject*)win, TwxNoteBook); + +inline bool VALID_NOTEBOOK(WINDOW notebk, short page_no) +{ return page_no >= 0 && wxDynamicCast((wxObject*)notebk, TwxNoteBook)!=nullptr; } + +BEGIN_EVENT_TABLE(TwxNoteBook, wxAuiNotebook) + EVT_AUINOTEBOOK_PAGE_CHANGING(wxID_ANY, TwxNoteBook::OnPageChanging) + EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, TwxNoteBook::OnPageChanged) + EVT_CHAR(TwxNoteBook::OnChar) +END_EVENT_TABLE(); + +bool TwxNoteBook::SetBackgroundColour(const wxColour& col) +{ + const bool ok = wxAuiNotebook::SetBackgroundColour(col); + if (ok) // Se cambio lo sfondo del tab control devo notificarlo all'art provider + { + TwxAuiDefaultTabArt* pArtist = (TwxAuiDefaultTabArt*)GetArtProvider(); + if (pArtist != nullptr) + pArtist->SetBackgroundColour(col); + } + return ok; +} + +bool TwxNoteBook::SetForegroundColour(const wxColour& col) +{ + const bool ok = wxAuiNotebook::SetForegroundColour(col); + if (ok) // Se cambio il colore del testo del tab control devo notificarlo all'art provider + { + TwxAuiDefaultTabArt* pArtist = (TwxAuiDefaultTabArt*)GetArtProvider(); + if (pArtist != nullptr) + pArtist->SetForegroundColour(col); + } + return ok; +} + + +void TwxNoteBook::OnChar(wxKeyEvent& evt) +{ + // Ridirige i tasti che non sono certamente di navigazione alla finestra nonna + const int kc = evt.GetKeyCode(); + if (kc >= WXK_F1 && kc <= WXK_F24 || kc == WXK_ESCAPE || kc == WXK_RETURN) + { + TwxWindow* gp = wxDynamicCast(GetGrandParent(), TwxWindow); + if (gp != nullptr) + gp->ProcessEvent(evt); + else + evt.Skip(); + } +} + +void TwxNoteBook::OnPageChanging(wxAuiNotebookEvent& evt) +{ + if (!m_bSuspended) + { + m_bSuspended = true; + XVT_EVENT e(E_CONTROL); + CONTROL_INFO& ci = e.v.ctl.ci; + e.v.ctl.id = evt.GetId(); + ci.type = WC_NOTEBK; + ci.win = WINDOW(this); + // page == NULL_WIN -> changing page; page != NULL_WIN -> page changed. + ci.v.notebk.page = NULL_WIN; + ci.v.notebk.page_new = evt.GetSelection(); + ci.v.notebk.page_old = evt.GetOldSelection(); + + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + const bool refused = win->DoXvtEvent(e) != 0; + if (refused) + evt.Veto(); // Vieta il passaggio alla pagina nuova + else + evt.Skip(); // Permette la notifica dell'evento PageChanged + + m_bSuspended = false; + } +} + +void TwxNoteBook::OnPageChanged(wxAuiNotebookEvent& evt) +{ + // Mando la notifica solo al book in basso di ba0 + //if (m_flags & wxAUI_NB_BOTTOM) // Perchè mai solo a ba0? + + if (!m_bSuspended) + { + m_bSuspended = true; + XVT_EVENT e(E_CONTROL); + CONTROL_INFO& ci = e.v.ctl.ci; + e.v.ctl.id = evt.GetId(); + ci.type = WC_NOTEBK; + ci.win = WINDOW(this); + // page == NULL_WIN -> changing page; page != NULL_WIN -> page changed. + ci.v.notebk.page = (WINDOW)GetPage(evt.GetSelection()); + ci.v.notebk.page_new = evt.GetSelection(); + ci.v.notebk.page_old = evt.GetOldSelection(); + + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + m_bSuspended = false; + } +} + +short TwxNoteBook::AddTab(wxWindow* pPage, const wxString text, XVT_IMAGE xvt_img, short idx) +{ + wxBitmap bmp = Image2Bitmap(xvt_img, BOOK_ICO_SIZE, BOOK_ICO_SIZE, true); + + if (idx < 0 || idx >= (int)GetPageCount()) + { + AddPage(pPage, text, false, bmp); + idx = ((short)GetPageCount())-1; + } + else + InsertPage(idx, pPage, text, false, bmp); + + return idx; +} + +void TwxNoteBook::SetTabImage(size_t idx, XVT_IMAGE img) +{ + wxBitmap bmp = Image2Bitmap(img, BOOK_ICO_SIZE, BOOK_ICO_SIZE, true); + SetPageBitmap(idx, bmp); +} + +int TwxNoteBook::ChangeSelection(size_t tab_no) +{ + const size_t nSel = GetSelection(); + if (!m_bSuspended && tab_no != nSel) + { + m_bSuspended = true; + SetSelection(tab_no); + m_bSuspended = false; + } + return nSel; +} + +long TwxNoteBook::Flags2Style(long flags) const +{ + long style = wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS; + bool bottom = false; + +#if wxCHECK_VERSION(2,8,9) + if (flags & (CTL_FLAG_TAB_TOP|CTL_FLAG_TAB_BOTTOM|CTL_FLAG_TAB_LEFT|CTL_FLAG_TAB_RIGHT)) + { + bottom = (flags & CTL_FLAG_TAB_BOTTOM) != 0; + } + else +#endif + { + bottom = (flags & CTL_FLAG_CENTER_JUST) != 0; + } + + if (bottom) + style |= wxAUI_NB_BOTTOM; + else + style |= wxAUI_NB_TOP; + + return style; +} + +TwxNoteBook::TwxNoteBook(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long flags) + : wxAuiNotebook(parent, id, pos, size, Flags2Style(flags)), m_bSuspended(false) +{ + TwxAuiDefaultTabArt* dta = new TwxAuiDefaultTabArt; + dta->SetMetroStyle((flags & WSF_NO_TASKBAR) != 0); + SetArtProvider(dta); + _nice_windows.Put((WINDOW)this, this); // Serve per poter fare la xvt_vobj_destroy + + wxAuiTabCtrl* atc = GetActiveTabCtrl(); + if (atc != nullptr) +#if wxCHECK_VERSION(2,9,0) + atc->GetEventHandler().Bind(wxEVT_CHAR, (functor)&TwxNoteBook::OnChar); +#else + atc->Connect(wxEVT_CHAR, (wxObjectEventFunction)&TwxNoteBook::OnChar); +#endif +} + +TwxNoteBook::~TwxNoteBook() +{ + m_bSuspended = true; + _nice_windows.Delete((WINDOW)this); +} + +short xvt_notebk_add_page(WINDOW notebk, WINDOW page, const char* title, XVT_IMAGE image, short tab_no) +{ + short idx = -1; + if (notebk != NULL_WIN) + { + CAST_NOTEBOOK(notebk, nb); + wxString strTitle = title; + if (strTitle.IsEmpty() && page != NULL_WIN) + { + wxWindow* pg = wxStaticCast((wxObject*)page, wxWindow); + strTitle = pg->GetLabel(); + } + idx = nb.AddTab((wxWindow*)page, strTitle, image, tab_no); + } + return idx; +} + +WINDOW xvt_notebk_get_page(WINDOW notebk, short tab_no) +{ + WINDOW page = NULL_WIN; + if (VALID_NOTEBOOK(notebk, tab_no)) + { + CAST_NOTEBOOK(notebk, nb); + page = (WINDOW)nb.GetPage(tab_no); + } + return page; +} + +short xvt_notebk_get_num_tabs(WINDOW notebk) +{ + short pg = 0; + + if (notebk != NULL_WIN) + { + CAST_NOTEBOOK(notebk, nb); + pg = (short) nb.GetPageCount(); + } + return pg; +} + +void xvt_notebk_rem_page(WINDOW notebk, short page_no) +{ + WINDOW win = xvt_notebk_get_page(notebk, page_no); + if (win != NULL_WIN) + { + xvt_notebk_rem_tab(notebk, page_no); + xvt_vobj_destroy(win); + } +} + +void xvt_notebk_rem_tab(WINDOW notebk, short tab_no) +{ + if (VALID_NOTEBOOK(notebk, tab_no)) + { + CAST_NOTEBOOK(notebk, nb); + nb.RemovePage(tab_no); + } +} + +void xvt_notebk_set_front_page(WINDOW notebk, short tab_no) +{ + if (VALID_NOTEBOOK(notebk, tab_no)) + { + CAST_NOTEBOOK(notebk, nb); + wxWindow* w = nb.GetPage(tab_no); + if (w != nullptr) + { + nb.ChangeSelection(tab_no); // Non genera evento di cambio pagina! + if (!w->IsShown()) // A volte succede che la prima pagina sia nascosta! + w->Show(true); + } + } +} + +short xvt_notebk_get_front_page(WINDOW notebk) +{ + short idx = -1; + if (notebk != NULL_WIN) + { + CAST_NOTEBOOK(notebk, nb); + idx = nb.GetSelection(); + } + return idx; +} + + +char* xvt_notebk_get_tab_title(WINDOW notebk, short tab_no, char* title, int sz_title) +{ + if (VALID_NOTEBOOK(notebk, tab_no)) + { + CAST_NOTEBOOK(notebk, nb); + wxStrncpy(title, nb.GetPageText(tab_no), sz_title); + title[sz_title-1] = '\0'; + } + else + *title = '\0'; + return title; +} + +void xvt_notebk_set_page_title(WINDOW notebk, short tab_no, const char* title) +{ + WINDOW win = xvt_notebk_get_page(notebk, tab_no); + if (win != NULL_WIN) + xvt_vobj_set_title(win, title); +} + +void xvt_notebk_set_tab_image(WINDOW notebk, short tab_no, XVT_IMAGE img) +{ + if (notebk != NULL_WIN && tab_no >= 0) + { + CAST_NOTEBOOK(notebk, nb); + nb.SetTabImage(tab_no, img); // Se img=NULL toglie l'immagine + } +} + +void xvt_notebk_set_tab_icon(WINDOW notebk, short tab_no, int rid) +{ + const wxString strName = xvtart_GetResourceName("Icon", rid); + XVT_IMAGE img = xvt_image_read(strName); + xvt_notebk_set_tab_image(notebk, tab_no, img); + xvt_image_destroy(img); +} + +void xvt_notebk_set_tab_title(WINDOW notebk, short tab_no, const char* title) +{ + if (VALID_NOTEBOOK(notebk, tab_no)) + { + CAST_NOTEBOOK(notebk, nb); + const short pc = (short) nb.GetPageCount(); + + if (tab_no >= pc) + nb.AddTab(nb.GetPage(pc-1), title, nullptr, pc); + else + nb.SetPageText(tab_no, title); + } +} + +/////////////////////////////////////////////////////////// +// TreeCtrl interface +/////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE(TwxTreeCtrl, wxTreeCtrl) + EVT_TREE_ITEM_EXPANDING(wxID_ANY, TwxTreeCtrl::OnExpanding) + EVT_TREE_ITEM_COLLAPSED(wxID_ANY, TwxTreeCtrl::OnCollapsed) + EVT_TREE_SEL_CHANGED(wxID_ANY, TwxTreeCtrl::OnSelected) + EVT_TREE_ITEM_ACTIVATED(wxID_ANY, TwxTreeCtrl::OnActivated) + EVT_RIGHT_DOWN(TwxTreeCtrl::OnRightDown) +END_EVENT_TABLE(); + +#define CAST_TREEVIEW(win, tv) TwxTreeCtrl& tv = *wxStaticCast((wxObject*)win, TwxTreeCtrl); + +struct TwxTreeItemData : public wxTreeItemData +{ + wxString m_strData; // Assumo sempre una stringa come dati +}; + +void TwxTreeCtrl::OnExpanding(wxTreeEvent& evt) +{ + if (!m_nFrozen) + { + const wxTreeItemId id = evt.GetItem(); + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = id.m_pItem; + e.v.ctl.ci.v.treeview.expanded = true; + if (GetChildrenCount(id) == 0) // Trucco perfido ... + e.v.ctl.ci.v.treeview.collapsed = true; // ... stato indeterminato = EXPANDING + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + if (GetChildrenCount(id) == 0) // Allora e' proprio vero ... + SetItemHasChildren(id, false); + } +} + +void TwxTreeCtrl::OnCollapsed(wxTreeEvent& evt) +{ + if (!m_nFrozen) + { + Suspend(); + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = evt.GetItem().m_pItem; + e.v.ctl.ci.v.treeview.collapsed = true; + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + Resume(); + } +} + +void TwxTreeCtrl::OnClick(wxTreeEvent& evt, bool bDouble) +{ + if (!m_nFrozen) + { + Suspend(); + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = evt.GetItem().m_pItem; + if (bDouble) + e.v.ctl.ci.v.treeview.dbl_click = true; + else + e.v.ctl.ci.v.treeview.sgl_click = true; + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + Resume(); + } +} + +wxColour TwxTreeCtrl::GetItemTextColour(const wxTreeItemId& id) const +{ + if (IsSelected(id)) + return m_clrSelFore; + return wxTreeCtrl::GetItemTextColour(id); +} + +wxColour TwxTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& id) const +{ + if (IsSelected(id)) + return m_clrSelBack; + return wxTreeCtrl::GetItemBackgroundColour(id); +} + +void TwxTreeCtrl::OnSelected(wxTreeEvent& evt) +{ + OnClick(evt, false); +} + +void TwxTreeCtrl::OnActivated(wxTreeEvent& evt) +{ +#if wxCHECK_VERSION(2,8,10) + const wxTreeItemId id = evt.GetItem(); + if (ItemHasChildren(id)) + { + if (IsExpanded(id)) + Collapse(id); + else + Expand(id); + } +#endif + OnClick(evt, true); +} + +void TwxTreeCtrl::OnRightDown(wxMouseEvent& evt) +{ + TwxWindow* pParent = wxDynamicCast(GetParent(), TwxWindow); + if (pParent != nullptr) + { + XVT_EVENT e(E_MOUSE_DOWN); + e.v.mouse.button = 1; + e.v.mouse.control = evt.ControlDown(); + e.v.mouse.shift = evt.ShiftDown(); + e.v.mouse.where.h = evt.GetX(); + e.v.mouse.where.v = evt.GetY(); + pParent->DoXvtEvent(e); + } +} + +int TwxTreeCtrl::img2int(XVT_IMAGE xvt_img) +{ + int i = -1; + if (xvt_img != nullptr) + { + i = m_img[xvt_img] - 1; // Ho memorizzato indice+1 + if (i < 0) // Immagine sconosciuta + { + const wxImage& img = *(wxImage*)xvt_img; + wxImageList* il = GetImageList(); + if (il == nullptr) // Lista non ancora creata + { + il = new wxImageList; + il->Create(img.GetWidth(), img.GetHeight(), true, 3); + AssignImageList(il); // DON'T CALL SetImageList! + } + else + { + int old_w, old_h; il->GetSize(0, old_w, old_h); + const int new_w = img.GetWidth(), new_h = img.GetHeight(); + if (new_w > old_w) // L'immagine nuova e' troppo grande? + { + const int old_ratio = old_w * 100 / old_h; + const int new_ratio = new_w * 100 / new_h; + const int old_count = il->GetImageCount(); + wxImageList* nil = new wxImageList; + nil->Create(new_w, new_h, true, 3*old_count/2); + for (int k = 0; k < old_count; k++) + { + wxImage old = il->GetBitmap(k).ConvertToImage(); + if (old_ratio == new_ratio) + old.Rescale(new_w, new_h, wxIMAGE_QUALITY_HIGH); + else + old.Resize(wxSize(new_w, new_h), wxPoint((new_w-old_w)/2, (new_h-old_h)/2)); + nil->Add(old); + } + AssignImageList(il = nil); + } + } + + if (!img.HasMask()) + { + wxImage& trans = (wxImage&)img; + const int r = img.GetRed(0,0); + const int g = img.GetGreen(0,0); + const int b = img.GetBlue(0,0); + trans.SetMask(); + trans.SetMaskColour(r, g, b); + } + const wxBitmap bmp(img); + i = il->Add(bmp); + m_img[xvt_img] = i+1; // Memorizzo indice+1 + } + if (i < 0) + SORRY_BOX(); + } + return i; +} + +void TwxTreeCtrl::SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + const int ii = img2int(item_image); + if (ii >= 0) + SetItemImage(id, ii); + else + { + const int ic = img2int(collapsed_image); + if (ic >= 0) + { + SetItemImage(id, ic); + const int ie = img2int(expanded_image); + if (ie >= 0) + SetItemImage(id, ie, wxTreeItemIcon_Selected); + } + } +} + +void TwxTreeCtrl::Enable(const wxTreeItemId& id, bool on) +{ + SetItemTextColour(id, on ? m_clrSelFore : m_clrDisFore); +} + +void TwxTreeCtrl::Suspend() +{ m_nFrozen++; } + +void TwxTreeCtrl::Resume() +{ + wxASSERT(m_nFrozen > 0); + if (m_nFrozen > 0) + m_nFrozen--; +} + +void TwxTreeCtrl::SetColors(const XVT_COLOR_COMPONENT* colors) +{ + for (int i = 0; colors[i].type; i++) + { + CAST_COLOR(colors[i].color, rgb); + switch(colors[i].type) + { + case XVT_COLOR_BACKGROUND: SetOwnBackgroundColour(rgb); break; + case XVT_COLOR_FOREGROUND: SetOwnForegroundColour(rgb); break; + case XVT_COLOR_HIGHLIGHT : m_clrSelBack = rgb; break; + case XVT_COLOR_SELECT : m_clrSelFore = rgb; break; + case XVT_COLOR_TROUGH : m_clrDisFore = rgb; break; + default : break; + } + } +} + +TwxTreeCtrl::TwxTreeCtrl(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size) + : wxTreeCtrl(parent, id, pos, size, wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT), + m_nFrozen(0) +{ + AddRoot("Root"); +} + +WINDOW xvt_treeview_create(WINDOW parent_win, + RCT * rct_p, char * title, long ctl_flags, + long app_data, int ctl_id, XVT_IMAGE WXUNUSED(item_image), + XVT_IMAGE WXUNUSED(collapsed_image), XVT_IMAGE WXUNUSED(expanded_image), + long WXUNUSED(attrs), int WXUNUSED(line_height)) +{ + WIN_DEF win_def; memset(&win_def, 0, sizeof(WIN_DEF)); + win_def.wtype = WC_TREE; + win_def.rct = *rct_p; + win_def.text = title; + win_def.v.ctl.ctrl_id = ctl_id; + win_def.v.ctl.flags = ctl_flags; + WINDOW win = xvt_ctl_create_def(&win_def, parent_win, app_data); + return win; +} + +XVT_TREEVIEW_NODE xvt_treeview_add_child_node(WINDOW win, + XVT_TREEVIEW_NODE parent, XVT_TREEVIEW_NODE_TYPE type, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + const char* string, XVT_TREEVIEW_CALLBACK WXUNUSED(callback), const char* data) +{ + XVT_TREEVIEW_NODE node = nullptr; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + TwxTreeItemData* pData = new TwxTreeItemData; + pData->m_strData = data; + wxTreeItemId pa(parent); + if (!pa.IsOk()) + pa = tv.GetRootItem(); + wxTreeItemId id = tv.AppendItem(pa, string, -1, -1, pData); + if (id.IsOk()) + { + tv.SetItemHasChildren(pa, true); + tv.SetItemHasChildren(id, type == XVT_TREEVIEW_NODE_NONTERMINAL); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + tv.SetItemFont(id, tv.GetFont()); + node = id.m_pItem; + } + } + return node; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_child_node(WINDOW win, XVT_TREEVIEW_NODE parent_node, + int position) +{ + XVT_TREEVIEW_NODE child_node = nullptr; + if (win != NULL_WIN && position >= 0) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId parent(parent_node); + if (!parent.IsOk()) + parent = tv.GetRootItem(); + + if (parent.IsOk() && position < (int)tv.GetChildrenCount(parent)) + { + wxTreeItemIdValue cookie; + wxTreeItemId id; + int i = -1; + for (id = tv.GetFirstChild(parent, cookie), i = -1; + i < position && id.IsOk(); id = tv.GetNextChild(parent, cookie), i++); + child_node = id.m_pItem; + } + } + return child_node; +} + +const char* xvt_treeview_get_node_data(WINDOW win, XVT_TREEVIEW_NODE node) +{ + const char* data = nullptr; + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + TwxTreeItemData* pData = (TwxTreeItemData*)tv.GetItemData(id); + if (pData != nullptr) + data = (const char*)pData->m_strData; + } + return data; +} + +void xvt_treeview_destroy_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId id(node); + tv.Delete(id); + } +} + +BOOLEAN xvt_treeview_enable_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN on) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId id(node); + tv.Enable(id, on != false); + } + return ok; +} + +BOOLEAN xvt_treeview_expand_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN recurse) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREEVIEW(win, tv); + tv.Suspend(); + const wxTreeItemId id(node); + if (recurse) + tv.ExpandAllChildren(id); + else + tv.Expand(id); + tv.Resume(); + } + return ok; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_root_node(WINDOW win) +{ + XVT_TREEVIEW_NODE pRoot = nullptr; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id = tv.GetRootItem(); + pRoot = id.m_pItem; + } + return pRoot; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_selected_node(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + const wxTreeItemId id = tv.GetSelection(); + return id.m_pItem; +} + +SLIST xvt_treeview_get_selected_list(WINDOW win) +{ + SLIST list = nullptr; + CAST_TREEVIEW(win, tv); + wxArrayTreeItemIds selections; + const size_t nSel = tv.GetSelections(selections); + if (nSel > 0) + { + list = xvt_slist_create(); + for (size_t i = 0; i < nSel; i++) + { + const wxTreeItemId& id = selections[i]; + const TwxTreeItemData* pData = (const TwxTreeItemData*)tv.GetItemData(id); + if (pData != nullptr) + xvt_slist_add_at_elt(list, nullptr, pData->m_strData, (long)id.m_pItem); + else + xvt_slist_add_at_elt(list, nullptr, "", (long)id.m_pItem); + } + } + return list; +} + + +BOOLEAN xvt_treeview_remove_child_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + if (id == tv.GetRootItem()) + tv.DeleteAllItems(); + else + { + tv.Suspend(); + tv.Delete(id); + tv.Resume(); + } + } + return ok; +} + +BOOLEAN xvt_treeview_remove_node_children(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = false; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + tv.Suspend(); + wxTreeItemId id(node); + if (!id.IsOk()) + id = tv.GetRootItem(); + tv.DeleteChildren(id); + tv.Resume(); + ok = true; + } + return ok; +} + +void xvt_treeview_resume(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + tv.Resume(); +} + +void xvt_treeview_select_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN sel) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + if (sel) + { + tv.Suspend(); + tv.SelectItem(id, true); + tv.EnsureVisible(id); + tv.Resume(); + } + else + tv.SelectItem(id, false); + } +} + +void xvt_treeview_set_node_images(WINDOW win, XVT_TREEVIEW_NODE node, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + } +} + +void xvt_treeview_set_node_bold(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN bold) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SetItemBold(id, bold != false); + } +} + +void xvt_treeview_set_node_string(WINDOW win, XVT_TREEVIEW_NODE node, const char* text) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SetItemText(id, text); + } +} + +void xvt_treeview_suspend(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + tv.Suspend(); +} + +static XVT_TREEVIEW_NODE FindTreeNodeString(wxTreeCtrl& tv, const wxTreeItemId& parent, + const char*text) +{ + if (parent.IsOk()) + { + TwxTreeItemData* pData = (TwxTreeItemData*)tv.GetItemData(parent); + if (pData != nullptr && pData->m_strData == text) + return parent.m_pItem; + + wxTreeItemIdValue cookie; + for (wxTreeItemId id = tv.GetFirstChild(parent, cookie); id.IsOk(); + id = tv.GetNextChild(parent, cookie)) + { + XVT_TREEVIEW_NODE node = FindTreeNodeString(tv, id, text); + if (node != nullptr) + return node; + } + } + return nullptr; +} + +XVT_TREEVIEW_NODE xvt_treeview_find_node_string(WINDOW win, const char* text) +{ + XVT_TREEVIEW_NODE node = nullptr; + if (win != NULL_WIN && text && *text) + { + CAST_TREEVIEW(win, tv); + node = FindTreeNodeString(tv, tv.GetSelection(), text); + if (node == nullptr) + node = FindTreeNodeString(tv, tv.GetRootItem(), text); + } + return node; +} + +/////////////////////////////////////////////////////////// +// TwxOutlookBar +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TwxOutlookBar, wxVListBox) + +BEGIN_EVENT_TABLE(TwxOutlookBar, wxVListBox) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_LISTBOX_SELECTED, TwxOutlookBar::OnSelected) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, TwxOutlookBar::OnSelected) + EVT_MOTION(TwxOutlookBar::OnMouseMove) + EVT_LEAVE_WINDOW(TwxOutlookBar::OnMouseLeave) +END_EVENT_TABLE() + +static const wxColour ModulateColour(const wxColour& col, int percent) +{ + int k = 0; + if (percent > 0) + k = 255; + else + percent = -percent; + const int inverse = 100-percent; + int r = ((k * percent) + (col.Red() * inverse)) / 100; + int g = ((k * percent) + (col.Green() * inverse)) / 100; + int b = ((k * percent) + (col.Blue() * inverse)) / 100; + return wxColour(r, g, b); +} + +void TwxOutlookBar::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t u) const +{ + const int n = u; // Anti warning + wxColour color1, color2; + if (n == m_nHovering) + { + if (n == GetSelection()) + { + color1 = wxColour(232,127,8); + color2 = wxColour(247,218,124); + } + else + { + color1 = wxColour(255,255,220); + color2 = wxColour(247,192,91); + } + } + else + { + if (n == GetSelection()) + { + color1 = wxColour(251,230,148); // Colori predefiniti di Outlook + color2 = wxColour(238,149, 21); + } + else + { + if (InheritsBackgroundColour()) + { + color1 = ModulateColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INACTIVECAPTION), +20); + color2 = ModulateColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION), -20); + } + else + { + const wxColour bkg = GetBackgroundColour(); + color1 = ModulateColour(bkg, +20); + color2 = ModulateColour(bkg, -20); + } + } + } + +#if wxCHECK_VERSION(2,8,12) + { + const wxColour color0 = ModulateColour(color2, +20); + const int delta = 2*rect.height/5; + wxRect r1 = rect, r2 = rect; + r1.height = delta; + r2.y += delta; r2.height -= delta; + dc.GradientFillLinear(r1, color0, color0, wxDOWN); + dc.GradientFillLinear(r2, color2, color1, wxDOWN); + + wxPen pen1(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT)); + dc.SetPen(pen1); + dc.DrawLine(rect.x, rect.y, rect.GetRight(), rect.y); + + wxPen pen2(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW)); + dc.SetPen(pen2); + dc.DrawLine(rect.x, rect.GetBottom(), rect.GetRight(), rect.GetBottom()); + } +#else + dc.GradientFillLinear(rect, color1, color2, wxDOWN); +#endif +} + +void TwxOutlookBar::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const +{ + const int nSide = rect.height; + const TwxOutlookItem& oi = m_item[n]; + int nTextOffset = 4; + if (oi.m_nIconId > 0) + { + const int sz = nSide > 16 ? (nSide < 48 ? (nSide/16*16) : 48) : 16; + const wxIcon ico = xvtart_GetIconResource(oi.m_nIconId, wxART_TOOLBAR, sz); + if (ico.IsOk()) + { + const wxSize szIco(ico.GetWidth(), ico.GetHeight()); + dc.DrawIcon(ico, rect.x+nTextOffset, rect.y+(nSide-szIco.y)/2); + nTextOffset += nTextOffset+szIco.x; + } + else + nTextOffset += nTextOffset+sz; + } + + dc.SetFont(GetFont()); // Imposta il font predefinito per questo controllo + + wxColour color = GetForegroundColour(); + if (InheritsBackgroundColour()) + color = wxSystemSettings::GetColour(wxSYS_COLOUR_CAPTIONTEXT); + dc.SetTextForeground(color); + + const wxString& str = oi.m_strText; + const int nMaxX = rect.width - nTextOffset; + const wxSize szText = dc.GetTextExtent(str); + if (szText.x > nMaxX && szText.y*2 < nSide) + { + const int nMid = str.Len() / 2; + int nBest = nMid, nDist = nMid; + for (int i = 0; i < 2*nMid; i++) if (str[i] <= wxChar(' ')) + { + const int d = abs(nMid-i); + if (d < nDist) + { + nBest = i; + nDist = d; + } + } + dc.DrawText(str.Left(nBest+1), rect.x+nTextOffset, rect.y+nSide/2-szText.y); + dc.DrawText(str.Mid(nBest+1), rect.x+nTextOffset, rect.y+nSide/2); + } + else + dc.DrawText(oi.m_strText, rect.x+nTextOffset, rect.y+(nSide-szText.y)/2); +} + +wxCoord TwxOutlookBar::OnMeasureItem(size_t WXUNUSED(n)) const +{ + const int nItems = GetItemCount(); + wxCoord nHeight = 32 + 4; // Icon size + gap + if (nItems > 1) + { + const wxSize sz = GetSize(); + nHeight = max(sz.y / nItems, nHeight); + } + return nHeight; +} + +void TwxOutlookBar::OnMouseMove(wxMouseEvent& evt) +{ + const int nWasHovering = m_nHovering; + m_nHovering = HitTest(evt.GetPosition()); + if (m_nHovering != nWasHovering) + { + if (nWasHovering != wxNOT_FOUND) + RefreshLine(nWasHovering); + if (m_nHovering != wxNOT_FOUND) + RefreshLine(m_nHovering); + } +} + +void TwxOutlookBar::OnMouseLeave(wxMouseEvent& WXUNUSED(e)) +{ + if (m_nHovering != wxNOT_FOUND) + { + const int nWasHovering = m_nHovering; + m_nHovering = wxNOT_FOUND; + RefreshLine(nWasHovering); + } +} + +void TwxOutlookBar::OnSelected(wxCommandEvent& evt) +{ + TwxWindow* win = wxDynamicCast(GetParent(), TwxWindow); + if (win != nullptr) + { + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_OUTLOOKBAR; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.lbox.dbl_click = evt.GetEventType() == wxEVT_COMMAND_LISTBOX_DOUBLECLICKED; + win->DoXvtEvent(e); + } +} + +int TwxOutlookBar::Add(short nIconId, const wxString strText, int nFlags) +{ + int i = GetItemCount(); + const bool ok = i < MAX_ITEMS-1; + if (ok) + { + m_item[i].m_nIconId = nIconId; + m_item[i].m_strText = strText; + m_item[i].m_nFlags = nFlags; + SetItemCount(i+1); + } + else + i = -1; + return i; +} + +TwxOutlookBar::TwxOutlookBar(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style) + : wxVListBox(parent, id, pos, size, style), m_nHovering(wxNOT_FOUND) +{ + SetItemCount(0); +} + +TwxOutlookBar::~TwxOutlookBar() +{ } + +BOOLEAN xvt_list_add(WINDOW win, int index, const char* text) +{ + wxListBox* lb = wxDynamicCast((wxObject*)win, wxListBox); + BOOLEAN ok = lb != nullptr; + if (ok) + { + const wxString str = text; + if (index < 0 || index >= (int)lb->GetCount()) + lb->AppendString(str); + else + lb->Insert(str, index); + } + return ok; +} + +int xvt_list_add_item(WINDOW win, short icon, const char* text, int flags) +{ + int n = -1; + if (win != NULL_WIN) + { + TwxOutlookBar* olb = wxDynamicCast((wxObject*)win, TwxOutlookBar); + if (olb != nullptr) + n = olb->Add(icon, text, flags); + else + { + TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + n = mb->Add(icon, text, flags); + } + } + return n; +} + +BOOLEAN xvt_list_clear(WINDOW win) +{ + BOOLEAN ok = win != NULL_WIN; + if (ok) + { + wxVListBox* olb = wxDynamicCast((wxObject*)win, wxVListBox); + if (olb != nullptr) + olb->Clear(); + else + { + wxListBox* lb = wxDynamicCast((wxObject*)win, wxListBox); + if (lb != nullptr) + lb->Clear(); + else + { + TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + mb->Clear(); + } + } + } + return ok; +} + +int xvt_list_get_sel_index(WINDOW win) +{ + int sel = -1; + if (win != NULL_WIN) + { + wxVListBox* olb = wxDynamicCast((wxObject*)win, wxVListBox); + if (olb != nullptr) + sel = olb->GetSelection(); + else + { + wxListBox* lb = wxDynamicCast((wxObject*)win, wxListBox); + if (lb != nullptr) + sel = lb->GetSelection(); + else + { + TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + sel = mb->GetSelection(); + } + } + } + return sel; +} + +BOOLEAN xvt_list_set_sel(WINDOW win, int index, BOOLEAN select) +{ + BOOLEAN ok = win != NULL_WIN; + if (ok) + { + wxVListBox* olb = wxDynamicCast((wxObject*)win, wxVListBox); + if (olb != nullptr) + { + if (select) + olb->SetSelection(index); + } + else + { + wxListBox* lb = wxDynamicCast((wxObject*)win, wxListBox); + if (lb != nullptr) + lb->SetSelection(index, select != 0); + else + { + TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + mb->SetSelection(index, select!=0); + } + } + } + return ok; +} + +int xvt_list_count(WINDOW win) +{ + int n = 0; + if (win != NULL_WIN) + { + wxVListBox* olb = wxDynamicCast((wxObject*)win, wxVListBox); + if (olb != nullptr) + n = olb->GetItemCount(); + else + { + wxListBox* lb = wxDynamicCast((wxObject*)win, wxListBox); + if (lb != nullptr) + n = lb->GetCount(); + else + { + TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + mb->GetItemCount(); + } + + } + } + return n; +} + +/////////////////////////////////////////////////////////// +// TwxMetroBar +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TwxMetroBar, wxWindow) + +BEGIN_EVENT_TABLE(TwxMetroBar, wxWindow) + EVT_SIZE(TwxMetroBar::OnResize) + EVT_PAINT(TwxMetroBar::OnPaint) + EVT_MOTION(TwxMetroBar::OnMouseMove) + EVT_LEAVE_WINDOW(TwxMetroBar::OnMouseLeave) + EVT_LEFT_DOWN(TwxMetroBar::OnMouseDown) +END_EVENT_TABLE() + +void TwxMetroBar::OnResize(wxSizeEvent& e) +{ + m_nWidth = e.m_size.x; + m_nHeight = e.m_size.y; + + m_nRows = m_nCols = 0; + if (m_nItems > 0 && m_nWidth >= 32 && m_nHeight >= 32) + { + int nSide = int(sqrt(double(m_nWidth * m_nHeight) / m_nItems)); + for ( ; nSide > 32 && m_nRows*m_nCols < m_nItems; nSide--) + { + m_nRows = m_nHeight / nSide; + m_nCols = m_nWidth / nSide; + } + } +} + +wxRect TwxMetroBar::GetRect(int i) const +{ + wxCoord x0=0, y0=0, x1=0, y1=0; + if (i >= 0 && i < m_nItems && m_nCols > 0) + { + const int r = i / m_nCols; + const int c = i % m_nCols; + + x0 = c * m_nWidth / m_nCols; + y0 = r * m_nHeight / m_nRows; + x1 = (i == m_nItems-1)||(c%m_nCols==m_nCols-1) ? m_nWidth : (c+1) * m_nWidth / m_nCols; + y1 = r == m_nRows-1 ? m_nHeight : (r+1) * m_nHeight / m_nRows; + } + return wxRect(x0, y0, x1-x0, y1-y0); +} + +void TwxMetroBar::DrawCell(wxDC& dc, int i) const +{ + const bool bSelected = (i == m_nHover) || (i == m_nCurr); + + dc.SetFont(GetFont()); // Imposta il font predefinito per questo controllo + dc.SetPen(*wxTRANSPARENT_PEN); + + wxRect rct = GetRect(i); + dc.SetBrush(bSelected ? m_rgbSelectFore : m_rgbBorder); + dc.DrawRectangle(rct); + rct.Deflate(2, 2); + dc.SetBrush(GetBackgroundColour()); + dc.DrawRectangle(rct); + + const TwxOutlookItem& oi = m_item[i]; + + int nIco = 0; + if (oi.m_nIconId > 0 && rct.height > 32) + { + nIco = RoundToIcon(rct.height/2); + const wxIcon ico = xvtart_GetIconResource(oi.m_nIconId, wxART_TOOLBAR, nIco); + if (ico.IsOk()) + { + const wxSize szIco(ico.GetWidth(), ico.GetHeight()); + dc.DrawIcon(ico, rct.x + (rct.width-szIco.x)/2, rct.y+2); + } + else + nIco = 0; + } + + wxString s = oi.m_strText; + const wxRect rctText(rct.x+2, rct.y + nIco, rct.width-4, rct.height - nIco-2); + const wxSize sz = dc.GetTextExtent(oi.m_strText); + if (sz.x > rctText.width) + { + if (sz.x > 3*rctText.width/2) + { + int nSplit1 = s.rfind(' ', s.Length()/3+1); + if (nSplit1 < 0) + nSplit1 = s.find(' '); + if (nSplit1 > 0) + s[nSplit1] = '\n'; + int nSplit2 = s.find(' ', 2*s.Length()/3-1); + if (nSplit2 < 0) + nSplit2 = s.rfind(' '); + if (nSplit2 > nSplit1) + s[nSplit2] = '\n'; + } + else + { + const int l2 = s.Length()/2; + int nSplit = s.rfind(' ', l2); + if (nSplit < 0) + { + nSplit = s.find(' ', l2); + if (nSplit < 0) + s.insert(l2, "\n"); + } + if (nSplit > 0) + s[nSplit] = '\n'; + } + } + dc.DrawLabel(s, rctText, wxALIGN_BOTTOM); +} + +void TwxMetroBar::OnPaint(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + dc.SetBackground(wxBrush(m_rgbBorder)); + dc.Clear(); + + if (m_nItems > 0) + { + if (m_nItems != m_nRows*m_nCols) + { + wxSizeEvent e; + e.m_size = GetClientRect().GetSize(); + OnResize(e); + } + for (int i = 0; i < m_nItems; i++) + DrawCell(dc, i); + } +} + +int TwxMetroBar::HitTest(const wxPoint& pt) const +{ + int i = wxNOT_FOUND; + for (i = m_nItems-1; i >= 0; i--) + { + const wxRect r = GetRect(i); + if (r.Contains(pt)) + break; + } + return i; +} + +void TwxMetroBar::OnMouseMove(wxMouseEvent& evt) +{ + const int nWasHovering = m_nHover; + m_nHover = HitTest(evt.GetPosition()); + if (m_nHover != nWasHovering) + { + wxClientDC dc(this); + if (nWasHovering != wxNOT_FOUND) + DrawCell(dc, nWasHovering); + if (m_nHover != wxNOT_FOUND) + DrawCell(dc, m_nHover); + } +} + +void TwxMetroBar::OnMouseLeave(wxMouseEvent& WXUNUSED(e)) +{ + if (m_nHover != wxNOT_FOUND) + { + wxClientDC dc(this); + const int nWasHovering = m_nHover; + m_nHover = wxNOT_FOUND; + DrawCell(dc, nWasHovering); + } +} + +void TwxMetroBar::OnMouseDown(wxMouseEvent& e) +{ + const int ht = HitTest(e.GetPosition()); + if (ht != m_nCurr) + { + const int nPrev = m_nCurr; + m_nCurr = ht; + if (nPrev != wxNOT_FOUND) + { + wxClientDC dc(this); + DrawCell(dc, nPrev); + } + + if (m_nCurr >= 0 && m_nCurr < m_nItems ) + { + TwxWindow* win = wxDynamicCast(GetParent(), TwxWindow); + if (win != nullptr) + { + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = GetId(); + e.v.ctl.ci.type = WC_METROBAR; + e.v.ctl.ci.win = WINDOW(this); + win->DoXvtEvent(e); + } + } + } +} + +int TwxMetroBar::Add(short nIconId, const wxString strText, int nFlags) +{ + if (m_nItems < MAX_ITEMS) + { + TwxOutlookItem& oi = m_item[m_nItems++]; + oi.m_nFlags = nFlags; + oi.m_nIconId = nIconId; + oi.m_strText = strText; + } + return m_nItems; +} + +TwxMetroBar::TwxMetroBar(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) + : wxWindow(parent, id, pos, size, style), m_nItems(0), m_nCurr(wxNOT_FOUND), m_nHover(wxNOT_FOUND), + m_rgbBorder(0x80,0x80,0x80), m_rgbSelectFore(*wxLIGHT_GREY) +{ +} + +/////////////////////////////////////////////////////////// +// TwxPopUp +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TwxPopUp, wxVListBox) + +BEGIN_EVENT_TABLE(TwxPopUp, wxVListBox) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_LISTBOX_SELECTED, TwxPopUp::OnSelected) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, TwxPopUp::OnSelected) + EVT_MOTION(TwxPopUp::OnMouseMove) + EVT_LEFT_DOWN(TwxPopUp::OnLeftDown) + EVT_KILL_FOCUS(TwxPopUp::OnKillFocus) + EVT_KEY_DOWN(TwxPopUp::OnKeyDown) +END_EVENT_TABLE() + + +void TwxPopUp::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t u) const +{ + const int n = u; // Anti warning + if (n == m_nHovering || (m_nHovering == wxNOT_FOUND && IsCurrent(u))) + { + dc.SetBrush(m_clrBack); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rect); + } +} + +void TwxPopUp::OnDrawItem(wxDC& dc, const wxRect& rect, size_t u) const +{ + const int n = u; // Anti warning + wxColour color; + if (n == m_nHovering || (m_nHovering == wxNOT_FOUND && IsCurrent(u))) + color = m_clrFore; + else + color = GetForegroundColour(); + dc.SetTextForeground(color); + dc.SetFont(GetFont()); + dc.DrawText(m_menu[n], rect.x, rect.y); +} + +wxCoord TwxPopUp::OnMeasureItem(size_t WXUNUSED(n)) const +{ + return m_nRowHeight; +} + +void TwxPopUp::OnMouseMove(wxMouseEvent& evt) +{ + int nHover = wxNOT_FOUND; + + const wxRect rect = GetClientRect(); + if (rect.Contains(evt.GetPosition())) + nHover = HitTest(evt.GetPosition()); + + if (nHover != m_nHovering) + { + const int nWasHovering = m_nHovering; + m_nHovering = nHover; + if (nWasHovering != wxNOT_FOUND) + RefreshLine(nWasHovering); + if (m_nHovering != wxNOT_FOUND) + RefreshLine(m_nHovering); + } +} + +void TwxPopUp::OnLeftDown(wxMouseEvent& evt) +{ + const wxRect rect = GetClientRect(); + const wxPoint pt = evt.GetPosition(); + if (rect.Contains(evt.GetPosition())) + wxVListBox::OnLeftDown(evt); + else + Hide(); +} + +void TwxPopUp::OnKillFocus(wxFocusEvent& WXUNUSED(e)) +{ + Hide(); +} + +void TwxPopUp::NotifySelection() +{ + TwxWindow* win = wxDynamicCast(GetParent(), TwxWindow); + if (win != nullptr) + { + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = GetId(); + e.v.ctl.ci.type = WC_LISTEDIT; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.listedit.active = GetSelection(); + win->DoXvtEvent(e); + } + Hide(); +} + +void TwxPopUp::OnSelected(wxCommandEvent& WXUNUSED(evt)) +{ + if (m_nHovering >= 0) + NotifySelection(); +} + +int TwxPopUp::Add(const wxString str) +{ + m_menu.Add(str); + const int i = m_menu.GetCount(); + SetItemCount(i); + return i; +} + +void TwxPopUp::OnKeyDown(wxKeyEvent& evt) +{ + m_nHovering = wxNOT_FOUND; // Evita chiusura involontaria della lista + int key = evt.GetKeyCode(); + switch (key) + { + case WXK_RETURN: + NotifySelection(); + break; + default: + if (key > ' ' && key <= 'z') + { + key = toupper(key); + const int curr = max(GetSelection(), 0); + const int tot = m_menu.GetCount(); + int i = curr; + for (i = (i+1)%tot; i != curr; i = (i+1)%tot) + { + if (toupper(m_menu[i][0]) == key) + break; + } + SetSelection(i); + } + else + evt.Skip(); + break; + } +} + +TwxPopUp::TwxPopUp(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size) + : wxVListBox(parent, id, pos, size, wxBORDER|wxCLIP_SIBLINGS), + m_nHovering(wxNOT_FOUND) +{ + m_clrFore = wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT); + m_clrBack = GetSelectionBackground(); + + const wxFont font = parent->GetFont(); + m_nRowHeight = abs(font.GetPixelSize().y) + 4; +} + +static int RoundPopupHeight(int list_h, int row_h) +{ + const int rem = list_h % (row_h+1); + if (rem > 0) + list_h -= rem; + return list_h; +} + +MENU_TAG xvt_list_popup(WINDOW parent_win, const RCT* ownrct, const MENU_ITEM* menu, + const XVT_COLOR_COMPONENT* colors, MENU_TAG first) +{ + int sel = -1; + int items = 0; + if (parent_win != NULL_WIN && ownrct != nullptr && menu != nullptr) + { + wxWindow* parent = wxStaticCast((wxObject*)parent_win, wxWindow); + int width = ownrct->right - ownrct->left; + for (items = 0; menu[items].tag != 0; items++) if (menu[items].tag > 0 && menu[items].text) + { + const wxString str = menu[items].text; + int w = 0, h = 0; parent->GetTextExtent(str, &w, &h); + w += 24; + if (w > width) + width = w; + } + + const wxFont font = parent->GetFont(); + const int nRowHeight = abs(font.GetPixelSize().y)+4; + const wxRect rctClient = parent->GetClientRect(); + const int nBottom = rctClient.GetBottom(); + + wxPoint pos(ownrct->right-width, ownrct->bottom); + wxSize size(width, items*nRowHeight+2); + + if (pos.y + size.y > nBottom) // La lista deborda di sotto? + { + if (ownrct->top > nBottom-ownrct->bottom) // Ho piu' spazio sopra che sotto? + { + pos.y = ownrct->top - size.y; // Sposto la lista sopra al campo di testo + if (pos.y < 0) + { + size.y = RoundPopupHeight(size.y + pos.y, nRowHeight); + pos.y = ownrct->top - size.y; + } + } + else + { + // Accorcio la lista in basso + size.y = RoundPopupHeight(nBottom-pos.y, nRowHeight); + } + } + if (pos.x < 0) + pos.x = 0; + + WIN_DEF wd; memset(&wd, 0, sizeof(wd)); + wd.ctlcolors = (XVT_COLOR_COMPONENT*)colors; + xvt_rect_set(&wd.rct, pos.x, pos.y, pos.x+size.x, pos.y+size.y); + wd.v.ctl.ctrl_id = wxID_ANY; + wd.v.ctl.flags = CTL_FLAG_INVISIBLE; + wd.wtype = WC_POPUP; + WINDOW win = xvt_ctl_create_def(&wd, parent_win, 0); + + TwxPopUp* lb = wxDynamicCast((wxObject*)win, TwxPopUp); + if (lb != nullptr) + { + for (int i = 0; menu[i].tag != 0; i++) + { + const MENU_ITEM& mi = menu[i]; + if (mi.tag > 0) + { + lb->Add(mi.text); + if (mi.tag == first) + sel = i; + } + } + if (sel >= 0) + lb->SetSelection(sel); + lb->Show(); + lb->SetFocus(); + + lb->CaptureMouse(); + wxApp* a = wxTheApp; // Memorizzo il risultato di wxGetInstance + while (lb->IsShown()) + { + while (a->Pending()) + a->Dispatch(); + lb->Raise(); + a->ProcessIdle(); + wxMilliSleep(50); + } + sel = lb->GetSelection(); + lb->ReleaseMouse(); + + delete lb; + } + } + return sel >= 0 && sel < items ? menu[sel].tag : 0; +} + +/////////////////////////////////////////////////////////// +// ToolBar +/////////////////////////////////////////////////////////// + +#if wxCHECK_VERSION(3,8,9) +#include +#define TwxToolBarBase wxAuiToolBar +#else +#define TwxToolBarBase wxToolBar +#endif + +class wxToolObject : public wxObject +{ + wxToolBarToolBase * _tool; + +public: + wxToolBarToolBase * tool() const { return _tool; } + + wxToolObject(wxToolBarToolBase * tool) : _tool(tool) {} +}; + +class wxToolData : public wxObject +{ + short _pos; + int _ico; + +public: + short pos() const { return _pos; } + int ico() const { return _ico; } + + void set_pos(short pos) { _pos = pos; } + void set_ico(short ico) { _ico = ico; } + + wxToolData(int ico, short pos = -1) : _pos(pos), _ico(ico) {} +}; + +WX_DECLARE_OBJARRAY(wxToolObject, wxToolArray); +#include +WX_DEFINE_OBJARRAY(wxToolArray); + +class TwxToolBar : public TwxToolBarBase +{ + DECLARE_DYNAMIC_CLASS(TwxToolBar) + wxBitmap m_texture; + bool m_bMetroStyle; + wxToolArray _hidden_tool; + +protected: + DECLARE_EVENT_TABLE() + void OnTool(wxCommandEvent& evt); + void OnEraseBackground(wxEraseEvent& evt); + virtual bool SetBackgroundColour(const wxColour& colour); + virtual bool SetForegroundColour(const wxColour& colour); + + TwxToolBar() : TwxToolBarBase(nullptr, wxID_ANY) { wxASSERT(false); } + +public: + void ShowTool(int id, bool on); + void SetBackgroundTexture(XVT_IMAGE img); + void SetMetroStyle(bool ms); + + wxToolArray & hidden() { return _hidden_tool; } + + TwxToolBar(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style); +}; + +IMPLEMENT_DYNAMIC_CLASS(TwxToolBar, TwxToolBarBase) + +BEGIN_EVENT_TABLE(TwxToolBar, TwxToolBarBase) + EVT_TOOL(wxID_ANY, TwxToolBar::OnTool) + EVT_ERASE_BACKGROUND(TwxToolBar::OnEraseBackground) +END_EVENT_TABLE(); + +void TwxToolBar::OnTool(wxCommandEvent& evt) +{ + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_ICON; // WC_PUSHBUTTON entra in conflitto coi bottoni + e.v.ctl.ci.win = WINDOW(this); + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); +} + +void TwxToolBar::OnEraseBackground(wxEraseEvent& evt) +{ + wxDC& dc = *evt.GetDC(); + if (m_texture.IsOk()) + { + const wxCoord tw = m_texture.GetWidth(); + const wxCoord th = m_texture.GetHeight(); + wxCoord cw, ch; dc.GetSize(&cw, &ch); + for (wxCoord y = 0; y < ch; y += th) + for (wxCoord x = 0; x < cw; x += tw) + dc.DrawBitmap(m_texture, x, y); + } + else + { + if (m_bMetroStyle) + { + evt.Skip(); + } + else + { + const wxColour b0 = GetBackgroundColour(); + const wxColour b1 = ModulateColour(b0, -10); + const wxColour b2 = ModulateColour(b0, +70); + wxCoord cw, ch; dc.GetSize(&cw, &ch); +#if wxCHECK_VERSION(2,8,12) + // Nuovo modo: effetto acqua in stile Outlook + const wxColour b3 = ModulateColour(b1, +20); + const int delta = 2*ch/5; + wxRect r1(0,0,cw,ch), r2(0,0,cw,ch); + r1.height = delta; + r2.y += delta; r2.height -= delta; + dc.GradientFillLinear(r1, b3, b3, wxDOWN); + dc.GradientFillLinear(r2, b1, b2, wxDOWN); +#else + // Vecchio modo: gradiente classico + dc.GradientFillLinear(wxRect(0,0,cw,ch),b1,b2,wxSOUTH); +#endif + } + } +} + +bool TwxToolBar::SetBackgroundColour(const wxColour& colour) +{ + const bool ok = TwxToolBarBase::SetBackgroundColour(colour); + if (ok) // Se cambio lo sfondo della toolbar devo aggiornare anche quello del gripper + { + wxAuiDockArt* pArtist = FindArtist(this); + if (pArtist != nullptr) + pArtist->SetColor(wxAUI_DOCKART_GRIPPER_COLOUR, colour); + } + return ok; +} + +bool TwxToolBar::SetForegroundColour(const wxColour& colour) +{ + const bool ok = TwxToolBarBase::SetForegroundColour(colour); + if (ok) // Se cambio lo sfondo della toolbar devo aggiornare anche quello del gripper + { + wxAuiDockArt* pArtist = FindArtist(this); + if (pArtist != nullptr) + pArtist->SetColor(wxAUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR, colour); + } + return ok; +} + +void TwxToolBar::SetBackgroundTexture(XVT_IMAGE xvt_img) +{ + if (xvt_img != nullptr) + { + const wxImage& img = *(wxImage*)xvt_img; + wxColour mean, dark, light; + Image2Colors(img, mean, dark, light); + SetBackgroundColour(mean); + + m_texture = wxBitmap(img); + m_bMetroStyle = false; + } + else + m_texture = wxNullBitmap; +} + +void TwxToolBar::SetMetroStyle(bool ms) +{ m_bMetroStyle = ms; } + +TwxToolBar::TwxToolBar(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) + : TwxToolBarBase(parent, id, pos, size, style), m_bMetroStyle(false) +{ } + +static TwxToolBar* Win2Bar(WINDOW win) +{ + wxASSERT(win != NULL_WIN); + return wxDynamicCast((wxObject*)win, TwxToolBar); +} + +BOOLEAN xvt_toolbar_add_control(WINDOW win, int cid, TOOL_TYPE type, const char *title, + int ico, int WXUNUSED(cust_width), int idx) +{ + BOOLEAN ok = false; + TwxToolBar* ptb = Win2Bar(win); + if (ptb != nullptr) + { + TwxToolBar& tb = *ptb; + switch (type) + { + case TOOL_SEPARATOR: +#ifdef wxAuiToolBar + tb.AddSeparator(); + ok = idx < 0; +#else + if (idx < 0) + ok = tb.AddSeparator() != nullptr; + else + ok = tb.InsertSeparator(idx) != nullptr; +#endif + break; + default: + { + const wxBitmap bmp = xvtart_GetToolResource(ico, tb.GetToolBitmapSize().y); + wxString cap, tip; + wxChar acc = 0; + + for (const char* t = title; *t; t++) + { + if (*t == '~' || *t == '&') + { + cap << '&'; + acc = toupper(*(t + 1)); + } + else + { + cap << *t; + tip << *t; + } + } + if (acc > '\0') + { + if (acc >= 'A' && acc <= 'Z') + tip << "\n(Alt+" << acc << ")"; + } + else + { + switch (ico) // Gestione bottoni speciali + { + case 102: tip << "\n(Esc)"; break; + case 114: tip << "\n(Alt+F4)"; break; + case 162: tip << "\n(F2)"; break; + case 163: tip << "\n(F1)"; break; + default: break; + } + } + + wxToolData *data = new wxToolData(ico); + +#ifdef wxAuiToolBar + tb.AddTool(cid, cap, bmp, wxNullBitmap, wxItemKind(type), tip, tip, data); + ok = idx < 0; + idx = tb.GetToolPos(cid); +#else + if (idx < 0) + { + ok = tb.AddTool(cid, cap, bmp, wxNullBitmap, wxItemKind(type), tip, wxEmptyString, data) != nullptr; + idx = tb.GetToolPos(cid); + } + else + ok = tb.InsertTool(idx, cid, cap, bmp, wxNullBitmap, wxItemKind(type), tip, wxEmptyString, data) != nullptr; +#endif + data->set_pos(idx); + } + break; + } + } + return ok; +} + +WINDOW xvt_toolbar_create(int cid, int left, int top, int right, int bottom, long nFlags, WINDOW parent) +{ +#ifdef wxAuiToolBar + long nStyle = wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_GRIPPER; + if (nFlags & CTL_FLAG_PASSWORD) + nStyle |= wxAUI_TB_TEXT; + + const wxPoint ptPos(left, top); + wxSize szSize(right-left, bottom-top); + + int nIcoSize = 24; + if (bottom > 0) + { + nIcoSize = RoundToIcon(szSize.y); + } + else + { + nStyle |= wxAUI_TB_VERTICAL; + nIcoSize = RoundToIcon(szSize.x); + } +#else + long nStyle = wxNO_BORDER | wxTB_NODIVIDER; + if (nFlags & CTL_FLAG_PASSWORD) + nStyle |= wxTB_TEXT | wxTB_FLAT; + + const wxPoint ptPos(left, top); + wxSize szSize(right-left, bottom-top); + + int nIcoSize = 24; + if (bottom > 0) + { + nStyle |= wxTB_HORIZONTAL; + nIcoSize = RoundToIcon(szSize.y); + } + else + { + nStyle |= wxTB_VERTICAL; + nIcoSize = RoundToIcon(szSize.x); + } +#endif + + wxWindow* pParent = wxStaticCast((wxObject*)parent, wxWindow); + TwxToolBar* tb = new TwxToolBar(pParent, cid, ptPos, wxDefaultSize, nStyle); + tb->SetToolBitmapSize(wxSize(nIcoSize, nIcoSize)); + tb->SetMetroStyle((nFlags & WSF_NO_TASKBAR) != 0); + + return (WINDOW)tb; +} + +void xvt_toolbar_enable_control(WINDOW win, int cid, BOOLEAN on) +{ + TwxToolBar* ptb = Win2Bar(win); + if (ptb != nullptr && cid > 0) + ptb->EnableTool(cid, on != 0); +} + +BOOLEAN xvt_toolbar_set_last_tool(WINDOW win, int id) +{ + BOOLEAN bMoved = false; + TwxToolBar* ptb = Win2Bar(win); + if (ptb != nullptr) // Is a valid toolbar? + { + const int pos = ptb->GetToolPos(id); + if (pos >= 0) + { +#ifdef wxAuiToolBar + // TBI +#else + const int nCount = ptb->GetToolsCount(); + if (pos < nCount-1) + { + wxToolBarToolBase* tool = ptb->RemoveTool(id); + ptb->InsertTool(nCount-1, tool); + } + bMoved = true; +#endif + } + } + return bMoved; +} + +void xvt_toolbar_realize(WINDOW win) +{ + TwxToolBar* ptb = Win2Bar(win); + if (ptb != nullptr) // Is a valid toolbar? + { + ptb->Realize(); // Update tools + wxAuiPaneInfo* pi = LockPane(win); + if (pi != nullptr) + { + const wxSize szBar = ptb->GetSize(); + if (pi->min_size.x < szBar.x || pi->min_size.y < szBar.y) + { + pi->MinSize(szBar); + pi->BestSize(szBar); + UnlockPane(win); + } + } + + // Iucunde repetita juvant: forzo il colore del gripper che viene spesso dimenticato + wxAuiDockArt* pArtist = FindArtist(ptb); + if (pArtist != nullptr) + pArtist->SetColor(wxAUI_DOCKART_GRIPPER_COLOUR, ptb->GetBackgroundColour()); + } +} + +void xvt_toolbar_show_control(WINDOW win, int cid, BOOLEAN on) +{ + if (win != NULL_WIN && cid > 0) + { + TwxToolBar* ptb = Win2Bar(win); + + if (ptb != nullptr && cid > 0) + { + const int items = ptb->hidden().GetCount(); + bool found = false; + int i; + + for (i = 0; !found && i < items; i++) + { + wxToolObject & obj = (wxToolObject &) ptb->hidden().Item(i); + wxToolBarToolBase * tool = obj.tool(); + + if (tool->GetId() == cid) + { + found = true; + break; + } + } + if (on) + { + if (found) + { + wxToolObject & obj = (wxToolObject &)ptb->hidden().Item(i); + wxToolBarToolBase * tool = obj.tool(); + wxToolData & data = (wxToolData &)*tool->GetClientData(); + const short pos = data.pos(); + + xvt_toolbar_add_control(win, cid, (TOOL_TYPE) tool->GetKind(), tool->GetLabel(), + data.ico(), -1, pos); + ptb->hidden().RemoveAt(i); + delete tool; + } + } + else + { + const short pos = ptb->GetToolPos(cid); + + if (pos >= 0) + { + wxToolBarToolBase* tool = ptb->RemoveTool(cid); + + if (tool != nullptr) + ptb->hidden().Add((_wxObjArraywxToolArray *) new wxToolObject(tool)); + } + } + } + } +} + +BOOLEAN xvt_toolbar_remove_control(WINDOW win, int cid) +{ + BOOLEAN ok = false; + TwxToolBar* ptb = Win2Bar(win); + + if (ptb != nullptr) + { + TwxToolBar& tb = *ptb; + +#ifdef wxAuiToolBar + tb.AddSeparator(); + ok = idx < 0; +#else + wxToolBarToolBase* tool = tb.RemoveTool(cid); + + ok = tool != nullptr; + if (ok) delete tool; +#endif + } + return ok; +} + +BOOLEAN xvt_toolbar_toggle_control(WINDOW win, int cid, BOOLEAN on) +{ + TwxToolBar* ptb = Win2Bar(win); + bool ok = ptb != nullptr; + + if (ok) + { + TwxToolBar& tb = *ptb; + int size = tb.GetToolBitmapSize().y; + int idx = tb.GetToolPos(cid); + + tb.ToggleTool(cid, on); + xvt_toolbar_realize(win); + tb.Refresh(); + } + return ok; +} + +BOOLEAN xvt_toolbar_set_image(WINDOW win, int cid, int ico) +{ + TwxToolBar* ptb = Win2Bar(win); + bool ok = ptb != nullptr; + + if (ok) // non si capisce perchè non debba aggiornare le bitmap + { + TwxToolBar& tb = *ptb; + int size = tb.GetToolBitmapSize().y; + int idx = ptb->GetToolPos(cid); + wxToolBarToolBase* tool = tb.RemoveTool(cid); + + ok = tool != nullptr; + if (ok) + { + wxString label = tool->GetLabel(); + + delete tool; + ok = xvt_toolbar_add_control(win, cid, TOOL_BUTTON, label.c_str(), ico, size, idx); + } + if (ok) + xvt_toolbar_realize(win); + } + return ok; +} + +void xvt_dwin_draw_tool(WINDOW win, int x, int y, int rid, int size) +{ + const wxBitmap bmp = xvtart_GetToolResource(rid, size); + + if (bmp.IsOk()) + { + wxDC& dc = GetTDCMapper().GetDC(win); + dc.DrawBitmap(bmp, x, y); + } +} + +void xvt_ctl_set_texture(WINDOW win, XVT_IMAGE xvt_img) +{ + TwxToolBar* w = wxDynamicCast((wxObject*)win, TwxToolBar); + if (w != nullptr) + w->SetBackgroundTexture(xvt_img); +} + +/////////////////////////////////////////////////////////// +// wxPropertyGrid +/////////////////////////////////////////////////////////// + +#include + +BEGIN_EVENT_TABLE(TwxPropertyGrid, wxPropertyGrid) + EVT_PG_CHANGED(wxID_ANY, TwxPropertyGrid::OnPropertyChanged) +END_EVENT_TABLE(); + +void TwxPropertyGrid::SetColors(const XVT_COLOR_COMPONENT* colors) +{ + for (int i = 0; colors[i].type; i++) + { + CAST_COLOR(colors[i].color, rgb); + switch(colors[i].type) + { + case XVT_COLOR_BACKGROUND : SetCellBackgroundColour(rgb); break; + case XVT_COLOR_FOREGROUND : SetCellTextColour(rgb); break; + case XVT_COLOR_HIGHLIGHT : SetSelectionBackground(rgb); break; + case XVT_COLOR_SELECT : SetSelectionForeground(rgb); break; + case XVT_COLOR_BLEND : SetCaptionBackgroundColour(rgb); SetMarginColour(rgb); break; + case XVT_COLOR_TROUGH : SetEmptySpaceColour(rgb); break; + case XVT_COLOR_CAPTIONTEXT: SetCaptionForegroundColour(rgb); break; + default : break; + } + } +} + +void TwxPropertyGrid::OnPropertyChanged(wxPropertyGridEvent& evt) +{ + TwxWindow* win = wxDynamicCast(GetParent(), TwxWindow); + if (win != nullptr && !IsFrozen()) + { + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.v.treeview.sgl_click = true; + e.v.ctl.ci.v.treeview.node = evt.GetProperty(); + e.v.ctl.ci.type = WC_PROPGRID; + e.v.ctl.ci.win = WINDOW(this); + win->DoXvtEvent(e); + } +} + +TwxPropertyGrid::TwxPropertyGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) + : wxPropertyGrid(parent, id, pos, size, style) +{ } + +static BOOLEAN xvt_prop_freeze(WINDOW win, BOOLEAN on) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + const BOOLEAN ok = pg != nullptr && on != BOOLEAN(pg->IsFrozen()); + if (ok) + { + if (on) + pg->Freeze(); + else + { + pg->Thaw(); + pg->Refresh(); + } + } + return ok; +} + +BOOLEAN xvt_prop_restart(WINDOW win) +{ return xvt_prop_freeze(win, false); } + +BOOLEAN xvt_prop_suspend(WINDOW win) +{ return xvt_prop_freeze(win, true); } + +static wxColour STR2COLOUR(const char* value) +{ + wxColour col; + + if (value && *value) + { + if (*value == '(') + value++; + if (isdigit(*value)) + { + int r, g, b; + const int n = sscanf(value, "%d,%d,%d", &r, &g, &b); + if (n == 3) + col = wxColour(r, g, b); + else + { + CAST_COLOR(r, w); // NON usare wxColour(r) in quanto si aspetta un numero in formato BGR + col = w; + } + } + else + col = wxColour(value); // Black, White, Yellow, ... + } + return col; +} + +BOOLEAN xvt_prop_set_data(WINDOW win, XVT_TREEVIEW_NODE node, const char* value) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp != nullptr) + { + const wxString strType = pgp->GetType(); + if (strType == "wxColour") + { + wxColourPropertyValue val(STR2COLOUR(value)); + wxVariant& var = pgp->GetValueRef(); + var = ((wxColourProperty*)pgp)->DoTranslateVal(val); + } + else + { + if (strType == "long" || strType == "int") + pgp->SetValue(atol(value)); else + if (strType == "bool") + pgp->SetValue(*value > '0' && strchr("1TXY", *value) != nullptr); + else + pgp->SetValue(value); + } + return true; + } + } + return false; +} + +XVT_TREEVIEW_NODE xvt_prop_add(WINDOW win, const char* type, const char* name, const char* value, const char* label) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + + if (pg != nullptr) + { + wxPGProperty* pgp = pg->GetPropertyByName(name); + + if (pgp == nullptr) + { + const wxString strLabel = (label && *label) ? label : name; + if (type && *type > ' ') + { + switch (toupper(*type)) + { + case 'B': + pgp = new wxBoolProperty(strLabel, name, *value > '0' && strchr("1TXY", *value) != nullptr); + pgp->SetAttribute(wxString("UseCheckbox"), true); + break; + case 'C': + pgp = new wxColourProperty(strLabel, name, STR2COLOUR(value)); + break; + case 'I': + case 'L': + pgp = new wxIntProperty(strLabel, name, atol(value)); + break; + default : + pgp = new wxStringProperty(strLabel, name, value); + break; + } + } + else + pgp = new wxPropertyCategory(strLabel, name); + pg->Append(pgp); + } + else + xvt_prop_set_data(win, pgp, value); + return pgp; + } + return nullptr; +} + +XVT_TREEVIEW_NODE xvt_prop_current(WINDOW win) +{ + XVT_TREEVIEW_NODE node = nullptr; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + node = pg->GetSelection(); + return node; +} + +XVT_TREEVIEW_NODE xvt_prop_find(WINDOW win, const char* name) +{ + XVT_TREEVIEW_NODE node = nullptr; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + node = pg->GetPropertyByName(name); + return node; +} + +void xvt_prop_fit_columns(WINDOW win) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + pg->FitColumns(); +} + +BOOLEAN xvt_prop_remove(WINDOW win, XVT_TREEVIEW_NODE node) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp != nullptr) + { + pg->DeleteProperty(pgp->GetId()); + return true; + } + } + return false; +} + +int xvt_prop_get_string(WINDOW win, XVT_TREEVIEW_NODE node, char* label, int maxlen) +{ + int len = -1; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + const wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp != nullptr) + { + const wxString& str = pgp->GetLabel(); + if (label && maxlen > 0) + { + wxStrncpy(label, str, maxlen); + label[maxlen-1] = '\0'; + } + len = str.Len(); + } + } + return len; +} + +int xvt_prop_get_type(WINDOW win, XVT_TREEVIEW_NODE node, char* type, int maxlen) +{ + int len = 0; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + const wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp != nullptr) + { + wxString strType = pgp->GetType(); + if (strType == "wxColour") + strType = "color"; + wxStrncpy(type, strType, maxlen); + len = strType.Len(); + } + } + return len; +} + +int xvt_prop_get_data(WINDOW win, XVT_TREEVIEW_NODE node, char* value, int maxlen) +{ + int len = -1; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + const wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp != nullptr) + { + wxString str = pgp->GetValueAsString(); + wxString strType = pgp->GetType(); + + if (strType == "wxColour") + { + strType = "color"; + str.RemoveLast(1); // Toglie la ) + str.Remove(0, 1); // Toglie la ( + } + len = str.Len(); + if (value != nullptr && maxlen > 0) + { + wxStrncpy(value, str, maxlen); + value[maxlen-1] = '\0'; + } + } + } + return len; +} + +static BOOLEAN xvt_for_each_property(WINDOW pg, const wxPGProperty* prop, PROP_CALLBACK pcb, void* jolly) +{ + BOOLEAN ok = prop != nullptr && pcb != nullptr; + if (ok && !prop->IsRoot()) + ok = pcb(pg, (XVT_TREEVIEW_NODE)prop, jolly); + if (ok) + { + const int nc = prop->GetChildCount(); + for (int c = 0; c < nc && ok; c++) + ok = xvt_for_each_property(pg, prop->Item(c), pcb, jolly); + } + return ok; +} + +BOOLEAN xvt_prop_for_each(WINDOW win, PROP_CALLBACK pcb, void* jolly) +{ + BOOLEAN ok = false; + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + ok = xvt_for_each_property(win, pg->GetRoot(), pcb, jolly); + return ok; +} + +BOOLEAN xvt_prop_set_read_only(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN ro) +{ + wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + { + wxPGProperty* pgp = wxDynamicCast((wxObject*)node, wxPGProperty); + if (pgp == nullptr) + pgp = pg->GetRoot(); + pgp->SetFlagRecursively(wxPG_PROP_DISABLED, ro != 0); + } + return pg != nullptr; +} + +/////////////////////////////////////////////////////////// +// TwxTreeListCtrl +/////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE(TwxTreeListCtrl, wxTreeListCtrl) + EVT_TREE_ITEM_EXPANDING(wxID_ANY, TwxTreeListCtrl::OnExpanding) + EVT_TREE_ITEM_EXPANDED (wxID_ANY, TwxTreeListCtrl::OnExpanded) + EVT_TREE_ITEM_COLLAPSED(wxID_ANY, TwxTreeListCtrl::OnCollapsed) + EVT_TREE_SEL_CHANGED (wxID_ANY, TwxTreeListCtrl::OnSelChanged) +END_EVENT_TABLE(); + +int TwxTreeListCtrl::img2int(XVT_IMAGE xvt_img) +{ + int i = -1; + if (xvt_img != nullptr) + { + i = m_img[xvt_img] - 1; // Ho memorizzato indice+1 + if (i < 0) // Immagine sconosciuta + { + const wxImage& img = *(wxImage*)xvt_img; + wxImageList* il = GetImageList(); + if (il == nullptr) // Lista non ancora creata + { + il = new wxImageList; + il->Create(img.GetWidth(), img.GetHeight(), true, 3); + AssignImageList(il); // DON'T CALL SetImageList! + } + else + { + int old_w, old_h; il->GetSize(0, old_w, old_h); + const int new_w = img.GetWidth(), new_h = img.GetHeight(); + if (new_w > old_w) // L'immagine nuova e' troppo grande? + { + const int old_ratio = old_w * 100 / old_h; + const int new_ratio = new_w * 100 / new_h; + const int old_count = il->GetImageCount(); + wxImageList* nil = new wxImageList; + nil->Create(new_w, new_h, true, 3*old_count/2); + for (int k = 0; k < old_count; k++) + { + wxImage old = il->GetBitmap(k).ConvertToImage(); + if (old_ratio == new_ratio) + old.Rescale(new_w, new_h, wxIMAGE_QUALITY_HIGH); + else + old.Resize(wxSize(new_w, new_h), wxPoint((new_w-old_w)/2, (new_h-old_h)/2)); + nil->Add(old); + } + AssignImageList(il = nil); + } + } + + if (!img.HasMask()) + { + wxImage& trans = (wxImage&)img; + const int r = img.GetRed(0,0); + const int g = img.GetGreen(0,0); + const int b = img.GetBlue(0,0); + trans.SetMask(); + trans.SetMaskColour(r, g, b); + } + const wxBitmap bmp(img); + i = il->Add(bmp); + m_img[xvt_img] = i+1; // Memorizzo indice+1 + } + if (i < 0) + SORRY_BOX(); + } + return i; +} + +void TwxTreeListCtrl::OnExpanding(wxTreeEvent& evt) +{ + const wxTreeItemId id = evt.GetItem(); + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREELIST; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = id.m_pItem; + e.v.ctl.ci.v.treeview.expanded = true; + if (GetChildrenCount(id) == 0) // Trucco perfido ... + e.v.ctl.ci.v.treeview.collapsed = true; // ... stato indeterminato = EXPANDING + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + if (GetChildrenCount(id) == 0) // Allora e' proprio vero ... + SetItemHasChildren(id, false); +} + +void TwxTreeListCtrl::OnExpanded(wxTreeEvent& WXUNUSED(evt)) +{ Refresh(false); } // Non dovrebbe servire ma ... + +void TwxTreeListCtrl::OnCollapsed(wxTreeEvent& WXUNUSED(evt)) +{ Refresh(false); } // Non dovrebbe servire ma ... + +void TwxTreeListCtrl::OnSelChanged(wxTreeEvent& evt) +{ + if (!m_nFrozen) + { + Suspend(); + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREELIST; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = evt.GetItem().m_pItem; + e.v.ctl.ci.v.treeview.sgl_click = true; + TwxWindow* win = wxStaticCast(GetParent(), TwxWindow); + win->DoXvtEvent(e); + Resume(); + } + Refresh(false); // Non dovrebbe servire ma ... +} + +void TwxTreeListCtrl::Enable(const wxTreeItemId& id, bool on) +{ SetItemTextColour(id, on ? m_clrSelFore : m_clrDisFore); } + +void TwxTreeListCtrl::Suspend() +{ m_nFrozen++; } + +void TwxTreeListCtrl::Resume() +{ + wxASSERT(m_nFrozen > 0); + if (m_nFrozen > 0) + m_nFrozen--; +} + +void TwxTreeListCtrl::SetColors(const XVT_COLOR_COMPONENT* colors) +{ + for (int i = 0; colors[i].type; i++) + { + CAST_COLOR(colors[i].color, rgb); + switch(colors[i].type) + { + case XVT_COLOR_BACKGROUND: SetOwnBackgroundColour(rgb); break; + case XVT_COLOR_FOREGROUND: SetOwnForegroundColour(rgb); break; + case XVT_COLOR_HIGHLIGHT : m_clrSelBack = rgb; break; + case XVT_COLOR_SELECT : m_clrSelFore = rgb; break; + case XVT_COLOR_TROUGH : m_clrDisFore = rgb; break; + default : break; + } + } +} + +void TwxTreeListCtrl::SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + const int ii = img2int(item_image); + if (ii >= 0) + SetItemImage(id, ii); + else + { + const int ic = img2int(collapsed_image); + if (ic >= 0) + { + SetItemImage(id, ic); + const int ie = img2int(expanded_image); + if (ie >= 0) + SetItemImage(id, ie, wxTreeItemIcon_Selected); + } + } +} + +TwxTreeListCtrl::TwxTreeListCtrl(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, bool multisel) + : wxTreeListCtrl(parent, id, pos, size, + wxTR_HAS_BUTTONS|wxTR_HIDE_ROOT|wxTR_ROW_LINES|wxTR_COLUMN_LINES|(multisel ? wxTR_MULTIPLE : wxTR_SINGLE)), + m_nFrozen(0) +{ + AddColumn(wxEmptyString, size.x); + AddRoot("Root"); + SetIndent(GetIndent()/2); +} + +#define CAST_TREELIST(win, tv) TwxTreeListCtrl& tv = *wxStaticCast((wxObject*)win, TwxTreeListCtrl); + +WINDOW xvt_treelist_create(WINDOW parent_win, + RCT * rct_p, char * title, long ctl_flags, + long app_data, int ctl_id, XVT_IMAGE WXUNUSED(item_image), + XVT_IMAGE WXUNUSED(collapsed_image), XVT_IMAGE WXUNUSED(expanded_image), + long WXUNUSED(attrs), int line_height) +{ + wxASSERT(parent_win != NULL_WIN); + // La xvt_ctl_create_def accetta un array di controlli da inizializzare, + // per cui le passero' un elemento valido ed uno nullo che funga da terminatore + WIN_DEF win_def[2]; memset(win_def, 0, sizeof(WIN_DEF)); + win_def->wtype = WC_TREELIST; + if (xvt_rect_is_empty(rct_p)) + xvt_vobj_get_client_rect(parent_win, &win_def->rct); + else + win_def->rct = *rct_p; + win_def->text = title; + win_def->v.ctl.ctrl_id = ctl_id; + win_def->v.ctl.flags = ctl_flags; + WINDOW win = xvt_ctl_create_def(win_def, parent_win, app_data); + + if (win != NULL_WIN && line_height > 12) + { + CAST_TREELIST(win, tv); + tv.SetLineSpacing(line_height); + } + return win; +} + +XVT_TREEVIEW_NODE xvt_treelist_add_child_node(WINDOW win, + XVT_TREEVIEW_NODE parent, XVT_TREEVIEW_NODE_TYPE type, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + const char* string, XVT_TREEVIEW_CALLBACK WXUNUSED(callback), const char* data) +{ + XVT_TREEVIEW_NODE node = nullptr; + if (win != NULL_WIN) + { + CAST_TREELIST(win, tv); + TwxTreeItemData* pData = new TwxTreeItemData; + pData->m_strData = data; + wxTreeItemId pa(parent); + if (!pa.IsOk()) + pa = tv.GetRootItem(); + + wxStringTokenizer tok(string, "\t", wxTOKEN_RET_EMPTY); + + wxTreeItemId id = tv.AppendItem(pa, tok.GetNextToken(), -1, -1, pData); + if (id.IsOk()) + { + const int nColumns = tv.GetColumnCount(); + for (int c = 1; c < nColumns && tok.HasMoreTokens(); c++) + tv.SetItemText(id, c, tok.GetNextToken()); + tv.SetItemHasChildren(pa, true); + tv.SetItemHasChildren(id, type == XVT_TREEVIEW_NODE_NONTERMINAL); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + tv.SetItemFont(id, tv.GetFont()); + node = id.m_pItem; + } + } + return node; +} + +XVT_TREEVIEW_NODE xvt_treelist_get_child_node(WINDOW win, XVT_TREEVIEW_NODE parent_node, + int position) +{ + XVT_TREEVIEW_NODE child_node = nullptr; + if (win != NULL_WIN && position >= 0) + { + CAST_TREELIST(win, tv); + wxTreeItemId parent(parent_node); + if (!parent.IsOk()) + parent = tv.GetRootItem(); + + if (parent.IsOk() && position < (int)tv.GetChildrenCount(parent)) + { + wxTreeItemIdValue cookie; + wxTreeItemId id; + int i = -1; + for (id = tv.GetFirstChild(parent, cookie), i = -1; + i < position && id.IsOk(); id = tv.GetNextChild(parent, cookie), i++); + child_node = id.m_pItem; + } + } + return child_node; +} + +const char* xvt_treelist_get_node_data(WINDOW win, XVT_TREEVIEW_NODE node) +{ + const char* data = nullptr; + if (win != NULL_WIN && node != nullptr) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id(node); + TwxTreeItemData* pData = (TwxTreeItemData*)tv.GetItemData(id); + if (pData != nullptr) + data = (const char*)pData->m_strData; + } + return data; +} + +void xvt_treelist_destroy_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREELIST(win, tv); + wxTreeItemId id(node); + tv.Delete(id); + } +} + +BOOLEAN xvt_treelist_enable_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN on) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREELIST(win, tv); + wxTreeItemId id(node); + tv.Enable(id, on != false); + } + return ok; +} + +BOOLEAN xvt_treelist_expand_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN recurse) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREELIST(win, tv); + tv.Suspend(); + const wxTreeItemId id(node); + if (recurse) + tv.ExpandAll(id); + else + tv.Expand(id); + tv.Resume(); + } + return ok; +} + +XVT_TREEVIEW_NODE xvt_treelist_get_root_node(WINDOW win) +{ + XVT_TREEVIEW_NODE pRoot = nullptr; + if (win != NULL_WIN) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id = tv.GetRootItem(); + pRoot = id.m_pItem; + } + return pRoot; +} + +XVT_TREEVIEW_NODE xvt_treelist_get_selected_node(WINDOW win) +{ + CAST_TREELIST(win, tv); + const wxTreeItemId id = tv.GetSelection(); + return id.m_pItem; +} + +SLIST xvt_treelist_get_selected_list(WINDOW win) +{ + SLIST list = nullptr; + CAST_TREELIST(win, tv); + wxArrayTreeItemIds selections; + const size_t nSel = tv.GetSelections(selections); + if (nSel > 0) + { + list = xvt_slist_create(); + for (size_t i = 0; i < nSel; i++) + { + const wxTreeItemId& id = selections[i]; + const TwxTreeItemData* pData = (const TwxTreeItemData*)tv.GetItemData(id); + if (pData != nullptr) + xvt_slist_add_at_elt(list, nullptr, pData->m_strData, (long)id.m_pItem); + else + xvt_slist_add_at_elt(list, nullptr, "", (long)id.m_pItem); + } + } + return list; +} + + +BOOLEAN xvt_treelist_remove_child_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != nullptr); + if (ok) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id(node); + if (id == tv.GetRootItem()) + tv.DeleteChildren(id); + else + { + tv.Suspend(); + tv.Delete(id); + tv.Resume(); + } + } + return ok; +} + +BOOLEAN xvt_treelist_remove_node_children(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = false; + if (win != NULL_WIN) + { + CAST_TREELIST(win, tv); + tv.Suspend(); + wxTreeItemId id(node); + if (!id.IsOk()) + id = tv.GetRootItem(); + tv.DeleteChildren(id); + tv.Resume(); + ok = true; + } + return ok; +} + +void xvt_treelist_resume(WINDOW win) +{ + CAST_TREELIST(win, tv); + tv.Resume(); +} + +void xvt_treelist_select_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN sel) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id(node); + if (sel) + { + tv.Suspend(); + tv.SelectItem(id, id, true); + tv.EnsureVisible(id); + tv.Resume(); + } + else + tv.UnselectAll(); + } +} + +void xvt_treelist_set_node_images(WINDOW win, XVT_TREEVIEW_NODE node, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id(node); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + } +} + +void xvt_treelist_set_node_string(WINDOW win, XVT_TREEVIEW_NODE node, const char* text) +{ + if (win != NULL_WIN) + { + CAST_TREELIST(win, tv); + const int cc = tv.GetColumnCount(); + wxStringTokenizer tok(text, "\t", wxTOKEN_RET_EMPTY); + if (node != nullptr) + { + const wxTreeItemId id(node); + for (int c = 0; c < cc && tok.HasMoreTokens(); c++) + tv.SetItemText(id, c, tok.GetNextToken()); + } + else + { + for (int c = 0; tok.HasMoreTokens(); c++) + { + wxString str = tok.GetNextToken(); + int width = 0; + bool bRightAlign = false; + const int a = str.Find('@'); + if (a > 0) + { + width = 10*wxAtoi(str.Mid(a+1)); + bRightAlign = str.Find('R', true) > a; + str.Truncate(a); + } + else + width = 10*str.Len(); + if (c >= cc) + tv.AddColumn(str, width, bRightAlign ? wxALIGN_RIGHT : wxALIGN_LEFT); + else + { + tv.SetColumnText(c, str); + const int oldw = tv.GetColumnWidth(c); + if (width < 2*oldw/3 || width > 3*oldw/2) + tv.SetColumnWidth(c, width); + } + } + } + } +} + +void xvt_treelist_suspend(WINDOW win) +{ + CAST_TREELIST(win, tv); + tv.Suspend(); +} + +void xvt_treelist_set_node_bold(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN bold) +{ + if (win != NULL_WIN && node != nullptr) + { + CAST_TREELIST(win, tv); + const wxTreeItemId id(node); + tv.SetItemBold(id, bold != false); + } +} + +static XVT_TREEVIEW_NODE FindTreeListNodeString(wxTreeListCtrl& tv, const wxTreeItemId& parent, const char* text) +{ + if (parent.IsOk()) + { + TwxTreeItemData* pData = (TwxTreeItemData*)tv.GetItemData(parent); + if (pData != nullptr && pData->m_strData == text) + return parent.m_pItem; + + wxTreeItemIdValue cookie; + for (wxTreeItemId id = tv.GetFirstChild(parent, cookie); id.IsOk(); + id = tv.GetNextChild(parent, cookie)) + { + XVT_TREEVIEW_NODE node = FindTreeListNodeString(tv, id, text); + if (node != nullptr) + return node; + } + } + return NULL; +} + +XVT_TREEVIEW_NODE xvt_treelist_find_node_string(WINDOW win, const char* text) +{ + XVT_TREEVIEW_NODE node = nullptr; + if (win != NULL_WIN && text && *text) + { + CAST_TREELIST(win, tv); + node = FindTreeListNodeString(tv, tv.GetSelection(), text); + if (node == nullptr) + node = FindTreeListNodeString(tv, tv.GetRootItem(), text); + } + return node; +} + +BOOLEAN xvt_html_set_url(WINDOW win, const char* url) +{ + BOOLEAN done = false; + wxHtmlWindow* w = win ? wxDynamicCast((wxObject*)win, wxHtmlWindow) : nullptr; + if (w) + { + const wxString strLocation = url; + if (strLocation.IsEmpty() || strLocation.StartsWith("<")) + done = w->SetPage(strLocation); + else + done = w->LoadPage(strLocation); + } + return done; +} + +/////////////////////////////////////////////////////////// +// Sad but needed migration from xvaga.cpp +/////////////////////////////////////////////////////////// + +WIN_TYPE xvt_vobj_get_type(WINDOW win) +{ + if (win == NULL_WIN) + return W_NONE; + if (win == TASK_WIN) + return W_TASK; + if (win == SCREEN_WIN) + return W_SCREEN; + if (win == PRINTER_WIN) + return W_PRINT; + + const TwxWindow* w = wxDynamicCast((wxObject*)win, TwxWindow); + if (w != nullptr) + return w->_type; + + const wxControl* ctl = wxDynamicCast((wxObject*)win, wxControl); + if (ctl != nullptr) + { + if (ctl->IsKindOf(CLASSINFO(wxHtmlWindow))) return WC_HTML; + if (ctl->IsKindOf(CLASSINFO(wxTreeCtrl))) return WC_TREE; + if (ctl->IsKindOf(CLASSINFO(wxTreeListCtrl))) return WC_TREELIST; + if (ctl->IsKindOf(CLASSINFO(wxPropertyGrid))) return WC_PROPGRID; // Siamo fiduciosi, ma ... + } + else + { + // ... non deriva da wxControl :-) + const wxPropertyGrid* pg = wxDynamicCast((wxObject*)win, wxPropertyGrid); + if (pg != nullptr) + return WC_PROPGRID; + const TwxMetroBar* mb = wxDynamicCast((wxObject*)win, TwxMetroBar); + if (mb != nullptr) + return WC_METROBAR; + } + + return WO_TE; // Unknown custom control +} + diff --git a/src/xvaga01/xvtdm.cpp b/src/xvaga01/xvtdm.cpp new file mode 100644 index 000000000..756985855 --- /dev/null +++ b/src/xvaga01/xvtdm.cpp @@ -0,0 +1,866 @@ +#include "wxinc.h" + +#include "xvt.h" +#include "xvtwin.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __WXMSW__ +#include "oswin32.h" +#endif + +/////////////////////////////////////////////////////////// +// TwxHtmlWindow +/////////////////////////////////////////////////////////// + +class TwxHtmlWindow : public wxHtmlWindow +{ +protected: + virtual void OnLinkClicked(const wxHtmlLinkInfo& link); +}; + +void TwxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link) +{ + const wxString href = link.GetHref(); + if (href.StartsWith("mailto:")) + xvt_mail_send(href.AfterFirst(':'), NULL, NULL, _GetAppTitle(), ToText(), NULL, 1); + else + wxHtmlWindow::OnLinkClicked(link); +} + +/////////////////////////////////////////////////////////// +// TMessageBox +/////////////////////////////////////////////////////////// + +class TMessageBox : public wxDialog +{ + wxTimer m_timer; + +protected: + void OnButton(wxCommandEvent& evt); + void OnTimeout(wxTimerEvent& evt); + void AddButton(wxSizer* sz, wxWindowID id); + DECLARE_EVENT_TABLE() + + wxString GetMessage() const; + +public: + TMessageBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout = 0); +}; + +BEGIN_EVENT_TABLE(TMessageBox, wxDialog) + EVT_BUTTON(wxID_ANY, TMessageBox::OnButton) + EVT_TIMER(wxID_ANY, TMessageBox::OnTimeout) +END_EVENT_TABLE() + +wxString TMessageBox::GetMessage() const +{ + wxString str; + const wxWindow* txt = FindWindowById(wxID_EDIT, this); + if (txt != NULL) + { + wxHtmlWindow* html = wxDynamicCast(txt, wxHtmlWindow); + if (html != NULL) + str = html->ToText(); + else + str = txt->GetLabel(); + } + return str; +} + +void TMessageBox::OnButton(wxCommandEvent& evt) +{ + int ec = wxCANCEL; + switch (evt.GetId()) + { + case wxID_YES: ec = wxYES; break; + case wxID_OK : ec = wxOK; break; + case wxID_NO : ec = wxNO; break; + case wxID_COPY: + wxTheClipboard->Open(); + wxTheClipboard->SetData(new wxTextDataObject(GetMessage())); + wxTheClipboard->Close(); + return; // DO NOT EXIT + case wxID_SAVEAS: + xvt_mail_send("hotline@sirio-is.it", NULL, NULL, _GetAppTitle(), GetMessage(), NULL, 1); + return; // DO NOT EXIT + default: ec = GetEscapeId(); break; + } + EndModal(ec); +} + +void TMessageBox::OnTimeout(wxTimerEvent& WXUNUSED(evt)) +{ + wxWindowID id = GetEscapeId(); + if (id <= 0) + id = GetAffirmativeId(); + if (id > 0) + { + wxCommandEvent cmd(wxEVT_COMMAND_BUTTON_CLICKED, id); + AddPendingEvent(cmd); + } + else + EndModal(wxCANCEL); +} + +void TMessageBox::AddButton(wxSizer* sz, wxWindowID id) +{ + wxString strPrompt; + switch (id) + { + case 0x20: strPrompt = _("Si Tutti"); break; + case 0x40: strPrompt = _("No Tutti"); break; + default : break; + } + wxButton* btn = new wxButton(this, id, strPrompt, wxDefaultPosition, wxSize(64,-1)); + sz->Add(btn, 0, wxALL|wxALIGN_CENTER_VERTICAL, 2); +} + +TMessageBox::TMessageBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout) + : wxDialog(pParent, wxID_ANY, _GetAppTitle(), wxDefaultPosition, wxDefaultSize, + wxCAPTION | wxRAISED_BORDER | wxSTAY_ON_TOP), m_timer(this) +{ + TTaskWin* tw = wxDynamicCast(pParent ? pParent : _task_win, TTaskWin); + if (tw != NULL) + { + const COLOR col = tw->GetCtlColor(XVT_COLOR_BACKGROUND); + if (col != COLOR_INVALID) + { + CAST_COLOR(col, rgb); + SetOwnBackgroundColour(rgb); + } + } + + wxBoxSizer* pMainSizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* pTopSizer = new wxBoxSizer(wxHORIZONTAL); + pMainSizer->Add(pTopSizer); + + wxArtID nIco = wxART_INFORMATION; + if (nStyle & wxICON_HAND) nIco = wxART_ERROR; else + if (nStyle & wxICON_INFORMATION) nIco = wxART_INFORMATION; else + if (nStyle & wxICON_EXCLAMATION) nIco = wxART_WARNING; else + if (nStyle & wxICON_QUESTION) nIco = wxART_QUESTION; else + if (nStyle & 0x1000) nIco = "220"; + + const BOOLEAN bTerminalino = xvt_sys_is_pda(); + const int nBorder = bTerminalino ? 2 : 4; + const int nIcon = bTerminalino ? 32 : 64; + const int nWrap = bTerminalino ?160 :400; + + const wxBitmap img = wxArtProvider::GetBitmap(nIco, wxART_MESSAGE_BOX, wxSize(nIcon,nIcon)); + + pTopSizer->Add(new wxStaticBitmap(this, wxID_ANY, img), 0, wxALL|wxALIGN_CENTER, nBorder); + + if (msg.StartsWith("") && msg.EndsWith("")) + { + TwxHtmlWindow* html = new TwxHtmlWindow; + html->Create(this, wxID_EDIT, wxDefaultPosition, wxSize(nWrap,nWrap/1.6180339887)); + html->SetPage(msg); + pTopSizer->Add(html, 0, wxALL|wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL, nBorder); + } + else + { + wxStaticText* ss = NULL; + if (bTerminalino) + { + int nLines = 0; + wxStringTokenizer tok(msg, wxT("\n")); + for (nLines = 0; tok.HasMoreTokens(); nLines++) + nLines += tok.GetNextToken().Len()/32; + ss = new wxStaticText(this, wxID_EDIT, wxEmptyString, wxDefaultPosition, + wxSize(nWrap, 16*nLines), wxST_NO_AUTORESIZE); + } + else + ss = new wxStaticText(this, wxID_EDIT, wxEmptyString); + + ss->Wrap(nWrap); + ss->SetLabel(msg); + pTopSizer->Add(ss, 0, wxALL|wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL, nBorder); + } + + pMainSizer->Add(new wxStaticLine(this), wxID_STATIC, wxALL|wxEXPAND, nBorder); + + wxFlexGridSizer* pBottomSizer = new wxFlexGridSizer(0, 2, 0, 0); + pBottomSizer->AddGrowableCol(1); + pMainSizer->Add(pBottomSizer, 0, wxGROW|wxALL, nBorder); + + wxBoxSizer* pSmallSizer = new wxBoxSizer(wxHORIZONTAL); + pBottomSizer->Add(pSmallSizer, 0, wxALIGN_TOP|wxALL, 0); + + wxBoxSizer* pButtonSizer = new wxBoxSizer(wxHORIZONTAL); + pBottomSizer->Add(pButtonSizer, 0, wxALIGN_RIGHT|wxALL, 0); + + if (nStyle & wxYES_NO) + { + if (nStyle & 0x60) // Yes,No,*All + { + if (nStyle & 0x20) // No, Yes, Yes All + { + SetAffirmativeId(wxID_YES); + SetEscapeId(wxID_NO); + AddButton(pButtonSizer, wxID_NO); + AddButton(pButtonSizer, wxID_YES); + AddButton(pButtonSizer, 0x20); + } + else // Yes, No, No All + { + SetAffirmativeId(wxID_NO); + SetEscapeId(wxID_YES); + AddButton(pButtonSizer, wxID_YES); + AddButton(pButtonSizer, wxID_NO); + AddButton(pButtonSizer, 0x40); + } + } + else + { + if (nStyle & wxNO_DEFAULT) + { + SetAffirmativeId(wxID_NO); + SetEscapeId(wxID_YES); + AddButton(pButtonSizer, wxID_NO); + AddButton(pButtonSizer, wxID_YES); + } + else + { + SetAffirmativeId(wxID_YES); + SetEscapeId(wxID_NO); + AddButton(pButtonSizer, wxID_YES); + AddButton(pButtonSizer, wxID_NO); + } + } + } + if (nStyle & wxOK) + { + SetAffirmativeId(wxID_OK); + AddButton(pButtonSizer, wxID_OK); + } + if (nStyle & wxCANCEL) + { + SetEscapeId(wxID_CANCEL); + AddButton(pButtonSizer, wxID_CANCEL); + } + + if (!bTerminalino) + { + const int nAssYear = xvt_vobj_get_attr(NULL_WIN, ATTR_APPL_VERSION_YEAR); + if (nAssYear >= 2121) + { + const wxBitmap bmpCopy = wxArtProvider::GetBitmap(wxART_COPY, wxART_BUTTON); + wxBitmapButton* btnCopy = new wxBitmapButton(this, wxID_COPY, bmpCopy); + pSmallSizer->Add(btnCopy, 0, wxALIGN_TOP); + /* + if (xvt_mail_installed()) + { + const wxBitmap bmpMail = wxArtProvider::GetBitmap("139", wxART_BUTTON, wxSize(bmpCopy.GetWidth(), bmpCopy.GetHeight())); + wxBitmapButton* btnMail = new wxBitmapButton(this, wxID_SAVEAS, bmpMail); + pSmallSizer->Add(btnMail, 0, wxALIGN_TOP); + } + */ + } + } + + + SetSizerAndFit(pMainSizer); + CentreOnParent(); + + if (nTimeout > 0) + m_timer.Start(1000*nTimeout, true); +} + +/////////////////////////////////////////////////////////// +// _*Box +/////////////////////////////////////////////////////////// + +int _MessageBox(const wxString& msg, int nStyle, int nTimeout = 0) +{ + xvt_dm_post_speech(msg, 1, TRUE); + + xvt_sys_beep((nStyle & wxICON_ERROR) ? 2 : (nStyle & wxICON_WARNING) ? 1 : 0); + + TMessageBox dlg(NULL, msg, nStyle, nTimeout); + const int ret = dlg.ShowModal(); + + switch(ret) + { + case wxOK : xvt_dm_post_speech(_("ok"), 7, TRUE); break; + case wxYES: xvt_dm_post_speech(_("si"), 7, TRUE); break; + case wxNO : xvt_dm_post_speech(_("no"), 7, TRUE); break; + default : xvt_dm_post_speech(_("annulla"), 7, TRUE); break; + } + return ret; +} + +/////////////////////////////////////////////////////////// +// _PopUpBox +/////////////////////////////////////////////////////////// + +class TPopUpBox : public wxDialog +{ + DECLARE_EVENT_TABLE(); + wxTimer m_Timer; + int m_nStep, m_nTimeout; + +protected: + void OnTimer(wxTimerEvent& evt); + void OnChar(wxKeyEvent& evt); + void OnClick(wxMouseEvent& evt); + +public: + TPopUpBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout); +}; + +BEGIN_EVENT_TABLE(TPopUpBox, wxDialog) + EVT_TIMER(wxID_ANY, TPopUpBox::OnTimer) + EVT_CHAR(TPopUpBox::OnChar) + EVT_LEFT_DOWN(TPopUpBox::OnClick) +END_EVENT_TABLE() + +void TPopUpBox::OnChar(wxKeyEvent& WXUNUSED(evt)) +{ + if (IsShown()) + { + m_Timer.Stop(); + EndModal(wxID_CANCEL); + } +} + +void TPopUpBox::OnClick(wxMouseEvent& WXUNUSED(evt)) +{ + if (IsShown()) + { + m_Timer.Stop(); + EndModal(wxID_CANCEL); + } +} + +void TPopUpBox::OnTimer(wxTimerEvent& WXUNUSED(evt)) +{ + if (IsShown()) + { + const wxRect rctMain = GetParent()->GetRect(); + const wxRect rctMine = GetRect(); + const int msec = (m_nStep++)*m_Timer.GetInterval(); + if (msec <= m_nTimeout/4) + { + const double perc = double(msec)/(m_nTimeout/4); + Move(rctMain.x, rctMain.GetBottom() - rctMine.height * perc); + } + if (msec >= 3*m_nTimeout/4 && msec <= m_nTimeout) + { + const double perc = double(m_nTimeout-msec)/(m_nTimeout/4); + Move(rctMain.x, rctMain.GetBottom() - rctMine.height * perc); + } + if (msec > m_nTimeout) + { + m_Timer.Stop(); + EndModal(wxID_CANCEL); + } + } +} + +TPopUpBox::TPopUpBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout) + : wxDialog(pParent, wxID_ANY, wxEmptyString, wxPoint(0,2024), wxDefaultSize, wxBORDER_SIMPLE), + m_nTimeout(nTimeout*1000), m_Timer(this), m_nStep(0) +{ + TTaskWin* tw = wxDynamicCast(pParent ? pParent : _task_win, TTaskWin); + if (tw != NULL) + { + const COLOR col = tw->GetCtlColor(XVT_COLOR_BACKGROUND); + if (col != COLOR_INVALID) + { + CAST_COLOR(col, rgb); + SetOwnBackgroundColour(rgb); + } + } + + wxBoxSizer* sz = new wxBoxSizer(wxHORIZONTAL); + + wxArtID nIco = wxART_ERROR; + if (nStyle & wxICON_HAND) nIco = wxART_ERROR; else + if (nStyle & wxICON_INFORMATION) nIco = wxART_INFORMATION; else + if (nStyle & wxICON_EXCLAMATION) nIco = wxART_WARNING; else + if (nStyle & 0x1000) nIco = "220"; + const wxBitmap img = wxArtProvider::GetBitmap(nIco, wxART_MESSAGE_BOX); + + wxStaticBitmap* bmp = new wxStaticBitmap(this, wxID_ANY, img); + sz->Add(bmp, 0, wxALL, 8); + + wxStaticText* ss = new wxStaticText(this, wxID_ANY, wxEmptyString); + ss->Wrap(160); + ss->SetLabel(msg); + sz->Add(ss, 0, wxALL | wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 8); + + SetSizerAndFit(sz); + m_Timer.Start(25); +} + +static void _PopUpBox(const wxString& msg, int nStyle, int nTimeout = 4) +{ + wxWindow* pFrame = wxTheApp->GetTopWindow(); + bool bCanPopUp = pFrame != NULL && xvt_sys_get_oem_int("OEM", -1) == 0; +#ifdef __WXMSW__ + if (bCanPopUp) + bCanPopUp = !OsWin32_IsWindowsServer(); // Animazioni non consigliabili in TS +#endif + + if (bCanPopUp) + { + xvt_sys_beep(nStyle & wxICON_ERROR ? 2 : 1); + TPopUpBox dlg(pFrame, msg, nStyle, nTimeout <= 0 ? 4 : nTimeout); + dlg.ShowModal(); + } + else + _MessageBox(msg, nStyle|wxOK, nTimeout); +} + +WX_DECLARE_STRING_HASH_MAP(int, TMessagesMap); + +void xvt_sys_sorry_box(const char* func, const char* file, int line) +{ +#ifndef NDEBUG + static TMessagesMap sorry; + if (sorry[func]++ == 0) + { + wxString strMessage; + strMessage.Printf("Function %s in file %s at line %d\nis not implemented yet: be patient...", + func, file, line); + _PopUpBox(strMessage, 0x1000); // Smiley Icon + } +#endif +} + +void xvt_sys_deprecated_box(const char* oldfunc, const char* file, const char* newfunc) +{ +#ifndef NDEBUG + static TMessagesMap deprecated; + if (deprecated[oldfunc]++ == 0) + { + wxString strMessage; + strMessage.Printf("Function %s in file %s is deprecated:\n%s is much more trendy now!\nYou can blame Guy for this, if you're bold enough!", + oldfunc, file, newfunc); + _PopUpBox(strMessage, 0x1000); + } +#endif +} + +/////////////////////////////////////////////////////////// +// Speech support +/////////////////////////////////////////////////////////// + +// 0 Errors +// 1 Warnings +// 2 Messages +// 3 Requests +// 7 Buttons +static int m_nSpeechMode = 0; + +void xvt_dm_speech_enable(int mode) +{ +#ifdef SPEECH_API + m_nSpeechMode = mode; + if (m_nSpeechMode != 0) + { + if (!OsWin32_InitializeSpeech()) + m_nSpeechMode = 0; + } + else + { + OsWin32_DeinitializeSpeech(); + } +#endif +} + +int xvt_dm_speech_enabled(void) +{ return m_nSpeechMode; } + +/////////////////////////////////////////////////////////// +// Common dialogs +/////////////////////////////////////////////////////////// + +void xvt_dm_post_about_box() +{ + const char* ver = (const char*)xvt_vobj_get_attr(NULL_WIN, ATTR_APPL_VERSION_STRING); + if (ver == NULL || !*ver) ver = "2015 12.0/100"; + wxString msg; msg << "Versione " << ver; + xvt_dm_post_message(msg); +} + +BOOLEAN xvt_dm_post_color_sel(COLOR* color, unsigned long reserved) +{ + CAST_COLOR(*color, wc); + + wxColourData cd; + cd.SetChooseFull(true); + cd.SetColour(wc); + for (int i = 0; i < 16; i++) + { + const unsigned char val = (i & 0x8) ? 255 : 127; + const unsigned char red = (i & 0x1) ? val : 0; + const unsigned char green = (i & 0x2) ? val : 0; + const unsigned char blue = (i & 0x4) ? val : 0; + wxColour col(red, green, blue); + cd.SetCustomColour(i, col); + } + + wxWindow* win = wxDynamicCast ((void*)reserved, wxWindow); + wxColourDialog dialog(win, &cd); + if (dialog.ShowModal() == wxID_OK) + { + *color = MAKE_XVT_COLOR(dialog.GetColourData().GetColour()); + if (*color == 0) *color = COLOR_BLACK; // 0x000000 confonde XI, mentre con 0x07000000 e' a suo agio + return TRUE; + } + + return FALSE; +} + +class TwxCalendarDlg : public wxDialog +{ + enum { ID_CAL = 1883 }; + wxDateTime& m_date; + wxCalendarCtrl* m_cal; + +protected: + virtual bool TransferDataFromWindow(); + void OnCalendar(wxCalendarEvent& e); + +public: + TwxCalendarDlg(wxWindow* parent, wxDateTime& date); + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(TwxCalendarDlg, wxDialog) + EVT_CALENDAR(wxID_ANY, TwxCalendarDlg::OnCalendar) +END_EVENT_TABLE() + +void TwxCalendarDlg::OnCalendar(wxCalendarEvent& WXUNUSED(e)) +{ + wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); + AddPendingEvent(evt); +} + +bool TwxCalendarDlg::TransferDataFromWindow() +{ + bool ok = wxDialog::TransferDataFromWindow(); + if (ok) + m_date = m_cal->GetDate(); + return ok; +} + +TwxCalendarDlg::TwxCalendarDlg(wxWindow* parent, wxDateTime& date) + : wxDialog(parent, wxID_ANY, "Data", wxDefaultPosition, wxDefaultSize, wxRAISED_BORDER), m_date(date) +{ + + m_cal = new wxCalendarCtrl(this, ID_CAL, m_date, wxDefaultPosition, wxDefaultSize, + wxCAL_MONDAY_FIRST | wxCAL_SHOW_HOLIDAYS | wxCAL_SHOW_SURROUNDING_WEEKS); + + wxButton* button = new wxButton(this, wxID_OK, "OK"); + + wxGridSizer* sizer = new wxFlexGridSizer(2, 1, 8, 8); + sizer->Add(m_cal, 0, wxALIGN_CENTER); + sizer->Add(button, 0, wxALIGN_CENTER); + SetSizer(sizer); + sizer->SetSizeHints(this); +} + +unsigned int xvt_dm_post_date_sel(WINDOW win, const RCT* rct, unsigned int ansidate) +{ + int d = ansidate%100; + int m = (ansidate/100)%100; + int y = ansidate / 10000; + + wxDateTime date; + if (d >= 1 && d <= 31 && m >= 1 && m <= 12 && y > 1900) + date.Set(d, wxDateTime::Month(m-1), y); + else + date = wxDateTime::Today(); + + CAST_WIN(win, w); + wxDialog* dlg = new TwxCalendarDlg(&w, date); + + if (rct != NULL) + { + const wxRect client = w.GetClientRect(); + const wxRect rect = dlg->GetRect(); + wxPoint pos(rct->right - rect.width, rct->bottom); + if (pos.x < 0) + pos.x = rct->left; + if (rct->bottom + rect.height > client.GetBottom()) + pos.y = rct->top - rect.height; + dlg->Move(w.ClientToScreen(pos)); + } + + if (dlg->ShowModal() == wxID_OK) + { + d = date.GetDay(); + m = date.GetMonth()+1; + y = date.GetYear(); + ansidate = y*10000 + m*100 + d; + } + dlg->Destroy(); + + return ansidate; +} + +BOOLEAN xvt_dm_post_speech(const char* text, int priority, BOOLEAN async) +{ + BOOLEAN ok = FALSE; +#ifdef SPEECH_API + if ((m_nSpeechMode & (1 << priority)) != 0) + ok = OsWin32_Speak(text, async != 0); +#endif + return ok; +} + +ASK_RESPONSE xvt_dm_post_ask(const char* Btn1, const char* WXUNUSED(Btn2), const char* Btn3, const char* fmt) +{ + int nFlags = wxICON_QUESTION | wxYES_NO; + if (wxStricmp(Btn1, "no") == 0) + nFlags |= wxNO_DEFAULT; + if (Btn3 != NULL) //il Btn3 è presente sulla maschera (es. noyesall_box, yesnocancel_box) + { + if (wxStricmp(Btn3, "Si Tutti") == 0) + nFlags |= 0x20; else + if (wxStricmp(Btn3, "No Tutti") == 0) + nFlags |= 0x40; + else + nFlags |= wxCANCEL; + } + + const int answer = _MessageBox(fmt, nFlags); + return answer == wxYES ? RESP_DEFAULT : (answer == wxNO ? RESP_2 : RESP_3); +} + +void xvt_dm_post_error(const char *fmt) +{ + _MessageBox(fmt, wxOK | wxICON_HAND); +} + +void xvt_dm_post_fatal_exit(const char *fmt) +{ + _MessageBox(fmt, wxOK | wxICON_HAND, 10); + abort(); +} + +static wxString MakeFileName(const wxChar* name, const wxChar* ext) +{ + wxString f = name; + if (ext && *ext) + { + if (*ext != '.') + f += '.'; + f += ext; + } + return f; +} + +static FL_STATUS xvt_dm_post_file_ask(FILE_SPEC *fsp, const char *msg, int flags) +{ + DIRECTORY savedir; xvt_fsys_get_curr_dir(&savedir); // Salvo cartella corrente + + wxString path = fsp->dir.path; + wxString name = MakeFileName(fsp->name, fsp->type); + wxString extension = fsp->type; + wxString wild; + if (!extension.IsEmpty() && extension != "*") + wild << _("File ") << extension << " (*." << extension << ")|*." << extension << "|"; + if (flags & wxFD_OPEN) + wild << _("Tutti i file (*.*)|*.*|"); + wild << '|'; + + wxString selectedname = wxFileSelector(msg, path, name, extension , wild, flags); + if (selectedname.IsEmpty()) + return FL_CANCEL; + xvt_fsys_convert_str_to_fspec(selectedname, fsp); + + xvt_fsys_set_dir(&savedir); // Ripristino cartella corrente + + return FL_OK; +} + +FL_STATUS xvt_dm_post_file_open(FILE_SPEC *fsp, const char *msg) +{ + const int flags = wxFD_OPEN | wxFD_FILE_MUST_EXIST; + return xvt_dm_post_file_ask(fsp, msg, flags); +} + +FL_STATUS xvt_dm_post_file_save(FILE_SPEC *fsp, const char *msg) +{ + const int flags = wxFD_SAVE | wxFD_OVERWRITE_PROMPT; + return xvt_dm_post_file_ask(fsp, msg, flags); +} + +FL_STATUS xvt_dm_post_dir_sel(DIRECTORY *dir) +{ + wxDirDialog dlg(_task_win); + dlg.SetPath(dir->path); + if (dlg.ShowModal() == wxID_OK) + { + xvt_fsys_convert_str_to_dir(dlg.GetPath(), dir); + return FL_OK; + } + return FL_CANCEL; +} + +BOOLEAN xvt_dm_post_font_sel(WINDOW win, XVT_FNTID font_id, PRINT_RCD* WXUNUSED(precp), unsigned long reserved) +{ + CAST_FONT(font_id, font); + wxFontData data; + data.SetInitialFont(font.Font(NULL, win)); + data.EnableEffects(reserved != 0); + wxFontDialog dlg(_task_win, data); + BOOLEAN ok = dlg.ShowModal() == wxID_OK; + if (ok) + { + font.Copy(dlg.GetFontData().GetChosenFont()); + if (win == (WINDOW)_task_win) + { + EVENT e; memset(&e, 0, sizeof(EVENT)); + e.type = E_FONT; + e.v.font.font_id = font_id; + _task_win_handler(win, &e); + } + } + return ok; +} + +void xvt_dm_post_message(const char *fmt) +{ + _MessageBox(fmt, wxOK | wxICON_INFORMATION); +} + +void xvt_dm_post_note(const char *fmt) +{ + _PopUpBox(fmt, wxICON_INFORMATION); +} + +char* xvt_dm_post_string_prompt(const char* message, char* response, int response_len) +{ + if (message && response && response_len > 0) + { + wxTextEntryDialog dlg(NULL, message, _GetAppTitle(), response); + if (dlg.ShowModal() == wxID_OK) + { + wxStrncpy(response, dlg.GetValue(), response_len); + response[response_len-1] = '\0'; + } + else + *response = '\0'; + } + return response; +} + +void xvt_dm_post_warning(const char *fmt) +{ + _MessageBox(fmt, wxOK|wxICON_EXCLAMATION); +} + +void xvt_dm_popup_error(const char *fmt) +{ + _PopUpBox(fmt, wxICON_HAND); +} + +void xvt_dm_popup_message(const char *fmt) +{ + _PopUpBox(fmt, wxICON_INFORMATION); +} + +void xvt_dm_popup_warning(const char *fmt) +{ + _PopUpBox(fmt, wxICON_EXCLAMATION); +} + +/////////////////////////////////////////////////////////// +// Help system +/////////////////////////////////////////////////////////// + +#ifdef __WXMSW__ +#include "OsWin32.h" +#endif + +struct XVAGA_HELP_INFO +{ + wxString m_strFilename; + bool m_hlp; +} help_info; + +XVT_HELP_INFO xvt_help_open_helpfile(FILE_SPEC* WXUNUSED(fs), unsigned long WXUNUSED(flags)) +{ + return (XVT_HELP_INFO)&help_info; +} + +void xvt_help_close_helpfile(XVT_HELP_INFO hi) +{ + if (hi == NULL_HELP_INFO) + hi = (XVT_HELP_INFO)&help_info; +} + +BOOLEAN xvt_help_process_event(XVT_HELP_INFO WXUNUSED(hi), WINDOW win, EVENT *ev) +{ + BOOLEAN bProcessed = FALSE; + +#ifdef __WXMSW__ + WXHWND hwnd = (WXHWND)xvt_vobj_get_attr(win, ATTR_NATIVE_WINDOW); + switch (ev->type) + { + case E_COMMAND: + bProcessed = OsWin32_Help(hwnd, "", ev->v.cmd.tag, NULL); + break; + case E_HELP: + bProcessed = OsWin32_Help(hwnd, "", M_HELP_ONCONTEXT, (const char*)ev->v.help.tid); + break; + default: + break; + } +#endif // WIN32 + + return bProcessed; +} + + +/////////////////////////////////////////////////////////// +// Progress dialog +/////////////////////////////////////////////////////////// + +WINDOW xvt_dm_progress_create(WINDOW owner, const char* title, long nTotal, BOOLEAN cancellable) +{ +#ifdef __WXMSW__ + WXHWND hwnd = (WXHWND)xvt_vobj_get_attr(owner, ATTR_NATIVE_WINDOW); + return (WINDOW)OsWin32_ProgressCreate(hwnd, title, nTotal, cancellable != 0); +#endif + return NULL_WIN; +} + +void xvt_dm_progress_destroy(WINDOW prog) +{ +#ifdef __WXMSW__ + if (prog) + OsWin32_ProgressDestroy((WXHWND)prog); +#endif +} + +BOOLEAN xvt_dm_progress_set_status(WINDOW prog, long nCurrent, long nTotal) +{ +#ifdef __WXMSW__ + return OsWin32_ProgressSetStatus((WXHWND)prog, nCurrent, nTotal); +#endif + return FALSE; +} + +void xvt_dm_progress_set_text(WINDOW prog, const char* msg) +{ +#ifdef __WXMSW__ + OsWin32_ProgressSetText((WXHWND)prog, msg); +#endif + if (msg && *msg) + xvt_app_process_pending_events(); +} diff --git a/src/xvaga01/xvtextra.cpp b/src/xvaga01/xvtextra.cpp new file mode 100644 index 000000000..bd7bb9ac7 --- /dev/null +++ b/src/xvaga01/xvtextra.cpp @@ -0,0 +1,1524 @@ +#include "wxinc.h" +#include +#include +#include +#include + +#include "xvt.h" +#include "xvtart.h" + +#ifdef __WXMSW__ +#include "wx/dcps.h" +#include "wx/msw/printdlg.h" +#include "oswin32.h" +#else +#include "wx/setup.h" +#include "wx/dcps.h" +#include "oslinux.h" +#include "incstr.h" +#endif + +#include "xvtpdf.h" +#include "xvtwin.h" + +extern wxString xvt_fsys_get_default_dir_name(); + +#pragma pack(4) + +struct TPRINT_RCD : public PRINT_RCD +{ +#ifdef __WXMSW__ + unsigned char m_data[16*1024]; + unsigned int m_size; // Dimensione della struct DEVMODE + + void SetData(void * data, unsigned int nSize); +#else + wxPrintNativeDataBase* m_data; + unsigned int m_size; // Dimensione di wxPostScriptPrintNativeData + + void GetData(wxPrintNativeDataBase* data) const; + void SetData(void * data); +#endif + + unsigned int GetSize() const { return m_size; } + + TPRINT_RCD(); + ~TPRINT_RCD(); +}; + +#pragma pack() + +#ifdef __WXMSW__ + +void TPRINT_RCD::SetData(void* data, unsigned int nSize) +{ + if (nSize <= sizeof(m_data)) + { + memset(m_data, 0, sizeof(m_data)); // Azzero per bene anche tutto quanto segue nSize + memcpy(m_data, data, nSize); + m_size = nSize; + } + else + xvt_dm_post_error("Printer info exceeds 16K"); +} + +TPRINT_RCD::TPRINT_RCD() : m_size(0) +{ + pr = NULL; + memset(m_data, 0, sizeof(m_data)); +} + +TPRINT_RCD::~TPRINT_RCD() +{ + memset(m_data, 0, sizeof(m_data)); + m_size = 0; +} + +#else + +void TPRINT_RCD::GetData(wxPrintNativeDataBase * data) const +{ + memcpy(data, m_data, GetSize()); +} + +void TPRINT_RCD::SetData(void* data) +{ + memcpy(m_data, data, GetSize()); +} + +wxNativePrintFactory __factory; + +TPRINT_RCD::TPRINT_RCD() +{ + m_data = __factory.CreatePrintNativeData(); + m_size = sizeof(*m_data); +} + +TPRINT_RCD::~TPRINT_RCD() +{ + delete m_data; +} + +#endif + +/////////////////////////////////////////////////////////// +// TwxPrintOut +/////////////////////////////////////////////////////////// + +class TwxPrintOut : public wxPrintout +{ +protected: + const TPRINT_RCD* m_prcd; + bool m_bBadDriver; + + virtual bool HasPage(int pageNum); + virtual bool OnPrintPage(int pageNum); + void ResetDC(); + + wxDC* CreateDC(const TPRINT_RCD* prcd, const char* title); + +public: + void SetBadDriver(bool bd) { m_bBadDriver = bd; } + bool HasBadDriver() const { return m_bBadDriver; } + + wxString PrinterName() const; + bool IsPDF() const { return !HasBadDriver() && xvt_print_is_pdf(m_prcd) != 0; } + + bool InitDC(const TPRINT_RCD* prcd, const char* title); + TwxPrintOut(const TPRINT_RCD* prcd = NULL); + + virtual ~TwxPrintOut() {} +}; + +wxString TwxPrintOut::PrinterName() const +{ + char strName[MAX_PATH] = ""; + xvt_print_get_name(m_prcd, strName, sizeof(strName)); + return wxString(strName); +} + +bool TwxPrintOut::HasPage(int WXUNUSED(pageNum)) +{ return true; } + +bool TwxPrintOut::OnPrintPage(int WXUNUSED(pageNum)) +{ return false; } + +void TwxPrintOut::ResetDC() +{ + wxDC* dc = GetDC(); + if (dc != NULL) + { + delete dc; + SetDC(NULL); + } +} + +static void RCD2data(const TPRINT_RCD* prcd, wxPrintData& data) +{ +#ifdef WIN32 + wxWindowsPrintNativeData ndb; + ndb.SetDevMode(OsWin32_ConvertToNativePrinterInfo((void*)prcd->m_data, prcd->m_size)); + ndb.TransferTo(data); + + // in assenza di PDEVNAMES aggiorno il nome in questo modo + char strName[MAX_PATH] = ""; + xvt_print_get_name(prcd, strName, sizeof(strName)); + data.SetPrinterName(strName); +#else + prcd->GetData(data.GetNativeData()); + data.ConvertFromNative(); +#endif +} + +static void data2RCD(const wxPrintData& data, TPRINT_RCD* prcd) +{ +#ifdef WIN32 + wxWindowsPrintNativeData* pNative = (wxWindowsPrintNativeData*)data.GetNativeData(); + unsigned int nSize = 0; + void* ptr = OsWin32_ConvertFromNativePrinterInfo(pNative->GetDevMode(), nSize); + prcd->SetData(ptr, nSize); + delete ptr; +#else + ((wxPrintData&)data).ConvertToNative(); + prcd->SetData(data.GetNativeData()); +#endif +} + +wxDC* TwxPrintOut::CreateDC(const TPRINT_RCD* prcd, const char* title) +{ + m_prcd = prcd; + wxDC* dc = NULL; + + if (m_prcd == NULL) + { + wxPrinter printer; +#ifdef WIN32 + dc = new wxPrinterDC(printer.GetPrintDialogData().GetPrintData()); +#else + dc = new wxPostScriptDC(printer.GetPrintDialogData().GetPrintData()); +#endif + } + else + { + wxPrintData data; + RCD2data(prcd, data); + + const bool ispdf = IsPDF(); + if (ispdf) + dc = new TwxPDFDC(data, title); + else +#ifdef WIN32 + dc = new wxPrinterDC(data); +#else + dc = new wxPostScriptDC(data); +#endif + } + + if (dc->IsOk()) + { + wxSize s = dc->GetPPI(); + SetPPIPrinter(s.x, s.y); + + s = dc->GetSize(); + SetPageSizePixels(s.x, s.y); + + SetDC(dc); + + wxWindow* pAbort = wxPrinterBase::sm_abortWindow; + if (pAbort != NULL) + { + wxWindow* pStatic = pAbort->FindWindow(wxID_STATIC); + if (pStatic != NULL) + { + wxString strPrompt; + if (IsPDF()) + { + const wxFileName fn(title); + strPrompt << wxT("Generazione di ") << fn.GetFullName(); + } + else + strPrompt << wxT("Stampa su ") << PrinterName(); + pStatic->SetLabel(strPrompt); + } + } + } + else + { +// delete dc; + dc = NULL; + } + return dc; +} + +bool TwxPrintOut::InitDC(const TPRINT_RCD* prcd, const char* title) +{ + ResetDC(); + wxDC* dc = CreateDC(prcd, title); + if (dc != NULL) + { + wxSize s = dc->GetPPI(); + if (s.x > 0) + SetPPIPrinter(s.x, s.y); + + s = dc->GetSize(); + if (s.x > 0) + SetPageSizePixels(s.x, s.y); + SetDC(dc); + } + m_bBadDriver = dc == NULL; + return !m_bBadDriver; +} + +TwxPrintOut::TwxPrintOut(const TPRINT_RCD* prcd) + : wxPrintout(_GetAppTitle()), m_bBadDriver(false) +{ + InitDC(prcd, _GetAppTitle()); +} + +/////////////////////////////////////////////////////////// +// TwxPrintOutCache +/////////////////////////////////////////////////////////// + +class TwxPrintOutCache +{ + unsigned long m_signature; + TwxPrintOut* m_po; + bool m_bLocked; + +protected: + unsigned long Signature(const TPRINT_RCD* prcd) const; + +public: + TwxPrintOut& Get(const TPRINT_RCD* prcd); + void Reset(); + + void Lock() { m_bLocked = true; } + void Unlock() { m_bLocked = false; } + + bool Ok() const { return m_po != NULL; } + bool Locked() const { return m_bLocked; } + bool Printing() const { return Ok() && Locked(); } + + TwxPrintOutCache(); + ~TwxPrintOutCache(); +} m_PrintoutCache; + +unsigned long TwxPrintOutCache::Signature(const TPRINT_RCD* prcd) const +{ + unsigned long h = 0; + if (prcd != NULL) + { + const unsigned char* data = (const unsigned char*)prcd; + const size_t sz = prcd->GetSize(); + for (size_t c = 0; c < sz; c++) + { + h = (h << 2) + data[c]; + const unsigned long i = h & 0xC0000000; + if (i) h = (h ^ (i >> 12)) & 0x3FFFFFFF; + } + } + return h; +} + +void TwxPrintOutCache::Reset() +{ + wxASSERT(!Locked()); + if (m_po != NULL) + { + delete m_po; + m_po = NULL; + + // Marca come non valido anche il puntatore al DC contenuto nel defunto m_po + TDCMapper& m = GetTDCMapper(); + if (m.HasValidDC(PRINTER_WIN)) + m.GetTDC(PRINTER_WIN).KillDC(); + } +} + +TwxPrintOut& TwxPrintOutCache::Get(const TPRINT_RCD* prcd) +{ + if (!Locked()) + { + if (prcd == NULL) + { + if (m_po == NULL) + m_po = new TwxPrintOut; + } + else + { + unsigned long signature = Signature(prcd); + if (m_po != NULL && m_signature == signature) + return *m_po; + Reset(); + m_po = new TwxPrintOut(prcd); + m_signature = signature; + } + } + wxASSERT(m_po != NULL); + return *m_po; +} + +TwxPrintOutCache::TwxPrintOutCache() : m_signature(0), m_po(NULL) +{ } + +TwxPrintOutCache::~TwxPrintOutCache() +{ + // Reset(); // Essendo un oggetto statico la delete m_po non funziona! +} + +/////////////////////////////////////////////////////////// +// TPrintDC +/////////////////////////////////////////////////////////// + +// Flag di reset ad inizio pagina +bool TPrintDC::_page_start = false; + +void TPrintDC::SetPageStart() +{ _page_start = true; } + +wxDC& TPrintDC::GetDC(bool) +{ + _dc = m_PrintoutCache.Get(NULL).GetDC(); // Forza display context corrente + if (_page_start) + { + _dirty = -1; + _page_start = false; + } + return TDC::GetDC(false); +} + +void TPrintDC::KillDC() +{ + _dc = NULL; // _dc is owned by wxPrintout +} + +TPrintDC::TPrintDC(wxWindow* owner) : TDC(owner) +{ + _page_start = false; +} + +TPrintDC::~TPrintDC() +{ + KillDC(); +} + +/////////////////////////////////////////////////////////// +// Printing management :-((((( +/////////////////////////////////////////////////////////// + +BOOLEAN xvt_app_escape(int esc_code, PRINT_RCD* rcd, long* ph, long* pw, long* pvr, long* phr) +{ + switch (esc_code) + { + case XVT_ESC_GET_PRINTER_INFO: + if (ph) *ph = *pw = 0; + if (pvr) *pvr = *phr = 0; + if (rcd == NULL || xvt_print_is_valid(rcd)) + { + const TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)rcd); + int w, h; + if (ph) + { + po.GetPageSizePixels(&w, &h); + *pw = w; *ph = h; + } + if (pvr) + { + po.GetPPIPrinter(&w, &h); + *phr = w; *pvr = h; + } + return TRUE; + } + break; + case XVT_ESC_SET_PRINTER_INFO: + if (xvt_print_is_valid(rcd) && ph != NULL && pw != NULL) + { + TPRINT_RCD* prcd = (TPRINT_RCD*)rcd; + wxPrintData data; + + RCD2data(prcd, data); + data.SetOrientation(*ph >= *pw ? wxPORTRAIT : wxLANDSCAPE); + data.ConvertToNative(); + data2RCD(data, prcd); + + TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)rcd); + po.InitDC(prcd, _GetAppTitle()); + + return true; + } + break; + default: + break; + } + return FALSE; +} + +BOOLEAN xvt_dm_post_page_setup(PRINT_RCD* precp) +{ + wxPageSetupDialog dlg((wxWindow*)TASK_WIN); + TPRINT_RCD* rcd = (TPRINT_RCD*)precp; + + wxPageSetupData& pdd = dlg.GetPageSetupData(); + wxPrintData& data = pdd.GetPrintData(); + + RCD2data(rcd, data); + + pdd.EnableMargins(false); + + const BOOLEAN ok = dlg.ShowModal() == wxID_OK; + if (ok) + { + data2RCD(data, rcd); + m_PrintoutCache.Reset(); + } + + return ok; +} + +static wxBitmap& GetCachedBitmap(const wxString& strName, const wxRect& dst) +{ + static wxString _strName; + static wxRect _dst; + static wxBitmap _bmp; + + if (strName != _strName || dst.GetSize() != _dst.GetSize()) + { + wxImage img; + if (img.LoadFile(strName)) + { + if (img.HasAlpha() || img.HasMask()) + img.Rescale(dst.width, dst.height, wxIMAGE_QUALITY_NORMAL); + else + img.Rescale(dst.width, dst.height, wxIMAGE_QUALITY_HIGH); + _bmp = wxBitmap(img); + _strName = strName; + _dst = dst; + } + else + { + _bmp = wxNullBitmap; + _strName = ""; + _dst.width = _dst.height = 0; + } + } + + return _bmp; +} + +void xvt_dwin_draw_image_on_pdf(WINDOW win, const char* name, const RCT* dest) +{ + const wxRect dst = RCT2Rect(dest); + wxDC& dc = GetTDCMapper().GetDC(win); + if (win == PRINTER_WIN) + { + TwxPDFDC* pPDF = wxDynamicCast(&dc, TwxPDFDC); + if (pPDF != NULL) + { + pPDF->DrawImage(name, dst); + return; + } + } + + wxString strName(name); strName.MakeLower(); + wxBitmap& bmp = GetCachedBitmap(strName, dst); + if (bmp.IsOk()) + { + //wxIcon ico; ico.CopyFromBitmap(bmp); + //dc.DrawIcon(ico, dst.x, dst.y); + wxMemoryDC mem(bmp); + dc.Blit(dst.x, dst.y, dst.width, dst.height, &mem, 0, 0, wxCOPY, true); + } +} + +long xvt_fmap_get_family_sizes(PRINT_RCD *precp, char *family, long *size_array, BOOLEAN *scalable, long max_sizes) +{ + long size = 0; + *scalable = FALSE; + +#ifdef __WXMSW__ + if (xvt_print_is_valid(precp)) + { + const TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)precp); + if (!po.HasBadDriver()) + size = OsWin32_EnumerateSizes(po.GetDC()->GetHDC(), family, size_array, scalable, max_sizes); + } + else + { + size = OsWin32_EnumerateSizes(NULL, family, size_array, scalable, max_sizes); + } +#else + size = OsLinux_EnumerateSizes(family, size_array, scalable, max_sizes); +#endif + + return size; +} + +long xvt_fmap_get_families(PRINT_RCD *precp, char **family_array, long max_families) +{ + long size = 0; + family_array[0] = NULL; + +#ifdef __WXMSW__ + if (xvt_print_is_valid(precp)) + { + TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)precp); + if (!po.HasBadDriver()) + { + size = OsWin32_EnumerateFamilies(po.GetDC()->GetHDC(), family_array, max_families); + if (size == 0) + po.SetBadDriver(true); + } + } + else + { + wxFrame* tw = (wxFrame*)TASK_WIN; + wxClientDC dc(tw); + size = OsWin32_EnumerateFamilies(dc.GetHDC(), family_array, max_families); + } +#else + size = OsLinux_EnumerateFamilies(family_array, max_families); +#endif + + return size; +} + +void xvt_print_close(void) +{ + // Nothing to do ? + m_PrintoutCache.Reset(); +} + +BOOLEAN xvt_print_close_page(PRINT_RCD* WXUNUSED(precp)) +{ + BOOLEAN ok = m_PrintoutCache.Printing(); + if (ok) + { + const TwxPrintOut& po = m_PrintoutCache.Get(NULL); + wxDC* dc = po.GetDC(); + dc->EndPage(); + + //GetTDCMapper().DestroyTDC(PRINTER_WIN); // Elimina dalla lista dei display context + } + return ok; +} + +PRINT_RCD* xvt_print_create(int *sizep) +{ + return xvt_print_create_by_name(sizep, NULL); +} + +// Impone il nome ad un PRINT_RCD. +// Utilizzato per la definiz. della stamp. virtuale PDF predefinita +int xvt_print_set_name(PRINT_RCD* precp, const char* name) +{ + if (precp == NULL) + return 0; + + if (name == NULL || !*name) + return 0; + + wxString n = name; + +#ifdef __WXMSW__ + wxStrncpy(((char*)precp) + 4, name, 32); +#else + TPRINT_RCD* rcd = (TPRINT_RCD*)precp; + wxPrintData data; + + rcd->GetData(data); + data.SetPrinterName(n); + rcd->SetData(data); +#endif + + return n.Length(); +} + +// Nuova funzione inventata da Aga +PRINT_RCD* xvt_print_create_by_name(int* sizep, const char* name) +{ + TPRINT_RCD* pr = NULL; + *sizep = 0; + + const bool ispdf = name != NULL && xvt_str_same(name, XVT_PDF_PRINTER_NAME); + if (ispdf) + name = NULL; + +#ifdef __WXMSW__ + void* data = OsWin32_GetPrinterInfo(*sizep, name); + if (data == NULL) + { + SLIST plist = xvt_print_list_devices(); + SLIST_ELT pitem = xvt_slist_get_first(plist); + name = xvt_slist_get(plist, pitem, NULL); + data = OsWin32_GetPrinterInfo(*sizep, name); + xvt_slist_destroy(plist); + } + if (data != NULL) + { + pr = new TPRINT_RCD; + pr->SetData(data, *sizep); + *sizep += 4; // Spazio per puntatore iniziale + delete data; + } +#else + wxPrintData data; + + data.SetPrinterName(name == NULL ? "" : name); + pr = new TPRINT_RCD; + data2RCD(data, pr); + *sizep = pr->GetSize(); +#endif + + if (ispdf) + xvt_print_set_name(pr, XVT_PDF_PRINTER_NAME); + + return pr; +} + +WINDOW xvt_print_create_win(PRINT_RCD* precp, const char* title) +{ + bool ok = xvt_print_is_valid(precp) != FALSE; + if (ok) + { + TPRINT_RCD* rcd = (TPRINT_RCD*)precp; + if (m_PrintoutCache.Printing()) + { + TwxPrintOut& po = m_PrintoutCache.Get(NULL); + ok = po.InitDC(rcd, title); + if (ok) + { + po.OnBeginPrinting(); + po.OnBeginDocument(1, 32000); + } + } + else + { + TwxPrintOut& po = m_PrintoutCache.Get(rcd); + ok = po.InitDC(rcd, title); + } + } + return ok ? PRINTER_WIN : NULL_WIN; +} + +void xvt_print_destroy(PRINT_RCD* precp) +{ + if (precp != NULL) + delete precp; +} + +RCT* xvt_print_get_next_band(void) +{ + static bool yes = false; + static RCT rct; + yes = !yes; + + if (!yes) + return NULL; + + const TwxPrintOut& po = m_PrintoutCache.Get(NULL); + int w = 0, h = 0; + po.GetPageSizePixels(&w, &h); + rct.left = rct.top = 0; + rct.right = w; + rct.bottom = h; + + return &rct; +} + +BOOLEAN xvt_print_is_pdf(const PRINT_RCD* precp) +{ + bool yes = precp != NULL; + if (yes) + { + char strName[MAX_PATH]; + xvt_print_get_name(precp, strName, sizeof(strName)); + yes = xvt_str_same(strName, XVT_PDF_PRINTER_NAME) != 0; + } + return yes; +} + +BOOLEAN xvt_print_pdf_version(char* version, int size) +{ + const BOOLEAN ok = version && size > 12; + if (ok) + { + wxString str = "PDFlib "; + str += PDFLIB_VERSIONSTRING; + wxStrncpy(version, str, size); + } + return ok; +} + +BOOLEAN xvt_print_is_valid(const PRINT_RCD* precp) +{ + BOOLEAN ok = precp != NULL && precp->pr == NULL; + if (ok) + { + const TPRINT_RCD* rcd = (const TPRINT_RCD*)precp; + +#ifdef __WXMSW__ + ok = OsWin32_CheckPrinterInfo(rcd->m_data, rcd->m_size); +#else + wxPrintData data; + RCD2data(rcd, data); + ok = data.Ok(); +#endif + } + return ok; +} + +int xvt_print_get_name(const PRINT_RCD* precp, char* name, int sz_s) +{ + if (!xvt_print_is_valid(precp)) + return 0; + +#ifdef __WXMSW__ + wxString n = ((const char*)precp) + 4; + if (n.Length() >= 30) + { + double dBest = 0.0; + wxString strBest = n; + SLIST plist = xvt_print_list_devices(); + for (SLIST_ELT pitem = xvt_slist_get_first(plist); + pitem != NULL; pitem = xvt_slist_get_next(plist, pitem)) + { + const char* pname = xvt_slist_get(plist, pitem, NULL); + const double dScore = xvt_str_fuzzy_compare_ignoring_case(n, pname); + if (dScore > dBest) + { + dBest = dScore; + strBest = pname; + if (dScore >= 1.0) + break; + } + } + xvt_slist_destroy(plist); + n = strBest; + } +#else + TPRINT_RCD* rcd = (TPRINT_RCD*)precp; + wxPrintData data; + + RCD2data(rcd, data); + wxString n = data.GetPrinterName(); +#endif + if (name != NULL && sz_s > 0) + { + wxStrncpy(name, n, sz_s); + name[sz_s-1] = '\0'; + } + return n.Length(); +} + +BOOLEAN xvt_print_open(void) +{ + return m_PrintoutCache.Ok(); +} + +/////////////////////////////////////////////////////////// + +class TwxPrintAbortDialog : public wxPrintAbortDialog +{ +public: + void Pulse(); + TwxPrintAbortDialog(); +}; + +void TwxPrintAbortDialog::Pulse() +{ + wxGauge* pGauge = wxStaticCast(FindWindow(wxID_FORWARD), wxGauge); + pGauge->Pulse(); +} + +TwxPrintAbortDialog::TwxPrintAbortDialog() + : wxPrintAbortDialog(NULL, _("Stampa"), + wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) +{ + wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); + + button_sizer->Add(new wxStaticText(this, wxID_STATIC, _("Stampa in corso..."), + wxDefaultPosition, wxSize(480,-1)), 0, wxALL, 10 ); + button_sizer->Add(new wxGauge(this, wxID_FORWARD, 1, wxDefaultPosition, wxSize(480,-1)), 0, wxALL, 10 ); + + //button_sizer->Add(new wxButton(this, wxID_CANCEL, wxT("Annulla") ), 0, wxALL | wxALIGN_CENTER, 10 ); + button_sizer->Add(new wxBitmapButton(this, wxID_CANCEL, xvtart_GetToolResource(102,32) ), 0, wxALL | wxALIGN_CENTER, 10 ); + + SetAutoLayout(true); + SetSizer(button_sizer); + + button_sizer->Fit(this); + button_sizer->SetSizeHints(this); + + Show(); + Update(); +} + +void CreateAbortWindow() +{ + wxPrinterBase::sm_abortWindow = new TwxPrintAbortDialog; +} + +void DestroyAbortWindow() +{ + if (wxPrinterBase::sm_abortWindow != NULL) + { + wxPrinterBase::sm_abortWindow->Hide(); + delete wxPrinterBase::sm_abortWindow; + wxPrinterBase::sm_abortWindow = NULL; + } +} + +/////////////////////////////////////////////////////////// + +BOOLEAN xvt_print_start_thread(BOOLEAN(*print_fcn)(long), long data) +{ + const wxString strDir = xvt_fsys_get_default_dir_name(); // Memorizzo la directory corrente (Acrobat la cambia) + + wxBeginBusyCursor(); + m_PrintoutCache.Reset(); // Forza nuovo contesto di stampa + TwxPrintOut& po = m_PrintoutCache.Get(NULL); + m_PrintoutCache.Lock(); + wxEndBusyCursor(); + + CreateAbortWindow(); + const BOOLEAN success = print_fcn(data); + DestroyAbortWindow(); + + if (!po.HasBadDriver()) + { + po.OnEndDocument(); + po.OnEndPrinting(); + } + + m_PrintoutCache.Unlock(); + m_PrintoutCache.Reset(); + + ::wxSetWorkingDirectory(strDir); // Ripristino la directory corrente (Acrobat l'ha cambiata) + + return success; +} + +BOOLEAN xvt_print_suspend_thread() +{ + BOOLEAN ok = m_PrintoutCache.Printing(); + if (ok) + { + TwxPrintOut& po = m_PrintoutCache.Get(NULL); + po.OnEndDocument(); // Sembra generare una pagina vuota indesiderata + po.OnEndPrinting(); + } + return ok; +} + +BOOLEAN xvt_print_restart_thread() +{ + TwxPrintOut& po = m_PrintoutCache.Get(NULL); + po.OnBeginPrinting(); + return po.OnBeginDocument(1, 32000); +} + +BOOLEAN xvt_print_open_page(PRINT_RCD* WXUNUSED(precp)) +{ + BOOLEAN ok = m_PrintoutCache.Printing(); + if (ok) + { + if (wxPrinterBase::sm_abortIt) + ok = FALSE; + else + { + TwxPrintOut& po = m_PrintoutCache.Get(NULL); + po.GetDC()->StartPage(); + TPrintDC::SetPageStart(); // Flag per azzeramento dati DC + + // Aggiorna barra di attesa + TwxPrintAbortDialog* pad = wxDynamicCast(wxPrinterBase::sm_abortWindow, TwxPrintAbortDialog); + if (pad != NULL) + { + pad->Pulse(); + wxWakeUpIdle(); + } + } + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Added by XVAGA +/////////////////////////////////////////////////////////// + +SLIST xvt_print_list_devices() +{ + SLIST list = xvt_slist_create(); + + const DWORD dwFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS; + const int level = xvt_sys_get_os_version() >= XVT_WS_WIN_NT ? 4 : 5; + DWORD dwSize = 0, dwPrinters = 0; + ::EnumPrinters (dwFlags, NULL, level, NULL, 0, &dwSize, &dwPrinters); + if (dwSize > 0) + { + BYTE* pBuffer = new BYTE[dwSize]; + ::EnumPrinters (dwFlags, NULL, level, pBuffer, dwSize, &dwSize, &dwPrinters); + if (level == 4) + { + const PRINTER_INFO_4* pPrnInfo = (const PRINTER_INFO_4*)pBuffer; + for (UINT i=0; i < dwPrinters; i++) + { + xvt_slist_add_at_elt(list, NULL, pPrnInfo->pPrinterName, NULL); + pPrnInfo++; + } + } + else + { + const PRINTER_INFO_5* pPrnInfo = (const PRINTER_INFO_5*)pBuffer; + for (UINT i=0; i < dwPrinters; i++) + { + xvt_slist_add_at_elt(list, NULL, pPrnInfo->pPrinterName, NULL); + pPrnInfo++; + } + } + delete[] pBuffer; + } + + return list; +} + +BOOLEAN xvt_print_set_default_device(const char* name) +{ + BOOLEAN ok = name != NULL && *name > ' '; + if (ok) + { + wxString pdev(name); + if (pdev.Find(',') < 0) + { + char szDevice[_MAX_PATH]; + ::GetProfileString ("devices", pdev, "", szDevice, sizeof(szDevice)); + pdev << ',' << szDevice; + } + ok = ::WriteProfileString("windows", "device", pdev) != 0; + } + return ok; +} + +BOOLEAN xvt_print_get_default_device(char* name, int namesize) +{ + return ::GetProfileString ("windows", "device", ",,,", name, namesize) != 0; +} + +/////////////////////////////////////////////////////////// +// Gestione files di configurazione +/////////////////////////////////////////////////////////// + +int xvt_fsys_get_campo_stp_value(const char* name, char* value, int valsize) +{ + BOOLEAN bFound = FALSE; + + const char* const stpfile = "c:/campo.stp"; + int p; + DIRECTORY dir; + char exedir[_MAX_PATH], path[_MAX_PATH]; + xvt_fsys_get_default_dir(&dir); + xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); + + for (p = 1; ; p++) + { + char para[4]; sprintf(para, "%d", p); + int len = xvt_sys_get_profile_string(stpfile, para, "Program", "", path, sizeof(path)); + if (len <= 0) + break; + if (wxEndsWithPathSeparator(path)) + { + len--; + path[len] = '\0'; + } + if (xvt_str_same(path, exedir)) + { + xvt_sys_get_profile_string(stpfile, para, name, "", value, valsize); + bFound = *value > ' '; + break; + } + } + + return bFound; +} + +/* + @($) xvt_fsys_get_home_dir FILES + + @(ID) + Restituisce il nome del direttorio home. + @(FD) + + Versione WIN32 e LINUX. + @(FSV) +*/ +const char* xvt_fsys_get_home_dir() +{ + static wxString homedir; + + if (homedir.IsEmpty()) + { + char path[_MAX_PATH]; + + xvt_fsys_build_pathname(path, nullptr, wxGetHomeDir(), nullptr, nullptr, nullptr); + homedir = path; + } + return homedir; +} + +/* + @($) CGetCampoIni FILES + + @(ID) + Restituisce il nome del file che contiene il prefisso corrente. + @(FD) + + @(ISV) + s,s1 = stringhe di lavoro. + + Versione WIN32 e LINUX. + @(FSV) +*/ +const char* xvt_fsys_get_campo_ini() +{ + static wxString prawin; + + if (prawin.IsEmpty()) + { + BOOLEAN bFound = FALSE; + char exedir[_MAX_PATH], path[_MAX_PATH]; + // Nelle installazioni sfigate con programmi in rete cerca di stabilire il percorso locale di Campo.ini + DIRECTORY dir; + + xvt_fsys_get_default_dir(&dir); + xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); + + if (xvt_fsys_is_network_drive(exedir)) + bFound = xvt_fsys_get_campo_stp_value("CampoIni", path, sizeof(path)); + + if (!bFound) + { + if (OsWin32_IsWindowsServer()) + { + xvt_fsys_build_pathname(path, NULL, wxGetHomeDir(), "campo", "ini", NULL); + bFound = xvt_fsys_file_exists(path); + if (!bFound) + { + char pathstd[_MAX_PATH]; + xvt_fsys_build_pathname(pathstd, NULL, exedir, "campo", "ini", NULL); + if (xvt_fsys_file_exists(pathstd)) + wxCopyFile(pathstd, path); + } + } + } + + if (!bFound) + xvt_fsys_build_pathname(path, NULL, exedir, "campo", "ini", NULL); + + if (!xvt_fsys_file_exists(path)) + { + char msg[_MAX_PATH]; + sprintf(msg, _("Impossibile aprire '%s'"), path); + xvt_dm_post_fatal_exit(msg); + } + prawin = path; + } + return prawin; +} + +/////////////////////////////////////////////////////////// +// Gestione MD5 +/////////////////////////////////////////////////////////// + +#include "MD5Checksum.h" + +BOOLEAN xvt_str_md5(const char* instr, char* outstr) +{ + wxASSERT(outstr != NULL); + BOOLEAN ok = instr && *instr && outstr; + if (ok) + { + wxStrcpy(outstr, wxMD5Checksum::GetMD5((unsigned char*)instr, strlen(instr))); + ok = *outstr != '\0'; + } + return ok; +} + +BOOLEAN xvt_fsys_file_md5(const char* path, char* outstr) +{ + wxASSERT(outstr != NULL); + BOOLEAN ok = path && *path && outstr; + if (ok) + { + wxStrcpy(outstr, wxMD5Checksum::GetMD5(wxString(path))); + ok = *outstr != '\0'; + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Gestione firma digitale +/////////////////////////////////////////////////////////// + +class TwxSignatureDlg : public wxDialog +{ +private: + virtual bool TransferDataToWindow(); + virtual bool TransferDataFromWindow(); + +protected: + wxTextCtrl* AddString(wxSizer* ctlSizer, int id, const char* label, + wxString* str, int nFlags = 0); + +public: + wxString m_strUser, m_strPIN; + bool m_bMark; + + TwxSignatureDlg(); +}; + +bool TwxSignatureDlg::TransferDataToWindow() +{ + FindWindowById(1001, this)->SetLabel(m_strUser); + // FindWindowById(1002, this)->SetLabel(m_strPin); // Non riproporre + wxCheckBox* cb = wxStaticCast(FindWindowById(1003, this), wxCheckBox); + cb->SetValue(m_bMark); + return true; +} + +bool TwxSignatureDlg::TransferDataFromWindow() +{ + m_strUser = FindWindowById(1001, this)->GetLabel(); + m_strPIN = FindWindowById(1002, this)->GetLabel(); + wxCheckBox* cb = wxStaticCast(FindWindowById(1003, this), wxCheckBox); + m_bMark = cb->IsEnabled() && cb->GetValue(); + return !m_strUser.IsEmpty() && !m_strPIN.IsEmpty(); +} + +wxTextCtrl* TwxSignatureDlg::AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str, int nFlags) +{ + wxStaticText* lbl = new wxStaticText(this, wxID_ANY, label); + wxTextCtrl* txt = new wxTextCtrl(this, id, wxEmptyString, wxDefaultPosition, wxSize(120, -1), + nFlags, wxTextValidator(wxFILTER_ASCII, str)); + ctlSizer->Add(lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4); + ctlSizer->Add(txt, 1, wxALIGN_LEFT | wxALL, 4); + + return txt; +} + +TwxSignatureDlg::TwxSignatureDlg() : wxDialog(NULL, wxID_ANY, "ESigner", wxDefaultPosition) +{ + wxSizer* ctlSizer = new wxFlexGridSizer(4, 2, 4, 4); + AddString(ctlSizer, 1001, "Utente", &m_strUser); + AddString(ctlSizer, 1002, "PIN", &m_strPIN, wxTE_PASSWORD); + + wxCheckBox* ctlMark = new wxCheckBox(this, 1003, "Marcatura temporale"); + if (xvt_net_get_status() <= 0) + ctlMark->Disable(); + ctlSizer->AddSpacer(4); + ctlSizer->Add(ctlMark, 0, wxALIGN_LEFT | wxALL, 4); + + wxSizer* ctlButtonSizer = CreateButtonSizer(wxOK | wxCANCEL); + + wxBoxSizer* ctlTopSizer = new wxBoxSizer(wxVERTICAL); + ctlTopSizer->Add(ctlSizer, 0, wxALIGN_CENTER); + ctlTopSizer->Add(ctlButtonSizer, 0, wxALIGN_CENTER); + + SetSizer(ctlTopSizer); + ctlTopSizer->SetSizeHints(this); +} + +typedef + int (*dllSignMethod) ( + char *operation, //operazione : S (firma file), + // S+D (firma directory), + // S+T (firma + marca file), + // S+T+D (firma + marca directory) + char *method, //metodo : F (file cert), P (file PFX), T (token/smartcard) + char *inputFile, //percorso file di input + char *outputFile, //percorso file di output (senza estensione) + char *timestampOutputFile, //percorso file di output TSR (marca temporale separata) + char *extension, //estensione in caso di input PDF + char *certificateFile, //nome file .cer o .crt contenente il certificato + char *kprivFile, //nome file .pem contenente la chiave privata + char *pfxFile, //nome file pfx contenente certificato e chiave privata + char *pkcs11Dll, //nome dll PKCS11 + char *pin_passphrase, //passphrase o PIN (per chiave privata, pfx o token) + char *directoryTokenCache, //directory cache certificati estratti da token + char *indexCertificateOnToken, //numero certificato del token + char *tsaURI, //URI della TSA (http:\\....) + char *tsaUsername, //Username TSA + char *tsaPassword, //Password TSA + char *tsaPolicy, //Policy TSA + char *tsaCoding, //Codifica TSA: binary o base64 + char *rootCADir) //percorso directory contenente i certificati della rootca + ; + +typedef int (*dllVerifyMethod) ( + char *operation, //operazione : V (verifica file), + // V+D (verifica directory), + char *inputFileName, //percorso file di input + char *responseFileName, //percorso file di esito + char *rootCADir, //percorso directory contenente i certificati della rootca + char *rootTSADir, //percorso directory contenente i certificati delle rootTSA + char *resultDescription //parametro di output contenente l'esito della verifica +); + +class TEsigner +{ +#ifdef WIN32 + HMODULE m_hESigner; + dllSignMethod _SignPDF; + dllVerifyMethod _VerifyPDF; +#endif + + wxString m_strUser, m_strPin, m_strDllFile, m_strCertificate; + wxString m_strTSAuri, m_strTSAuser, m_strTSApwd, m_strPolicy, m_strTSAcoding; + bool m_bMark; + +public: + bool Init(bool on); + bool Sign(const wxString& strInput, wxString& strOutput); + bool Verify(const wxString& strInput); + + TEsigner(); + ~TEsigner(); +} __TheSigner; + +TEsigner::TEsigner() : m_bMark(false) +#ifdef WIN32 + , m_hESigner(NULL), _SignPDF(NULL), _VerifyPDF(NULL) +#endif +{} + +TEsigner::~TEsigner() +{ Init(false); } + +bool TEsigner::Init(bool bLoad) +{ + bool ok = false; +#ifdef WIN32 + if (bLoad) + { + char str[_MAX_PATH] = ""; + xvt_sys_get_profile_string(NULL, NULL, "Study", "", str, sizeof(str)); + wxString strConfig; strConfig = str; + if (!wxEndsWithPathSeparator(strConfig)) + strConfig << wxFILE_SEP_PATH; + strConfig << "config" << wxFILE_SEP_PATH << wxGetHostName() << ".ini"; + + if (m_hESigner == NULL) + { + m_hESigner = ::LoadLibrary("esigner.dll"); + if (m_hESigner != NULL) + { + _SignPDF = (dllSignMethod)::GetProcAddress(m_hESigner, "Sign"); + _VerifyPDF = (dllVerifyMethod)::GetProcAddress(m_hESigner, "Verify"); + m_strPin.Empty(); + + TwxSignatureDlg dlg; + if (m_strUser.IsEmpty()) + m_strUser = wxGetUserId(); + dlg.m_strUser = m_strUser; + dlg.m_bMark = m_bMark; + if (dlg.ShowModal() == wxID_OK) + { + m_strUser = dlg.m_strUser; + m_strPin= dlg.m_strPIN; + m_bMark = dlg.m_bMark; + } + else + return ok = false; + + xvt_sys_get_profile_string(strConfig, "fd", "Cert_"+m_strUser, "", str, sizeof(str)); + if (*str == '\0') // Se non trova l'utente corrente di riprova con Guest + xvt_sys_get_profile_string(strConfig, "fd", "Cert_Guest", "", str, sizeof(str)); + + wxStringTokenizer strDllCert(str, ","); + m_strDllFile = strDllCert.GetNextToken(); m_strDllFile.MakeLower(); + m_strCertificate = strDllCert.GetNextToken(); + if (m_strCertificate.IsEmpty() && m_strDllFile.EndsWith(".dll")) + m_strCertificate = "0"; + + if (m_bMark) + { + m_strTSAuri = strDllCert.GetNextToken(); + m_strTSAuser = strDllCert.GetNextToken(); + m_strTSApwd = strDllCert.GetNextToken(); + m_strPolicy = strDllCert.GetNextToken(); + m_strTSAcoding = strDllCert.GetNextToken(); + + if (m_strTSAcoding.IsEmpty()) + m_strTSAcoding = wxT("binary"); + + if (m_strTSAuri.IsEmpty()) + { + wxString msg; + msg << "Mancano i parametri per la marcatura temporale" + << "\nControllare Cert_" << m_strUser + << " nel paragrafo [fd]\ndel file " << strConfig; + xvt_dm_post_warning(msg); + m_bMark = false; + } + } + } + } + ok = m_hESigner != NULL && _SignPDF != NULL && _VerifyPDF != NULL; + if (ok) + { + ok = wxFileExists(m_strDllFile); + if (!ok) + { + wxString msg; + msg << "Impossibile caricare il certificato/driver " << m_strDllFile + << "\nControllare Cert_" << m_strUser + << " nel paragrafo [fd]\ndel file " << strConfig; + xvt_dm_post_error(msg); + } + } + else + xvt_dm_post_error("Impossibile caricare 'ESigner.dll'"); + } + else + { + if (m_hESigner != NULL) + { + ::FreeLibrary(m_hESigner); + m_hESigner = NULL; + _SignPDF = NULL; + _VerifyPDF = NULL; + m_strPin.Empty(); + } + } +#endif + return ok; +} + +bool TEsigner::Sign(const wxString& strInput, wxString& strOutput) +{ + if ((m_strPin.IsEmpty() || m_strDllFile.IsEmpty()) && !Init(true)) + return false; + + const char* ext = strInput.Lower().EndsWith(".pdf") ? ".pdf.p7m" : ""; + + if (strOutput.IsEmpty()) + strOutput = strInput + ".p7m"; + ::wxRemoveFile(strOutput); // Altrimenti la fantastica dll s'incazza come una biscia + + const wxString strFile = strOutput.BeforeFirst('.'); + + int res = 0; + if (m_strDllFile.Lower().EndsWith(".dll")) + { + if (m_bMark && !m_strTSAuri.IsEmpty()) // Firma con marcatura temporale + { + res = _SignPDF("S", "T", // "S"ignature with "T"oken or smartcard + (char*)(const char*)strInput, (char*)(const char*)strFile, + NULL, (char*)ext, NULL, NULL, NULL, (char*)(const char*)m_strDllFile, + (char*)(const char*)m_strPin, NULL, (char*)(const char*)m_strCertificate, + (char*)(const char*)m_strTSAuri, (char*)(const char*)m_strTSAuser, + (char*)(const char*)m_strTSApwd, (char*)(const char*)m_strPolicy, + (char*)(const char*)m_strTSAcoding, NULL); + } + else // Firma normale + { + res = _SignPDF("S", "T", // "S"ignature with "T"oken or smartcard + (char*)(const char*)strInput, (char*)(const char*)strFile, + NULL, (char*)ext, NULL, NULL, NULL, (char*)(const char*)m_strDllFile, + (char*)(const char*)m_strPin, NULL, (char*)(const char*)m_strCertificate, + NULL, NULL, NULL, NULL, NULL, NULL); + } + } + else + { + if (m_bMark && !m_strTSAuri.IsEmpty()) // Firma con marcatura temporale + { + res = _SignPDF("S", "P", // "S"ignature with "P"fx file + (char*)(const char*)strInput, (char*)(const char*)strFile, + NULL, (char*)ext, NULL, NULL, (char*)(const char*)m_strDllFile, NULL, + (char*)(const char*)m_strPin, NULL, NULL, + (char*)(const char*)m_strTSAuri, (char*)(const char*)m_strTSAuser, + (char*)(const char*)m_strTSApwd, (char*)(const char*)m_strPolicy, + (char*)(const char*)m_strTSAcoding, NULL); + } + else + { + res = _SignPDF("S", "P", // "S"ignature with "P"fx file + (char*)(const char*)strInput, (char*)(const char*)strFile, + NULL, (char*)ext, NULL, NULL, (char*)(const char*)m_strDllFile, NULL, + (char*)(const char*)m_strPin, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL); + } + } + + if (res == 0) + { + if (!xvt_fsys_file_exists(strOutput)) + { + wxString str = "ESigner.dll can't create " + strOutput; + xvt_dm_post_error(str); + res = -1; + } + } + else + { + wxString str; + str.Printf("ESigner.dll error %d", res); + xvt_dm_post_error(str); + } + + return res == 0; +} + +bool TEsigner::Verify(const wxString& strInput) +{ + int res = -1; + if (Init(!strInput.IsEmpty())) + { + char file[_MAX_PATH], result[_MAX_PATH]; + wxStrncpy(file, strInput, _MAX_PATH); + res = _VerifyPDF("V", file, NULL, NULL, NULL, result); + } + return res == 0; +} + +BOOLEAN xvt_sign_start() +{ + return __TheSigner.Init(true); +} + +BOOLEAN xvt_sign_stop() +{ + __TheSigner.Init(false); + return TRUE; +} + +BOOLEAN xvt_sign_file(const char* input_name, char* output_name) +{ + wxString strInput = input_name, strOutput = output_name; + if (strInput.IsEmpty()) + { + FILE_SPEC fs; + xvt_fsys_convert_str_to_fspec(strInput, &fs); + if (xvt_dm_post_file_open(&fs, "File") != FL_OK) + return false; + } + strInput.MakeLower(); + BOOLEAN ok = __TheSigner.Sign(strInput, strOutput); + if (ok && output_name != NULL) + wxStrncpy(output_name, strOutput, _MAX_PATH); + return ok; +} + + +BOOLEAN xvt_sign_test(const char* input_name) +{ + wxString strInput = input_name; + if (strInput.IsEmpty()) + { + FILE_SPEC fs; + xvt_fsys_convert_str_to_fspec(strInput, &fs); + if (xvt_dm_post_file_open(&fs, "File") != FL_OK) + return FALSE; + } + return __TheSigner.Verify(strInput); +} diff --git a/src/xvaga01/xvtmail.cpp b/src/xvaga01/xvtmail.cpp new file mode 100644 index 000000000..1668cf265 --- /dev/null +++ b/src/xvaga01/xvtmail.cpp @@ -0,0 +1,660 @@ +#include "wxinc.h" +#include "xvt.h" + +#include "smapi.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static wxString GetMailParam(const char* key, const char* def = "") +{ + static wxString ini; // C:\campo\dati\config\user.ini + + if (ini.IsEmpty()) + { + wxString cu = "ADMIN"; + for (int i = __argc-1; i > 1; i--) + { + wxString u = __argv[i]; u.MakeUpper(); + if (u.StartsWith("/U") || u.StartsWith("-U")) + { + cu = u.Mid(2); + break; + } + } + + char study[_MAX_PATH]; xvt_sys_get_profile_string(NULL, "Main", "Study", "", study, sizeof(study)); + ini = study; + if (!wxEndsWithPathSeparator(ini)) + ini += wxFILE_SEP_PATH; + ini += "config\\"; ini += cu; ini += ".ini"; + } + wxString val; const size_t sz = _MAX_PATH; + xvt_sys_get_profile_string(ini, "Mail", key, def, val.GetWriteBuf(sz), sz); + val.UngetWriteBuf(); + return val; +} + +static wxString __smtp = "notset"; +static wxString __port = "notset"; +static wxString __user = "notset"; +static wxString __pass = "notset"; +static wxString __from = "notset"; + +void xvt_set_mail_params(const char * smtp, const char * port, const char * user, const char * pass, const char * from) +{ + if (__smtp == "notset") + { + __smtp = GetMailParam("Server", "MAPI"); + __port = GetMailParam("Port"); + __user = GetMailParam("User"); + __pass = GetMailParam("Password"); + + wxString f = (user && *user) ? user: __user; + + if (f.find('@') < 0) + { + f += "@"; + f += __smtp.AfterFirst('.'); + } + __from = GetMailParam("From", f); + } + if (smtp && *smtp) + __smtp = _strdup(smtp); + if (port && *port) + __port = _strdup(port); + if (user && *user) + __user = _strdup(user); + if (pass && *pass) + __pass = _strdup(pass); +} + +static bool GetMailParams(wxString& smtp, wxString& port, wxString& user, wxString& pass, wxString& from) +{ + if (__smtp == "notset") + { + __smtp = GetMailParam("Server", "MAPI"); + __port = GetMailParam("Port"); + __user = GetMailParam("User"); + __pass = GetMailParam("Password"); + } + smtp = __smtp; + port = __port; + user = __user; + pass = __pass; + if (__from == "notset") + { + wxString f = user; + + if (f.find('@') < 0) + { + f += "@"; + f += __smtp.AfterFirst('.'); + } + __from = GetMailParam("From", f); + } + from = __from; + return !smtp.IsEmpty() && !pass.IsEmpty(); +} + +static bool has_power_mail() +{ + return GetMailParam("Powershell") == "X"; +} + +static bool has_ccnsend() +{ + return GetMailParam("CcnSend") == "X"; +} + +short xvt_mail_installed() +{ + short bInstalled = 0; + + if (::GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0 && + SearchPath(NULL, _T("MAPI32.DLL"), NULL, 0, NULL, NULL) != 0) + bInstalled |= 0x1; + + if (xvt_fsys_file_exists("servers/mailsend.exe") || has_power_mail()) + { + wxString smtp, port, user, pass, from; + + GetMailParams(smtp, port, user, pass, from); + if (!pass.IsEmpty() && smtp != "MAPI") + bInstalled |= 0x2; + } + + return bInstalled; +} + +static void AppendQuotedString(wxString& cmd, const char* key, const wxString& value) +{ + if (!value.IsEmpty()) + cmd << " -" << key << " \"" << value << "\""; +} + +static void AppendAttachment(wxString& cmd, const wxString& fname, bool att = true) +{ + if (wxFileName::FileExists(fname)) + { + char ext[_MAX_EXT] = { 0 }; + xvt_fsys_parse_pathname (fname, NULL, NULL, NULL, ext, NULL); + wxString mime = ext; + wxFileType* ft = wxTheMimeTypesManager->GetFileTypeFromExtension(mime); + if (ft != NULL) + { + wxArrayString aMime; + if (ft->GetMimeTypes(aMime)) + mime = aMime[0]; + } + + if (att) + { + wxString a; a << fname << "," << mime << ",a"; + AppendQuotedString(cmd, "attach", a); + } + else + { + wxString a; a << fname << "," << mime << ",i"; + AppendQuotedString(cmd, "attach", a); + } + } +} + +/////////////////////////////////////////////////////////// +// wxEmailDlg +/////////////////////////////////////////////////////////// + +class wxEmailDlg : public wxDialog +{ +protected: + wxTextCtrl* AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str); + +public: + wxString _strEmail; + wxEmailDlg(); +}; + +wxTextCtrl* wxEmailDlg::AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str) +{ + wxStaticText* lbl = new wxStaticText(this, wxID_ANY, label); + + const int k = 20, b = k / 10; + wxTextCtrl* txt = new wxTextCtrl(this, id, wxEmptyString, wxDefaultPosition, wxSize(20 * k, k), + 0, wxTextValidator(wxFILTER_ASCII, str)); + ctlSizer->Add(lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, b); + ctlSizer->Add(txt, 1, wxALIGN_LEFT | wxALL, b); + + return txt; +} + +wxEmailDlg::wxEmailDlg() : wxDialog(NULL, wxID_ANY, "Email", + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE) +{ + wxSizer* ctlTextSizer = new wxFlexGridSizer(4, 2, 8, 8); + + AddString(ctlTextSizer, 1001, "Destinatario", &_strEmail); + + wxSizer* ctlButtonSizer = CreateButtonSizer(wxOK | wxCANCEL); + wxBoxSizer* ctlTopSizer = new wxBoxSizer(wxVERTICAL); + + ctlTopSizer->Add(ctlTextSizer, 0, wxALIGN_CENTER); + ctlTopSizer->Add(ctlButtonSizer, 0, wxALIGN_CENTER); + SetSizer(ctlTopSizer); + ctlTopSizer->SetSizeHints(this); +} + +BOOLEAN xvt_mail_send(const char* to, const char* cc, const char* ccn, + const char* subject, const char* msg, + const char* attach, short flags) +{ + const short mail_inst = xvt_mail_installed(); + wxString server, port, user, password, from; + bool mailsend = (mail_inst & 0x2) && GetMailParams(server, port, user, password, from); + bool ui = mailsend && ((flags & 0x1) != 0); + wxString str_to(to); + + if (ui) + { + wxEmailDlg dlg; + + dlg._strEmail = str_to; + if (dlg.ShowModal() == wxID_OK) + str_to = dlg._strEmail; + } + + wxStringTokenizer tokTo(str_to, _T(";")); + wxMailMessage Msg(subject, tokTo.GetNextToken(), msg); + + Msg.m_query_receipt = flags & 0x2; + + while (tokTo.HasMoreTokens()) + Msg.AddTo(tokTo.GetNextToken()); + if (Msg.m_to[0].IsEmpty()) + { + Msg.m_to[0] = " "; // Il destinatario "" fa piantare MAPI con errore 25 + ui = true; // Forza user interface in assenza di recipient + } + + if (attach && *attach) + { + wxStringTokenizer tokAttach(attach, _T(";")); + while (tokAttach.HasMoreTokens()) + Msg.AddAttachment(tokAttach.GetNextToken()); + } + + if (cc && *cc) + { + wxStringTokenizer Tok(cc, _T(";")); + while (Tok.HasMoreTokens()) + Msg.AddCc(Tok.GetNextToken()); + } + + if (ccn && *ccn) + { + wxString strCCn(ccn); + + if (has_ccnsend()) + strCCn << ";" << from; + wxStringTokenizer Tok(strCCn, _T(";")); + + while (Tok.HasMoreTokens()) + Msg.AddBcc(Tok.GetNextToken()); + } + + BOOLEAN ok = false; + + if (mailsend) + { + wxString cmd = "servers/mailsend.exe"; + AppendQuotedString(cmd, "smtp", server); + if (!port.IsEmpty()) + { + cmd += " -port "; + cmd += port; + } + AppendQuotedString(cmd, "from", from); + + if ((flags & 0x2) && from.Find("@") > 0) + { + //AppendQuotedString(cmd, "rt", from); + AppendQuotedString(cmd, "rrr", from); + } + + // Lista dei destinatari + for (size_t i = 0; i < Msg.m_to.size(); i++) + AppendQuotedString(cmd, "to", Msg.m_to[i]); + + // Lista dei destinatari in copia + for (size_t i = 0; i < Msg.m_cc.size(); i++) + AppendQuotedString(cmd, "cc", Msg.m_cc[i]); + if (cmd.Find("-cc") < 0) + cmd += " +cc"; // In assenza di destinatari in copia aggiungo +cc + + // Lista dei destinatari in copia nascosta + for (size_t i = 0; i < Msg.m_bcc.size(); i++) + AppendQuotedString(cmd, "bc", Msg.m_bcc[i]); + if ((flags & 0x4) && from.Find("@") > 0) + { + wxString strMyself; strMyself << "c " << from; + if (cmd.Find(strMyself) < 0) + AppendQuotedString(cmd, "bc", from); // Aggiungo me stesso ai destinatari nascosti + } + if (cmd.Find("-bc") < 0) + cmd += " +bc"; // In assenza di destinatari nascosti aggiungo +bc + + AppendQuotedString(cmd, "sub", Msg.m_subject); + AppendQuotedString(cmd, "user", user); + AppendQuotedString(cmd, "pass", password); + + AppendQuotedString(cmd, "enc-type", "base64"); + + if (!Msg.m_attachments.IsEmpty()) + { + for (size_t a = 0; a < Msg.m_attachments.size(); a++) + { + const wxString& fn = Msg.m_attachments[a]; + if (wxFileName::FileExists(fn)) + AppendAttachment(cmd, fn); + } + } + + wxString ftmp; + if (Msg.m_body.IsEmpty()) + { + if (cmd.Find("-M ") < 0) + { + wxString m; m << "Cordiali saluti\n" << from; + m.Trim(); + AppendQuotedString(cmd, "M", m); + } + } + else + { + wxStringTokenizer tok(Msg.m_body, "\n"); + Msg.m_body.Trim(); + if (Msg.m_body.Find("\n") < 0) + AppendQuotedString(cmd, "M", Msg.m_body); + else + { + DIRECTORY tmp; xvt_fsys_get_temp_dir(&tmp); + xvt_fsys_build_pathname(ftmp.GetWriteBuf(_MAX_PATH), NULL, tmp.path, "msgbody", "html", NULL); + ftmp.UngetWriteBuf(); + wxFile file(ftmp, wxFile::write); + file.Write("\n"); + Msg.m_body.Replace("\n", "
"); + file.Write(Msg.m_body); + file.Write("\n\n"); + file.Close(); + AppendAttachment(cmd, ftmp, false); + } + } + + const wxString strLog = "mailsend.log"; + xvt_fsys_remove_file(strLog); + AppendQuotedString(cmd, "log", strLog); + + int nRetry = wxAtoi(GetMailParam("Retry", "2")); + if (nRetry <= 0) nRetry = 2; + + ok = FALSE; + for (int r = 0; r < nRetry && !ok; r++) + { + if (r > 0) + { + const int nSeconds = 5*r; + WINDOW w = xvt_dm_progress_create(TASK_WIN, "MailSend retrying...", nSeconds, TRUE); + for (int s = 1; s <= nSeconds; s++) + { + xvt_sys_sleep(1000); + xvt_dm_progress_set_status(w, s, nSeconds); + } + xvt_dm_progress_destroy(w); + } + wxExecute(cmd, wxEXEC_SYNC); + wxFile fLog(strLog, wxFile::read); + const wxFileOffset flen = fLog.Length(); + if (flen > 0) + { + char* buff = (char*)calloc(flen+8, 1); // zero filled buffer + fLog.Read(buff, flen); + if (wxStrstr(buff, "Mail sent successfully")) + ok = TRUE; + delete [] buff; + } + } + } + else + if (mail_inst & 1) + { + xvt_fsys_save_dir(); + ok = Msg.Send(wxEmptyString, ui); + xvt_fsys_restore_dir(); + } + return ok; +} + + +void buildPSArray(wxString& str) +{ + if (str.Find(";") >= 0) + { + wxStringTokenizer str_tok(str, ";"); + + str = ""; + + while (str_tok.HasMoreTokens()) + { + if (str_tok.GetPosition() > 0) + str << ","; + str << '\'' << str_tok.GetNextToken() << '\''; + } + } + else + { + wxString wrkstr(str); + str = "\'"; + str << wrkstr << "\'"; + } +} + +BOOLEAN xvt_powermail_send(const char* to, const char* cc, const char* ccn, + const char* subject, const char* msg, + const char* attach, short flags, const char* usr) +{ + wxString server, port, user, password, from; + + // Controllo che Windows sia almeno 8 e che riesca a ricevere i parametri E-mail + if(xvt_sys_get_os_version() < XVT_WS_WIN_7 || !GetMailParams(server, port, user, password, from)) + xvt_mail_send(to, cc, ccn, subject, msg, attach, flags); + + wxString str_to(to); + + if ((flags & 0x1) != 0) + { + wxEmailDlg dlg; + + dlg._strEmail = str_to; + if (dlg.ShowModal() == wxID_OK) + str_to = dlg._strEmail; + } + + DIRECTORY tmp; xvt_fsys_get_temp_dir(&tmp); + + // Per togliere il rischio di sovrapposizioni vado nella cartella dell'utente + wxString userTemp; userTemp << tmp.path << "\\" << usr; + + wxString powerFile; + static int powerNumber = 0; + wxString powerName = "powermail_"; powerName << ++powerNumber; + xvt_fsys_build_pathname(powerFile.GetWriteBuf(_MAX_PATH), NULL, userTemp, powerName, "ps1", NULL); + powerFile.UngetWriteBuf(); + + // Creo il file + wxFile file(powerFile, wxFile::write); + + // Parsing port tokens + /* Token dictionary (all case insensitive): + * 465/587/... port + * -SSL Enable ssl/tls + * -nbcc No Blind Carbon Copy + */ + wxStringTokenizer portTok(port, " "); + wxString port_number; + bool ssl = false, hasccn = ccn && *ccn, hascc = cc && *cc; + + while(portTok.HasMoreTokens()) + { + wxString tok = portTok.GetNextToken(); + if (tok[0] >= '0' && tok[0] <= '9') + port_number = tok; + if (tok.Upper() == "-SSL") + ssl = true; + if (tok.Upper() == "-NBCC") + hasccn = false; + } + + // Hard code and no play makes Tolla a dull programmer + file.Write("$Server = \""); file.Write(server); file.Write("\"\n"); + + file.Write("$Port = \""); file.Write(port_number); file.Write("\"\n"); + file.Write("$SSL = "); + + if(ssl) + file.Write("$true"); + else + file.Write("$false"); + + file.Write("\n"); + file.Write("$Username = \""); file.Write(user); file.Write("\"\n"); + file.Write("$Password = \""); file.Write(password); file.Write("\"\n"); + file.Write("$From = \""); file.Write(from); file.Write("\"\n"); + + + buildPSArray(str_to); + file.Write("$To = "); file.Write(str_to); file.Write("\n"); + file.Write("$Subject = \""); file.Write(subject); file.Write("\"\n"); + file.Write("$Body = \""); file.Write(msg); file.Write("\"\n"); + + if (hascc) + { + wxString str_cc(cc); + + buildPSArray(str_cc); + file.Write("$CC = "); file.Write(str_cc); file.Write("\n"); + } + + if (hasccn || has_ccnsend()) + { + wxString str_ccn(from); + + if (ccn && *ccn) + str_ccn << ";" << ccn; + buildPSArray(str_ccn); + file.Write("$Bcc = "); file.Write(str_ccn); file.Write("\n"); + } + + file.Write( + "$message = new-object Net.Mail.MailMessage\n" + "$message.From = $From\n" + "$message.To.Add($To)\n"); + + //TODO same per from e to + //mettere un flag nella mask per decidere se mettere in CC o in CCn + if (hascc) + { + file.Write("foreach($i in $CC)\n" + "{ $message.CC.Add($i) }\n"); + } + if (hasccn || has_ccnsend()) + { + file.Write("foreach($i in $Bcc)\n" + "{ $message.Bcc.Add($i)}\n"); + } + + file.Write( + "$message.Subject = $Subject\n" + "$message.Body = $Body\n" + ); + + if (flags & 0x2) + file.Write("$message.DeliveryNotificationOptions = 1\n"); + + // Aggiungo a schiena gli allegati + if (attach && *attach) + { + wxStringTokenizer tokAttach(attach, _T(";")); + int i = 0; + while (tokAttach.HasMoreTokens()) + { + wxString attachmentLine; + attachmentLine << "$attach" << ++i << "= New-Object Net.Mail.Attachment(\"" + << tokAttach.GetNextToken() << "\");\n" << "$message.Attachments.Add(" + << "$attach" << i << ")\n"; + file.Write(attachmentLine); + } + } + + file.Write( + "$smtp = new-object Net.Mail.SmtpClient($Server, $Port);\n" + "$smtp.EnableSSL = $SSL;\n" + "$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);\n" + "try\n" + "{\n" + " $smtp.send($message);\n" + " write-host \"E-Mail sent\" \n" + " $exitCode = 0 \n" + " exit $exitCode \n" + "}\n" + "catch\n" + "{\n" + " write-host \"E-Mail not sent\" ; \n" + " write-host $_.Exception.Message ;\n" + " $exitCode = 1 \n" + " exit $exitCode \n" + "}\n" + ); + file.Close(); + + wxString command("powershell.exe "); + + //una volta scritto lo scritp ps1 cos'è che lo runna? Dove vinene aperta la PowerShell? + // al momento lo script generato da campo funziona se runnato direttamente da powershell + command << powerFile; + + FILE *f; + + fopen_s(&f, "maillog.log", "w"); + fprintf(f, "Comando %s\n", (const char*)command); + int exit = xvt_sys_execute(command, true, true); + fprintf(f, "exitcode = %d\n", exit); + fclose(f); + return exit == 0; +} + +BOOLEAN xvt_wx_mail_send(const char* to, const char* cc, const char* ccn, + const char* subject, const char* msg, + const char* attach, short flags) +{ + wxString server, port, user, password, from; + GetMailParams(server, port, user, password, from); + bool ui = (flags & 0x1) != 0; + wxSMTP * Smtp = new wxSMTP(nullptr); + wxString str_to(to); + bool ok = true; + + if (ui) + { + wxEmailDlg dlg; + + dlg._strEmail = str_to; + if (dlg.ShowModal() == wxID_OK) + str_to = dlg._strEmail; + } + + wxStringTokenizer tokTo(str_to, _T(";")); + wxEmailMessage * Msg = new wxEmailMessage(subject, msg, from); + +// da trovare Msg->m_query_receipt = flags & 0x2; + while (tokTo.HasMoreTokens()) + Msg->AddTo(tokTo.GetNextToken()); + if (attach && *attach) + { + wxStringTokenizer tokAttach(attach, _T(";")); + while (tokAttach.HasMoreTokens()) + Msg->AddFile(tokAttach.GetNextToken()); + } + if (cc && *cc) + { + wxStringTokenizer Tok(cc, _T(";")); + while (Tok.HasMoreTokens()) + Msg->AddCc(Tok.GetNextToken()); + } + if (ccn && *ccn) + { + wxString strCCn(ccn); + + if (has_ccnsend()) + strCCn << ";" << from; + wxStringTokenizer Tok(strCCn, _T(";")); + while (Tok.HasMoreTokens()) + Msg->AddBcc(Tok.GetNextToken()); + } + + int service = atoi(port); + + if (service == 0) + service = 25; + Smtp->SetHost(server, service, from, password); + Smtp->Send(Msg); + Smtp->SendData(); + delete Msg; + delete Smtp; + return ok; +} \ No newline at end of file diff --git a/src/xvaga01/xvtodbc.cpp b/src/xvaga01/xvtodbc.cpp new file mode 100644 index 000000000..878e18e4d --- /dev/null +++ b/src/xvaga01/xvtodbc.cpp @@ -0,0 +1,298 @@ +#include "wxinc.h" +#include "xvt.h" + +#include + +/////////////////////////////////////////////////////////// +// TwxConnectionDlg +/////////////////////////////////////////////////////////// + +class TwxConnectionDlg : public wxDialog +{ +protected: + wxTextCtrl* AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str); + +public: + wxString _strDsn, _strUsr, _strPwd, _strDir; + + TwxConnectionDlg(); +}; + +wxTextCtrl* TwxConnectionDlg::AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str) +{ + wxStaticText* lbl = new wxStaticText(this, wxID_ANY, label); + + const int k = 20, b = k/10; + wxTextCtrl* txt = new wxTextCtrl(this, id, wxEmptyString, wxDefaultPosition, wxSize(20*k, k), + 0, wxTextValidator(wxFILTER_ASCII, str)); + ctlSizer->Add(lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, b); + ctlSizer->Add(txt, 1, wxALIGN_LEFT | wxALL, b); + + return txt; +} + +TwxConnectionDlg::TwxConnectionDlg() : wxDialog(NULL, wxID_ANY, "ODBC", + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE) +{ + wxSizer* ctlTextSizer = new wxFlexGridSizer(4, 2, 8, 8); + AddString(ctlTextSizer, 1001, "Dsn", &_strDsn); + AddString(ctlTextSizer, 1002, "User", &_strUsr); + AddString(ctlTextSizer, 1003, "Password", &_strPwd); + AddString(ctlTextSizer, 1004, "Directory", &_strDir); + + wxSizer* ctlButtonSizer = CreateButtonSizer(wxOK | wxCANCEL); + + wxBoxSizer* ctlTopSizer = new wxBoxSizer(wxVERTICAL); + ctlTopSizer->Add(ctlTextSizer, 0, wxALIGN_CENTER); + ctlTopSizer->Add(ctlButtonSizer, 0, wxALIGN_CENTER); + + SetSizer(ctlTopSizer); + ctlTopSizer->SetSizeHints(this); +} + +/////////////////////////////////////////////////////////// +// xvt_odbc_... +/////////////////////////////////////////////////////////// + +static wxDbConnectInf* ci = nullptr; +static wxString strDsn, strUsr, strPwd, strDir; + +XVT_ODBC xvt_odbc_get_connection(const char* dsn, const char* usr, const char* pwd, const char* dir) +{ + if (strDsn != dsn && ci != nullptr) + { + delete ci; + ci = nullptr; + } + + strDsn = dsn; + strUsr = usr; + strPwd = pwd; + strDir = dir; + + if (strDsn.IsEmpty()) + { + TwxConnectionDlg* dlg = new TwxConnectionDlg; + if (dlg->ShowModal() == wxID_OK) + { + strDsn = dlg->_strDsn; + strUsr = dlg->_strUsr; + strPwd = dlg->_strPwd; + strDir = dlg->_strDir; + } + dlg->Destroy(); + if (strDsn.IsEmpty()) + return (XVT_ODBC)nullptr; + } + if (ci == nullptr) + { + ci = new wxDbConnectInf(NULL, strDsn, strUsr, strPwd, strDir); + + // Set the ODBC version environment + SQLSetEnvAttr(ci->GetHenv(), SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER); + } + + bool bSuccess = false; + wxDb* db = new wxDb(ci->GetHenv(), true); + + if (strDsn.Find(';') > 0) + bSuccess = db->Open(strDsn); // Use connection string + else + bSuccess = db->Open(ci); // Use DSN, user and password + + if (!bSuccess) + { + int err = db->DB_STATUS; + + db->DispNextError(); + if (ci != nullptr) + { + delete ci; + ci = nullptr; + } + strDsn = ""; + delete db; + db = nullptr; + } + + return (XVT_ODBC)db; +} + +BOOLEAN xvt_odbc_free_connection(XVT_ODBC handle) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + wxDb* db = (wxDb*)handle; + db->CommitTrans(); + db->Close(); + if (ci != nullptr) + { + delete ci; + ci = nullptr; + } + strDsn = ""; + delete db; + } + return ok; +} + +BOOLEAN xvt_odbc_log_file(XVT_ODBC handle, const char* str) +{ + BOOLEAN ok = handle != NULL; + if (ok) + { + wxDb* db = (wxDb*)handle; + if (str && *str) + ok = db->SetSqlLogging(sqlLogON, wxString(str)); + else + db->SetSqlLogging(sqlLogOFF, wxEmptyString); + } + return ok; +} + +ULONG xvt_odbc_execute(XVT_ODBC handle, const char* sql, ODBC_CALLBACK cb, void* jolly) +{ + ULONG nCount = 0; + + if (handle && sql && *sql) + { + wxDb* db = (wxDb*)handle; + + if (cb != NULL) // Ho una vera callback? + { + wxDbColInf* columns = NULL; + short numcols = 0; + + if (db->ExecSql(sql, &columns, numcols) && numcols > 0) + { + const size_t BUF_SIZE = 1024*64; + char* buffer = new char[BUF_SIZE]; // Valore di un singolo campo + + char** values = new char*[numcols]; // Lista dei valori del record corrente + memset(values, 0, numcols*sizeof(char*)); + + char** names = new char*[numcols*2]; // Lista dei nomi dei campi e dei tipi + memset(names, 0, numcols*2*sizeof(char*)); + + short c; + for (c = 0; c < numcols; c++) + { + const wxDbColInf& info = columns[c]; + names[c] = (char*)info.colName; + switch (info.dbDataType) + { + case DB_DATA_TYPE_INTEGER: + case DB_DATA_TYPE_FLOAT: + names[c+numcols] = "NUMERIC"; break; + case DB_DATA_TYPE_DATE: + names[c+numcols] = "DATE"; break; + default: + names[c+numcols] = "VARCHAR"; break; + } + } + + wxArrayString data; + for (nCount = 0; db->GetNext(); nCount++) + { + data.Empty(); // Svuota l'array + for (c = 0; c < numcols; c++) + { + const wxDbColInf& info = columns[c]; + + try + { + SDWORD cbReturned = SQL_NULL_DATA; + + switch (info.dbDataType) + { + case DB_DATA_TYPE_DATE: + { + db->GetData(c+1, SQL_C_CHAR, buffer, BUF_SIZE, &cbReturned); + int d = 0, m = 0, y = 0; + int n = sscanf(buffer, "%04d-%02d-%02d", &y, &m, &d); + if (n == 3 && d > 0) + sprintf(buffer, "%04d%02d%02d", y, m, d); + else + buffer[0] = '\0'; + } + break; + default: + db->GetData(c+1, SQL_C_CHAR, buffer, BUF_SIZE, &cbReturned); + break; + } + if (cbReturned == SQL_NULL_DATA) + buffer[0] = '\0'; + data.Add(buffer); + } + catch (...) + { + break; + } + } + for (c = 0; c < (short)data.GetCount(); c++) + values[c] = (char*)data[c].c_str(); + const int err = cb(jolly, numcols, values, names); + if (err != 0) + break; + } + + delete values; // butta la lista dei valori + delete names; // butta la lista dei nomi + delete buffer; // butta il buffer temporaneo + } + } + else + { + wxString cmd(sql); cmd.MakeUpper(); + + if (cmd.StartsWith("BEGIN")) + /* DO NOTHING! */; else + if (cmd.StartsWith("COMMIT")) + db->CommitTrans(); else + if (cmd.StartsWith("SELECT")) + { + // Senza callback mi limito a contare i records + if (db->ExecSql(sql)) + for (nCount = 0; db->GetNext(); nCount++); + else + nCount = -db->nativeError; + } + else + if (cmd.StartsWith("SHOW")) + { + if (db->ExecSql(sql)) + for (nCount = 0; db->GetNext(); nCount++); + else + nCount = -db->nativeError; + } + else + { + db->SetDebugErrorMessages(true); + if (db->ExecSql(sql)) + nCount = 1; + else + nCount = -db->nativeError; + db->SetDebugErrorMessages(false); + } + } + } + + return nCount; +} + +BOOLEAN xvt_odbc_driver(XVT_ODBC handle, char* str, int max_size) +{ + if (str != NULL && max_size > 8) + { + if (handle != NULL) + { + const wxDb* db = (const wxDb*)handle; + wxStrncpy(str, db->dbInf.driverName, max_size); + } + else + wxStrncpy(str, "ODBC 2.0", max_size); + } + return handle != NULL; +} diff --git a/src/xvaga01/xvtpdf.cpp b/src/xvaga01/xvtpdf.cpp new file mode 100644 index 000000000..54389187f --- /dev/null +++ b/src/xvaga01/xvtpdf.cpp @@ -0,0 +1,1233 @@ +#include "wxinc.h" + +#include "XFont.h" +#include "xvtpdf.h" + +#define RAD2DEG 57.29577951308 +#define BEZIERK 0.55228475 +#define PDF_DPI 720 + +IMPLEMENT_DYNAMIC_CLASS(TwxPDFDC, wxDC) + +//-- Contructor and Destructor ------------------------------------------- + +TwxPDFDC::TwxPDFDC() +{ + wxASSERT(false); // Dummy constructor! +} + +TwxPDFDC::TwxPDFDC (const wxPrintData& printData, const char* strFilename) + : m_PDFlib(NULL), m_p(NULL), m_fileName(strFilename) +{ + m_pageNumber = 0; + m_topDown = true; + m_clipping = false; + m_pageopen = false; + m_printData = printData; + + for(int i=0; i < PDF_IMG_CACHE_SIZE; i++) + { + m_filenames[i].Empty(); + m_handles[i] = 0; + } + m_cacheidx = 0; + + m_PDFlib = PDF_new_dl(&m_p); + m_ok = m_PDFlib != NULL; + if (!m_ok) + ::wxMessageBox(_("Cannot create PDFlib object (DLL not found?)"), "PDFlib", wxOK|wxICON_ERROR); +} + +TwxPDFDC::~TwxPDFDC () +{ + if (m_PDFlib != NULL) + { + PDF_delete_dl(m_PDFlib, m_p); + m_PDFlib = NULL; + m_p = NULL; + } +} + +//-- Status -------------------------------------------------------------- + +bool TwxPDFDC::Ok() const +{ return m_ok; } + +//-- Document and Pages -------------------------------------------------- + +bool TwxPDFDC::StartDoc( const wxString& message ) +{ + wxCHECK_MSG( m_ok, FALSE, wxT("invalid PDF dc") ); + + if (m_PDFlib->PDF_begin_document(m_p, m_fileName, 0, "") == -1) + { + wxLogError( _("Cannot open file for PDF printing!")); + return m_ok = false; + } + + PDF_TRY_DL(m_PDFlib, m_p) + { + wxString strFontPath; + wxChar* lpszFontPath = strFontPath.GetWriteBuf(_MAX_PATH); + ::GetFontsFolder(lpszFontPath, _MAX_PATH); + strFontPath.UngetWriteBuf(); + m_PDFlib->PDF_set_parameter(m_p, "SearchPath", strFontPath); + + const wxString strUser = wxGetUserId(); + m_PDFlib->PDF_set_info(m_p, "Author", strUser); + m_PDFlib->PDF_set_info(m_p, "Creator", "Campo"); + m_PDFlib->PDF_set_info(m_p, "Title", message); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + m_ok = false; + } + + m_pageNumber = 0; + return m_ok = true; +} + +void TwxPDFDC::EndDoc () +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + ResetClipping(); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_end_document(m_p, ""); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + m_ok = false; + } +} + +void TwxPDFDC::StartPage() +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + if (m_pageopen) + return; + + m_pageNumber++; + SetAxisOrientation(true, false); + + PDF_TRY_DL(m_PDFlib, m_p) + { + int size_x, size_y; DoGetSize(&size_x, &size_y); + const double scale = 72.0 / PDF_DPI; + m_PDFlib->PDF_begin_page_ext(m_p, size_x*scale, size_y*scale, ""); + m_PDFlib->PDF_scale(m_p, scale, scale); + m_pageopen = true; + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + m_ok = false; + } + + SetBrush(*wxBLACK_BRUSH); + SetPen(*wxBLACK_PEN); + SetBackground(*wxWHITE_BRUSH); + SetTextForeground(*wxBLACK); +} + +void TwxPDFDC::EndPage() +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!m_ok || !m_pageopen) + return; + + if (m_clipping) + DestroyClippingRegion(); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_end_page_ext(m_p, ""); + m_pageopen = false; + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + m_ok = false; + } +} + +//-- Graphics ------------------------------------------------------------ + +void TwxPDFDC::DoDrawPoint(wxCoord x, wxCoord y) +{ + DoDrawLine(x, y, x+1, y); +} + +void TwxPDFDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT) + return; + + SetPen(m_pen); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_moveto(m_p, x1, y1); + m_PDFlib->PDF_lineto(m_p, x2, y2); + m_PDFlib->PDF_stroke(m_p); + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawLines (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT) + return; + + if (n <= 0) + return; + + SetPen(m_pen); + + PDF_TRY_DL(m_PDFlib, m_p) + { + int i; + CalcBoundingBox(points[0].x+xoffset, points[0].y+yoffset); + m_PDFlib->PDF_moveto(m_p, points[0].x+xoffset, points[0].y+yoffset); + for (i=1;iPDF_lineto(m_p, points[i].x+xoffset, points[i].y+yoffset); + CalcBoundingBox(points[i].x+xoffset, points[i].y+yoffset); + } + m_PDFlib->PDF_stroke(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawPolygon (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle)) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (n <= 0) + return; + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + PDF_TRY_DL(m_PDFlib, m_p) + { + CalcBoundingBox(points[0].x + xoffset, points[0].y + yoffset); + m_PDFlib->PDF_moveto(m_p, points[0].x+xoffset, points[0].y+yoffset); + for (int i=1;iPDF_lineto(m_p, points[i].x+xoffset, points[i].y+yoffset); + CalcBoundingBox(points[i].x+xoffset, points[i].y+yoffset); + } + m_PDFlib->PDF_closepath(m_p); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_rect(m_p, x, y + height, width, height); + CalcBoundingBox( x, y ); + CalcBoundingBox( x + width, y + height ); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + const wxCoord radius = (wxCoord)_hypot(x1 - xc, y1 - yc) / 2; + double alpha1, alpha2; + + if (x1 == x2 && y1 == y2) + { + alpha1 = 0.0; + alpha2 = 360.0; + } + else if (radius == 0.0) + { + alpha1 = alpha2 = 0.0; + } + else + { + alpha1 = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1-yc), double(x1-xc)) * RAD2DEG; + alpha2 = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2-yc), double(x2-xc)) * RAD2DEG; + } + while (alpha1 < 0) alpha1 += 360; + while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between + while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree + while (alpha2 > 360) alpha2 -= 360; + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_moveto(m_p, xc, yc); + m_PDFlib->PDF_arc(m_p, xc, yc, radius, alpha1, alpha2); + m_PDFlib->PDF_closepath(m_p); + + CalcBoundingBox( xc-radius, yc-radius ); + CalcBoundingBox( xc+radius, yc+radius ); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + PDF_TRY_DL(m_PDFlib, m_p) + { + width /= 2; + height /= 2; + x += width; + y += height; + m_PDFlib->PDF_moveto(m_p, x+width, y); + m_PDFlib->PDF_curveto(m_p, x+width, y+BEZIERK*height, x+BEZIERK*width, y+height, x, y+height); + m_PDFlib->PDF_curveto(m_p, x-BEZIERK*width, y+height, x-width, y+BEZIERK*height, x-width, y); + m_PDFlib->PDF_curveto(m_p, x-width, y-BEZIERK*height, x-BEZIERK*width, y-height, x, y-height); + m_PDFlib->PDF_curveto(m_p, x+BEZIERK*width, y-height, x+width, y-BEZIERK*height, x+width, y); + m_PDFlib->PDF_closepath(m_p); + CalcBoundingBox(x-width, y-height); + CalcBoundingBox(x+width, y+height); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (sa>=360 || sa<=-360) sa=sa-int(sa/360)*360; + if (ea>=360 || ea<=-360) ea=ea-int(ea/360)*360; + if (sa<0) sa+=360; + if (ea<0) ea+=360; + + if (sa==ea) + { + DrawEllipse(x,y,w,h); + return; + } + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_save(m_p); + m_PDFlib->PDF_moveto(m_p, x, y); + m_PDFlib->PDF_scale(m_p, 1, h/w); + m_PDFlib->PDF_arc(m_p, x, y, w, sa, ea); + m_PDFlib->PDF_closepath(m_p); + + CalcBoundingBox( x ,y ); + CalcBoundingBox( x+w, y+h ); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + + m_PDFlib->PDF_restore(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawRoundedRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT && m_brush.GetStyle() == wxTRANSPARENT) + return; + + if (m_pen.GetStyle () != wxTRANSPARENT) + SetPen(m_pen); + + if (m_brush.GetStyle() != wxTRANSPARENT) + SetBrush(m_brush); + + if (radius < 0.0) + { + const double smallest = width < height ? width : height; + radius = (-radius * smallest); + } + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_moveto(m_p, x, y+radius); + m_PDFlib->PDF_lineto(m_p, x, y+height-radius); + m_PDFlib->PDF_arc(m_p, x+radius, y+height-radius, radius, 180, 270); + m_PDFlib->PDF_lineto(m_p, x+width-radius, y+height); + m_PDFlib->PDF_arc(m_p, x+width-radius, y+height-radius, radius, 270, 360); + m_PDFlib->PDF_lineto(m_p, x+width, y+radius); + m_PDFlib->PDF_arc(m_p, x+width-radius, y+radius, radius, 0, 90); + m_PDFlib->PDF_lineto(m_p, x+radius, y); + m_PDFlib->PDF_arc(m_p, x+radius, y+radius, radius, 90, 180); + m_PDFlib->PDF_closepath(m_p); + + CalcBoundingBox(x ,y); + CalcBoundingBox(x+width, y+height); + + if (m_pen.GetStyle () != wxTRANSPARENT && m_brush.GetStyle() != wxTRANSPARENT) + m_PDFlib->PDF_fill_stroke(m_p); + else + { + if (m_pen.GetStyle () != wxTRANSPARENT) + m_PDFlib->PDF_stroke(m_p); + else + m_PDFlib->PDF_fill(m_p); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawSpline( wxList *points ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + SetPen(m_pen); + + double a, b, c, d, x1, y1, x2, y2, x3, y3; + wxPoint *p, *q; + + wxNode *node = points->GetFirst(); + p = (wxPoint *)node->GetData(); + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + c = p->x; + d = p->y; + x3 = a = (double)(x1 + c) / 2; + y3 = b = (double)(y1 + d) / 2; + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_moveto(m_p, x1, y1); + m_PDFlib->PDF_lineto(m_p, x3, y3); + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + + while ((node = node->GetNext()) != NULL) + { + q = (wxPoint *)node->GetData(); + + x1 = x3; + y1 = y3; + x2 = c; + y2 = d; + c = q->x; + d = q->y; + x3 = (double)(x2 + c) / 2; + y3 = (double)(y2 + d) / 2; + + m_PDFlib->PDF_curveto(m_p, x1, y1, x2, y2, x3, y3); + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + } + + m_PDFlib->PDF_lineto(m_p, c, d); + m_PDFlib->PDF_stroke(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + PDF_TRY_DL(m_PDFlib, m_p) + { + const double ir = initialColour.Red() / 255.0; + const double ig = initialColour.Green() / 255.0; + const double ib = initialColour.Blue() / 255.0; + const double fr = destColour.Red() / 255.0; + const double fg = destColour.Green() / 255.0; + const double fb = destColour.Blue() / 255.0; + const double x = rect.x; + const double y = rect.y; + const double w = rect.width; + const double h = rect.height; + + m_PDFlib->PDF_save(m_p); + m_PDFlib->PDF_setcolor(m_p, "fill", "rgb", ir, ig, ib, 0); + m_PDFlib->PDF_moveto(m_p, x, y); + m_PDFlib->PDF_lineto(m_p, x+w, y); + m_PDFlib->PDF_lineto(m_p, x+w, y+h); + m_PDFlib->PDF_lineto(m_p, x, y+h); + m_PDFlib->PDF_closepath(m_p); + m_PDFlib->PDF_clip(m_p); + CalcBoundingBox(x ,y); + CalcBoundingBox(x+w, y+h); + + double x0=x,y0=y+h/2,x1=x+w,y1=y0; + switch (nDirection) + { + case wxNORTH: x0=x+w/2; y0=y+h; x1=x0; y1 = y; break; + case wxSOUTH: x0=x+w/2; y0=y; x1=x0; y1 = y+h; break; + case wxWEST : x0=x+w; y0=y+h/2; x1=x; y1 = y0; break; + case wxEAST : + default : x0=x; y0=y+h/2; x1=x+w; y1 = y0; break; + } + const int sh = m_PDFlib->PDF_shading(m_p, "axial", x0, y0, x1, y1, fr, fg, fb, 0.0, ""); + m_PDFlib->PDF_shfill(m_p, sh); + m_PDFlib->PDF_restore(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +//-- Images and Bitmaps -------------------------------------------------- + +void TwxPDFDC::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y ) +{ + DrawBitmap( icon, x, y, TRUE ); +} + +void TwxPDFDC::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!bitmap.Ok()) + return; + + int intImgHandle = GetBitmapHandle(bitmap); + const wxCoord h = bitmap.GetHeight(); + + if (intImgHandle<0) + return; + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_fit_image(m_p, intImgHandle, x, y+h, ""); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::DoDrawImage( const wxString& name, const wxRect& dst ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + const int intImgHandle = GetImageHandle(name); + if (intImgHandle<0) + return; + + PDF_TRY_DL(m_PDFlib, m_p) + { + wxString strOptions; + strOptions.Printf("boxsize={%d %d} fitmethod=entire", dst.GetWidth(), dst.GetHeight()); + m_PDFlib->PDF_fit_image(m_p, intImgHandle, dst.GetX(), dst.GetY()+dst.GetHeight(), strOptions); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +int TwxPDFDC::GetBitmapHandle(const wxBitmap& bitmap) const +{ + wxString strFilename = wxGetTempFileName(wxT("tmpbmp")); + ((wxBitmap&)bitmap).SaveFile(strFilename, wxBITMAP_TYPE_PNG); + + PDF_TRY_DL(m_PDFlib, m_p) + { + return m_PDFlib->PDF_load_image(m_p, "png", strFilename, 0, ""); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + + return -1; +} + +int TwxPDFDC::GetImageHandle(const wxString& name) +{ + int intFound = -1; + + if (!name.IsEmpty()) + { + for (int i=PDF_IMG_CACHE_SIZE; i>0; i--) + { + const int idx = (i + m_cacheidx) % PDF_IMG_CACHE_SIZE; + if (m_filenames[idx]==name) + { + intFound = idx; + break; + } + } + // Se non la trovo, provo ad aggiungerla + if (intFound<0 && m_cacheidxPDF_load_image(m_p, "auto", name, 0, ""); + if (intNewHandle >=0 ) + { + PDF_TRY_DL(m_PDFlib, m_p) + { + m_filenames[m_cacheidx] = name; + m_handles[m_cacheidx] = intNewHandle; + intFound = m_cacheidx++; + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + } + } + } + + return intFound >= 0 ? m_handles[intFound] : -1; +} + +bool TwxPDFDC::DoBlit( wxCoord xdest, wxCoord ydest, + wxCoord fwidth, wxCoord fheight, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + int rop, bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) ) +{ + wxCHECK_MSG( m_ok, FALSE, wxT("invalid PDF dc") ); + wxCHECK_MSG( source, FALSE, wxT("invalid source dc") ); + + wxBitmap bitmap( (int)fwidth, (int)fheight ); + wxMemoryDC memDC; + memDC.SelectObject(bitmap); + memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); + memDC.SelectObject(wxNullBitmap); + + DrawBitmap( bitmap, xdest, ydest ); + + return TRUE; +} + +//-- Text ---------------------------------------------------------------- + +void TwxPDFDC::DoDrawText( const wxString& text, wxCoord x, wxCoord y ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + SetFont(m_font); + SetFontColor(m_textForegroundColour); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_set_text_pos(m_p, x, y + m_ascent); + m_PDFlib->PDF_show(m_p, text); + wxCoord text_w = m_PDFlib->PDF_stringwidth(m_p, text, m_fontnr, m_fontsize); + CalcBoundingBox( x, y ); + CalcBoundingBox( x + text_w , y + m_fontsize ); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + + SetBrush(m_brush); +} + +void TwxPDFDC::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle ) +{ + if (angle == 0.0) + { + DoDrawText(text, x, y); + return; + } + + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + SetFont( m_font ); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_save(m_p); + m_PDFlib->PDF_set_text_pos(m_p, x, y); + m_PDFlib->PDF_translate(m_p, x, y); + m_PDFlib->PDF_rotate(m_p, angle); + m_PDFlib->PDF_show(m_p, text); + m_PDFlib->PDF_restore(m_p); + + CalcBoundingBox( x, y ); + CalcBoundingBox( m_PDFlib->PDF_get_value(m_p, "textx", x), m_PDFlib->PDF_get_value(m_p, "texty", y) ); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +wxCoord TwxPDFDC::GetCharHeight() const +{ + wxCoord y = 0; + DoGetTextExtent("M", NULL, &y, NULL, NULL, NULL); + return y; +} + +wxCoord TwxPDFDC::GetCharWidth() const +{ + wxCoord x = 0; + DoGetTextExtent("M", &x, NULL, NULL, NULL, NULL); + return x; +} + +void TwxPDFDC::DoGetTextExtent(const wxString& text, + wxCoord *x, wxCoord *y, + wxCoord *d, wxCoord *e, + wxFont *theFont ) const +{ + PDF_TRY_DL(m_PDFlib, m_p) + { + if (d) *d = 0; + if (e) *e = 0; + if (m_font.Ok() && (theFont==NULL || *theFont==m_font)) + { + if (x) *x = m_PDFlib->PDF_stringwidth(m_p, text, m_fontnr, m_fontsize); + if (y) *y = m_fontsize; + if (d) *d = m_descent; + if (e) *e = m_leading; + } + else + { + if (theFont!=NULL) + { + wxString strStyle = (theFont->GetWeight()==wxBOLD?"bold":""); + strStyle += (theFont->GetStyle()==wxITALIC?"italic":""); + wxString strFamily = theFont->GetFaceName(); + double fontsize = theFont->GetPointSize(); + int fontnr = m_PDFlib->PDF_load_font(m_p, strFamily, 0, "auto", "fontstyle {" + strStyle + "}"); + if (x) *x = m_PDFlib->PDF_stringwidth(m_p, text, fontnr, fontsize); + if (y) *y = fontsize; + if (d) *d = fontsize/5; + if (e) *e = fontsize/10; + } + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +//-- Settings ------------------------------------------------------------ + +bool TwxPDFDC::IsValidFontFile(const char* szFontFile) const +{ + wxString strFile = szFontFile; + strFile.MakeLower(); + return strFile.EndsWith(".ttf"); +} + +bool TwxPDFDC::GetFontFamily(const wxFont& font, wxString& file, wxString& family) const +{ + static wxFont m_LastFont; + static wxString m_LastFile, m_strFamily; + + if (!m_LastFont.IsOk() || + font.GetPointSize()!= m_LastFont.GetPointSize() || // FAMILY NON DOVREBBE DIPENDERE DA POINTSIZE! + font.GetWeight() != m_LastFont.GetWeight() || + font.GetStyle() != m_LastFont.GetStyle() || + font.GetFaceName() != m_LastFont.GetFaceName()) + { + wxString strStyle = font.GetWeight() >= wxBOLD ? " Bold" : ""; + strStyle += font.GetStyle() == wxITALIC ? " Italic" : ""; + m_strFamily = font.GetFaceName(); + + TCHAR szDisplayName[MAX_PATH], szFontFile[MAX_PATH]; + bool ok = GetFontFile(m_strFamily + strStyle, szDisplayName, MAX_PATH, szFontFile, MAX_PATH) != 0; + if (ok) + m_strFamily += strStyle; + else + ok = GetFontFile(m_strFamily, szDisplayName, MAX_PATH, szFontFile, MAX_PATH) != 0; + + m_LastFont = font; + if (ok) + m_LastFile = szFontFile; + else + m_LastFile = m_strFamily = wxEmptyString; + + if (!IsValidFontFile(szFontFile)) + { + const wxFont swiss(font.GetPointSize(), font.GetFamily(), font.GetStyle(), + font.GetWeight(), font.GetUnderlined()); + return GetFontFamily(swiss, file, family); + } + } + + file = m_LastFile; + family = m_strFamily; + return !file.IsEmpty(); +} + +void TwxPDFDC::SetFont( const wxFont& font ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!font.Ok()) + return; + + wxString strFontFile, strFamily; + bool ok = GetFontFamily(font, strFontFile, strFamily); + if (ok) + { + PDF_TRY_DL(m_PDFlib, m_p) + { + const wxString strScope = m_PDFlib->PDF_get_parameter(m_p, "scope", 0); + if (strScope != "document") // Solitamente strScope = "page" + { + const wxString strParameter = strFamily + "=" + strFontFile; + m_PDFlib->PDF_set_parameter(m_p, "FontOutline", strParameter); + m_fontsize = font.GetPointSize(); + + // maialata gigante da eliminare data dal fatto che a volte la GetPointSize() scazza + // completamente a ritornare la dimensione (problema di wxWindoz) e ritorna un valore + // molto molto minore di quello effettivo + if (m_fontsize < 36) + m_fontsize *= 9; + m_descent = m_fontsize/5; + m_ascent = m_fontsize-m_descent; + m_leading = m_descent/2; + + m_font = font; + m_fontnr = m_PDFlib->PDF_load_font(m_p, strFamily, 0, "host", ""); + + m_PDFlib->PDF_setfont(m_p, m_fontnr, m_fontsize); + m_PDFlib->PDF_set_parameter(m_p, "underline", m_font.GetUnderlined()?"true":"false"); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + } + else + wxLogError("SetFont(%s): Can't find font file", (const char*)font.GetFaceName()); +} + +void TwxPDFDC::SetPen( const wxPen& pen ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!pen.Ok()) + return; + + m_pen = pen; + + static const char *dotted = "dasharray {2 5} dashphase {2}"; + static const char *short_dashed = "dasharray {4 4} dashphase {2}"; + static const char *long_dashed = "dasharray {4 8} dashphase {2}"; + static const char *dotted_dashed = "dasharray {6 6 2 6} dashphase {4}"; + const char *pdfdash = (char *) NULL; + + const double redPDF = m_pen.GetColour().Red() / 255.0; + const double greenPDF = m_pen.GetColour().Green() / 255.0; + const double bluePDF = m_pen.GetColour().Blue() / 255.0; + bool solid = false; + switch (m_pen.GetStyle()) + { + case wxDOT : pdfdash = dotted; break; + case wxSHORT_DASH : pdfdash = short_dashed; break; + case wxLONG_DASH : pdfdash = long_dashed; break; + case wxDOT_DASH : pdfdash = dotted_dashed; break; + case wxSOLID : + case wxTRANSPARENT: + default : solid = true; break; + } + + PDF_TRY_DL(m_PDFlib, m_p) + { + wxString strScope = m_PDFlib->PDF_get_parameter(m_p, "scope", 0); + if (strScope != "document") + { + const int nWidth = m_pen.GetWidth(); + const double dWidth = nWidth <= 0 ? 1 : nWidth; + m_PDFlib->PDF_setlinewidth(m_p, dWidth); + if (solid) + m_PDFlib->PDF_setdash(m_p, 0, 0); + else + m_PDFlib->PDF_setdashpattern(m_p, pdfdash); + m_PDFlib->PDF_setcolor(m_p, "stroke", "rgb", redPDF, greenPDF, bluePDF, 0); + } + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::SetBrush( const wxBrush& brush ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!brush.Ok()) + return; + + m_brush = brush; + + unsigned char red = m_brush.GetColour().Red(); + unsigned char blue = m_brush.GetColour().Blue(); + unsigned char green = m_brush.GetColour().Green(); + + double redPDF = (double)(red) / 255.0; + double bluePDF = (double)(blue) / 255.0; + double greenPDF = (double)(green) / 255.0; + + int intPatHandle; + int intStyle = m_brush.GetStyle(); + bool solid = (intStyle==wxSOLID || intStyle==wxTRANSPARENT); + wxSize step = GetPPI(); + step.x /= 180; + step.y /= 180; + + PDF_TRY_DL(m_PDFlib, m_p) + { + wxString strScope = m_PDFlib->PDF_get_parameter(m_p, "scope", 0); + if (strScope != "document") + { + intPatHandle = m_PDFlib->PDF_begin_pattern(m_p, step.x, step.y , step.x, step.y, 2); + m_PDFlib->PDF_setlinewidth(m_p, 0.2f); + switch (intStyle) + { + case wxBDIAGONAL_HATCH: + m_PDFlib->PDF_moveto(m_p, 0, 0); + m_PDFlib->PDF_lineto(m_p, step.x, step.y); + m_PDFlib->PDF_stroke(m_p); + break; + case wxCROSSDIAG_HATCH: + m_PDFlib->PDF_moveto(m_p, 0, step.y); + m_PDFlib->PDF_lineto(m_p, step.x, 0); + m_PDFlib->PDF_stroke(m_p); + m_PDFlib->PDF_moveto(m_p, 0, 0); + m_PDFlib->PDF_lineto(m_p, step.x, step.y); + m_PDFlib->PDF_stroke(m_p); + break; + case wxFDIAGONAL_HATCH: + m_PDFlib->PDF_moveto(m_p, 0, step.y); + m_PDFlib->PDF_lineto(m_p, step.x, 0); + m_PDFlib->PDF_stroke(m_p); + break; + case wxCROSS_HATCH: + m_PDFlib->PDF_moveto(m_p, 0, step.y/2); + m_PDFlib->PDF_lineto(m_p, step.x, step.y/2); + m_PDFlib->PDF_stroke(m_p); + m_PDFlib->PDF_moveto(m_p, step.x/2, 0); + m_PDFlib->PDF_lineto(m_p, step.x/2, step.y); + m_PDFlib->PDF_stroke(m_p); + break; + case wxHORIZONTAL_HATCH: + m_PDFlib->PDF_moveto(m_p, 0, step.y/2); + m_PDFlib->PDF_lineto(m_p, step.x, step.y/2); + m_PDFlib->PDF_stroke(m_p); + break; + case wxVERTICAL_HATCH: + m_PDFlib->PDF_moveto(m_p, step.x/2, 0); + m_PDFlib->PDF_lineto(m_p, step.x/2, step.y); + m_PDFlib->PDF_stroke(m_p); + break; + default: + break; + } + m_PDFlib->PDF_end_pattern(m_p); + } + m_PDFlib->PDF_setcolor(m_p, "fill", "rgb", redPDF, greenPDF, bluePDF, 0); + if (!solid) + m_PDFlib->PDF_setcolor(m_p, "fill", "pattern", intPatHandle, 0, 0, 0); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::SetFontColor( const wxColour& color ) const +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (!color.Ok()) + return; + + PDF_TRY_DL(m_PDFlib, m_p) + { + const double redPDF = color.Red() / 255.0; + const double bluePDF = color.Blue() / 255.0; + const double greenPDF = color.Green() / 255.0; + m_PDFlib->PDF_setcolor(m_p, "fill", "rgb", redPDF, greenPDF, bluePDF, 0); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + m_topDown = !yBottomUp; + //m_signX = (xLeftRight ? 1 : -1); + //m_signY = (yBottomUp ? 1 : -1); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_set_parameter(m_p, "topdown", m_topDown?"true":"false"); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +void TwxPDFDC::SetDeviceOrigin(wxCoord x, wxCoord y) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_translate(m_p, x, y); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } +} + +//-- Page Size ----------------------------------------------------------- + +void TwxPDFDC::DoGetSizeMM(int* size_x, int* size_y) const +{ + const wxSize s = m_printData.GetPaperSize(); + if (m_printData.GetOrientation() == wxLANDSCAPE) + { + *size_x = s.y; + *size_y = s.x; + } + else + { + *size_x = s.x; + *size_y = s.y; + } +} + +void TwxPDFDC::DoGetSize(int *width, int *height) const +{ + DoGetSizeMM(width, height); + *width = *width * (10 * PDF_DPI) / 254 ; + *height = *height * (10 * PDF_DPI) / 254 ; +} + +wxSize TwxPDFDC::GetPPI(void) const +{ + return wxSize(PDF_DPI, PDF_DPI); +} + +//-- Unimplemented ------------------------------------------------------- + +void TwxPDFDC::SetBackground (const wxBrush& brush) +{ + // unimplemented +} + +void TwxPDFDC::SetLogicalFunction (int WXUNUSED(function)) +{ + // unimplemented +} + +void TwxPDFDC::Clear() +{ + // unimplemented +} + +bool TwxPDFDC::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style)) +{ + // unimplemented + return FALSE; +} + +bool TwxPDFDC::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const +{ + // unimplemented + return FALSE; +} + +void TwxPDFDC::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) +{ + // unimplemented +} + +//-- Clipping ------------------------------------------------------------ + +void TwxPDFDC::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + ResetClipping(); // Almost useless + + m_clipX1 = x; m_clipX2 = x+w; + m_clipY1 = y; m_clipY2 = y+h; + m_clipping = true; + + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_save(m_p); + m_PDFlib->PDF_moveto(m_p, x, y); + m_PDFlib->PDF_lineto(m_p, x+w, y); + m_PDFlib->PDF_lineto(m_p, x+w, y+h); + m_PDFlib->PDF_lineto(m_p, x, y+h); + m_PDFlib->PDF_closepath(m_p); + m_PDFlib->PDF_clip(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + +} + +void TwxPDFDC::DestroyClippingRegion() +{ + wxCHECK_RET( m_ok, wxT("invalid PDF dc") ); + + if (m_clipping) + { + m_clipping = false; + PDF_TRY_DL(m_PDFlib, m_p) + { + m_PDFlib->PDF_restore(m_p); + } + PDF_CATCH_DL(m_PDFlib, m_p) + { + wxLogError("%s: %s", m_PDFlib->PDF_get_apiname(m_p), m_PDFlib->PDF_get_errmsg(m_p)); + } + } + ResetClipping(); +} + diff --git a/src/xvaga01/xvtpdf.h b/src/xvaga01/xvtpdf.h new file mode 100644 index 000000000..652abd2b9 --- /dev/null +++ b/src/xvaga01/xvtpdf.h @@ -0,0 +1,133 @@ +#ifndef __XVTPDF_H +#define __XVTPDF_H + +#ifndef PDFLIB_H +struct PDF_c {}; +#include "../pdf/pdflib/pdflibdl.h" +#endif + +/////////////////////////////////////////////////////////// +// TwxPDFDC +/////////////////////////////////////////////////////////// + +class TwxPDFDC : public wxDC +{ + enum { PDF_IMG_CACHE_SIZE = 32 }; + +protected: + TwxPDFDC(); // Dummy constructor for dynamic construction + + bool IsValidFontFile(const char* strFontFile) const; + bool GetFontFamily(const wxFont& font, wxString& file, wxString& family) const; + +public: + // Recommended constructor + TwxPDFDC(const wxPrintData& data, const char* strFilename); + + ~TwxPDFDC(); + + virtual bool Ok() const; + + bool DoFloodFill(wxCoord x1, wxCoord y1, const wxColour &col, int style=wxFLOOD_SURFACE ); + bool DoGetPixel(wxCoord x1, wxCoord y1, wxColour *col) const; + + void DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2); + void DoCrossHair(wxCoord x, wxCoord y) ; + void DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2,wxCoord xc,wxCoord yc); + void DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea); + void DoDrawPoint(wxCoord x, wxCoord y); + void DoDrawLines(int n, wxPoint points[], wxCoord xoffset = 0, wxCoord yoffset = 0); + void DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset = 0, wxCoord yoffset = 0, int fillStyle=wxODDEVEN_RULE); + void DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height); + void DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius = 20); + void DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height); + void DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection); + void DoDrawSpline(wxList *points); + + bool DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop = wxCOPY, bool useMask = FALSE, + wxCoord xsrcMask = -1, wxCoord ysrcMask = -1); + bool CanDrawBitmap() const { return true; } + + void DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y ); + void DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool useMask=FALSE ); + void DoDrawImage( const wxString& name, const wxRect& dst ); + void DrawImage( const wxString& name, const wxRect& dst ) + { DoDrawImage(name, dst); } + + void DoDrawText(const wxString& text, wxCoord x, wxCoord y ); + void DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle); + + void Clear(); + void SetFont( const wxFont& font ); + void SetPen( const wxPen& pen ); + void SetBrush( const wxBrush& brush ); + void SetLogicalFunction( int function ); + void SetBackground( const wxBrush& brush ); + + void DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height); + void DestroyClippingRegion(); + + void DoSetClippingRegionAsRegion( const wxRegion &WXUNUSED(clip) ) { } + + bool StartDoc(const wxString& message); + void EndDoc(); + void StartPage(); + void EndPage(); + + wxCoord GetCharHeight() const; + wxCoord GetCharWidth() const; + bool CanGetTextExtent() const { return true; } + void DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, + wxCoord *descent = (wxCoord *) NULL, + wxCoord *externalLeading = (wxCoord *) NULL, + wxFont *theFont = (wxFont *) NULL ) const; + + void DoGetSize(int* width, int* height) const; + void DoGetSizeMM(int *width, int *height) const; + + // Resolution in pixels per logical inch + wxSize GetPPI() const; + + void SetAxisOrientation( bool xLeftRight, bool yBottomUp ); + void SetDeviceOrigin( wxCoord x, wxCoord y ); + + void SetBackgroundMode(int WXUNUSED(mode)) { } + void SetPalette(const wxPalette& WXUNUSED(palette)) { } + + const wxPrintData& GetPrintData() const { return m_printData; } + void SetPrintData(const wxPrintData& data) { m_printData = data; } + + virtual int GetDepth() const { return 24; } + const wxString& OutputFile() const { return m_fileName; } + +protected: + + void SetFontColor(const wxColor& color) const; + int GetBitmapHandle(const wxBitmap& bitmap) const; + int GetImageHandle(const wxString& name); + + PDF *m_p; + PDFlib_api *m_PDFlib; + + wxPrintData m_printData; + wxString m_fileName; + wxColor m_color; + + int m_pageNumber; + int m_fontnr; + bool m_clipping; + bool m_topDown; + bool m_pageopen; + + double m_fontsize; // m_ascent + m_descent + double m_ascent, m_descent, m_leading; + + wxString m_filenames[PDF_IMG_CACHE_SIZE]; + int m_handles[PDF_IMG_CACHE_SIZE]; + int m_cacheidx; + + DECLARE_DYNAMIC_CLASS(TwxPDFDC) +}; + +#endif diff --git a/src/xvaga01/xvtslt.h b/src/xvaga01/xvtslt.h new file mode 100644 index 000000000..f5f8ffc05 --- /dev/null +++ b/src/xvaga01/xvtslt.h @@ -0,0 +1,28 @@ +#ifndef XVT_XSLT +#define XVT_XSLT + + + +#ifdef WIN32 + #ifdef XVAGADLL + #define XSLTDLL __declspec(dllexport) + #else + #define XSLTDLL __declspec(dllimport) + #endif +#else + #define XSLTDLL +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTDLL int xvt_xslt_transform(const char * infile, const char * stylefile, const char * outfile); // Added by AGA + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/xvaga01/xvtwin.cpp b/src/xvaga01/xvtwin.cpp new file mode 100644 index 000000000..c06840195 --- /dev/null +++ b/src/xvaga01/xvtwin.cpp @@ -0,0 +1,1247 @@ +#include "wxinc.h" + +#define XTWIN_CPP 1 +#include "xvt.h" +#include "xvtart.h" +#include "xvtwin.h" + +#include +#include +//#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////// +// Utilities +/////////////////////////////////////////////////////////// + +wxHashTable _nice_windows; +wxFrame* _task_win = NULL; +EVENT_HANDLER _task_win_handler = NULL; + +wxRect RCT2Rect(const RCT* prct) +{ + wxRect rct; + if (prct != NULL) + { + rct.x = min(prct->left, prct->right); + rct.y = min(prct->top, prct->bottom); + rct.width = abs(prct->right - prct->left); + rct.height = abs(prct->bottom - prct->top); + } + return rct; +} + +void Rect2RCT(const wxRect& r, RCT* rct) +{ xvt_rect_set(rct, r.x, r.y, r.GetRight()+1, r.GetBottom()+1); } + +/////////////////////////////////////////////////////////// +// Caret emulation +/////////////////////////////////////////////////////////// + +class TwxCaret : private wxTimer +{ + WINDOW _owner; + PNT _pos; + wxSize _size; + bool _visible; + bool _drawn; + +protected: + void Toggle(); + virtual void Notify() { Toggle(); } + +public: + void SetPos(int x, int y); + void SetSize(int x, int y) { _size.x = x; _size.y = y; } + void Show(WINDOW w, bool on = true); + void Hide() { Show(NULL_WIN, false); } + bool IsVisible() const { return _visible; } + WINDOW Owner() const { return _owner; } + void Kill(); + + TwxCaret() : _owner(NULL_WIN), _visible(false) { } + virtual ~TwxCaret() { Kill(); } +} _TheCaret; + +void TwxCaret::Kill() +{ _owner = NULL_WIN; } + +void TwxCaret::SetPos(int x, int y) +{ + if (_visible && _drawn) // Lo cancella se necessario + Toggle(); + _pos.h = x; _pos.v = y; +} + +void TwxCaret::Show(WINDOW w, bool on) +{ + if (_visible && _drawn) + Toggle(); // Lo cancella + + _visible = on; + if (on) + { + _owner = w; + Toggle(); + wxTimer::Start(500); // Lampeggia ogni mezzo secondo + } + else + { + if (w == _owner || w == NULL_WIN) + Kill(); + } +} + +void TwxCaret::Toggle() +{ + if (!_visible || _owner == NULL_WIN) + return; + + _drawn = !_drawn; + + if (_nice_windows.Get(_owner)) + { + DRAW_CTOOLS dct; + xvt_dwin_get_draw_ctools(_owner, &dct); + + CPEN pen; + pen.width = _size.x; + pen.pat = PAT_SOLID; + pen.style = P_SOLID; + pen.color = dct.fore_color; + xvt_dwin_set_draw_mode(_owner, M_NOT_XOR); + + xvt_dwin_set_cpen(_owner, &pen); + xvt_dwin_draw_set_pos(_owner, _pos); + PNT p = _pos; p.v -= _size.y-1; + + xvt_dwin_set_clip(_owner, NULL); // Non si sa mai! + xvt_dwin_draw_line(_owner, p); + xvt_dwin_set_draw_ctools(_owner, &dct); + } + else + { + _owner = NULL_WIN; + } +} + +void xvt_win_set_caret_size(WINDOW win, int width, int height) +{ + if (win != NULL_WIN) + _TheCaret.SetSize(width, height); +} + +void xvt_win_set_caret_pos(WINDOW win, PNT p) +{ + if (win != NULL_WIN) + _TheCaret.SetPos(p.h, p.v-1); +} + +void xvt_win_set_caret_visible(WINDOW win, BOOLEAN on) +{ + _TheCaret.Show(win, on != 0); +} + +/////////////////////////////////////////////////////////// +// Generic Display context +/////////////////////////////////////////////////////////// + +TDC::TDC(wxWindow* owner) : _dc(NULL) +{ + _owner = owner; + + memset(&_dct, 0, sizeof(_dct)); + _dct.pen.width = 0; + _dct.pen.pat = PAT_SOLID; + _dct.pen.style = P_SOLID; + _dct.pen.color = COLOR_BLACK; + _dct.brush.pat = PAT_HOLLOW; + _dct.brush.color = COLOR_WHITE; + _dct.mode = M_COPY; + _dct.fore_color = COLOR_BLACK; + _dct.back_color = COLOR_WHITE; + _dct.opaque_text = FALSE; + + _font.SetPointSize(9); // Default font + _deltaf = 0; + + // Reset clip area + SetClippingBox(NULL); + _real_clip = _clip; + + _dirty = -1; // Absolutely force setting +} + +TDC::~TDC() +{ + KillDC(); +} + +void TDC::SetDirty(int d) +{ + if (_dirty >= 0) + _dirty = d; +} + +static int PatternToStyle(PAT_STYLE pat) +{ + int style = wxSOLID; + switch (pat) + { + case PAT_NONE: + case PAT_HOLLOW: style = wxTRANSPARENT; break; + case PAT_SOLID: style = wxSOLID; break; + case PAT_HORZ: style = wxHORIZONTAL_HATCH; break; + case PAT_VERT: style = wxVERTICAL_HATCH; break; + case PAT_FDIAG: style = wxFDIAGONAL_HATCH; break; + case PAT_BDIAG: style = wxBDIAGONAL_HATCH; break; + case PAT_CROSS: style = wxCROSS_HATCH; break; + case PAT_DIAGCROSS: style = wxCROSSDIAG_HATCH; break; + case PAT_SPECIAL: style = wxSOLID; break; // Used for gradient + case PAT_RUBBER: + default: style = wxSOLID; SORRY_BOX(); break; + } + return style; +} + +static int PenStyleToStyle(PEN_STYLE s, PAT_STYLE p) +{ + int style = wxSOLID; + if (p != PAT_HOLLOW) + { + switch (s) + { + case P_DOT : style = wxDOT; break; + case P_DASH: style = wxSHORT_DASH; break; + default: break; + } + } + else + style = wxTRANSPARENT; + + return style; +} + +bool TDC::PenChanged() const +{ + const int diff = memcmp(&_dct.pen, &_real_dct.pen, sizeof(_dct.pen)); + return diff != 0; +} + +bool TDC::BrushChanged() const +{ + const int diff = memcmp(&_dct.brush, &_real_dct.brush, sizeof(_dct.brush)); + return diff != 0; +} + +bool TDC::FontChanged() const +{ + return _font != _real_font; +} + +bool TDC::ClipChanged() const +{ + const int diff = memcmp(&_clip, &_real_clip, sizeof(_clip)); + return diff != 0; +} + +#ifdef LINUX +bool is_printer_dc(wxDC * dc) { return wxDynamicCast(dc, wxPostScriptDC) != NULL; } +#endif + +#define NULL_CLIP_SIZE 32000 + +wxDC& TDC::GetDC(bool bPaint) +{ + if (bPaint) + { + KillDC(); + //_dc = new wxAutoBufferedPaintDC(_owner); // Funziona ma si vedono cose strane temporanee + _dc = new wxPaintDC(_owner); + _dirty = -1; + } + else + { + if (_dc == NULL) + { + if (_owner == NULL || (unsigned long)_owner == SCREEN_WIN) + _dc = new wxScreenDC(); + else + _dc = new wxClientDC(_owner); + _dirty = -1; + } + } + + if (_dirty) + { + if (_dirty < 0 || PenChanged()) + { + CAST_COLOR(_dct.pen.color, pen_color); + wxPen* pen = wxThePenList->FindOrCreatePen(pen_color, _dct.pen.width, PenStyleToStyle(_dct.pen.style, _dct.pen.pat)); + _dc->SetPen(*pen); + _real_dct.pen = _dct.pen; + } + + if (_dirty < 0 || BrushChanged()) + { + CAST_COLOR(_dct.brush.color, brush_color); + wxBrush* brush = wxTheBrushList->FindOrCreateBrush(brush_color, PatternToStyle(_dct.brush.pat)); + _dc->SetBrush(*brush); + _real_dct.brush = _dct.brush; + } + + if (_dirty < 0 || _dct.mode != _real_dct.mode) + { +#ifdef LINUX + if(!is_printer_dc(_dc)) +#endif + switch(_dct.mode) + { + case M_COPY: _dc->SetLogicalFunction(wxCOPY); break; + case M_OR: _dc->SetLogicalFunction(wxOR); break; + case M_XOR: _dc->SetLogicalFunction(wxXOR); break; + case M_CLEAR: _dc->SetLogicalFunction(wxCLEAR); break; + case M_NOT_COPY: _dc->SetLogicalFunction(wxSRC_INVERT); break; + case M_NOT_OR: _dc->SetLogicalFunction(wxNOR); break; + case M_NOT_XOR: _dc->SetLogicalFunction(wxEQUIV); break; + case M_NOT_CLEAR:_dc->SetLogicalFunction(wxSET); break; + default: SORRY_BOX(); + } + _real_dct.mode = _dct.mode; + } + + if (_dirty < 0 || _dct.fore_color != _real_dct.fore_color) + { + CAST_COLOR(_dct.fore_color, fore_color); + _dc->SetTextForeground(fore_color); + _real_dct.fore_color = _dct.fore_color; + } + + if (_dirty < 0 || _dct.back_color != _real_dct.back_color) + { + CAST_COLOR(_dct.back_color, back_color); + _dc->SetTextBackground(back_color); + _real_dct.back_color = _dct.back_color; + } + + if (_dirty < 0 || _dct.opaque_text != _real_dct.opaque_text) + { + _dc->SetBackgroundMode(_dct.opaque_text ? wxSOLID : wxTRANSPARENT); + _real_dct.opaque_text = _dct.opaque_text; + } + + if (_dirty < 0 || FontChanged()) + { + const wxFont& f = _font.Font(_dc, (WINDOW)_owner); + wxASSERT_MSG(f.IsOk(), "Trying to set an invalid font"); + + _dc->SetFont(f); + _real_font = _font; + + int height, desc, lead; + _dc->GetTextExtent("Kpfx", NULL, &height, &desc, &lead); + _deltaf = height-desc; // Baseline offset from top + } + + if (_dirty < 0 || ClipChanged()) + { + _dc->DestroyClippingRegion(); + if (_clip.bottom < NULL_CLIP_SIZE) + _dc->SetClippingRegion(RCT2Rect(&_clip)); + _real_clip = _clip; + } + + _dirty = false; + } + return *_dc; +} + +void TDC::KillDC() +{ + if (_dc != NULL) + { + SetClippingBox(NULL); + _real_clip = _clip; + delete _dc; + _dc = NULL; + } +} + +void TDC::SetClippingBox(const RCT* pRct) +{ + if (pRct != NULL) + { + // Normalizza posizione e dimensioni invece di limitarsi a fare _clip=*pRct + const wxRect rct = RCT2Rect(pRct); + Rect2RCT(rct, &_clip); + } + else + { + _clip.left = _clip.top = 0; + _clip.right = _clip.bottom = NULL_CLIP_SIZE; + } +} + +bool TDC::GetClippingBox(RCT* pRct) const +{ + if (pRct != NULL) + *pRct = _clip; + return _clip.right > _clip.left; +} + +TDCMapper& GetTDCMapper() +{ + static TDCMapper* _dc_map = NULL; + if (_dc_map == NULL) + _dc_map = new TDCMapper; + return *_dc_map; +} + +void TDCMapper::DestroyDC(WINDOW owner) +{ + if (owner) + { + TDC* pTDC = (*this)[owner]; + if (pTDC) + pTDC->KillDC(); + } + else + { + for (TDCMapper::iterator it = begin(); it != end(); ++it) + { + TDC* pTDC = it->second; + if (pTDC) + pTDC->KillDC(); + } + } +} + +void TDCMapper::DestroyTDC(WINDOW owner) +{ + if (owner != NULL_WIN) + { + TDC* pTDC = (*this)[owner]; + if (pTDC) + delete pTDC; + erase(owner); + } + else + { + TDCMapper::iterator it; + for (it = begin(); it != end(); ++it) + { + TDC* pTDC = it->second; + if (pTDC) + delete pTDC; + } + clear(); + } + _pLastOwner = NULL_WIN; +} + +TDC& TDCMapper::GetTDC(WINDOW owner) +{ + if (owner != _pLastOwner) + { + wxASSERT(owner != NULL_WIN); + TDC* pTDC = (*this)[owner]; + if (pTDC == NULL) + { + if (owner == PRINTER_WIN) + pTDC = new TPrintDC((wxWindow*)owner); + else + pTDC = new TDC((wxWindow*)owner); + (*this)[owner] = pTDC; + } + _pLastOwner = owner; + _pLastTDC = pTDC; + } + return *_pLastTDC; +} + +bool TDCMapper::HasValidDC(WINDOW owner) const +{ + if (owner == NULL_WIN) + return false; + + if (owner == (WINDOW)_pLastOwner) + return true; + + TDC* pTDC = (*((TDCMapper *) this))[owner]; + return pTDC != NULL; +} + +/////////////////////////////////////////////////////////// +// Generic window class +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TwxWindowBase, wxWindow) + +#ifdef WIN32 +WXLRESULT TwxWindowBase::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + WXLRESULT rc = 0; + bool processed = false; + + switch (nMsg) + { + case WM_CLOSE: + processed = !Close(); + break; + default: + break; + } + + if ( !processed ) + rc = wxWindow::MSWWindowProc(nMsg, wParam, lParam); + + return rc; +} +#endif + +bool TwxWindowBase::CreateBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style) +{ + wxWindowBase::Show(false); // Evita inutili sfarfallamenti + return Create(parent, id, pos, size, style, title); +} + +TwxWindowBase::TwxWindowBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style) +{ + CreateBase(parent, id, title, pos, size, style); +} + +IMPLEMENT_DYNAMIC_CLASS(TwxWindow, TwxWindowBase) + +BEGIN_EVENT_TABLE(TwxWindow, TwxWindowBase) + EVT_CHAR(TwxWindow::OnChar) + EVT_KEY_DOWN(TwxWindow::OnKeyDown) + EVT_CLOSE(TwxWindow::OnClose) + EVT_KILL_FOCUS(TwxWindow::OnKillFocus) + EVT_LEFT_DCLICK(TwxWindow::OnMouseDouble) + EVT_LEFT_DOWN(TwxWindow::OnMouseDown) + EVT_LEFT_UP(TwxWindow::OnMouseUp) + EVT_MENU_RANGE(1000, 32766, TwxWindow::OnMenu) + EVT_MIDDLE_DOWN(TwxWindow::OnMouseDown) + EVT_MIDDLE_UP(TwxWindow::OnMouseUp) + EVT_MOTION(TwxWindow::OnMouseMove) + EVT_MOUSE_CAPTURE_LOST(TwxWindow::OnMouseCaptureLost) + EVT_MOUSEWHEEL(TwxWindow::OnMouseWheel) + EVT_PAINT(TwxWindow::OnPaint) + EVT_RIGHT_DOWN(TwxWindow::OnMouseDown) + EVT_RIGHT_UP(TwxWindow::OnMouseUp) + EVT_SCROLL(TwxWindow::OnScroll) + EVT_SCROLLWIN(TwxWindow::OnScrollWin) + EVT_SET_FOCUS(TwxWindow::OnSetFocus) + EVT_SIZE(TwxWindow::OnSize) + EVT_TIMER(TIMER_ID, TwxWindow::OnTimer) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, TwxWindow::OnButton) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, TwxWindow::OnCheckBox) + EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, TwxWindow::OnRadioButton) +END_EVENT_TABLE() + +long TwxWindow::DoXvtEvent(EVENT& e) +{ + long ret = 0; + if (this != NULL && _eh != NULL) + ret = _eh((WINDOW)this, &e); + return ret; +} + +void TwxWindow::OnChar(wxKeyEvent& evt) +{ + XVT_EVENT e(E_CHAR); + int k = evt.GetKeyCode(); + + switch (k) + { + case WXK_ALT: + case WXK_MENU: + case WXK_NUMPAD0: + case WXK_NUMPAD1: + case WXK_NUMPAD2: + case WXK_NUMPAD3: + case WXK_NUMPAD4: + case WXK_NUMPAD5: + case WXK_NUMPAD6: + case WXK_NUMPAD7: + case WXK_NUMPAD8: + case WXK_NUMPAD9: + evt.Skip(); + return; + case WXK_NUMPAD_ADD: k = '+';break; + case WXK_DOWN : k = K_DOWN; break; + case WXK_END : k = K_LEND; break; + case WXK_HOME : k = K_LHOME; break; + case WXK_LEFT : k = K_LEFT; break; + case WXK_PAGEDOWN : k = K_NEXT; break; + case WXK_PAGEUP : k = K_PREV; break; + case WXK_RIGHT : k = K_RIGHT; break; + case WXK_UP : k = K_UP; break; + case WXK_TAB: + if (evt.ShiftDown()) + k = K_BTAB; + break; + default: + if (k >= WXK_F1 && k <= WXK_F24) + k = K_F1 + k - WXK_F1; + break; + } + + e.v.chr.shift = evt.ShiftDown(); + e.v.chr.control = evt.ControlDown(); + if (evt.AltDown()) + { + e.v.chr.control = TRUE; + if (xvt_chr_is_alnum(k)) + k = toupper(k); + else + { + if (strchr("+-", k) == NULL) // Aggiungere qui vari testi eventuali + { + evt.Skip(); + return; + } + } + } + e.v.chr.ch = k; + + DoXvtEvent(e); +} + +void TwxWindow::OnKeyDown(wxKeyEvent& e) +{ + // Triste necessita' per gestire corretamente Alt+'+' del tasterino + const int k = e.GetKeyCode(); + if (k == WXK_NUMPAD_ADD) + { + if (e.AltDown()) + { + OnChar(e); + return; + } + } else + if (k == WXK_NUMPAD_DECIMAL) + { + static int nPoint2Comma = -883; // Valore indefinito + if (nPoint2Comma == -883) // Devo stabilire se attivare la gestione o no + { + char str[4] = { 0 }; + xvt_sys_get_profile_string(NULL, "Main", "Point2Comma", "1", str, sizeof(str)); + nPoint2Comma = wxStrchr("1XY", *str) ? 1 : 0; // Dis/Abilita conversione punto in virgola + } + if (nPoint2Comma) + { + e.m_keyCode = ','; + OnChar(e); + return; + } + } + e.Skip(); +} + +void TwxWindow::OnClose(wxCloseEvent& WXUNUSED(e)) +{ + XVT_EVENT e(E_CLOSE); + DoXvtEvent(e); +} + +void TwxWindow::OnKillFocus(wxFocusEvent& WXUNUSED(e)) +{ + if (_TheCaret.Owner() == (WINDOW)this) + _TheCaret.Hide(); + + XVT_EVENT e(E_FOCUS); + e.v.active = 0; + DoXvtEvent(e); +} + +void TwxWindow::OnMenu(wxCommandEvent& evt) +{ + XVT_EVENT e(E_COMMAND); + e.v.cmd.control = 0; e.v.cmd.shift = 0; + e.v.cmd.tag = evt.GetId(); + DoXvtEvent(e); +} + +void TwxWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(e)) +{ + xvt_win_release_pointer(); +} + +void TwxWindow::OnMouseDouble(wxMouseEvent& evt) +{ + XVT_EVENT e(E_MOUSE_DBL); + e.v.mouse.button = (evt.RightDown() ? 1 : 0) + (evt.MiddleDown() ? 2 : 0); + e.v.mouse.control = evt.ControlDown(); + e.v.mouse.shift = evt.ShiftDown(); + e.v.mouse.where.h = evt.GetX(); + e.v.mouse.where.v = evt.GetY(); + DoXvtEvent(e); +} + +void TwxWindow::OnMouseDown(wxMouseEvent& evt) +{ + XVT_EVENT e(E_MOUSE_DOWN); + e.v.mouse.button = (evt.RightDown() ? 1 : 0) + (evt.MiddleDown() ? 2 : 0); + e.v.mouse.control = evt.ControlDown(); + e.v.mouse.shift = evt.ShiftDown(); + e.v.mouse.where.h = evt.GetX(); + e.v.mouse.where.v = evt.GetY(); + DoXvtEvent(e); + SetFocus(); // Triste necessita' +} + +void TwxWindow::OnMouseMove(wxMouseEvent& evt) +{ + XVT_EVENT e(E_MOUSE_MOVE); + e.v.mouse.button = (evt.RightIsDown() ? 1 : 0) + (evt.MiddleIsDown() ? 2 : 0); + e.v.mouse.control = evt.ControlDown(); + e.v.mouse.shift = evt.m_shiftDown; + e.v.mouse.where.h = evt.GetX(); + e.v.mouse.where.v = evt.GetY(); + DoXvtEvent(e); +} + +void TwxWindow::OnMouseUp(wxMouseEvent& evt) +{ + XVT_EVENT e(E_MOUSE_UP); + e.v.mouse.button = (evt.RightUp() ? 1 : 0) + (evt.MiddleUp() ? 2 : 0); + e.v.mouse.control = evt.ControlDown(); + e.v.mouse.shift = evt.ShiftDown(); + e.v.mouse.where.h = evt.GetX(); + e.v.mouse.where.v = evt.GetY(); + DoXvtEvent(e); +} + +void TwxWindow::OnMouseWheel(wxMouseEvent& evt) +{ + const int nRot = evt.GetWheelRotation(); + if (nRot != 0) + { + XVT_EVENT e(E_VSCROLL); + e.v.scroll.pos = evt.GetY(); + e.v.scroll.what = nRot > 0 ? SC_LINE_UP : SC_LINE_DOWN; + DoXvtEvent(e); + } +} + +void TwxWindow::OnPaint(wxPaintEvent& WXUNUSED(evt)) +{ + const wxRect rctDamaged = GetUpdateRegion().GetBox(); + + XVT_EVENT e(E_UPDATE); + Rect2RCT(rctDamaged, &e.v.update.rct); + + TDC& tdc = GetTDCMapper().GetTDC((WINDOW)this); + tdc.GetDC(true); // Forza la creazione di un wxPaintDC + DoXvtEvent(e); + tdc.KillDC(); // Distrugge il wxPaintDC + GetTDCMapper().DestroyDC(NULL_WIN); // Distrugge davvero tutti i wxClientDC residui (risolve molte "porcate" del video) +} + +static SCROLL_CONTROL ConvertScrollToXVT(wxEventType et) +{ + if (et == wxEVT_SCROLL_TOP) + return SC_THUMB; // Meglio di niente + if (et == wxEVT_SCROLL_BOTTOM) + return SC_THUMB; // Meglio di niente + if (et == wxEVT_SCROLL_LINEUP) + return SC_LINE_UP; + if (et == wxEVT_SCROLL_LINEDOWN) + return SC_LINE_DOWN; + if (et == wxEVT_SCROLL_PAGEUP) + return SC_PAGE_UP; + if (et == wxEVT_SCROLL_PAGEDOWN) + return SC_PAGE_DOWN; + if (et == wxEVT_SCROLL_THUMBTRACK) + return SC_THUMBTRACK; + if (et == wxEVT_SCROLL_THUMBRELEASE) + return SC_THUMB; + return SC_NONE; +} + +void TwxWindow::OnScroll(wxScrollEvent& evt) +{ + SCROLL_CONTROL sc = ConvertScrollToXVT(evt.GetEventType()); + if (sc != SC_NONE) + { + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = evt.GetOrientation()==wxHORIZONTAL ? WC_HSCROLL : WC_VSCROLL; + e.v.ctl.ci.win = (WINDOW)evt.GetEventObject(); + e.v.ctl.ci.v.scroll.pos = evt.GetPosition(); + e.v.ctl.ci.v.scroll.what = sc; + DoXvtEvent(e); + } +} + +void TwxWindow::OnScrollWin(wxScrollWinEvent& evt) +{ + wxEventType et = evt.GetEventType(); + et -= (wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP); + const SCROLL_CONTROL sc = ConvertScrollToXVT(et); + if (sc != SC_NONE) + { + XVT_EVENT e(evt.GetOrientation() == wxHORIZONTAL ? E_HSCROLL : E_VSCROLL); + e.v.scroll.pos = evt.GetPosition(); + e.v.scroll.what = sc; + DoXvtEvent(e); + } +} + +void TwxWindow::OnSetFocus(wxFocusEvent& WXUNUSED(e)) +{ + XVT_EVENT e(E_FOCUS); + e.v.active = TRUE; + DoXvtEvent(e); +} + +void TwxWindow::OnSize(wxSizeEvent& evt) +{ + XVT_EVENT e(E_SIZE); + e.v.size.width = evt.GetSize().x; + e.v.size.height = evt.GetSize().y; + DoXvtEvent(e); +} + +void TwxWindow::OnTimer(wxTimerEvent& WXUNUSED(evt)) +{ + XVT_EVENT e(E_TIMER); + e.v.timer.id = (WINDOW)this; + DoXvtEvent(e); +} + +void TwxWindow::OnButton(wxCommandEvent& evt) +{ + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_PUSHBUTTON; + DoXvtEvent(e); +} + +void TwxWindow::OnCheckBox(wxCommandEvent& evt) +{ + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_CHECKBOX; + DoXvtEvent(e); +} + +void TwxWindow::OnRadioButton(wxCommandEvent& evt) +{ + XVT_EVENT e(E_CONTROL); + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_RADIOBUTTON; + DoXvtEvent(e); +} + +void TwxWindow::SetMenuTree(const MENU_ITEM* tree) +{ + wxASSERT(tree != NULL); + if (tree != NULL) + { + if (m_menu) + xvt_res_free_menu_tree(m_menu); + m_menu = xvt_menu_duplicate_tree(tree); + TTaskWin* tw = wxStaticCast(_task_win, TTaskWin); + tw->PushMenuTree(tree, this); + } +} + +BOOLEAN TwxWindow::AddPane(wxWindow* wnd, const char* caption, int nDock, int nFlags) +{ + BOOLEAN ok = wnd != NULL; + if (ok) + { + if (m_pManager == NULL) + m_pManager = xvtart_CreateManager(this); + wxAuiPaneInfo pane; + pane.DefaultPane(); pane.Dockable(false); + const wxSize sz = wnd->GetSize(); + switch (nDock) + { + case 1: // Left + pane.Left().Floatable(true).LeftDockable().RightDockable(); + pane.MinSize(sz.x/2, -1).BestSize(sz.x, -1).MaxSize(3*sz.x/2, -1); + break; + case 2: // Top + pane.Top().Floatable(true).TopDockable().BottomDockable().MinSize(-1, sz.y/2); + break; + case 3: // Right + pane.Right().Floatable(true).LeftDockable().RightDockable(); + pane.MinSize(sz.x/2, -1).BestSize(sz.x, -1).MaxSize(3*sz.x/2, -1); + break; + case 4: // Bottom + pane.Bottom().Floatable(true).TopDockable().BottomDockable().MinSize(-1, sz.y/2); + break; + case 52: // Center Top + pane.CentrePane().CaptionVisible(true).TopDockable(); + break; + case 54: // Center Bottom + pane.CentrePane().CaptionVisible(true).BottomDockable(); + break; + case 62: // Top toolbar + pane.ToolbarPane().Top().MinSize(wxSize(-1,sz.y)).Gripper(false); + break; + default: // Center + pane.CentrePane().Floatable(false); + break; + } + pane.CloseButton(false); + if (caption && *caption) + { + pane.Caption(caption); + pane.Name(caption); + } + if (nFlags) + pane.SetFlag(nFlags, true); + + ok = m_pManager->AddPane(wnd, pane); + if (ok) + m_pManager->Update(); + } + return ok; +} + +TwxWindow::TwxWindow() + : m_menu(NULL), _type(W_DOC), _eh(NULL), _app_data(0L), + _timer(NULL), m_pManager(NULL) +{ } + +TwxWindow::TwxWindow(wxWindow *parent, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style) + : TwxWindowBase(parent, id, title, pos, size, style), + m_menu(NULL), _eh(NULL), _app_data(0L), _timer(NULL), + m_pManager(NULL), m_bInDestroy(false) +{ + _nice_windows.Put((WINDOW)this, this); +} + +TwxWindow::~TwxWindow() +{ + if (!m_bInDestroy) // Controllo di non essere RIchiamato dalla gestione di E_DESTROY + { + m_bInDestroy = true; + XVT_EVENT e(E_DESTROY); + DoXvtEvent(e); + + // Rendo praticamente impossibile risalire a questo oggetto d'ora in poi + _nice_windows.Delete((WINDOW)this); + _eh = NULL; + _app_data = 0L; + + GetTDCMapper().DestroyTDC((WINDOW)this); // Elimina dalla lista dei display context + + if (HasCapture()) + { + ReleaseMouse(); + xvt_win_release_pointer(); // Paranoid? + } + + if (_timer != NULL) + delete _timer; + + if (m_pManager != NULL) + { + m_pManager->UnInit(); // Obbligatorio ma, chissa' perche', non gestito dal distruttore! + delete m_pManager; + } + + if (m_menu) + { + xvt_res_free_menu_tree(m_menu); + m_menu = NULL; + ((TTaskWin*)_task_win)->PopMenuTree(); + } + } +} + +/////////////////////////////////////////////////////////// +// Main application = TASK_WIN functions +/////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(TTaskWin, wxFrame) + +BEGIN_EVENT_TABLE(TTaskWin, wxFrame) + EVT_CLOSE(TTaskWin::OnClose) + EVT_MENU_RANGE(1000, 32766, TTaskWin::OnMenu) + EVT_PAINT(TTaskWin::OnPaint) + EVT_SIZE(TTaskWin::OnSize) + EVT_END_SESSION(TTaskWin::OnClose) + EVT_END_PROCESS(wxID_ANY, TTaskWin::OnEndProcess) +END_EVENT_TABLE() + +void TTaskWin::OnClose(wxCloseEvent& evt) +{ + if (evt.CanVeto()) + { + XVT_EVENT e(E_CLOSE); + const int veto = _task_win_handler((WINDOW)this, &e); + evt.Veto(veto != 0); + } + else + evt.Skip(); +} + +void TTaskWin::OnMenu(wxCommandEvent& evt) +{ + XVT_EVENT e(E_COMMAND); + e.v.cmd.control = 0; e.v.cmd.shift = 0; + e.v.cmd.tag = evt.GetId(); + + if (m_MenuOwner == nullptr || m_MenuOwner == this) + { + _task_win_handler((WINDOW)this, &e); + } + else + { + TwxWindow* w = wxDynamicCast(m_MenuOwner, TwxWindow); + + if (w != nullptr) + w->_eh((WINDOW)m_MenuOwner, &e); + } +} + +void TTaskWin::OnPaint(wxPaintEvent& WXUNUSED(evt)) +{ + const wxRect rctDamaged = GetUpdateRegion().GetBox(); + + XVT_EVENT e(E_UPDATE); + Rect2RCT(rctDamaged, &e.v.update.rct); + + TDC& dc = GetTDCMapper().GetTDC((WINDOW)this); + dc.GetDC(true); // Forza la creazione di un wxPaintDC + _task_win_handler((WINDOW)this, &e); + dc.KillDC(); +} + +void TTaskWin::OnSize(wxSizeEvent& evt) +{ + XVT_EVENT e(E_SIZE); + e.v.size.width = evt.GetSize().x; + e.v.size.height = evt.GetSize().y; + _task_win_handler((WINDOW)this, &e); +} + +void TTaskWin::OnEndProcess(wxProcessEvent& evt) +{ + if (_task_win_handler != NULL) + { + XVT_EVENT e(E_PROCESS); + e.v.process.msg_id = E_DESTROY; + e.v.process.pid = evt.GetPid(); + e.v.process.exit_code = evt.GetExitCode(); + _task_win_handler((WINDOW)this, &e); + delete evt.GetEventObject(); // delete wxProcess + } +} + +void TTaskWin::SetMenuTree(const MENU_ITEM* tree) +{ + wxMenuBar* bar = GetMenuBar(); + if (bar != NULL && tree != NULL) + { + if (m_menu) + xvt_res_free_menu_tree(m_menu); + m_menu = xvt_menu_duplicate_tree(tree); + + for ( ; tree != NULL && tree->tag != 0; tree++) + { + wxMenu* pMenu = new wxMenu; + for (MENU_ITEM* mi = tree->child; mi != NULL && mi->tag != 0; mi++) + { + wxMenuItem* item = NULL; + if (mi->separator) + item = new wxMenuItem(pMenu, wxID_SEPARATOR); + else + item = new wxMenuItem(pMenu, mi->tag, mi->text, wxEmptyString, mi->checkable); + pMenu->Append(item); + } + const int nLast = bar->GetMenuCount()-1; + int m; + for (m = 2; m < nLast; m++) + { + wxMenu* pMenu = bar->GetMenu(m); + if (pMenu->FindItem(tree->child->tag)) + { + bar->Remove(m); + // delete pMenu; + break; + } + } + bar->Insert(m, pMenu, tree->text); + } + } +} + +void TTaskWin::PushMenuTree(const MENU_ITEM* tree, wxWindow* owner) +{ + if(m_pOldBar != NULL) + PopMenuTree(); + m_pOldBar = GetMenuBar(); + + wxMenuBar* pBar = new wxMenuBar; + for (; tree && tree->tag != 0; tree++) + { + wxMenu* pMenu = new wxMenu; + for (MENU_ITEM* mi = tree->child; mi != NULL && mi->tag != 0; mi++) + { + wxMenuItem* item = NULL; + if (mi->separator) + item = new wxMenuItem(pMenu, wxID_SEPARATOR); + else + item = new wxMenuItem(pMenu, mi->tag, mi->text, wxEmptyString, mi->checkable); + pMenu->Append(item); + } + pBar->Append(pMenu, tree->text); + } + SetMenuBar(pBar); + m_MenuOwner = owner; +} + +void TTaskWin::PopMenuTree() +{ + wxASSERT(m_pOldBar != NULL); + wxMenuBar* pBar = GetMenuBar(); + SetMenuBar(m_pOldBar); + delete pBar; + m_pOldBar = NULL; + m_MenuOwner = NULL; // = this; +} + +const XVT_COLOR_COMPONENT* TTaskWin::GetCtlColors() const +{ + if (m_xcc == NULL) + ((TTaskWin*)this)->m_xcc = (XVT_COLOR_COMPONENT*)xvt_vobj_get_attr(NULL_WIN, ATTR_APP_CTL_COLORS); + return m_xcc; +} + +COLOR TTaskWin::GetCtlColor(XVT_COLOR_TYPE ct) const +{ + COLOR croma = COLOR_INVALID; + const XVT_COLOR_COMPONENT* xcc = GetCtlColors(); + for (int i = 0; i < 16 && xcc[i].type != XVT_COLOR_NULL; i++) + { + if (xcc[i].type == ct) + { + croma = xcc[i].color; + break; + } + } + return croma; +} + +void TTaskWin::SetCtlColors(const XVT_COLOR_COMPONENT* colors) +{ + GetCtlColors(); // Ensure m_xcc is not NULL + for (int c = 0; colors[c].type != XVT_COLOR_NULL; c++) + { + int k = -1; + for (k = 0; m_xcc[k].type != colors[c].type; k++); + if (k < 15) + { + m_xcc[k].type = colors[c].type; + m_xcc[k].color = colors[c].color; + } + } +} + +TTaskWin::TTaskWin(wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style) + : wxFrame(NULL, id, title, pos, size, style), m_menu(NULL), m_pOldBar(NULL), m_MenuOwner(NULL), m_xcc(NULL) +{ + SetIcon(xvtart_GetIconResource(ICON_RSRC)); + _nice_windows.Put((WINDOW)this, this); +} + +TTaskWin::~TTaskWin() +{ + _task_win = NULL; + _nice_windows.Delete((WINDOW)this); + if (m_menu) + { + xvt_res_free_menu_tree(m_menu); + m_menu = NULL; + } + if (m_xcc) + { + xvt_mem_free((DATA_PTR)m_xcc); + m_xcc = NULL; + } + wxExit(); // Exits main loop in the "rare" case it's still running +} + +/////////////////////////////////////////////////////////// +// TwxTaskBarIcon +/////////////////////////////////////////////////////////// + +class TwxTaskBarIcon : public wxTaskBarIcon +{ + wxWindow* _owned; + DECLARE_EVENT_TABLE(); + +protected: + void OnClick(wxTaskBarIconEvent& e); + +public: + TwxTaskBarIcon(wxWindow* owned, short icon, wxString strTip); +}; + +BEGIN_EVENT_TABLE(TwxTaskBarIcon, wxTaskBarIcon) + EVT_TASKBAR_LEFT_DOWN(OnClick) + EVT_TASKBAR_RIGHT_DOWN(OnClick) +END_EVENT_TABLE() + +void TwxTaskBarIcon::OnClick(wxTaskBarIconEvent& WXUNUSED(e)) +{ + if (_owned != NULL) + { + if (_owned->IsShown()) + _owned->Show(false); + else + { + _owned->Show(); + _owned->Raise(); + } + } +} + +TwxTaskBarIcon::TwxTaskBarIcon(wxWindow* owned, short icon, wxString strTip) + : _owned(owned) +{ + wxIcon ico; + if (icon <= 0 && _owned != NULL) + { + const wxFrame* pFrame = wxDynamicCast(_owned, wxFrame); + if (pFrame != NULL) + ico = pFrame->GetIcon(); + } + else + ico = xvtart_GetIconResource(icon); + + if (strTip.IsEmpty()) + strTip = _owned->GetLabel(); + + SetIcon(ico, strTip); +} + +WINDOW xvt_trayicon_create(WINDOW owned, short icon, const char* tooltip) +{ + WINDOW ti = NULL_WIN; + if (owned != NULL_WIN) + ti = (WINDOW)new TwxTaskBarIcon((wxWindow*)owned, icon, tooltip); + return ti; +} + +void xvt_trayicon_destroy(WINDOW tray) +{ + wxTaskBarIcon* pTray = wxDynamicCast((wxObject*)tray, wxTaskBarIcon); + if (pTray != NULL) + delete pTray; +} + diff --git a/src/xvaga01/xvtwin.h b/src/xvaga01/xvtwin.h new file mode 100644 index 000000000..23a167ad8 --- /dev/null +++ b/src/xvaga01/xvtwin.h @@ -0,0 +1,258 @@ +#ifndef __XVTWIN_H +#define __XVTWIN_H + +#ifndef _WX_PROCESSH__ +#include +#endif + +class TFontId : public wxObject +{ + wxString m_strFace; + int m_nSize; + XVT_FONT_STYLE_MASK m_wMask; + WINDOW m_win; + DECLARE_DYNAMIC_CLASS(TFontId); + +protected: + void Copy(const TFontId& pFont); + bool IsEqual(const TFontId& pFont) const; + +public: + void SetWin(WINDOW w) { m_win = w; } + WINDOW Win() const { return m_win; } + + void SetPointSize(int s) { m_nSize = s; } + int PointSize() const { return m_nSize; } + + void SetMask(XVT_FONT_STYLE_MASK mask) { m_wMask = mask; } + XVT_FONT_STYLE_MASK Mask() const { return m_wMask; } + int Style() const; + bool Underline() const; + int Weight() const; + + void SetFaceName(const char* f) { m_strFace = f; } + const char* FaceName() const; + int Family() const; + + void Copy(const wxFont& rFont); + const wxFont& Font(wxDC* dc, WINDOW w) const; + + TFontId& operator=(const TFontId& f) { Copy(f); return *this; } + bool operator==(const TFontId& f) const { return IsEqual(f); } + bool operator!=(const TFontId& f) const { return !IsEqual(f); } + + TFontId() : m_nSize(0), m_wMask(0), m_win(NULL_WIN) { } + TFontId(const TFontId& f) : m_win(NULL_WIN) { Copy(f); } +}; + +class TDC : public wxObject +{ + wxWindow* _owner; + +protected: + wxDC* _dc; + RCT _clip; + int _dirty; // false = 0, true = 1, very_dirty = -1; + int _deltaf; + + DRAW_CTOOLS _real_dct; + TFontId _real_font; + RCT _real_clip; + + bool PenChanged() const; + bool BrushChanged() const; + bool FontChanged() const; + bool ClipChanged() const; + +public: + DRAW_CTOOLS _dct; + TFontId _font; + wxPoint _pnt; + + void SetClippingBox(const RCT* pRct); + bool GetClippingBox(RCT* pRct) const; + void SetDirty(int d = 1); + int GetFontDelta() const { return _deltaf; } + + virtual wxDC& GetDC(bool bPaint = false); + virtual void KillDC(); + TDC(wxWindow* owner); + virtual ~TDC(); +}; + +class TPrintDC : public TDC +{ + static bool _page_start; + +public: + static void SetPageStart(); + + virtual wxDC& GetDC(bool); + virtual void KillDC(); + TPrintDC(wxWindow* owner); + virtual ~TPrintDC(); +}; + +WX_DECLARE_HASH_MAP(WINDOW, TDC*, wxIntegerHash, wxIntegerEqual, wxTDCHashMap); + +class TDCMapper : public wxTDCHashMap +{ + WINDOW _pLastOwner; + TDC* _pLastTDC; + +public: + TDC& GetTDC(WINDOW owner); + wxDC& GetDC(WINDOW owner, bool bPaint = false) { return GetTDC(owner).GetDC(bPaint); } + void DestroyDC(WINDOW owner); + void DestroyTDC(WINDOW owner); + bool HasValidDC(WINDOW owner) const; + + TDCMapper() : _pLastOwner(NULL_WIN), _pLastTDC(NULL) { } + virtual ~TDCMapper() { DestroyTDC(NULL_WIN); } +}; + +TDCMapper& GetTDCMapper(); + +class TwxWindowBase : public wxWindow +{ +#ifdef LINUX +private: + wxString m_strTitle; + virtual void SetTitle(const wxString& title) { wxWindow::SetTitle(m_strTitle = title); } + virtual wxString GetTitle() const { return m_strTitle; } +#endif + +#ifdef WIN32 + virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); +#endif + +public: + bool CreateBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style); + + TwxWindowBase() { } + TwxWindowBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint & pos, const wxSize & size, long style); + DECLARE_DYNAMIC_CLASS(TwxWindowBase) +}; + +class wxAuiManager; + +class TwxWindow : public TwxWindowBase +{ +private: + MENU_ITEM* m_menu; + wxAuiManager* m_pManager; + bool m_bInDestroy; + +protected: + virtual void OnChar(wxKeyEvent& e); + virtual void OnClose(wxCloseEvent& e); + virtual void OnKeyDown(wxKeyEvent& e); + virtual void OnKillFocus(wxFocusEvent& e); + virtual void OnMenu(wxCommandEvent& e); + virtual void OnMouseCaptureLost(wxMouseCaptureLostEvent& e); + virtual void OnMouseDouble(wxMouseEvent& e); + virtual void OnMouseDown(wxMouseEvent& e); + virtual void OnMouseMove(wxMouseEvent& e); + virtual void OnMouseUp(wxMouseEvent& e); + virtual void OnMouseWheel(wxMouseEvent& e); + virtual void OnScroll(wxScrollEvent& e); + virtual void OnScrollWin(wxScrollWinEvent& e); + virtual void OnSetFocus(wxFocusEvent& e); + virtual void OnSize(wxSizeEvent& e); + virtual void OnTimer(wxTimerEvent& e); + virtual void OnButton(wxCommandEvent& e); + virtual void OnCheckBox(wxCommandEvent& e); + virtual void OnRadioButton(wxCommandEvent& e); + +public: + long DoXvtEvent(EVENT& e); + virtual void OnPaint(wxPaintEvent& e); + virtual bool InDestroy() const { return m_bInDestroy; } + +public: + WIN_TYPE _type; + EVENT_HANDLER _eh; + long _app_data; + wxTimer* _timer; + + void SetMenuTree(const MENU_ITEM* menu); + MENU_ITEM* GetMenuTree() const { return m_menu; } + + BOOLEAN AddPane(wxWindow* wnd, const char* name, int nDock = 0, int nFlags = 0); + + TwxWindow(); + TwxWindow(wxWindow *parent, wxWindowID id, const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0); + virtual ~TwxWindow(); + + DECLARE_DYNAMIC_CLASS(TwxWindow); + DECLARE_EVENT_TABLE(); +}; + +class TTaskWin : public wxFrame +{ + MENU_ITEM* m_menu; + + wxMenuBar* m_pOldBar; + wxWindow* m_MenuOwner; + XVT_COLOR_COMPONENT* m_xcc; + +protected: + virtual void OnClose(wxCloseEvent& e); + virtual void OnMenu(wxCommandEvent& e); + virtual void OnSize(wxSizeEvent& e); + void OnEndProcess(wxProcessEvent& evt); + +public: + virtual void OnPaint(wxPaintEvent& e); + DECLARE_DYNAMIC_CLASS(TTaskWin); + DECLARE_EVENT_TABLE(); + TTaskWin() : wxFrame(), m_menu(NULL), m_pOldBar(NULL), m_MenuOwner(NULL), m_xcc(NULL) { } // Needed by DECLARE_DYNAMIC_CLASS + +public: + void SetMenuTree(const MENU_ITEM* tree); + const MENU_ITEM* GetMenuTree() const { return m_menu; } + void PushMenuTree(const MENU_ITEM* tree, wxWindow* owner); + void PopMenuTree(); + + COLOR GetCtlColor(XVT_COLOR_TYPE c) const; + const XVT_COLOR_COMPONENT* GetCtlColors() const; + void SetCtlColors(const XVT_COLOR_COMPONENT* colors); + + TTaskWin(wxWindowID id, const wxString& title, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE); + virtual ~TTaskWin(); +}; + +struct XVT_EVENT : public EVENT +{ + XVT_EVENT(EVENT_TYPE t) { memset(this, 0, sizeof(EVENT)); type = t; } +}; + +#define TIMER_ID 1 +const wxString& _GetAppTitle(); + +#define CAST_WIN(win,w) wxWindow& w = *wxStaticCast((wxObject*)win, wxWindow); +#define CAST_TWIN(win,w) TwxWindow& w = *wxStaticCast((wxObject*)win, TwxWindow); +#define CAST_TDC(win,dc) TDC& dc = GetTDCMapper().GetTDC(win); +#define CAST_DC(win,dc) wxDC& dc = GetTDCMapper().GetDC(win); +#define CAST_FONT(font_id, font) TFontId& font = *wxStaticCast(font_id, TFontId); + +#define CAST_COLOR(xc, wc) wxColour wc((xc>>16)&0xFF, (xc>>8)&0xFF, xc&0xFF) +#define MAKE_XVT_COLOR(wc) XVT_MAKE_COLOR(wc.Red(), wc.Green(), wc.Blue()) +wxRect RCT2Rect(const RCT* prct); +void Rect2RCT(const wxRect& rect, RCT* rct); + +#ifdef XVTWIN_CPP +#define extern +#endif + +extern wxHashTable _nice_windows; +extern wxFrame* _task_win; +extern EVENT_HANDLER _task_win_handler; + +#endif diff --git a/src/xvaga01/xvtxslt.cpp b/src/xvaga01/xvtxslt.cpp new file mode 100644 index 000000000..338c1ea1b --- /dev/null +++ b/src/xvaga01/xvtxslt.cpp @@ -0,0 +1,69 @@ +#include "xvtslt.h" +#include "libxslt/libxslt.h" +#include "libxslt/xsltconfig.h" +#include "libexslt/exslt.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +XSLTDLL int xvt_xslt_transform(const char * infile, const char * stylefile, const char * outfile) // Added by AGA +{ + int error = 0; + xsltStylesheetPtr cur = nullptr; + xmlDocPtr doc = nullptr; + const xmlChar * style = xmlCharStrdup(stylefile); + + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 1; + cur = xsltParseStylesheetFile(style); + if (cur == nullptr) + error = 2; // stile assente + if ((error == 0) && (cur != nullptr) && (cur->errors == 0)) + { + doc = xmlParseFile(infile); + if (doc == nullptr) + error = 1; // input assente o errato + if (error == 0) + { + xmlDocPtr res = xsltApplyStylesheet(cur, doc, nullptr); + + if (res != nullptr) + { + xsltSaveResultToFilename(outfile, res, cur, 0); + // xmlFreeDoc(res); + } + else + error = 3; + } + } + if (style != nullptr) + free((void *) style); + if (cur != nullptr) + xsltFreeStylesheet(cur); + if (doc != nullptr) + xmlFreeDoc(doc); + xsltCleanupGlobals(); + xmlCleanupParser(); + return error; +} \ No newline at end of file