#include "wxsheaders.h"
#include "wxsdragwindow.h"
#include <wx/dcclient.h>
#include <wx/dcbuffer.h>
#include <configmanager.h>
#include "widget.h"
#include "wxsevent.h"
#include "wxsmith.h"
#include "resources/wxswindowres.h"
wxsDragWindow::wxsDragWindow(wxWindow* Cover,wxsWidget* Wdg,const wxSize& Size):
wxControl(Cover,-1,wxDefaultPosition,Size,wxNO_BORDER|wxSTAY_ON_TOP),
RootWidget(Wdg), CurDragPoint(NULL), CurDragWidget(NULL), RefreshTimer(this,1),
BackFetchTimer(this,2), Background(NULL), BackFetchMode(true), PaintAfterFetch(false),
BlockTimerRefresh(false), BlockWidgetSelect(false),
DragParent(NULL), DragParentBitmap(NULL),
DragTarget(NULL), DragTargetBitmap(NULL)
{
RefreshTimer.Start(50);
Background = new wxBitmap(GetSize().GetWidth(),GetSize().GetHeight());
}
wxsDragWindow::~wxsDragWindow()
{
ClearDragPoints();
delete Background;
if ( DragTargetBitmap ) delete DragTargetBitmap;
if ( DragParentBitmap ) delete DragParentBitmap;
}
void wxsDragWindow::OnPaint(wxPaintEvent& event)
{
wxWindow* Wnd = this;
wxPaintDC DC(Wnd);
if ( !BackFetchMode || PaintAfterFetch )
{
AddGraphics(DC);
PaintAfterFetch = false;
BlockTimerRefresh = false;
}
else
{
BlockTimerRefresh = true;
// When in background fetch mode, this widget is hidden in order
// to fetch background image
Hide();
FetchArea.Union(GetUpdateRegion());
BackFetchTimer.Start(wxsDWFetchDelay,true);
}
}
void wxsDragWindow::TimerRefresh(wxTimerEvent& event)
{
if ( BlockTimerRefresh ) return;
wxClientDC DC(this);
AddGraphics(DC);
}
void wxsDragWindow::OnEraseBack(wxEraseEvent& event)
{
if ( !BackFetchMode || PaintAfterFetch )
{
wxDC& DC = *event.GetDC();
DC.DrawBitmap(*Background,0,0,false);
}
}
void wxsDragWindow::OnMouse(wxMouseEvent& event)
{
DragPointData* NewDragPoint = NULL;
wxsWidget* NewDragWidget = NULL;
int MouseX = event.GetX();
int MouseY = event.GetY();
wxsWidget* UnderCursor = FindWidgetAtPos(MouseX,MouseY,RootWidget);
// If we're out of window
if ( !UnderCursor )
{
UnderCursor = RootWidget;
// Small trick - changing to probably best container
while ( UnderCursor->GetChildCount()==1 &&
UnderCursor->GetChild(0)->IsContainer() )
{
UnderCursor = UnderCursor->GetChild(0);
}
}
// Posting this event to previews
ForwardMouseEventToPreview(event,UnderCursor);
// Disabling background fetch mode when dragging
BackFetchMode = !event.Dragging();
BlockTimerRefresh = event.Dragging();
// Searching for items covered by mouse
NewDragPoint = FindCoveredPoint(MouseX,MouseY);
if ( !NewDragPoint ) NewDragPoint = FindCoveredEdge(MouseX,MouseY);
if ( !NewDragPoint ) NewDragWidget = UnderCursor;
// Updating drag assist
UpdateAssist(event.Dragging(),UnderCursor);
// Processing events
if ( event.LeftUp() ) DragFinish(UnderCursor);
else if ( event.Dragging() ) DragProcess(MouseX,MouseY,UnderCursor);
else if ( event.LeftDown() ) DragInit(NewDragPoint,NewDragWidget,event.ControlDown(),MouseX,MouseY);
// Changing cursor
UpdateCursor(event.Dragging(),NewDragPoint,NewDragWidget);
}
void wxsDragWindow::ForwardMouseEventToPreview(wxMouseEvent& event,wxsWidget* Widget)
{
if ( Widget )
{
int WidgetRelativeX = event.GetX();
int WidgetRelativeY = event.GetY();
ClientToScreen(&WidgetRelativeX,&WidgetRelativeY);
Widget->GetPreview()->ScreenToClient(&WidgetRelativeX,&WidgetRelativeY);
event.m_x = WidgetRelativeX;
event.m_y = WidgetRelativeY;
Widget->PreviewMouseEvent(event);
}
}
wxsDragWindow::DragPointData* wxsDragWindow::FindCoveredPoint(int MouseX,int MouseY)
{
DragPointData* Found = NULL;
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
if ( !IsVisible((*i)->Widget) ) continue;
int PosX = (*i)->PosX - DragBoxSize/2;
int PosY = (*i)->PosY - DragBoxSize/2;
if ( MouseX >= PosX &&
MouseY >= PosY &&
MouseX <= PosX + DragBoxSize &&
MouseY <= PosY + DragBoxSize )
{
Found = *i;
if ( !Found->NoAction ) break;
}
}
return Found;
}
wxsDragWindow::DragPointData* wxsDragWindow::FindCoveredEdge(int MouseX,int MouseY)
{
DragPointData* Found = NULL;
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
DragPointData* DPD = *i;
if ( !IsVisible(DPD->Widget) ) continue;
switch ( DPD->Type )
{
case Top:
case Btm:
{
int PosX1, PosX2;
int SizeW, SizeH;
DPD->Widget->GetPreview()->GetSize(&SizeW,&SizeH);
if ( SizeH < DragBoxSize ) break; // There must be place to drag this widget
FindAbsolutePosition(DPD->Widget,&PosX1,&PosX2);
ScreenToClient(&PosX1,&PosX2);
PosX2 = PosX1 + SizeW;
int PosY = DPD->PosY - DragBoxSize / 2;
if ( MouseX >= PosX1 &&
MouseX <= PosX2 &&
MouseY >= PosY &&
MouseY <= PosY + DragBoxSize )
{
Found = DPD;
}
}
break;
case Left:
case Right:
{
int PosY1, PosY2;
int SizeW, SizeH;
DPD->Widget->GetPreview()->GetSize(&SizeW,&SizeH);
if ( SizeW < DragBoxSize ) break; // There must be place to drag this widget
FindAbsolutePosition(DPD->Widget,&PosY1,&PosY2);
ScreenToClient(&PosY1,&PosY2);
PosY1 = PosY2;
PosY2 = PosY1 + SizeH;
int PosX = DPD->PosX - DragBoxSize / 2;
if ( MouseY >= PosY1 &&
MouseY <= PosY2 &&
MouseX >= PosX &&
MouseX <= PosX + DragBoxSize )
{
Found = DPD;
}
}
break;
default:
break;
}
if ( Found && !Found->NoAction ) break;
}
return Found;
}
wxsDragWindow::DragPointData* wxsDragWindow::FindLeftTop(wxsWidget* Widget)
{
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
if ( (*i)->Widget == Widget )
{
return (*i)->WidgetPoints[LeftTop];
}
}
return NULL;
}
void wxsDragWindow::DragInit(wxsDragWindow::DragPointData* NewDragPoint,wxsWidget* NewDragWidget,bool MultipleSel,int MouseX,int MouseY)
{
if ( NewDragPoint || NewDragWidget )
{
DragMouseBegX = MouseX;
DragMouseBegY = MouseY;
DragDistanceSmall = true;
//CaptureMouse();
if ( NewDragWidget )
{
if ( MultipleSel ) { GrayDragPoints (); }
else { ClearDragPoints(); }
CurDragWidget = NewDragWidget;
CurDragPoint = FindLeftTop(CurDragWidget);
if ( !CurDragPoint )
{
// Haven't found drag point for this widget - new points will be added
CurDragPoint = BuildDragPoints(CurDragWidget);
BlackDragPoints(CurDragWidget);
}
else
{
// This widget is already selected - only main selected widget will be changed
GrayDragPoints();
BlackDragPoints(CurDragWidget);
}
SelectWidget(CurDragWidget);
UpdateGraphics();
}
else
{
// CurDragWidget == NULL means we're moving drag point only, not whole widget
CurDragWidget = NULL;
CurDragPoint = NewDragPoint;
}
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
// Copying initial position data
DragPointData* DPD = *i;
DPD->DragInitPosX = DPD->PosX;
DPD->DragInitPosY = DPD->PosY;
}
}
else
{
// Nothing selected
CurDragPoint = NULL;
CurDragWidget = NULL;
}
}
void wxsDragWindow::DragProcess(int MouseX,int MouseY,wxsWidget* UnderCursor)
{
if ( !CurDragPoint || CurDragPoint->NoAction ) return;
int ShiftX = MouseX - DragMouseBegX;
int ShiftY = MouseY - DragMouseBegY;
if ( abs(ShiftX) + abs(ShiftY) >= MinDragDistance ) DragDistanceSmall = false;
if ( DragDistanceSmall ) return;
// Creating local array of pointers to all drag points
DragPointData* WidgetPoints[DragBoxTypeCnt];
memcpy(WidgetPoints,CurDragPoint->WidgetPoints,sizeof(WidgetPoints));
// Shifting corner points
#define DoShiftX(Placement) WidgetPoints[Placement]->PosX = WidgetPoints[Placement]->DragInitPosX + ShiftX
#define DoShiftY(Placement) WidgetPoints[Placement]->PosY = WidgetPoints[Placement]->DragInitPosY + ShiftY
if ( CurDragWidget )
{
// Snapping to sizer area
if ( UnderCursor && !UnderCursor->IsContainer() &&
(wxsDWAssistType == wxsDTNone) )
{
wxsWidget* Parent = UnderCursor->GetParent();
if ( Parent && Parent->GetInfo().Sizer )
{
// Changing parent to sizer - current dragged widget
// will be placed in place of UnderCursor
ShiftX = 0;
ShiftY = 0;
UnderCursor->GetPreview()->ClientToScreen(&ShiftX,&ShiftY);
CurDragWidget->GetPreview()->ScreenToClient(&ShiftX,&ShiftY);
}
}
// Standard proceedure - just shifting everything
for ( DragPointsI i = DragPoints.begin(); i != DragPoints.end(); ++i )
{
(*i)->PosX = (*i)->DragInitPosX + ShiftX;
(*i)->PosY = (*i)->DragInitPosY + ShiftY;
}
RebuildEdgePoints(WidgetPoints);
}
else
{
// Shifting corners
switch ( CurDragPoint->Type )
{
case LeftTop:
DoShiftX(LeftTop);
DoShiftY(LeftTop);
DoShiftY(RightTop);
DoShiftX(LeftBtm);
break;
case Top:
DoShiftY(LeftTop);
DoShiftY(RightTop);
break;
case RightTop:
DoShiftY(LeftTop);
DoShiftX(RightTop);
DoShiftY(RightTop);
DoShiftX(RightBtm);
break;
case Left:
DoShiftX(LeftTop);
DoShiftX(LeftBtm);
break;
case Right:
DoShiftX(RightTop);
DoShiftX(RightBtm);
break;
case LeftBtm:
DoShiftX(LeftTop);
DoShiftX(LeftBtm);
DoShiftY(LeftBtm);
DoShiftY(RightBtm);
break;
case Btm:
DoShiftY(LeftBtm);
DoShiftY(RightBtm);
break;
case RightBtm:
DoShiftX(RightTop);
DoShiftY(LeftBtm);
DoShiftX(RightBtm);
DoShiftY(RightBtm);
break;
default:;
}
RebuildEdgePoints(WidgetPoints);
}
#undef DoShiftX
#undef DoShiftY
UpdateGraphics();
}
void wxsDragWindow::DragFinish(wxsWidget* UnderCursor)
{
if ( HasCapture() ) ReleaseMouse();
if ( !CurDragPoint || CurDragPoint->NoAction || DragDistanceSmall ) return;
int PosX = 0, PosY = 0;
int SizeX = 0, SizeY = 0;
if ( !CurDragWidget )
{
wxsWidget* Widget = CurDragPoint->Widget;
Widget->GetPreview()->GetPosition(&PosX,&PosY);
// Calculating new widget's position and size
DragPointData* LeftTopPoint = FindLeftTop(CurDragPoint);
PosX += LeftTopPoint->PosX - LeftTopPoint->DragInitPosX;
PosY += LeftTopPoint->PosY - LeftTopPoint->DragInitPosY;
SizeX = LeftTopPoint->WidgetPoints[Right]->PosX - LeftTopPoint->PosX;
SizeY = LeftTopPoint->WidgetPoints[Btm]->PosY - LeftTopPoint->PosY;
// Correcting negative size
if ( SizeX < 0 )
{
PosX += SizeX;
LeftTopPoint->PosX += SizeX;
SizeX = -SizeX;
}
if ( SizeY < 0 )
{
PosY += SizeY;
LeftTopPoint->PosY += SizeY;
SizeY = -SizeY;
}
// Applying changes
wxsWidgetBaseParams& Params = Widget->GetBaseParams();
if ( LeftTopPoint->PosX != LeftTopPoint->DragInitPosX ||
LeftTopPoint->PosY != LeftTopPoint->DragInitPosY )
{
Params.DefaultPosition =
Widget->GetParent() && Widget->GetParent()->GetInfo().Sizer;
Params.PosX = PosX;
Params.PosY = PosY;
}
Params.DefaultSize = false;
Params.SizeX = SizeX;
Params.SizeY = SizeY;
Widget->UpdateProperties();
Widget->PropertiesUpdated(false,false); // This will recreate preview
}
else
{
wxsWindowEditor* Editor = (wxsWindowEditor*)RootWidget->GetResource()->GetEditor();
std::vector<wxsWidget*> AllToMove;
GetSelectionNoChildren(AllToMove);
// Finding out what new parent widget will be
wxsWidget* NewParent = UnderCursor;
bool NewParentIsSizer = NewParent->GetInfo().Sizer;
int NewInSizerPos = -1;
int Cnt = (int)AllToMove.size();
for(;;)
{
bool ForceMoreParent = false;
for ( int i=0; i<Cnt; i++ )
{
if ( AllToMove[i] == NewParent ) ForceMoreParent = true;
}
if ( NewParent->IsContainer() && !ForceMoreParent ) break;
NewParent = NewParent->GetParent();
if ( !NewParent )
{
CurDragPoint = NULL;
CurDragWidget = NULL;
return;
}
NewParentIsSizer = NewParent->GetInfo().Sizer;
if ( NewParentIsSizer )
{
NewInSizerPos = NewParent->FindChild(UnderCursor);
// To make dragging more natural, we have to
// change insert pos little bit
if ( (CurDragWidget->GetParent() == NewParent) &&
(NewParent->FindChild(CurDragWidget) < NewInSizerPos) )
{
NewInSizerPos++;
}
}
}
// First pass - checking if widget can be moved and
// recalculating position
for ( int i=0; i<Cnt; i++ )
{
wxsWidget* Moved = AllToMove[i];
if ( (Moved != NewParent) &&
(Moved->FindChild(NewParent,0) < 0) &&
NewParent->CanAddChild(Moved) )
{
wxsWidgetBaseParams& Params = Moved->GetBaseParams();
DragPointData* LeftTopPoint = FindLeftTop(Moved);
if ( LeftTopPoint )
{
FindAbsolutePosition(Moved,&PosX,&PosY);
PosX += LeftTopPoint->PosX - LeftTopPoint->DragInitPosX;
PosY += LeftTopPoint->PosY - LeftTopPoint->DragInitPosY;
NewParent->GetPreview()->ScreenToClient(&PosX,&PosY);
Params.PosX = PosX;
Params.PosY = PosY;
}
}
else
{
// This widget won't be moved
AllToMove.erase(AllToMove.begin()+i);
i--;
Cnt--;
}
}
// Second pass - changing resource structure
// Must kill preview to avoid seg faults caused by
// differences between preview structure and resource's
// structure
Editor->KillPreview();
for ( int i=0; i<Cnt; i++ )
{
wxsWidget* Moved = AllToMove[i];
wxsWidget* OldParent = Moved->GetParent();
int OldInSizerPos = OldParent->FindChild(Moved);
if ( NewParent == OldParent )
{
if ( NewParentIsSizer )
{
if ( NewInSizerPos != OldInSizerPos )
{
Moved->KillTree(wxsTREE());
OldParent->ChangeChildPos(OldInSizerPos,NewInSizerPos);
NewInSizerPos = OldParent->FindChild(Moved);
Moved->BuildTree(wxsTREE(),NewParent->GetTreeId(),NewInSizerPos);
}
}
}
else
{
Moved->KillTree(wxsTREE());
OldParent->DelChildId(OldInSizerPos);
NewParent->AddChild(Moved,NewInSizerPos);
Moved->BuildTree(wxsTREE(),NewParent->GetTreeId(),NewInSizerPos);
}
wxsWidgetBaseParams& Params = Moved->GetBaseParams();
Params.DefaultPosition = NewParentIsSizer;
if ( NewInSizerPos >= 0 )
{
NewInSizerPos++;
}
}
wxsTREE()->Refresh();
RootWidget->PropertiesUpdated(false,false);
}
CurDragPoint = NULL;
CurDragWidget = NULL;
}
void wxsDragWindow::UpdateCursor(bool Dragging,DragPointData* NewDragPoint,wxsWidget* NewDragWidget)
{
if ( !Dragging )
{
// We're not dragging - checkign what's under cursor
if ( !NewDragWidget && NewDragPoint )
{
switch ( NewDragPoint->Type )
{
case LeftTop:
case RightBtm:
SetCur(wxCURSOR_SIZENWSE);
break;
case Top:
case Btm:
SetCur(wxCURSOR_SIZENS);
break;
case RightTop:
case LeftBtm:
SetCur(wxCURSOR_SIZENESW);
break;
case Left:
case Right:
SetCur(wxCURSOR_SIZEWE);
break;
default:
SetCur(wxCURSOR_ARROW);
}
}
else
{
SetCur(wxCURSOR_ARROW);
}
}
else
{
if ( CurDragWidget )
{
SetCur( CurDragPoint->NoAction ? wxCURSOR_NO_ENTRY : wxCURSOR_SIZING );
}
else if ( CurDragPoint )
{
if ( CurDragPoint->NoAction ) SetCur(wxCURSOR_NO_ENTRY);
}
else
{
SetCur(wxCURSOR_ARROW);
}
}
}
void wxsDragWindow::OnSelectWidget(wxsEvent& event)
{
if ( BlockWidgetSelect ) return;
if ( !IsInside(event.GetWidget(),RootWidget) )
{
ClearDragPoints();
}
else
{
wxsWidget* Wdg = event.GetWidget();
if ( Wdg->GetParent() ) Wdg->GetParent()->EnsurePreviewVisible(Wdg);
if ( ::wxGetKeyState(WXK_CONTROL) )
{
GrayDragPoints();
BlackDragPoints(Wdg);
}
else
{
ClearDragPoints();
BuildDragPoints(Wdg);
BlackDragPoints(Wdg);
}
}
Refresh();
}
void wxsDragWindow::OnUnselectWidget(wxsEvent& event)
{
for ( size_t i = 0; i < DragPoints.size(); )
{
DragPointData* DPD = DragPoints[i];
if ( DPD->Widget == event.GetWidget() )
{
DragPoints.erase(DragPoints.begin()+i);
}
else
{
i++;
}
}
UpdateGraphics();
}
void wxsDragWindow::ClearDragPoints()
{
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
delete *i;
}
DragPoints.clear();
}
wxsDragWindow::DragPointData* wxsDragWindow::BuildDragPoints(wxsWidget* Widget)
{
if ( !Widget ) return NULL;
if ( Widget->GetPreview() )
{
DragPointData* WidgetPoints[DragBoxTypeCnt];
for ( int i=0; i<DragBoxTypeCnt; ++i )
{
WidgetPoints[i] = new DragPointData;
WidgetPoints[i]->Inactive = false;
}
UpdateDragPointData(Widget,WidgetPoints);
for ( int i=0; i<DragBoxTypeCnt; ++i )
{
DragPoints.push_back(WidgetPoints[i]);
}
return WidgetPoints[0];
}
return NULL;
}
void wxsDragWindow::UpdateDragPointData(wxsWidget* Widget,DragPointData** WidgetPoints)
{
int PosX, PosY;
int SizeX, SizeY;
bool NoAction = false;// ! ( Widget->GetBPType() & ( wxsWidget::bptSize | wxsWidget::bptPosition ) );
FindAbsolutePosition(Widget,&PosX,&PosY);
ScreenToClient(&PosX,&PosY);
Widget->GetPreview()->GetSize(&SizeX,&SizeY);
for ( int i=0; i<DragBoxTypeCnt; ++i )
{
WidgetPoints[i]->Widget = Widget;
WidgetPoints[i]->Type = (DragBoxType)i;
WidgetPoints[i]->PosX = PosX;
WidgetPoints[i]->PosY = PosY;
WidgetPoints[i]->NoAction = NoAction;
if ( i == Top || i == Btm )
{
WidgetPoints[i]->PosX += SizeX / 2;
}
else if ( i == RightTop || i == Right || i == RightBtm )
{
WidgetPoints[i]->PosX += SizeX;
}
if ( i==Left || i == Right )
{
WidgetPoints[i]->PosY += SizeY / 2;
}
else if ( i == LeftBtm || i == Btm || i == RightBtm )
{
WidgetPoints[i]->PosY += SizeY;
}
WidgetPoints[i]->KillMe = false;
memcpy(WidgetPoints[i]->WidgetPoints,WidgetPoints,sizeof(WidgetPoints[0]->WidgetPoints));
}
}
void wxsDragWindow::RecalculateDragPoints()
{
// If there are no dragpoints we jujst build new array
if ( DragPoints.empty() ) return;
// Setting KillMe flag for all points
for ( DragPointsI i = DragPoints.begin(); i != DragPoints.end(); ++i )
{
(*i)->KillMe = true;
}
// Processing all widget in this window
int HintIndex = 0;
RecalculateDragPointsReq(RootWidget,HintIndex);
// Deleting invalid drag points
for ( size_t i=0; i<DragPoints.size(); )
{
if ( DragPoints[i]->KillMe )
{
delete DragPoints[i];
DragPoints.erase(DragPoints.begin()+i);
}
else
{
i++;
}
}
}
void wxsDragWindow::RecalculateDragPointsReq(wxsWidget* Widget,int& HintIndex)
{
for ( int i = 0; i<Widget->GetChildCount(); i++ )
{
RecalculateDragPointsReq(Widget->GetChild(i),HintIndex);
}
if ( Widget->GetPreview() )
{
int Index = HintIndex;
while ( DragPoints[Index]->Widget != Widget )
{
Index = (Index+1) % DragPoints.size();
if ( Index == HintIndex )
{
Index = -1;
break;
}
}
if ( Index != -1 )
{
UpdateDragPointData(Widget,DragPoints[Index]->WidgetPoints);
HintIndex = ( Index + 1 ) % DragPoints.size();
}
}
}
void wxsDragWindow::SetWidget(wxsWidget* _RootWidget)
{
if ( RootWidget == _RootWidget )
{
RecalculateDragPoints();
}
else
{
ClearDragPoints();
RootWidget = _RootWidget;
BuildDragPoints(RootWidget);
}
Refresh();
}
wxsWidget* wxsDragWindow::FindWidgetAtPos(int PosX,int PosY,wxsWidget* Widget)
{
if ( !Widget || !Widget->GetPreview() || !Widget->GetPreview()->IsShown() ) return NULL;
int WdgX, WdgY;
int WdgSX, WdgSY;
FindAbsolutePosition(Widget,&WdgX,&WdgY);
ScreenToClient(&WdgX,&WdgY);
Widget->GetPreview()->GetSize(&WdgSX,&WdgSY);
if ( PosX >= WdgX && PosY >= WdgY && PosX < WdgX + WdgSX && PosY < WdgY + WdgSY )
{
for ( int i=0; i<Widget->GetChildCount(); ++i )
{
wxsWidget* Wdg = FindWidgetAtPos(PosX,PosY,Widget->GetChild(i));
if ( Wdg ) return Wdg;
}
return Widget;
}
return NULL;
}
void wxsDragWindow::AddGraphics(wxDC& DC)
{
int DragAssistType = wxsDWAssistType;
if ( DragAssistType )
{
if ( DragParent && DragParent->GetPreview() )
{
int PosX, PosY;
int SizeX, SizeY;
FindAbsolutePosition(DragParent,&PosX,&PosY);
ScreenToClient(&PosX,&PosY);
DragParent->GetPreview()->GetSize(&SizeX,&SizeY);
long Col = wxsDWParentCol;
int R = (Col>>16)&0xFF;
int G = (Col>> 8)&0xFF;
int B = (Col )&0xFF;
if ( DragAssistType == 1 )
{
DC.SetPen(wxPen(wxColour(R,G,B),2));
DC.SetBrush(*wxTRANSPARENT_BRUSH);
DC.DrawRectangle(PosX,PosY,SizeX,SizeY);
}
else
{
if ( !DragParentBitmap )
{
wxImage Covered = Background->GetSubBitmap(wxRect(PosX,PosY,SizeX,SizeY)).ConvertToImage();
for ( int y=0; y<SizeY; y++ )
{
for ( int x=0; x<SizeX; x++ )
{
Covered.SetRGB(x,y,
( Covered.GetRed(x,y) + R ) / 2,
( Covered.GetGreen(x,y) + G ) / 2,
( Covered.GetBlue(x,y) + B ) / 2 );
}
}
DragParentBitmap = new wxBitmap(Covered);
}
if ( DragParentBitmap )
{
DC.DrawBitmap(*DragParentBitmap,PosX,PosY);
}
}
}
if ( DragTarget && (DragTarget!=DragParent) && DragTarget->GetPreview() )
{
int PosX, PosY;
int SizeX, SizeY;
FindAbsolutePosition(DragTarget,&PosX,&PosY);
ScreenToClient(&PosX,&PosY);
DragTarget->GetPreview()->GetSize(&SizeX,&SizeY);
long Col = wxsDWTargetCol;
int R = (Col>>16)&0xFF;
int G = (Col>> 8)&0xFF;
int B = (Col )&0xFF;
if ( DragAssistType == 1 )
{
DC.SetPen(wxPen(wxColour(R,G,B),2));
DC.SetBrush(*wxTRANSPARENT_BRUSH);
DC.DrawRectangle(PosX,PosY,SizeX,SizeY);
}
else
{
if ( !DragTargetBitmap )
{
wxImage Covered = Background->GetSubBitmap(wxRect(PosX,PosY,SizeX,SizeY)).ConvertToImage();
for ( int y=0; y<SizeY; y++ )
{
for ( int x=0; x<SizeX; x++ )
{
Covered.SetRGB(x,y,
( Covered.GetRed(x,y) + R ) / 2,
( Covered.GetGreen(x,y) + G ) / 2,
( Covered.GetBlue(x,y) + B ) / 2 );
}
}
DragTargetBitmap = new wxBitmap(Covered);
}
if ( DragTargetBitmap )
{
DC.DrawBitmap(*DragTargetBitmap,PosX,PosY);
}
}
}
}
for ( DragPointsI i = DragPoints.begin(); i != DragPoints.end(); ++i )
{
DragPointData* DPD = *i;
wxColor DrawColor( DPD->Inactive ? wxColor(0x80,0x80,0x80) : wxColor(0,0,0) );
DC.SetPen( wxPen(DrawColor,1) );
int Style = IsVisible(DPD->Widget) ? wxSOLID : wxTRANSPARENT;
DC.SetBrush( wxBrush(DrawColor,Style) );
int PosX = DPD->PosX - DragBoxSize/2;
int PosY = DPD->PosY - DragBoxSize/2;
DC.DrawRectangle(PosX , PosY, DragBoxSize, DragBoxSize );
}
}
void wxsDragWindow::SetCur(int Cur)
{
SetCursor(wxCursor(Cur));
if ( RootWidget && RootWidget->GetPreview() )
{
RootWidget->GetPreview()->SetCursor(wxCursor(Cur));
}
}
void wxsDragWindow::OnSize(wxSizeEvent& event)
{
NotifySizeChange(event.GetSize());
event.Skip();
}
void wxsDragWindow::NotifySizeChange(const wxSize& Size)
{
delete Background;
Background = new wxBitmap(Size.GetWidth(),Size.GetHeight());
}
wxsWidget* wxsDragWindow::GetSelection()
{
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
if ( !(*i)->Inactive )
{
// Here's active drag point - it's at the edge of current selection
return (*i)->Widget;
}
}
return NULL;
}
int wxsDragWindow::GetMultipleSelCount()
{
return DragPoints.size() / DragBoxTypeCnt;
}
wxsWidget* wxsDragWindow::GetMultipleSelWidget(int Index)
{
Index *= DragBoxTypeCnt;
if ( Index < 0 || Index >= (int)DragPoints.size() ) return NULL;
return DragPoints[Index]->Widget;
}
void wxsDragWindow::OnFetchBackground(wxTimerEvent& event)
{
if ( DragTargetBitmap )
{
delete DragTargetBitmap;
DragTargetBitmap = NULL;
}
if ( DragParentBitmap )
{
delete DragParentBitmap;
DragParentBitmap = NULL;
}
wxScreenDC DC;
wxMemoryDC DestDC;
int X = 0, Y = 0;
ClientToScreen(&X,&Y);
DestDC.SelectObject(*Background);
wxRegionIterator upd(FetchArea);
while ( upd )
{
int x = upd.GetX();
int y = upd.GetY();
int W = upd.GetW();
int H = upd.GetH();
DestDC.Blit(x,y,W,H,&DC,X+x,Y+y);
upd++;
}
FetchArea.Clear();
ProcessPendingEvents();
PaintAfterFetch = true;
Show();
Update();
ProcessPendingEvents();
}
void wxsDragWindow::FindAbsolutePosition(wxsWidget* Widget,int* X,int* Y)
{
*X = 0;
*Y = 0;
wxWindow* Wnd = Widget->GetPreview();
Wnd->GetPosition(X,Y);
Wnd->GetParent()->ClientToScreen(X,Y);
}
void wxsDragWindow::GrayDragPoints()
{
for ( DragPointsI i = DragPoints.begin(); i != DragPoints.end(); ++i )
{
(*i)->Inactive = true;
}
}
void wxsDragWindow::BlackDragPoints(wxsWidget* Widget)
{
for ( DragPointsI i = DragPoints.begin(); i != DragPoints.end(); ++i )
{
DragPointData* DPD = *i;
if ( DPD->Widget == Widget )
{
(*i)->Inactive = false;
}
}
}
bool wxsDragWindow::IsInside(wxsWidget* What,wxsWidget* Where )
{
if ( !Where ) return false;
return Where->FindChild(What,0) >= 0;
}
bool wxsDragWindow::IsVisible(wxsWidget* Widget)
{
if ( !Widget ) return true;
if ( !Widget->GetPreview() ) return false;
if ( !Widget->GetPreview()->IsShown() ) return false;
return IsVisible(Widget->GetParent());
}
void wxsDragWindow::GetSelectionNoChildren(std::vector<wxsWidget*>& Vector)
{
Vector.clear();
GetSelectionNoChildrenReq(RootWidget,Vector);
}
void wxsDragWindow::GetSelectionNoChildrenReq(wxsWidget* Widget,std::vector<wxsWidget*>& Vector)
{
if ( !Widget )
{
return;
}
if ( IsSelected(Widget) )
{
Vector.push_back(Widget);
return;
}
int Cnt = Widget->GetChildCount();
for ( int i=0; i<Cnt; i++ )
{
GetSelectionNoChildrenReq(Widget->GetChild(i),Vector);
}
}
void wxsDragWindow::SelectWidget(wxsWidget* Widget)
{
BlockWidgetSelect = true;
wxsSelectWidget(Widget);
BlockWidgetSelect = false;
}
void wxsDragWindow::UpdateGraphics()
{
wxClientDC ClientDC(this);
wxBufferedDC DC(&ClientDC,GetSize());
DC.DrawBitmap(*Background,0,0,false);
AddGraphics(DC);
}
bool wxsDragWindow::IsSelected(wxsWidget* Widget)
{
for ( DragPointsI i = DragPoints.begin(); i!=DragPoints.end(); ++i )
{
if ( (*i)->Widget == Widget ) return true;
}
return false;
}
void wxsDragWindow::UpdateAssist(bool Dragging,wxsWidget* UnderCursor)
{
if ( !Dragging || !UnderCursor || DragDistanceSmall || !CurDragWidget )
{
DragTarget = NULL;
DragParent = NULL;
if ( DragTargetBitmap )
{
delete DragTargetBitmap;
DragTargetBitmap = NULL;
}
if ( DragParentBitmap )
{
delete DragParentBitmap;
DragParentBitmap = NULL;
}
return;
}
wxsWidget* Parent = UnderCursor;
if ( !Parent->IsContainer() )
{
Parent = Parent->GetParent();
}
if ( DragTarget != UnderCursor )
{
DragTarget = UnderCursor;
if ( DragTargetBitmap )
{
delete DragTargetBitmap;
DragTargetBitmap = NULL;
}
}
if ( DragParent != Parent )
{
DragParent = Parent;
if ( DragParentBitmap )
{
delete DragParentBitmap;
DragParentBitmap = NULL;
}
}
}
void wxsDragWindow::RebuildEdgePoints(wxsDragWindow::DragPointData** WidgetPoints)
{
WidgetPoints[Top ]->PosX = ( WidgetPoints[LeftTop ]->PosX + WidgetPoints[RightTop]->PosX ) / 2;
WidgetPoints[Top ]->PosY = WidgetPoints[LeftTop ]->PosY;
WidgetPoints[Left ]->PosX = WidgetPoints[LeftTop ]->PosX;
WidgetPoints[Left ]->PosY = ( WidgetPoints[LeftTop ]->PosY + WidgetPoints[LeftBtm ]->PosY ) / 2;
WidgetPoints[Right]->PosX = WidgetPoints[RightTop]->PosX;
WidgetPoints[Right]->PosY = ( WidgetPoints[RightTop]->PosY + WidgetPoints[RightBtm]->PosY ) / 2;
WidgetPoints[Btm ]->PosX = ( WidgetPoints[LeftBtm ]->PosX + WidgetPoints[RightBtm]->PosX ) / 2;
WidgetPoints[Btm ]->PosY = WidgetPoints[LeftBtm ]->PosY;
}
BEGIN_EVENT_TABLE(wxsDragWindow,wxControl)
EVT_PAINT(wxsDragWindow::OnPaint)
EVT_MOUSE_EVENTS(wxsDragWindow::OnMouse)
EVT_ERASE_BACKGROUND(wxsDragWindow::OnEraseBack)
EVT_TIMER(1,wxsDragWindow::TimerRefresh)
EVT_TIMER(2,wxsDragWindow::OnFetchBackground)
EVT_SELECT_WIDGET(wxsDragWindow::OnSelectWidget)
EVT_UNSELECT_WIDGET(wxsDragWindow::OnUnselectWidget)
EVT_SIZE(wxsDragWindow::OnSize)
END_EVENT_TABLE()
syntax highlighted by Code2HTML, v. 0.9.1