You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
792 lines
29 KiB
792 lines
29 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, 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 3 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, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
|
|
#include "HeadSpin.h" |
|
#include "hsTemplates.h" |
|
#include "hsWindows.h" |
|
|
|
#include <max.h> |
|
#include <iparamm2.h> |
|
|
|
#include "MaxMain/MaxCompat.h" |
|
#include "MaxMain/plMaxNodeBase.h" |
|
#include "resource.h" |
|
#pragma hdrstop |
|
|
|
#include "pfGUISkinComp.h" |
|
#include "plGUICompClassIDs.h" |
|
|
|
|
|
pfGUISkinEditProc *pfGUISkinEditProc::fInstance = nil; |
|
int pfGUISkinEditProc::fZoom = 3; // So re-opening the dialog will keep the same zoom level |
|
|
|
extern HINSTANCE hInstance; |
|
|
|
pfGUISkinEditProc::pfGUISkinEditProc( plGUISkinComp *comp ) |
|
{ |
|
fInstance = this; |
|
fComp = comp; |
|
|
|
fDblDC = nil; |
|
fDblBitmap = nil; |
|
|
|
fXOffset = fYOffset = 0; |
|
|
|
fCurrPBRefSet = plGUISkinComp::kRefUpLeftCorner; |
|
|
|
fDefPen = CreatePen( PS_SOLID, 3, RGB( 200, 0, 0 ) ); |
|
fOtherPen = CreatePen( PS_DOT, 1, RGB( 200, 0, 0 ) ); |
|
|
|
fDragging = false; |
|
fDragTimer = 0; |
|
|
|
// Back up the old settings |
|
IParamBlock2 *pb = fComp->GetParamBlockByID( plComponent::kBlkComp ); |
|
for( int i = 0; i < pfGUISkin::kNumElements; i++ ) |
|
{ |
|
int id = i * 4 + plGUISkinComp::kRefUpLeftCorner; |
|
fBackups[ i ].fX = pb->GetInt( id + 0 ); |
|
fBackups[ i ].fY = pb->GetInt( id + 1 ); |
|
fBackups[ i ].fWidth = pb->GetInt( id + 2 ); |
|
fBackups[ i ].fHeight = pb->GetInt( id + 3 ); |
|
} |
|
} |
|
|
|
pfGUISkinEditProc::~pfGUISkinEditProc() |
|
{ |
|
fInstance = nil; |
|
DeleteObject( fDefPen ); |
|
IKillDblBuffer(); |
|
} |
|
|
|
void pfGUISkinEditProc::IJustDrawOneRect( int whichElement, IParamBlock2 *pb, HDC hDC, HPEN whichPen, int refToIgnore ) |
|
{ |
|
whichElement = ( whichElement * 4 ) + plGUISkinComp::kRefUpLeftCorner; |
|
|
|
if( whichElement == refToIgnore ) |
|
return; |
|
|
|
RECT r; |
|
SetRect( &r, pb->GetInt( whichElement + 0 ), |
|
pb->GetInt( whichElement + 1 ), |
|
pb->GetInt( whichElement + 0 ) + pb->GetInt( whichElement + 2 ), |
|
pb->GetInt( whichElement + 1 ) + pb->GetInt( whichElement + 3 ) ); |
|
|
|
r.left *= fZoom; r.right *= fZoom; r.top *= fZoom; r.bottom *= fZoom; |
|
|
|
SelectObject( hDC, whichPen ); |
|
int rop2 = SetROP2( hDC, R2_NOTXORPEN ); |
|
|
|
MoveToEx( hDC, r.left, r.top, nil ); |
|
LineTo( hDC, r.right, r.top ); |
|
LineTo( hDC, r.right, r.bottom ); |
|
LineTo( hDC, r.left, r.bottom ); |
|
LineTo( hDC, r.left, r.top ); |
|
|
|
SetROP2( hDC, rop2 ); |
|
} |
|
|
|
void pfGUISkinEditProc::IRefreshDblBuffer( void ) |
|
{ |
|
// Image buffer is where we keep our resized image. Dbl buffer is where we draw our bounds |
|
if( fDblDC == nil ) |
|
IInitDblBuffer(); |
|
else |
|
{ |
|
// Copy the zoomed image as our backdrop |
|
BitBlt( fDblDC, 0, 0, fDblWidth, fDblHeight, fImageDC, 0, 0, SRCCOPY ); |
|
|
|
RECT r; |
|
IParamBlock2 *pb = fComp->GetParamBlockByID( plComponent::kBlkComp ); |
|
if( pb != nil ) |
|
{ |
|
// Draw all the other elements other than our current one |
|
for( int i = 0; i < pfGUISkin::kNumElements; i++ ) |
|
IJustDrawOneRect( i, pb, fDblDC, fOtherPen, fCurrPBRefSet ); |
|
|
|
// Now draw the bounds of our current element |
|
SetRect( &r, pb->GetInt( fCurrPBRefSet + 0 ), |
|
pb->GetInt( fCurrPBRefSet + 1 ), |
|
pb->GetInt( fCurrPBRefSet + 0 ) + pb->GetInt( fCurrPBRefSet + 2 ), |
|
pb->GetInt( fCurrPBRefSet + 1 ) + pb->GetInt( fCurrPBRefSet + 3 ) ); |
|
|
|
// While we have it here, go ahead and update our status text for this element |
|
char str[ 256 ]; |
|
sprintf( str, "Left: %d\nTop: %d\nWidth: %d\nHeight: %d\n", r.left, r.top, r.right - r.left, r.bottom - r.top ); |
|
SetDlgItemText( fHWnd, IDC_GUI_INFO, str ); |
|
|
|
r.left *= fZoom; r.right *= fZoom; r.top *= fZoom; r.bottom *= fZoom; |
|
|
|
SelectObject( fDblDC, fDefPen ); |
|
int rop2 = SetROP2( fDblDC, R2_NOTXORPEN ); |
|
|
|
MoveToEx( fDblDC, r.left, r.top, nil ); |
|
LineTo( fDblDC, r.right, r.top ); |
|
LineTo( fDblDC, r.right, r.bottom ); |
|
LineTo( fDblDC, r.left, r.bottom ); |
|
LineTo( fDblDC, r.left, r.top ); |
|
|
|
SetROP2( fDblDC, rop2 ); |
|
|
|
fCurrElemRect = r; |
|
MapWindowPoints( GetDlgItem( fHWnd, IDC_GUI_PREVIEW ), fHWnd, (POINT *)&fCurrElemRect, 2 ); |
|
OffsetRect( &fCurrElemRect, -fXOffset, -fYOffset ); |
|
} |
|
} |
|
} |
|
|
|
void pfGUISkinEditProc::IRefreshImageBuffer( void ) |
|
{ |
|
IInitDblBuffer(); |
|
|
|
plLayerTex *layer = fComp->GetSkinBitmap(); |
|
PBBitmap *pbBMap = layer->GetPBBitmap(); |
|
|
|
if( pbBMap->bm == nil ) |
|
pbBMap->Load(); |
|
if( pbBMap->bm != nil ) |
|
{ |
|
// Copy into a new temp bitmap that is the right format for us to read |
|
Bitmap *newBM; |
|
BitmapInfo bi; |
|
bi.SetName( _T("y879873b") ); |
|
bi.SetType( BMM_TRUE_32 ); |
|
bi.SetFlags( MAP_HAS_ALPHA ); |
|
bi.SetWidth( fDblWidth ); |
|
bi.SetHeight( fDblHeight ); |
|
newBM = TheManager->Create( &bi ); |
|
|
|
BMM_Color_64 foo = BMMCOLOR(0, 0, 0, 0); |
|
newBM->CopyImage( pbBMap->bm, COPY_IMAGE_RESIZE_LO_QUALITY, foo, nil ); |
|
|
|
// Now copy from our newly created bitmap into our DC....way slow :( |
|
BITMAPINFO *bitInfo = newBM->ToDib( 24, nil, false ); |
|
if( bitInfo != nil ) |
|
{ |
|
SetDIBitsToDevice( fImageDC, 0, 0, fDblWidth, fDblHeight, |
|
0, 0, 0, fDblHeight, |
|
( (uint8_t *)bitInfo ) + bitInfo->bmiHeader.biSize, |
|
bitInfo, |
|
DIB_RGB_COLORS ); |
|
} |
|
|
|
newBM->DeleteThis(); |
|
} |
|
|
|
IRefreshDblBuffer(); |
|
} |
|
|
|
void pfGUISkinEditProc::IInitDblBuffer( void ) |
|
{ |
|
if( fDblDC == NULL ) |
|
{ |
|
int width, height; |
|
HDC desk = GetDC( NULL ); |
|
|
|
plLayerTex *layer = fComp->GetSkinBitmap(); |
|
PBBitmap *pbBMap = layer->GetPBBitmap(); |
|
if( pbBMap == nil ) |
|
return; |
|
width = pbBMap->bi.Width() * fZoom; |
|
height = pbBMap->bi.Height() * fZoom; |
|
// GetClientRect( fHWnd, &r ); |
|
// width = r.right - r.left; |
|
// height = r.bottom - r.top; |
|
|
|
// Note: For some strange reason, grabbing the HDC of the window doesn't do |
|
// any good, 'cause it's black-and-white (right, THAT makes sense). Grabbing |
|
// the desktop DC works, however. |
|
|
|
fDblDC = CreateCompatibleDC( desk ); |
|
fDblBitmap = CreateCompatibleBitmap( desk/*fDblDC*/, width, height ); |
|
SelectObject( fDblDC, fDblBitmap ); |
|
|
|
fImageDC = CreateCompatibleDC( desk ); |
|
fImageBitmap = CreateCompatibleBitmap( desk/*fDblDC*/, width, height ); |
|
SelectObject( fImageDC, fImageBitmap ); |
|
|
|
ReleaseDC( NULL, desk ); |
|
|
|
fDblWidth = width; |
|
fDblHeight = height; |
|
|
|
ISetScrollRanges(); |
|
IRefreshImageBuffer(); |
|
} |
|
} |
|
|
|
void pfGUISkinEditProc::IKillDblBuffer( void ) |
|
{ |
|
if( fDblDC != NULL ) |
|
{ |
|
SelectObject( fDblDC, (HBITMAP)NULL ); |
|
DeleteObject( fDblBitmap ); |
|
DeleteDC( fDblDC ); |
|
} |
|
|
|
if( fImageDC != NULL ) |
|
{ |
|
SelectObject( fImageDC, (HBITMAP)NULL ); |
|
DeleteObject( fImageBitmap ); |
|
DeleteDC( fImageDC ); |
|
} |
|
|
|
fDblDC = fImageDC = nil; |
|
fDblBitmap = fImageBitmap = nil; |
|
} |
|
|
|
void pfGUISkinEditProc::ISetScrollRanges( void ) |
|
{ |
|
SCROLLINFO info; |
|
|
|
|
|
int visW = fPreviewRect.right - fPreviewRect.left; |
|
int visH = fPreviewRect.bottom - fPreviewRect.top; |
|
|
|
if( visW < fDblWidth ) |
|
{ |
|
if( fXOffset > fDblWidth - visW ) |
|
fXOffset = fDblWidth - visW; |
|
else if( fXOffset < 0 ) |
|
fXOffset = 0; |
|
|
|
info.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; |
|
info.nMin = 0; |
|
info.nMax = fDblWidth;// - visW; |
|
info.nPage = visW; |
|
info.nPos = fXOffset; |
|
info.cbSize = sizeof( info ); |
|
|
|
SetScrollInfo( GetDlgItem( fHWnd, IDC_GUI_HORZSCROLL ), SB_CTL, &info, true ); |
|
ShowWindow( GetDlgItem( fHWnd, IDC_GUI_HORZSCROLL ), true ); |
|
} |
|
else |
|
{ |
|
ShowWindow( GetDlgItem( fHWnd, IDC_GUI_HORZSCROLL ), false ); |
|
fXOffset = 0; |
|
} |
|
|
|
if( visH < fDblHeight ) |
|
{ |
|
if( fYOffset > fDblHeight - visH ) |
|
fYOffset = fDblHeight - visH; |
|
else if( fYOffset < 0 ) |
|
fYOffset = 0; |
|
|
|
info.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; |
|
info.nMin = 0; |
|
info.nMax = fDblHeight;// - visH; |
|
info.nPage = visH; |
|
info.nPos = fYOffset; |
|
info.cbSize = sizeof( info ); |
|
|
|
SetScrollInfo( GetDlgItem( fHWnd, IDC_GUI_VERTSCROLL ), SB_CTL, &info, true ); |
|
ShowWindow( GetDlgItem( fHWnd, IDC_GUI_VERTSCROLL ), true ); |
|
} |
|
else |
|
{ |
|
ShowWindow( GetDlgItem( fHWnd, IDC_GUI_VERTSCROLL ), false ); |
|
fYOffset = 0; |
|
} |
|
} |
|
|
|
bool pfGUISkinEditProc::IPointWithinRange( int x, int y, int ptX, int ptY ) |
|
{ |
|
if( x > ptX - kRangeSlop && x < ptX + kRangeSlop && |
|
y > ptY - kRangeSlop && y < ptY + kRangeSlop ) |
|
return true; |
|
return false; |
|
} |
|
|
|
bool pfGUISkinEditProc::IPointWithinVertRange( int x, int y, int ptX, int ptY1, int ptY2 ) |
|
{ |
|
if( x > ptX - kRangeSlop && x < ptX + kRangeSlop && |
|
y > ptY1 - kRangeSlop && y < ptY2 + kRangeSlop ) |
|
return true; |
|
return false; |
|
} |
|
|
|
bool pfGUISkinEditProc::IPointWithinHorzRange( int x, int y, int ptX1, int ptX2, int ptY ) |
|
{ |
|
if( x > ptX1 - kRangeSlop && x < ptX2 + kRangeSlop && |
|
y > ptY - kRangeSlop && y < ptY + kRangeSlop ) |
|
return true; |
|
return false; |
|
} |
|
|
|
uint8_t pfGUISkinEditProc::IGetDragTypeFlags( int x, int y ) |
|
{ |
|
// Corners |
|
if( IPointWithinRange( x, y, fCurrElemRect.left, fCurrElemRect.top ) ) |
|
return kLeft | kTop; |
|
if( IPointWithinRange( x, y, fCurrElemRect.right, fCurrElemRect.top ) ) |
|
return kRight | kTop; |
|
if( IPointWithinRange( x, y, fCurrElemRect.right, fCurrElemRect.bottom ) ) |
|
return kRight | kBottom; |
|
if( IPointWithinRange( x, y, fCurrElemRect.left, fCurrElemRect.bottom ) ) |
|
return kLeft | kBottom; |
|
|
|
// Edges |
|
if( IPointWithinVertRange( x, y, fCurrElemRect.left, fCurrElemRect.top, fCurrElemRect.bottom ) ) |
|
return kLeft; |
|
if( IPointWithinVertRange( x, y, fCurrElemRect.right, fCurrElemRect.top, fCurrElemRect.bottom ) ) |
|
return kRight; |
|
|
|
if( IPointWithinHorzRange( x, y, fCurrElemRect.left, fCurrElemRect.right, fCurrElemRect.top ) ) |
|
return kTop; |
|
if( IPointWithinHorzRange( x, y, fCurrElemRect.left, fCurrElemRect.right, fCurrElemRect.bottom ) ) |
|
return kBottom; |
|
|
|
// The middle |
|
if( x >= fCurrElemRect.left && x <= fCurrElemRect.right && y >= fCurrElemRect.top && y <= fCurrElemRect.bottom ) |
|
return kDragAll; |
|
|
|
return 0; |
|
} |
|
|
|
INT_PTR CALLBACK pfGUISkinEditProc::DlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
return fInstance->DialogProc( hDlg, msg, wParam, lParam ); |
|
} |
|
|
|
INT_PTR CALLBACK pfGUISkinEditProc::DialogProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
PAINTSTRUCT pInfo; |
|
RECT r; |
|
HDC hDC; |
|
int maxDim, i, j, x, y; |
|
bool timerActive = false; |
|
|
|
|
|
static struct plElemPair |
|
{ |
|
pfGUISkin::Elements el; |
|
const char *name; |
|
} sElemPairs[] = { { pfGUISkin::kUpLeftCorner, "Upper-left Corner" }, |
|
{ pfGUISkin::kTopSpan, "Top Span" }, |
|
{ pfGUISkin::kUpRightCorner, "Upper-right Corner" }, |
|
{ pfGUISkin::kRightSpan, "Right Span" }, |
|
{ pfGUISkin::kLowerRightCorner, "Lower-right Corner" }, |
|
{ pfGUISkin::kBottomSpan, "Bottom Span" }, |
|
{ pfGUISkin::kLowerLeftCorner, "Lower-left Corner" }, |
|
{ pfGUISkin::kLeftSpan, "Left Span" }, |
|
{ pfGUISkin::kMiddleFill, "Middle Fill" }, |
|
{ pfGUISkin::kSelectedFill, "Selected Middle Fill" }, |
|
{ pfGUISkin::kSubMenuArrow, "Sub-Menu Arrow" }, |
|
{ pfGUISkin::kSelectedSubMenuArrow, "Selected Sub-Menu Arrow" }, |
|
{ pfGUISkin::kTreeButtonClosed, "Tree-view Button, Closed" }, |
|
{ pfGUISkin::kTreeButtonOpen, "Tree-view Button, Open" }, |
|
{ pfGUISkin::kNumElements, nil } }; |
|
|
|
|
|
fHWnd = hDlg; |
|
|
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
|
|
// Get preview rect |
|
GetClientRect( GetDlgItem( hDlg, IDC_GUI_PREVIEW ), &fPreviewRect ); |
|
MapWindowPoints( GetDlgItem( hDlg, IDC_GUI_PREVIEW ), hDlg, (POINT *)&fPreviewRect, 2 ); |
|
|
|
SendDlgItemMessage( hDlg, IDC_GUI_ZIN, BM_SETIMAGE, (WPARAM)IMAGE_ICON, |
|
(LPARAM)LoadImage( hInstance, MAKEINTRESOURCE( IDI_ZOOMIN ), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ) ); |
|
SendDlgItemMessage( hDlg, IDC_GUI_ZOUT, BM_SETIMAGE, (WPARAM)IMAGE_ICON, |
|
(LPARAM)LoadImage( hInstance, MAKEINTRESOURCE( IDI_ZOOMOUT ), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ) ); |
|
|
|
// Fill element list |
|
SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_RESETCONTENT, 0, 0 ); |
|
for( i = 0; sElemPairs[ i ].el != pfGUISkin::kNumElements; i++ ) |
|
{ |
|
int idx = SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_ADDSTRING, 0, (LPARAM)sElemPairs[ i ].name ); |
|
SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_SETITEMDATA, (WPARAM)idx, (LPARAM)sElemPairs[ i ].el ); |
|
if( sElemPairs[ i ].el == pfGUISkin::kUpLeftCorner ) |
|
j = idx; |
|
} |
|
SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_SETCURSEL, j, 0 ); |
|
|
|
fOrigCursor = LoadCursor( nil, IDC_ARROW );//GetCursor(); |
|
|
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDCANCEL ) |
|
{ |
|
// Since we've been editing the PB directly, we have to now restore them |
|
// to their original values |
|
IParamBlock2 *pb = fComp->GetParamBlockByID( plComponent::kBlkComp ); |
|
for( int i = 0; i < pfGUISkin::kNumElements; i++ ) |
|
{ |
|
int id = i * 4 + plGUISkinComp::kRefUpLeftCorner; |
|
pb->SetValue( id + 0, 0, (int)fBackups[ i ].fX ); |
|
pb->SetValue( id + 1, 0, (int)fBackups[ i ].fY ); |
|
pb->SetValue( id + 2, 0, (int)fBackups[ i ].fWidth ); |
|
pb->SetValue( id + 3, 0, (int)fBackups[ i ].fHeight ); |
|
} |
|
EndDialog( hDlg, 1 ); |
|
} |
|
else if( LOWORD( wParam ) == IDOK ) |
|
EndDialog( hDlg, 0 ); |
|
else if( LOWORD( wParam ) == IDC_GUI_ZIN ) |
|
{ |
|
fXOffset /= fZoom; fYOffset /= fZoom; |
|
fZoom++; |
|
fXOffset *= fZoom; fYOffset *= fZoom; |
|
|
|
IKillDblBuffer(); |
|
IRefreshImageBuffer(); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_ZOUT ) |
|
{ |
|
if( fZoom > 1 ) |
|
{ |
|
fXOffset /= fZoom; fYOffset /= fZoom; |
|
fZoom--; |
|
fXOffset *= fZoom; fYOffset *= fZoom; |
|
|
|
IKillDblBuffer(); |
|
IRefreshImageBuffer(); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_ELEMENTS ) |
|
{ |
|
int idx = SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_GETCURSEL, 0, 0 ); |
|
fCurrPBRefSet = SendDlgItemMessage( hDlg, IDC_GUI_ELEMENTS, LB_GETITEMDATA, (WPARAM)idx, 0 ) * 4 + plGUISkinComp::kRefUpLeftCorner; |
|
|
|
IRefreshDblBuffer(); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
} |
|
return true; |
|
|
|
case WM_CLOSE: |
|
EndDialog( hDlg, 0 ); |
|
return true; |
|
|
|
case WM_HSCROLL: |
|
OffsetRect( &fCurrElemRect, fXOffset, fYOffset ); |
|
switch( LOWORD( wParam ) ) |
|
{ |
|
case SB_PAGEUP: fXOffset -= 300; break; |
|
case SB_PAGEDOWN: fXOffset += 300; break; |
|
case SB_LINEUP: fXOffset -= 16; break; |
|
case SB_LINEDOWN: fXOffset += 16; break; |
|
case SB_THUMBPOSITION: |
|
case SB_THUMBTRACK: |
|
fXOffset = HIWORD( wParam ); |
|
break; |
|
} |
|
maxDim = fDblWidth - ( fPreviewRect.right - fPreviewRect.left ); |
|
if( fXOffset < 0 ) |
|
fXOffset = 0; |
|
else if( fXOffset > maxDim ) |
|
fXOffset = maxDim; |
|
SetScrollPos( GetDlgItem( hDlg, IDC_GUI_HORZSCROLL ), SB_CTL, fXOffset, true ); |
|
|
|
OffsetRect( &fCurrElemRect, -fXOffset, -fYOffset ); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
break; |
|
|
|
case WM_VSCROLL: |
|
OffsetRect( &fCurrElemRect, fXOffset, fYOffset ); |
|
switch( LOWORD( wParam ) ) |
|
{ |
|
case SB_PAGEUP: fYOffset -= 300; break; |
|
case SB_PAGEDOWN: fYOffset += 300; break; |
|
case SB_LINEUP: fYOffset -= 16; break; |
|
case SB_LINEDOWN: fYOffset += 16; break; |
|
case SB_THUMBPOSITION: |
|
case SB_THUMBTRACK: |
|
fYOffset = HIWORD( wParam ); |
|
break; |
|
} |
|
maxDim = fDblHeight - ( fPreviewRect.bottom - fPreviewRect.top ); |
|
if( fYOffset < 0 ) |
|
fYOffset = 0; |
|
else if( fYOffset > maxDim ) |
|
fYOffset = maxDim; |
|
SetScrollPos( GetDlgItem( hDlg, IDC_GUI_VERTSCROLL ), SB_CTL, fYOffset, true ); |
|
|
|
OffsetRect( &fCurrElemRect, -fXOffset, -fYOffset ); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
break; |
|
|
|
case WM_PAINT: |
|
{ |
|
BeginPaint( hDlg, &pInfo ); |
|
hDC = (HDC)pInfo.hdc; |
|
|
|
if( fDblDC == NULL ) |
|
IInitDblBuffer(); |
|
|
|
int width = fDblWidth; |
|
int height = fDblHeight; |
|
if( width > fPreviewRect.right - fPreviewRect.left ) |
|
width = fPreviewRect.right - fPreviewRect.left; |
|
if( height > fPreviewRect.bottom - fPreviewRect.top ) |
|
height = fPreviewRect.bottom - fPreviewRect.top; |
|
|
|
BitBlt( hDC, fPreviewRect.left, fPreviewRect.top, width, height, fDblDC, fXOffset, fYOffset, SRCCOPY ); |
|
|
|
r = fPreviewRect; |
|
r.left += width; |
|
FillRect( hDC, &r, ColorMan()->GetBrush( kBackground ) ); |
|
|
|
r = fPreviewRect; |
|
r.top += height; |
|
FillRect( hDC, &r, ColorMan()->GetBrush( kBackground ) ); |
|
|
|
EndPaint( hDlg, &pInfo ); |
|
} |
|
break; |
|
|
|
case WM_LBUTTONDOWN: |
|
SetCapture( hDlg ); |
|
fDragging = true; |
|
fDragType = IGetDragTypeFlags( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) ); |
|
if( fDragType == kDragAll ) |
|
{ |
|
fDragOffsetX = fCurrElemRect.left - GET_X_LPARAM( lParam ); |
|
fDragOffsetY = fCurrElemRect.top - GET_Y_LPARAM( lParam ); |
|
} |
|
else if( fDragType == 0 ) |
|
{ |
|
fDragOffsetX = GET_X_LPARAM( lParam ) + fXOffset; |
|
fDragOffsetY = GET_Y_LPARAM( lParam ) + fYOffset; |
|
} |
|
else |
|
fDragOffsetX = fDragOffsetY = 0; |
|
|
|
break; |
|
|
|
case WM_LBUTTONUP: |
|
ReleaseCapture(); |
|
fDragging = false; |
|
break; |
|
|
|
case WM_TIMER: |
|
// We do the same processing as MOUSEMOVE, but we need to make sure we have the right |
|
// mouse position first |
|
{ |
|
POINT pt; |
|
GetCursorPos( &pt ); |
|
MapWindowPoints( nil, hDlg, &pt, 1 ); |
|
lParam = MAKELPARAM( pt.x, pt.y ); |
|
} |
|
// Fall thru... |
|
|
|
case WM_MOUSEMOVE: |
|
x = GET_X_LPARAM( lParam ); |
|
y = GET_Y_LPARAM( lParam ); |
|
|
|
if( fDragging ) |
|
{ |
|
if( fDragType == 0 ) |
|
{ |
|
fXOffset = fDragOffsetX - x; |
|
fYOffset = fDragOffsetY - y; |
|
ISetScrollRanges(); // Will clamp offset \for us |
|
} |
|
else |
|
{ |
|
// Translate x and y into bitmap space |
|
POINT pt; |
|
pt.x = x; |
|
pt.y = y; |
|
|
|
if( PtInRect( &fPreviewRect, pt ) ) |
|
{ |
|
MapWindowPoints( hDlg, GetDlgItem( hDlg, IDC_GUI_PREVIEW ), &pt, 1 ); |
|
|
|
pt.x += fDragOffsetX; |
|
pt.y += fDragOffsetY; |
|
|
|
// Note the + 1/2 zoom so it's the closest pixel by center, not by area |
|
x = ( pt.x + fXOffset + ( fZoom >> 1 ) ) / fZoom; |
|
y = ( pt.y + fYOffset + ( fZoom >> 1 ) ) / fZoom; |
|
|
|
// Set depending on our current drag flags |
|
// Note the logic here: if we drag left, we want width and left changing, |
|
// if we drag both, just left, if we drag right, just width |
|
IParamBlock2 *pb = fComp->GetParamBlockByID( plComponent::kBlkComp ); |
|
if( fDragType & kLeft ) |
|
{ |
|
if( fDragType & kRight ) |
|
pb->SetValue( fCurrPBRefSet + 0, 0, (int)x ); |
|
else |
|
{ |
|
int old = pb->GetInt( fCurrPBRefSet + 0 ) + pb->GetInt( fCurrPBRefSet + 2 ); |
|
|
|
pb->SetValue( fCurrPBRefSet + 0, 0, (int)x ); |
|
pb->SetValue( fCurrPBRefSet + 2, 0, (int)old - x ); |
|
} |
|
} |
|
else if( fDragType & kRight ) |
|
pb->SetValue( fCurrPBRefSet + 2, 0, (int)x - pb->GetInt( fCurrPBRefSet + 0 ) ); |
|
|
|
if( fDragType & kTop ) |
|
{ |
|
if( fDragType & kBottom ) |
|
pb->SetValue( fCurrPBRefSet + 1, 0, (int)y ); |
|
else |
|
{ |
|
int old = pb->GetInt( fCurrPBRefSet + 1 ) + pb->GetInt( fCurrPBRefSet + 3 ); |
|
|
|
pb->SetValue( fCurrPBRefSet + 1, 0, (int)y ); |
|
pb->SetValue( fCurrPBRefSet + 3, 0, (int)old - y ); |
|
} |
|
} |
|
else if( fDragType & kBottom ) |
|
pb->SetValue( fCurrPBRefSet + 3, 0, (int)y - pb->GetInt( fCurrPBRefSet + 1 ) ); |
|
|
|
// Clamp width and height |
|
if( pb->GetInt( fCurrPBRefSet + 2 ) < 0 ) |
|
pb->SetValue( fCurrPBRefSet + 2, 0, (int)0 ); |
|
if( pb->GetInt( fCurrPBRefSet + 3 ) < 0 ) |
|
pb->SetValue( fCurrPBRefSet + 3, 0, (int)0 ); |
|
|
|
// Clamp X and Y |
|
if( pb->GetInt( fCurrPBRefSet + 0 ) < 0 ) |
|
pb->SetValue( fCurrPBRefSet + 0, 0, (int)0 ); |
|
else if( pb->GetInt( fCurrPBRefSet + 0 ) + pb->GetInt( fCurrPBRefSet + 2 ) > fDblWidth / fZoom ) |
|
pb->SetValue( fCurrPBRefSet + 0, 0, (int)fDblWidth / fZoom - pb->GetInt( fCurrPBRefSet + 2 ) ); |
|
|
|
if( pb->GetInt( fCurrPBRefSet + 1 ) < 0 ) |
|
pb->SetValue( fCurrPBRefSet + 1, 0, (int)0 ); |
|
else if( pb->GetInt( fCurrPBRefSet + 1 ) + pb->GetInt( fCurrPBRefSet + 3 ) > fDblHeight / fZoom ) |
|
pb->SetValue( fCurrPBRefSet + 1, 0, (int)fDblHeight / fZoom - pb->GetInt( fCurrPBRefSet + 3 ) ); |
|
} |
|
else |
|
{ |
|
// Mouse is outside our preview, so scroll if possible |
|
int dX = ( x < fPreviewRect.left ) ? x - fPreviewRect.left : ( x > fPreviewRect.right ) ? x - fPreviewRect.right : 0; |
|
int dY = ( y < fPreviewRect.top ) ? y - fPreviewRect.top : ( y > fPreviewRect.bottom ) ? y - fPreviewRect.bottom : 0; |
|
|
|
fXOffset += dX; |
|
fYOffset += dY; |
|
OffsetRect( &fCurrElemRect, -dX, -dY ); |
|
|
|
ISetScrollRanges(); // Will clamp origin for us |
|
|
|
// Don't actually drag our bounds, 'cause we're scrolling |
|
|
|
// Note: since we only get MOUSEMOVE when, gee, the mouse moves, if we've scrolled over, it'll only |
|
// do it once and then wait for the mouse to nudge again. We'd rather it keep going until the user |
|
// moves the mouse again, so we create a timer that calls us back in n somethingths so we can check again |
|
if( fDragTimer == 0 ) |
|
fDragTimer = SetTimer( hDlg, 0, 200, nil ); |
|
timerActive = true; // So we don't kill it at the end here... |
|
} |
|
} |
|
|
|
IRefreshDblBuffer(); |
|
InvalidateRect( hDlg, &fPreviewRect, false ); |
|
} |
|
else |
|
{ |
|
uint8_t dragType = IGetDragTypeFlags( x, y ); |
|
HCURSOR cursor; |
|
switch( dragType ) |
|
{ |
|
case kLeft | kTop: |
|
case kRight | kBottom: |
|
cursor = LoadCursor( nil, IDC_SIZENWSE ); |
|
break; |
|
case kLeft | kBottom: |
|
case kRight | kTop: |
|
cursor = LoadCursor( nil, IDC_SIZENESW ); |
|
break; |
|
case kLeft: |
|
case kRight: |
|
cursor = LoadCursor( nil, IDC_SIZEWE ); |
|
break; |
|
case kTop: |
|
case kBottom: |
|
cursor = LoadCursor( nil, IDC_SIZENS ); |
|
break; |
|
case kLeft | kTop | kRight | kBottom: |
|
cursor = LoadCursor( nil, IDC_SIZEALL ); |
|
break; |
|
default: |
|
{ |
|
POINT pt; |
|
pt.x = x; |
|
pt.y = y; |
|
if( PtInRect( &fPreviewRect, pt ) ) |
|
cursor = LoadCursor( nil, IDC_HAND ); |
|
else |
|
cursor = fOrigCursor; |
|
} |
|
break; |
|
} |
|
|
|
SetCursor( cursor ); |
|
|
|
if( !timerActive ) |
|
{ |
|
// No longer need our trick timer, so kill it |
|
KillTimer( hDlg, fDragTimer ); |
|
fDragTimer = 0; |
|
} |
|
} |
|
break; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
plGUISkinComp *plGUISkinComp::GetGUIComp( INode *node ) |
|
{ |
|
if( node == nil ) |
|
return nil; |
|
|
|
plComponentBase *base = ( ( plMaxNodeBase *)node )->ConvertToComponent(); |
|
if( base == nil ) |
|
return nil; |
|
|
|
if( base->ClassID() == GUI_SKIN_CLASSID ) |
|
return (plGUISkinComp *)base; |
|
|
|
return nil; |
|
} |
|
|
|
|