1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 BEGIN_MESSAGE_MAP(TileCtrl
, CListCtrl
)
24 //{{AFX_MSG_MAP(TileCtrl)
34 /////////////////////////////////////////////////////////////////////////////
35 // TileCtrl message handlers
40 int CALLBACK
CompareFunc(LPARAM lParam1
,LPARAM lParam2
,LPARAM lParamSort
)
42 TileCtrl
*theCtrl
= (TileCtrl
*)lParamSort
;
43 int i1
=((TileInfo
*)lParam1
)->id
;
44 int i2
=((TileInfo
*)lParam2
)->id
;
57 Loaded
=h
=g
=b
=d
=0; Bits
= NULL
;
76 if (line
) delete line
;
79 _Edge::_Edge(const _Edge
& edge
)
81 line
= new char[edge
.size
*3];
82 memcpy(line
,edge
.line
,edge
.size
*3);
86 int _Edge::operator == (const _Edge
& ed
) const
88 if (ed
.size
!=size
) return 0;
89 for (int i
=0;i
<size
*3;i
++)
91 if (ed
.line
[i
]!=line
[i
]) return 0;
96 void _Edge::CreateH(TileInfo
*tile
)
98 size
= tile
->BmpInfo
.bmiHeader
.biWidth
-2; //on n'inclut pas les coins dans les bordures
99 line
= new char[3*size
];
100 for (int i
=0;i
<size
;i
++)
102 line
[i
*3]=((char*)tile
->Bits
)[(i
+1)*3+(tile
->BmpInfo
.bmiHeader
.biWidth
)*(tile
->BmpInfo
.bmiHeader
.biHeight
-1)*3];
103 line
[i
*3+1]=((char*)tile
->Bits
)[(i
+1)*3+1+(tile
->BmpInfo
.bmiHeader
.biWidth
)*(tile
->BmpInfo
.bmiHeader
.biHeight
-1)*3];
104 line
[i
*3+2]=((char*)tile
->Bits
)[(i
+1)*3+2+(tile
->BmpInfo
.bmiHeader
.biWidth
)*(tile
->BmpInfo
.bmiHeader
.biHeight
-1)*3];
108 void _Edge::CreateB(TileInfo
*tile
)
110 size
= tile
->BmpInfo
.bmiHeader
.biWidth
-2; //on n'inclut pas les coins dans les bordures
111 line
= new char[3*size
];
112 for (int i
=0;i
<size
;i
++)
114 line
[i
*3]=((char*)tile
->Bits
)[(i
+1)*3];
115 line
[i
*3+1]=((char*)tile
->Bits
)[(i
+1)*3+1];
116 line
[i
*3+2]=((char*)tile
->Bits
)[(i
+1)*3+2];
120 void _Edge::CreateG(TileInfo
*tile
)
122 size
= tile
->BmpInfo
.bmiHeader
.biHeight
-2; //on n'inclut pas les coins dans les bordures
123 line
= new char[3*size
];
124 for (int i
=0;i
<size
;i
++)
126 line
[i
*3]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
];
127 line
[i
*3+1]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
+1];
128 line
[i
*3+2]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
+2];
132 void _Edge::CreateD(TileInfo
*tile
)
134 size
= tile
->BmpInfo
.bmiHeader
.biHeight
-2; //on n'inclut pas les coins dans les bordures
135 line
= new char[3*size
];
136 for (int i
=0;i
<size
;i
++)
138 line
[i
*3]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
+(tile
->BmpInfo
.bmiHeader
.biWidth
-1)*3];
139 line
[i
*3+1]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
+1+(tile
->BmpInfo
.bmiHeader
.biWidth
-1)*3];
140 line
[i
*3+2]=((char*)tile
->Bits
)[(i
+1)*3*tile
->BmpInfo
.bmiHeader
.biWidth
+2+(tile
->BmpInfo
.bmiHeader
.biWidth
-1)*3];
158 int TileList::Add(const char *path
)
160 TileInfo
*info
= new TileInfo
;
161 info
->id
= last_id
++;
164 info
->path
= new char[strlen(path
)];
165 strcpy(info
->path
,path
);
167 theList
.insert(theList
.end(),info
);
168 if (i
==NULL
) i
=theList
.begin();
173 void TileList::Delete(tilelist::iterator i
,int n
)
175 for (int k
=0;k
<n
;k
++)
181 // TODO : delete DIB section
187 void TileList::DeleteAll()
189 int size
= theList
.size();
191 Delete(theList
.begin()++,size
);
194 char buffer_bidon
[SIZE_BIG
*SIZE_BIG
*3];
195 void TileList::Reload(CDC
*pDC
,tilelist::iterator iFirst
,int n
) //recharge en memoire une tranche de tiles
197 /*tilelist::iterator p = iFirst;
198 for (int i=0;i<n;i++)
200 if (!(*p)->Loaded && _LoadBitmap((*p)->path,&(*p)->BmpInfo,&(*p)->Bits))
203 (*p)->DibSection = CreateDIBSection(pDC->m_hDC,&(*p)->BmpInfo,DIB_RGB_COLORS,(void**)&buffer_bidon,0,0);
218 sizetile_x
= SIZE_SMALL
; sizetile_y
= SIZE_SMALL
;
219 spacing_x
= SPACING_SMALL_X
; spacing_y
= SPACING_SMALL_Y
;
220 Zoom
=1; Texture
= 1; Sort
= 1; InfoTexte
= 1;
221 count_
= 0; ViewTileMode
= 0;
226 TileCtrl::~TileCtrl()
230 void TileCtrl::Init()
232 spacing_x
= 10; spacing_y
= 10; spacing_tile_text
= 5;
233 sizeicon_x
= spacing_tile_text
+ sizetile_x
;
234 sizeicon_y
= spacing_tile_text
+ sizetile_y
;
235 pipo_buffer
= (void *)new char[sizetile_x
* sizetile_y
* 3];
237 bmp
->CreateBitmap(sizetile_x
,sizetile_y
,1,24,pipo_buffer
);
238 pImList
= new CImageList
;
239 pImList
->Create(sizetile_x
,sizetile_y
,ILC_COLOR24
,0,1);
240 pImList
->Add(bmp
,(CBitmap
*)NULL
);
241 SetImageList(pImList
,0);
243 char *defautpath
= ((SelectionTerritoire
*)GetParent()->GetParent())->DefautPath
.GetBuffer(256);
244 /*sprintf(name,"%s%s",defautpath,"croix.bmp");
245 if (_LoadBitmap(name,&TileCroix.BmpInfo,&TileCroix.Bits,false,false))
247 int size=TileCroix.BmpInfo.bmiHeader.biHeight*TileCroix.BmpInfo.bmiHeader.biWidth*TileCroix.BmpInfo.bmiHeader.biBitCount/8;
248 char *temp = new char[size];
249 TileCroix.DibSection = CreateDIBSection(GetDC()->m_hDC,&TileCroix.BmpInfo,DIB_RGB_COLORS,(void**)&temp,0,0);
254 void TileCtrl::Delete()
256 count_
=0; pImList
= 0;
259 int TileCtrl::GetNbTileLine(void)
261 RECT rect
; GetClientRect(&rect
);
262 return ((rect
.right
- rect
.left
- spacing_x
)/(sizeicon_x
+ spacing_x
));
265 int TileCtrl::GetNbTileColumn(void)
267 RECT rect
; GetClientRect(&rect
);
268 return ((rect
.bottom
- rect
.top
- spacing_y
)/(sizeicon_y
+ spacing_y
));
271 void TileCtrl::GetVisibility(int &First
,int &Last
) //retourne l'indice du premier et du dernier item visible dans la fenetre
274 int i
= GetNbTileLine();
275 int j
= GetNbTileColumn();
276 GetClientRect(&rect
);
277 First
= (rect
.top
+ scrollpos
- spacing_y
)/(sizeicon_y
+ spacing_y
);
278 if (First
<0) First
= 0;
280 Last
= First
+ i
*(j
+1);
281 if (InfoList
.theList
.size()>0 && Last
>=InfoList
.theList
.size()) Last
= InfoList
.theList
.size()-1;
284 int TileCtrl::GetIndex(LPPOINT pt
) //retourne l'index d'un incone a partir de sa position dans le fenetre
285 //si le curseur n'est pas sur un icon, retourne -1
287 int i
= GetNbTileLine();
288 if ((pt
->y
+scrollpos
)<spacing_y
) return -1;
289 int y
= (pt
->y
+ scrollpos
- spacing_y
)%(spacing_y
+ sizeicon_y
);
290 if (y
>sizeicon_y
) return -1;
291 int il
= (pt
->y
+ scrollpos
- spacing_y
)/(spacing_y
+ sizeicon_y
);
292 int x
= (pt
->x
- spacing_x
)%(spacing_x
+ sizeicon_x
);
293 if (x
>sizeicon_x
) return -1;
294 int ic
= (pt
->x
- spacing_x
)/(spacing_x
+ sizeicon_x
);
296 if (i
<InfoList
.theList
.size()) return i
;
300 POINT
TileCtrl::GetPos(int i
) //fonction inverse de GetIndex
303 int nl
= GetNbTileLine();
304 ret
.x
= (i
%nl
)*(spacing_x
+ sizeicon_x
) + spacing_x
;
305 ret
.y
= (i
/nl
)*(spacing_y
+ sizeicon_y
) + spacing_y
+ scrollpos
;
309 void TileCtrl::UpdateBuffer() //gestion du cache
311 int c
= InfoList
.theList
.size();
314 if (iFirst
==-1) //le buffer est vide
316 int NbItem
=c
-iFV
; //nbitem : nb d'item a charger
317 if (NbItem
>BUFFERSIZE
) NbItem
= BUFFERSIZE
;
318 tilelist::iterator p
=InfoList
.theList
.begin();
319 for (int i
=0;i
<iFV
;i
++) p
++;
320 ASSERT(p
!=InfoList
.theList
.end());
321 InfoList
.Reload(GetDC(),p
,NbItem
);
323 iLast
= iFV
+ NbItem
-1;
327 if (iFV
<iFirst
) iFirst
= iFV
;
328 else if (iLV
>iLast
) iLast
= iLV
;
330 tilelist::iterator p
=InfoList
.theList
.begin();
331 for (int i
=0;i
<iFirst
;i
++) p
++;
332 InfoList
.Reload(GetDC(),p
,iLast
-iFirst
+1);
336 void TileCtrl::CheckTile(TileInfo
*theTile
)
348 for (edgelist::iterator p
=EdgeList
.begin();p
!=EdgeList
.end();++p
)
360 EdgeList
.insert(EdgeList
.end(),b
);
366 for (p
=EdgeList
.begin();p
!=EdgeList
.end();++p
)
378 EdgeList
.insert(EdgeList
.end(),h
);
384 for (p
=EdgeList
.begin();p
!=EdgeList
.end();++p
)
396 EdgeList
.insert(EdgeList
.end(),g
);
402 for (p
=EdgeList
.begin();p
!=EdgeList
.end();++p
)
414 EdgeList
.insert(EdgeList
.end(),d
);
420 void TileCtrl::DeleteTile(int i
)
422 /* for (tilelist::iterator p=InfoList.theList.begin();p!=InfoList.theList.end();++p)
424 if (*p==(TileInfo*)GetItemData(i))
426 InfoList.Delete(p,1);
430 //this->DeleteItem(i); //temp, should first delete the bitmap file and the DIB section
431 /*TileInfo *info = (TileInfo*)GetItemData(i);
432 if (info && info->Loaded)
434 //delete info->DibSection;
436 if (info->id==last_id-1) {
440 } while(i>=0 && !((TileInfo*)GetItemData(i))->Loaded);
446 item.mask=LVIF_STATE;
447 item.stateMask=LVIS_SELECTED;
449 SetItemState(i,&item);
452 SortItems(CompareFunc,(DWORD)this);*/
455 int TileCtrl::IsSelected(int i
)
457 POSITION pos
= this->GetFirstSelectedItemPosition();
458 for (int k
=0;k
<GetSelectedCount();k
++)
460 if (GetNextSelectedItem(pos
)==i
) return 1;
465 void TileCtrl::DrawTile(int i
,CDC
*pDC
)
467 TileInfo
*bmp
;// = (TileInfo*)this->GetItemData(i);
468 tilelist::iterator p
=InfoList
.theList
.begin();
469 for (int k
=0;k
<i
&& p
!=InfoList
.theList
.end();k
++) p
++;
470 if (p
==InfoList
.theList
.end()) return;
478 StretchDIBits(pDC
->m_hDC
,pt
.x
,pt
.y
,
479 sizeicon_x
,sizeicon_y
,0,0,
480 TileCroix
.BmpInfo
.bmiHeader
.biWidth
,TileCroix
.BmpInfo
.bmiHeader
.biHeight
,
481 TileCroix
.Bits
,&TileCroix
.BmpInfo
,DIB_RGB_COLORS
,SRCCOPY
);
486 GetClientRect(&rect
);
487 StretchDIBits(pDC
->m_hDC
,pt
.x
,pt
.y
,
488 rect
.right
- rect
.left
,rect
.bottom
- rect
.top
,0,0,
489 bmp
->BmpInfo
.bmiHeader
.biWidth
,bmp
->BmpInfo
.bmiHeader
.biHeight
,
490 bmp
->Bits
,&bmp
->BmpInfo
,DIB_RGB_COLORS
,SRCCOPY
);
493 CString str
= GetItemText(i
,0);
498 _splitpath(str
.GetBuffer(256),temp
,temp
,Name
,temp
);
502 sprintf(Name
,"%d",bmp
->id
);
507 void TileCtrl::ShadeRect( CDC
*pDC
, CRect
& rect
)
509 // Bit pattern for a monochrome brush with every
510 // other pixel turned off
511 WORD Bits
[8] = { 0x0055, 0x00aa, 0x0055, 0x00aa,
512 0x0055, 0x00aa, 0x0055, 0x00aa };
517 // Need a monochrome pattern bitmap
518 bmBrush
.CreateBitmap( 8, 8, 1, 1, &Bits
);
520 // Create the pattern brush
521 brush
.CreatePatternBrush( &bmBrush
);
523 CBrush
*pOldBrush
= pDC
->SelectObject( &brush
);
525 // Turn every other pixel to black
526 COLORREF clrBk
= pDC
->SetBkColor( RGB(255,255,255) );
527 COLORREF clrText
= pDC
->SetTextColor( RGB(0,0,0) );
528 // 0x00A000C9 is the ROP code to AND the brush with the destination
529 pDC
->PatBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(),
530 (DWORD
)0x00A000C9); //DPa - raster code
532 pDC
->SetBkColor( RGB(0,0,0) );
533 pDC
->SetTextColor( GetSysColor(COLOR_HIGHLIGHT
) );
534 // 0x00FA0089 is the ROP code to OR the brush with the destination
535 pDC
->PatBlt(rect
.left
, rect
.top
, rect
.Width(), rect
.Height(),
536 (DWORD
)0x00FA0089); //DPo - raster code
538 // Restore the device context
539 pDC
->SelectObject( pOldBrush
);
540 pDC
->SetBkColor( clrBk
);
541 pDC
->SetTextColor( clrText
);
544 void TileCtrl::OnPaint()
546 CPaintDC
dc(this); // device context for painting
547 // TODO: Add your message handler code here
548 Browse
*parent
= (Browse
*)this->GetParent();
549 GetVisibility(iFV
,iLV
);
551 int olds
= sizetile_x
;
552 if (Zoom
==1) {sizetile_x
= sizetile_y
= SIZE_SMALL
; spacing_x
= SPACING_SMALL_X
; spacing_y
= SPACING_SMALL_Y
;}
553 if (Zoom
==2) {sizetile_x
= sizetile_y
= SIZE_NORMAL
; spacing_x
= SPACING_NORMAL_X
; spacing_y
= SPACING_NORMAL_Y
;}
554 if (Zoom
==3) {sizetile_x
= sizetile_y
= SIZE_BIG
; spacing_x
= SPACING_BIG_X
; spacing_y
= SPACING_BIG_Y
;}
555 if (olds
!=sizetile_x
&& InfoList
.theList
.size())
558 bmp
->CreateBitmap(sizetile_x
,sizetile_y
,1,24,pipo_buffer
);
559 pImList
->DeleteImageList();
561 pImList
->Create(sizetile_x
,sizetile_y
,ILC_COLOR24
,0,1);
562 pImList
->Add(bmp
,(CBitmap
*)0);
563 //SetIconSpacing(spacing_x,spacing_y);
564 SetImageList(pImList
,0);
567 font
.CreateFont(-10,0,0,0,FW_THIN
,false,false,false,DEFAULT_CHARSET
,OUT_DEFAULT_PRECIS
,CLIP_DEFAULT_PRECIS
,DEFAULT_QUALITY
,FIXED_PITCH
,NULL
);
568 CFont
* oldFont
=dc
.SelectObject(&font
);
569 for (int i
=iFV
;i
<=iLV
;i
++) DrawTile(i
,&dc
);
570 ::ReleaseDC (*this, dc
);
571 dc
.SelectObject(oldFont
);
572 // Do not call CListCtrl::OnPaint() for painting messages
575 void TileCtrl::OnDropFiles(HDROP hDropInfo
)
577 // TODO: Add your message handler code here and/or call default
578 //first : on verifie s'il les tiles doivent etre inseres
580 int count
=DragQueryFile(hDropInfo
,0xffffffff,FileName
,256); //count = nombre de fichiers dans le drop
584 DragQueryPoint(hDropInfo
,&pos
); //retrieve cursor position
585 for (int i
=0;i
<count
;i
++)
587 DragQueryFile(hDropInfo
,i
,FileName
,256);
588 if (!InfoList
.Add(FileName
)) return;
589 // InfoList.Reload(GetDC(),InfoList.i,1);
590 int iItem
= InfoList
.theList
.size();
592 sprintf(num
,"%d",iItem
);
593 InsertItem(iItem
,num
,0);
594 SetItemData(iItem
,(DWORD
)*InfoList
.i
);
597 i
= InfoList
.theList
.size();
599 CListCtrl::OnDropFiles(hDropInfo
);
602 void TileCtrl::InsertItemInCtrlList(tilelist::iterator iFirst
,tilelist::iterator iLast
)
604 int iItem
= InfoList
.theList
.size();
605 for (tilelist::iterator i
=iFirst
;i
!=iLast
;++i
)
608 sprintf(num
,"%d",iItem
);
609 InsertItem(iItem
,num
,0);
610 SetItemData(iItem
++,(DWORD
)(*i
));
614 LRESULT
TileCtrl::WindowProc(UINT message
, WPARAM wParam
, LPARAM lParam
)
616 // TODO: Add your specialized code here and/or call the base class
617 if (message
==WM_MOUSEMOVE
)
619 MousePos
.x
= LOWORD(lParam
);
620 MousePos
.y
= HIWORD(lParam
);
622 if (message
==WM_DRAWITEM
)
626 if (message
==WM_CLOSE
) Delete();
627 if (message
==WM_COMMAND
) //The user had selected an item on popup menu
629 int id
=LOWORD(wParam
);
632 CFileDialog
*load
= new CFileDialog(true,"bmp",NULL
,OFN_ALLOWMULTISELECT
| OFN_ENABLESIZING
,"*.bmp ||",this->GetParent());
633 if (load
->DoModal()==IDOK
)
635 POSITION p
= load
->GetStartPosition(); //la doc dit que p=NULL quand il n'y a pas de selection : c'est faux, genial les MFC
638 CString str
= load
->GetNextPathName(p
);
639 if (str
!=CString(""))
641 const char *pathname
= (LPCTSTR
)str
;
642 InfoList
.Add(pathname
);
643 InfoList
.Reload(GetDC(),InfoList
.i
,1);
644 CheckTile(*InfoList
.i
);
653 POSITION p
= this->GetFirstSelectedItemPosition();
656 int i
= this->GetNextSelectedItem(p
);
663 CFileDialog
*load
= new CFileDialog(true,"bmp",NULL
,OFN_ENABLESIZING
,"*.bmp ||",this->GetParent());
664 if (load
->DoModal()==IDOK
)
666 POSITION p
= load
->GetStartPosition(); //la doc dit que p=NULL quand il n'y a pas de selection : c'est faux, genial les MFC
667 CString str
= load
->GetNextPathName(p
);
668 if (str
!=CString(""))
670 const char *pathname
= (LPCTSTR
)str
;
671 POSITION sel
= GetFirstSelectedItemPosition();
672 InfoList
.Add(pathname
);
673 // InfoList.Reload(GetDC(),InfoList.i,1);
674 int iItem
= InfoList
.theList
.size();
676 sprintf(num
,"%d",iItem
);
677 InsertItem(iItem
,num
,0);
678 SetItemData(iItem
,(DWORD
)*InfoList
.i
);
687 Browse
*parent
= (Browse
*) this->GetParent();
688 POSITION sel
= GetFirstSelectedItemPosition();
689 int i
= GetNextSelectedItem(sel
);
690 parent
->TileSelected
= (TileInfo
*)GetItemData(i
);
691 parent
->SendMessage(WM_PAINT
,0,0);
696 ViewTileMode
= 0; int iItem
=0;
697 ((Browse
*)GetParent())->TileSelected
= NULL
;
698 GetParent()->SendMessage(WM_PAINT
,0,0);
700 InsertItemInCtrlList(InfoList
.theList
.begin(),InfoList
.theList
.end());
703 SendMessage(WM_PAINT
,0,0);
705 return CListCtrl::WindowProc(message
, wParam
, lParam
);
709 void TileCtrl::OnRButtonDown(UINT nFlags
, CPoint point
)
711 // TODO: Add your message handler code here and/or call default
712 RECT wndpos
; CMenu popup
;
713 GetParent
->GetWindowRect(&wndpos
);
714 popup
.CreatePopupMenu();
717 popup
.AppendMenu(GetSelectedCount()==1 ? MF_STRING
: MF_STRING
| MF_GRAYED
,0,"Remplacer...");
718 popup
.AppendMenu(GetSelectedCount()>0 ? MF_STRING
: MF_STRING
| MF_GRAYED
,1,"Supprimer");
719 popup
.AppendMenu(MF_STRING
,3,"Inserer...");
721 popup
.TrackPopupMenu(TPM_LEFTALIGN
,MousePos
.x
+wndpos
.left
,MousePos
.y
+wndpos
.top
,GetParent(),NULL
);
722 CListCtrl::OnRButtonDown(nFlags
, point
);
725 void TileCtrl::OnLButtonDown(UINT nFlags
, CPoint point
)
727 // TODO: Add your message handler code here and/or call default
729 SendMessage(WM_PAINT
,0,0);
730 CListCtrl::OnLButtonDown(nFlags
, point
);
733 void TileCtrl::OnLButtonDblClk(UINT nFlags
, CPoint point
)
735 // TODO: Add your message handler code here and/or call default
736 if (GetSelectedCount()==1)
739 Browse
*parent
= (Browse
*) this->GetParent();
740 POSITION sel
= GetFirstSelectedItemPosition();
741 int i
= GetNextSelectedItem(sel
);
742 parent
->TileSelected
= (TileInfo
*)GetItemData(i
);
743 parent
->SendMessage(WM_PAINT
,0,0);
744 CListCtrl::OnLButtonDblClk(nFlags
, point
);
748 void TileCtrl::OnVScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
750 // TODO: Add your message handler code here and/or call default
751 CListCtrl::OnVScroll(nSBCode
, nPos
, pScrollBar
);