bitmap_tree.cpp

Go to the documentation of this file.
00001 #ifndef BITMAP_TREE_IMPLEMENTATION_FILE
00002 #define BITMAP_TREE_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : bitmap_tree                                                       *
00007 *  Author : came from an article about bitmaps, etc.  cannot locate.          *
00008 *  Mods   : Chris Koeritz                                                     *
00009 *                                                                             *
00010 *******************************************************************************
00011 * Copyright (c) 1998-$now By Author.  This program is free software; you can  *
00012 * redistribute it and/or modify it under the terms of the GNU General Public  *
00013 * License as published by the Free Software Foundation; either version 2 of   *
00014 * the License or (at your option) any later version.  This is online at:      *
00015 *     http://www.fsf.org/copyleft/gpl.html                                    *
00016 * Please send any updates to: fred@gruntose.com                               *
00017 \*****************************************************************************/
00018 
00019 #include "bitmap_tree.h"
00020 
00021 #include <basis/portable.h>
00022 #include <textual/string_convert.h>
00023 
00024 #define KEY_PRESSED 0x8000
00025 #define EVENT_DRAG_SCROLL 1
00026 
00028 
00029 BEGIN_MESSAGE_MAP(bitmap_tree, CTreeCtrl)
00030   ON_NOTIFY_REFLECT_EX(TVN_SELCHANGING, OnSelChanging)
00031   ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDED, OnExpanded)
00032   ON_NOTIFY_REFLECT_EX(TVN_KEYDOWN, OnKey)
00033   ON_NOTIFY_REFLECT_EX(NM_CLICK, OnClick)
00034 //  ON_NOTIFY_REFLECT_EX(NM_RCLICK, OnRClick)
00035   ON_NOTIFY_REFLECT_EX(NM_DBLCLK, OnDoubleClick)
00036   ON_NOTIFY_REFLECT_EX(TVN_BEGINDRAG, OnBeginDrag)
00037   ON_NOTIFY_REFLECT_EX(TVN_DELETEITEM, OnDelete)
00038   ON_WM_MOUSEMOVE()
00039   ON_WM_LBUTTONUP()
00040   ON_WM_TIMER()
00041 END_MESSAGE_MAP()
00042 
00044 
00045 // Comparison function for sorting; gives precedence to
00046 // the node image type, then compares strings.
00047 // lparam1 -- any structure, one member of which should be an HTREEITEM
00048 // lparam2 -- any structure, one member of which should be an HTREEITEM
00049 // lparamsort -- the bitmap_tree
00050 // NOTE: the m_itemOffset member of the bitmap_tree should reference the
00051 // place in the structure where the HTREEITEM lies.
00052 int CALLBACK bitmap_tree::NodeTypeCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
00053 {
00054   bitmap_tree *ctd = (bitmap_tree *)lParamSort;
00055   if (!ctd) return 0;
00056 
00057   ASSERT(ctd->ItemOffset() != -1);
00058 
00059   HTREEITEM a = (HTREEITEM)(lParam1+ctd->ItemOffset());
00060   HTREEITEM b = (HTREEITEM)(lParam2+ctd->ItemOffset());
00061 
00062   int aimg = 0, bimg = 0, simg = 0;
00063   ctd->GetItemImage(b, bimg, simg);
00064   ctd->GetItemImage(a, aimg, simg);
00065 
00066   if (aimg == bimg) {
00067     istring sb = from_unicode_temp(ctd->GetItemText(b));
00068     istring sa = from_unicode_temp(ctd->GetItemText(a));
00070     return sa == sb;
00071   } else
00072     return aimg - bimg;
00073 }
00074 
00075 bool bitmap_tree::ClearSelection(bitmap_tree *bt, HTREEITEM h, LPARAM l)
00076 {
00077   if (bt->GetSelectedItem() != h)
00078     bt->SelectAnotherItem(h, false);
00079 
00080   return true;
00081 }
00082 
00083 // Turn off selection of items which are not draggable.
00084 bool bitmap_tree::PrepareDrag(bitmap_tree *bt, HTREEITEM h, LPARAM l)
00085 {
00086   if (bt->GetSelectedItem() == h)
00087     bt->SelectAnotherItem(h, true);
00088   else {
00089     int img = 0, simg = 0;
00090     bt->GetItemImage(h, img, simg);
00091     if (!bt->IsDraggable(h, img))
00092       bt->SelectAnotherItem(h, false);
00093   }
00094 
00095   return true;
00096 }
00097 
00098 // Create a new tree item as a child of the target item.
00099 // Delete the original.
00100 bool MoveTreeItemCB(bitmap_tree *bt, HTREEITEM h, LPARAM l)
00101 {
00102   HTREEITEM target = (HTREEITEM)l;
00103   TV_INSERTSTRUCT tvis;
00104 
00105   // valid target
00106   if (!target) return false;
00107 
00108   // get item info
00109   memset(&tvis, 0, sizeof(tvis));
00110   tvis.item.mask = (TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATE);
00111   tvis.item.hItem = h;
00112   bt->GetItem(&tvis.item);
00113 
00114   // dropping on top of itself?
00115   if ((bt->GetParentItem(h) == target) ||
00116       !(bt->IsDraggable(h, tvis.item.iImage)))
00117     return true;
00118 
00119   // get item text
00120   istring s = string_convert::to_istring(bt->GetItemText(h));
00121   to_unicode_persist(temp_s, s);
00122   tvis.item.pszText = temp_s;
00123   tvis.item.mask |= TVIF_TEXT;
00124 
00125   // move node
00126   bt->DeleteItem(h);
00127   tvis.hParent= target;
00128   tvis.hInsertAfter= TVI_LAST;
00129   bt->InsertItem(&tvis);
00130 
00131   return true;
00132 }
00133 
00135 
00136 bitmap_tree::bitmap_tree()
00137 : m_numOverlays(0),
00138   m_itemOffset(-1),
00139   m_sStateImage(0, 0),
00140   m_sNormalImage(0, 0),
00141   m_ilNormal(),
00142   m_ilState(),
00143   m_toggle(0),
00144   m_overlaySet(false),
00145   m_multiSet(false),
00146   m_multiSelected(0),
00147   m_canChangeSel(true),
00148   m_lastSelected(NIL),
00149   m_firstKey(0),
00150   m_dragFunction(NIL),
00151   m_dragList(NIL),
00152   m_draggable(0),
00153   m_dropTarget(0),
00154   m_xDrag(0),
00155   m_docDrag(0),
00156   m_multiDrag(0)
00157 {
00158   memset(&m_sortcb, 0, sizeof(m_sortcb));
00159 }
00160 
00161 bitmap_tree::~bitmap_tree()
00162 {
00163   m_ilNormal.DeleteImageList();
00164   m_ilState.DeleteImageList();
00165 }
00166 
00167 void bitmap_tree::SetExpandable(int base)
00168 {
00169   ASSERT(base < (sizeof(m_toggle)*8 -1));
00170   m_toggle|= (1UL << base);
00171 }
00172 
00173 bool bitmap_tree::IsExpandable(int base)
00174 {
00175   ASSERT(base < (sizeof(m_toggle)*8 -1));
00176   return m_toggle & (1UL << base);
00177 }
00178 
00179 void bitmap_tree::SetDraggable(int base)
00180 {
00181   ASSERT(base < (sizeof(m_draggable)*8 -1));
00182   m_draggable |= (1UL << base);
00183 }
00184 
00185 bool bitmap_tree::IsDraggable(HTREEITEM h, int base)
00186 {
00187   ASSERT(base < (sizeof(m_draggable)*8 -1));
00188   return m_draggable & (1UL << base);
00189 }
00190 
00191 void bitmap_tree::SetDropTarget(int base)
00192 {
00193   ASSERT(base < (sizeof(m_dropTarget)*8 -1));
00194   m_dropTarget |= (1UL << base);
00195 }
00196 
00197 bool bitmap_tree::IsDropTarget(HTREEITEM h, int base)
00198 {
00199   ASSERT(base < (sizeof(m_dropTarget)*8 -1));
00200   return m_dropTarget & (1UL << base);
00201 }
00202 
00203 void bitmap_tree::SetMultiSelect(bool b)
00204 {
00205   if (!b)
00206     ClearMultiSelect();
00207   m_multiSet = b;
00208 }
00209 
00210 // Call this function to add images to the TVSIL_NORMAL ImageList.
00211 int bitmap_tree::SetNormalImages(UINT bitmap, int number, COLORREF mask)
00212 {
00213   CBitmap b;
00214   int num = 0;
00215 
00216   // load bitmap
00217   HBITMAP hb = LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(bitmap));
00218 
00219   BITMAP bi;
00220   GetObject(hb, sizeof(BITMAP), &bi);
00221   ASSERT((bi.bmWidth % number) == 0);
00222   if (m_sNormalImage.cx == 0) {
00223     m_sNormalImage.cx= (bi.bmWidth/number);
00224     m_sNormalImage.cy= bi.bmHeight;
00225     m_ilNormal.Create(m_sNormalImage.cx, m_sNormalImage.cy, true, number,
00226         number);
00227     SetImageList(&m_ilNormal, TVSIL_NORMAL);
00228   }
00229   ASSERT(m_sNormalImage.cx == (bi.bmWidth/number));
00230   ASSERT(m_sNormalImage.cy == bi.bmHeight);
00231 
00232   // add images
00233   b.Attach(hb);
00234   num= m_ilNormal.Add(&b, mask);
00235   b.DeleteObject();
00236 
00237   return num;
00238 }
00239 
00240 // Call this function to add images to the overlay list.  The
00241 // index of the first overlay will be m_overlay1.  You must call
00242 // SetNormalImages at least once before calling this function in order
00243 // to initialize m_sNormalImage.  This function can only be called once.
00244 int bitmap_tree::SetOverlayImages(UINT bitmap, COLORREF mask)
00245 {
00246   int i = 0;
00247   CBitmap b;
00248   int num = 0;
00249 
00250   // number of images in the list before we add the overlays
00251   int numNormals = m_ilNormal.GetImageCount();
00252 
00253   ASSERT(!m_overlaySet && numNormals);
00254   if (m_overlaySet || !numNormals) return common::BAD_INPUT;
00255   m_overlaySet= true;
00256 
00257   // load bitmap
00258   HBITMAP hb = LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(bitmap));
00259 
00260   BITMAP obi;
00261   GetObject(hb, sizeof(BITMAP), &obi);
00262 
00263   // assert that overlay images are the same size as normal images and that there are
00264   // fewer than four of them (which is the maximum allowed by Windows)
00265   ASSERT((obi.bmWidth % m_sNormalImage.cx) == 0);
00266   ASSERT(obi.bmHeight == m_sNormalImage.cy);
00267   m_numOverlays= (obi.bmWidth / m_sNormalImage.cx);
00268   ASSERT(m_numOverlays <= 4);
00269 
00270   // add images to the normal list
00271   b.Attach(hb);
00272   num= m_ilNormal.Add(&b, mask);
00273   b.DeleteObject();
00274 
00275   // designate these images as overlays
00276   for(i= 0; i< m_numOverlays; i++)
00277     m_ilNormal.SetOverlayImage((numNormals+m_overlay1+i)-1, m_overlay1+i);
00278 
00279   return num;
00280 }
00281 
00283 // SetStateImages
00284 // Call this function to add images to the TVSIL_STATE list.
00285 int bitmap_tree::SetStateImages(UINT bitmap, int number, COLORREF mask)
00286 {
00287   BITMAP bi;
00288   HBITMAP hb;
00289   CBitmap b;
00290   int num;
00291 
00292   // load bitmap
00293   hb= LoadBitmap(AfxGetInstanceHandle(),
00294                  MAKEINTRESOURCE(bitmap));
00295   GetObject(hb, sizeof(BITMAP), &bi);
00296   ASSERT((bi.bmWidth % number) == 0);
00297   if (m_sStateImage.cx == 0)
00298   {
00299     m_sStateImage.cx= (bi.bmWidth/number);
00300     m_sStateImage.cy= bi.bmHeight;
00301     m_ilState.Create(m_sStateImage.cx, m_sStateImage.cy, true, number, number);
00302     SetImageList(&m_ilState, TVSIL_STATE);
00303   }
00304   ASSERT(m_sStateImage.cx == (bi.bmWidth/number));
00305   ASSERT(m_sStateImage.cy == bi.bmHeight);
00306 
00307   // add images
00308   b.Attach(hb);
00309   num= m_ilState.Add(&b, mask);
00310   b.DeleteObject();
00311 
00312   return num;
00313 }
00314 
00315 HTREEITEM bitmap_tree::GetItemUnderMouse(TV_HITTESTINFO *tvhti)
00316 {
00317   CPoint p;
00318   DWORD dwpos;
00319 
00320   // where did we hit?
00321   dwpos = GetMessagePos();
00322   p.x = LOWORD(dwpos);
00323   p.y = HIWORD(dwpos);
00324   ScreenToClient(&p);
00325 
00326   if (tvhti)
00327   {
00328     tvhti->pt= p;
00329     return HitTest(tvhti);
00330   }
00331   else
00332   {
00333     UINT f;
00334     return HitTest(p, &f);
00335   }
00336 }
00337 
00338 // For each item with the state TVIS_SELECTED, call the
00339 // specified function.
00340 bool bitmap_tree::DoForAllSelected(TREE_CALLBACK func, HTREEITEM hitem,
00341     LPARAM l)
00342 {
00343   HTREEITEM child, sibling;
00344   bool proceed= true;
00345 
00346   // ensure hitem is nonnull
00347   if (hitem == NULL)
00348     hitem= GetRootItem();
00349   if (hitem == NULL)
00350     return false;
00351 
00352   // iterate through children and siblings
00353   while (hitem)
00354   {
00355     child= GetChildItem(hitem);
00356     if (child != NULL)
00357     {
00358       proceed= DoForAllSelected(func, child, l);
00359       if (!proceed)
00360         return proceed;
00361     }
00362 
00363     // get sibling item
00364     sibling= GetNextSiblingItem(hitem);
00365 
00366     // call function
00367     if (IsSelected(hitem))
00368     {
00369       SetSelChange(false);
00370       proceed= func(this, hitem, l);
00371       SetSelChange(true);
00372 
00373       if (!proceed)
00374         return proceed;
00375     }
00376 
00377     hitem= sibling;
00378   }
00379 
00380   return true;
00381 }
00382 
00383 // Clear TVIS_SELECTED from all item states except the item
00384 // returned by GetSelectedItem()
00385 void bitmap_tree::ClearMultiSelect()
00386 {
00387   if (!m_multiSet || !m_multiSelected)
00388     return;
00389 
00390   m_lastSelected= NULL;
00391   DoForAllSelected(ClearSelection, NULL, 0);
00392   m_multiSelected= false;
00393 }
00394 
00395 // Select only the visible items appearring between
00396 // h1 and h3.
00397 void bitmap_tree::SelectRange(HTREEITEM h1, HTREEITEM h2)
00398 {
00399   HTREEITEM p= GetRootItem(), endrange;
00400 
00401   if ((h1 == NULL) || (h2 == NULL) || !m_multiSet)
00402     return;
00403 
00404   // mark as unselected
00405   while ((p != h1) && (p != h2) && (p != NULL))
00406   {
00407     SelectAnotherItem(p, false);
00408     p= GetNextVisibleItem(p);
00409   }
00410 
00411   if (p == NULL)
00412     return;
00413 
00414   (p == h1)?endrange= h2:endrange= h1;
00415 
00416   // mark as selected
00417   while ((p != endrange) && (p != NULL))
00418   {
00419     SelectAnotherItem(p, true);
00420     p= GetNextVisibleItem(p);
00421   }
00422 
00423   // mark as unselected
00424   while (p != NULL)
00425   {
00426     SelectAnotherItem(p, false);
00427     p= GetNextVisibleItem(p);
00428   }
00429 
00430   SelectAnotherItem(h1, true);
00431   SelectAnotherItem(h2, true);
00432 }
00433 
00434 // Sets/unsets the TVIS_SELECTED state for an item.
00435 void bitmap_tree::SelectAnotherItem(HTREEITEM h, bool select)
00436 {
00437   bool selected= IsSelected(h);
00438 
00439   if (!m_multiSet)
00440     return;
00441 
00442   if (select && !selected)
00443   {
00444     m_multiSelected= true;
00445     SetItemState(h, TVIS_SELECTED, TVIS_SELECTED);
00446   }
00447   else if (!select && selected)
00448   {
00449     SetItemState(h, 0, TVIS_SELECTED);
00450   }
00451 }
00452 
00453 void bitmap_tree::SetSortFunction(PFNTVCOMPARE func, LPARAM l)
00454 {
00455   m_sortcb.lpfnCompare= func;
00456   m_sortcb.lParam= l;
00457 }
00458 
00459 // Set up a sort callback function which will sort by image first, name second.
00460 void bitmap_tree::SetDocumentSortFunction(int offset)
00461 {
00462   SetSortFunction(NodeTypeCompare, (LPARAM)this);
00463 
00464   m_itemOffset= offset;
00465 }
00466 
00467 // Sorts all descendants of a node (not just the immediate
00468 // children like SortChildren does).
00469 void bitmap_tree::SortTree(HTREEITEM hitem)
00470 {
00471   HTREEITEM child;
00472 
00473   if (hitem == NULL)
00474   {
00475     if (m_sortcb.lpfnCompare)
00476     {
00477       m_sortcb.hParent= NULL;
00478       SortChildrenCB(&m_sortcb);
00479     }
00480     else
00481       SortChildren(NULL);
00482     hitem= GetRootItem();
00483   }
00484 
00485   while (hitem != NULL)
00486   {
00487     if (m_sortcb.lpfnCompare)
00488     {
00489       m_sortcb.hParent= hitem;
00490       SortChildrenCB(&m_sortcb);
00491     }
00492     else
00493       SortChildren(hitem);
00494 
00495     child= GetChildItem(hitem);
00496     if (child != NULL)
00497       SortTree(child);
00498     hitem= GetNextSiblingItem(hitem);
00499   }
00500 
00501   return;
00502 }
00503 
00504 void bitmap_tree::ToggleTree(UINT code, HTREEITEM hitem)
00505 {
00506   if (hitem == NULL)
00507     hitem= GetRootItem();
00508 
00509   while (hitem != NULL)
00510   {
00511     if (ItemHasChildren(hitem))
00512     {
00513       HTREEITEM child;
00514 
00515       Expand(hitem, code);
00516       child= GetChildItem(hitem);
00517       if (child)
00518         ToggleTree(code, child);
00519     }
00520     hitem= GetNextSiblingItem(hitem);
00521   }
00522 }
00523 
00524 // change image when expanded
00525 BOOL bitmap_tree::OnExpanded(NMHDR* pNMHDR, LRESULT* pResult)
00526 {
00527   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
00528   TV_ITEM *tv= &pNMTreeView->itemNew;
00529   bool expand= (tv->state & TVIS_EXPANDED);
00530   int img = 0, simg = 0, offset = 0;
00531 
00532   if ((GetNormalImageCount() == 0) ||
00533       (m_toggle == 0) ||
00534       !(GetItemImage(tv->hItem, img, simg)))
00535     return false;
00536 
00537   offset= (expand)?0:-1;
00538 
00539   // can the base version of this image be toggled?
00540   if ((img+offset < 0) ||
00541       !(IsExpandable(img+offset)))
00542     return false;
00543 
00544   offset= (expand)?1:-1;
00545 
00546   // set the image to its companion
00547   SetItemImage(tv->hItem, img+offset, img+offset);
00548 
00549   *pResult = 0;
00550   return false;
00551 }
00552 
00553 // called when item selection changes
00554 // setting pResult to false allows the selection to change, true prevents it
00555 BOOL bitmap_tree::OnSelChanging(NMHDR* pNMHDR, LRESULT *pResult)
00556 {
00557   *pResult= 0;
00558 
00559   if (!(m_canChangeSel) ||
00560       (m_multiSet &&
00561        ((GetAsyncKeyState(VK_CONTROL) & KEY_PRESSED) ||
00562         (GetAsyncKeyState(VK_SHIFT) & KEY_PRESSED))))
00563     *pResult= 1;
00564 
00565   return (BOOL)*pResult;
00566 }
00567 
00568 // called when key is pressed
00569 BOOL bitmap_tree::OnKey(NMHDR* pNMHDR, LRESULT* pResult)
00570 {
00571   TV_KEYDOWN *tvk= (TV_KEYDOWN *) pNMHDR;
00572   HTREEITEM hitem= GetSelectedItem(), newselect;
00573   bool down= (tvk->wVKey == VK_DOWN);
00574 
00575   if (!m_multiSet ||
00576       (hitem == NULL) ||
00577       (!down && (tvk->wVKey != VK_UP)))
00578     return false;
00579 
00580   if (GetAsyncKeyState(VK_SHIFT) & KEY_PRESSED)
00581   {
00582     if (m_lastSelected == NULL)
00583     {
00584       ClearMultiSelect();
00585       m_lastSelected= hitem;
00586       m_firstKey= tvk->wVKey;
00587     }
00588 
00589     if (down)
00590       newselect= GetNextItem(m_lastSelected, TVGN_NEXTVISIBLE);
00591     else
00592       newselect= GetNextItem(m_lastSelected, TVGN_PREVIOUSVISIBLE);
00593     if (newselect == NULL)
00594       return false;
00595 
00596     if ((m_firstKey != tvk->wVKey) && (IsSelected(m_lastSelected)))
00597       SelectAnotherItem(m_lastSelected, false);
00598     else if (newselect != hitem)
00599       SelectAnotherItem(newselect, (m_firstKey == tvk->wVKey));
00600 
00601     int err= EnsureVisible(newselect);
00602 
00603     if (newselect == hitem)
00604       m_lastSelected= NULL;
00605     else
00606       m_lastSelected= newselect;
00607   }
00608   else
00609     ClearMultiSelect();
00610 
00611   return false;
00612 }
00613 
00614 // called when item is clicked upon
00615 BOOL bitmap_tree::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
00616 {
00617   bool shift= (GetAsyncKeyState(VK_SHIFT) & KEY_PRESSED);
00618   HTREEITEM hitem;
00619 
00620   // clear multiselection
00621   if (!m_multiSet ||
00622       (!(shift) &&
00623        !(GetAsyncKeyState(VK_CONTROL) & KEY_PRESSED)))
00624   {
00625     ClearMultiSelect();
00626     return false;
00627   }
00628 
00629   // do multiselection
00630   hitem= GetItemUnderMouse();
00631   if (shift) {
00632     HTREEITEM hselected= GetSelectedItem();
00633 
00634     if (hselected)
00635       SelectRange(hitem, hselected);
00636   } else
00637     SelectAnotherItem(hitem, !(IsSelected(hitem)));
00638 
00639   return false;
00640 }
00641 
00642 /*
00643 BOOL bitmap_tree::OnRClick(NMHDR* pNMHDR, LRESULT* pResult)
00644 {
00645   if (!(GetAsyncKeyState(VK_SHIFT) & KEY_PRESSED) &&
00646       !(GetAsyncKeyState(VK_CONTROL) & KEY_PRESSED))
00647     ClearMultiSelect();
00648   *pResult = 0;
00649   return false;
00650 }
00651 */
00652 
00653 BOOL bitmap_tree::OnDoubleClick(NMHDR *pNMHDR, LRESULT *pResult)
00654 {
00655   ClearMultiSelect();
00656   *pResult = 0;
00657   return false;
00658 }
00659 
00660 BOOL bitmap_tree::OnDelete(NMHDR* pNMHDR, LRESULT* pResult)
00661 {
00662   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
00663   HTREEITEM h;
00664 
00665   if (!(m_canChangeSel)) {
00666     h= pNMTreeView->itemOld.hItem;
00667     m_postSelect= GetNextSiblingItem(h);
00668     if (m_postSelect == NULL)
00669       m_postSelect= GetPrevSiblingItem(h);
00670     if (m_postSelect == NULL)
00671       m_postSelect= GetParentItem(h);
00672   }
00673 
00674   *pResult= 0;
00675   return false;
00676 }
00677 
00678 void bitmap_tree::OnLButtonUp(UINT nFlags, CPoint point)
00679 {
00680   if (m_dragList)
00681   {
00682     HTREEITEM target;
00683 
00684     KillTimer(EVENT_DRAG_SCROLL);
00685 
00686     ReleaseCapture();
00687     m_dragList->EndDrag();
00688     ShowCursor(true);
00689 
00690     m_dragList= NULL;
00691 
00692     if ((target = GetDropHilightItem()) != NULL)
00693     {
00694       DoForAllSelected(m_dragFunction, NULL, (LPARAM) target);
00695 
00696       SelectDropTarget(NULL);
00697       SelectItem(target);
00698     }
00699 
00700     ClearMultiSelect();
00701   }
00702 
00703   CTreeCtrl::OnLButtonUp(nFlags, point);
00704 }
00705 
00706 BOOL bitmap_tree::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
00707 {
00708   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
00709   HTREEITEM h= pNMTreeView->itemNew.hItem;
00710   int img, simg;
00711   CPoint point;
00712 
00713   if ((m_dragFunction == NULL) ||
00714       (h == NULL))
00715     return false;
00716 
00717   ASSERT(GetNormalImageCount());
00718 
00719   if (m_multiSelected)
00720   {
00721     // turn off selection of nodes that can't be dragged
00722     DoForAllSelected(PrepareDrag, NULL, 0);
00723   }
00724   else
00725   {
00726     // if we have started dragging an unselected item, we need to complete
00727     // the selection change before dragging it
00728     SelectItem(h);
00729   }
00730 
00731   // can we drag this node?
00732   GetItemImage(h, img, simg);
00733   if (!(IsDraggable(h, img)))
00734     return false;
00735 
00736   // set up drag list
00737   if (m_ilDrag.m_hImageList != NULL)
00738     m_dragList= &m_ilDrag;
00739   else
00740   {
00741     m_dragList= CreateDragImage(h);
00742     if (m_dragList == NULL)
00743       return false;
00744   }
00745 
00746   if (m_multiSelected)
00747     m_dragList->BeginDrag(m_multiDrag, CPoint(0,0));
00748   else
00749     m_dragList->BeginDrag(m_docDrag, CPoint(0,0));
00750 
00751   MapWindowPoints(NULL, &pNMTreeView->ptDrag, 1);
00752   m_dragList->DragEnter(NULL, pNMTreeView->ptDrag);
00753 
00754   ShowCursor(false);
00755   SetCapture();
00756 
00757   // allow scrolling to occur while dragging
00758   start_timer();
00759 
00760   *pResult= 0;
00761   return false;
00762 }
00763 
00764 void bitmap_tree::start_timer()
00765 {
00766   SetTimer(EVENT_DRAG_SCROLL, 250, NULL);
00767 }
00768 
00769 void bitmap_tree::stop_timer()
00770 {
00771   KillTimer(EVENT_DRAG_SCROLL);
00772 }
00773 
00774 void bitmap_tree::OnTimer(UINT nIDEvent)
00775 {
00776   switch (nIDEvent) {
00777     case EVENT_DRAG_SCROLL: {
00778       stop_timer();
00779       CRect r, itemr;
00780       CPoint point;
00781       HTREEITEM h;
00782 
00783       if (!m_dragList) {
00784         start_timer();
00785         return;
00786       }
00787 
00788       // get dimensions
00789       GetCursorPos(&point);
00790       GetClientRect(&r);
00791       ClientToScreen(&r);
00792 
00793       h= GetFirstVisibleItem();
00794       if (!h) {
00795         start_timer();
00796         return;
00797       }
00798 
00799       // scroll the tree control window
00800       if (point.y > r.bottom) {
00801         h= GetNextVisibleItem(h);
00802         if (h) {
00803           m_dragList->DragLeave(NULL);
00804           SelectSetFirstVisible(h);
00805           UpdateWindow();
00806           m_dragList->DragEnter(NULL, point);
00807         }
00808       } else if (point.y < r.top) {
00809         h= GetPrevVisibleItem(h);
00810         if (h) {
00811           m_dragList->DragLeave(NULL);
00812           SelectSetFirstVisible(h);
00813           UpdateWindow();
00814           m_dragList->DragEnter(NULL, point);
00815         }
00816       }
00817 
00818       start_timer();
00819       break;
00820     }
00821     default: {
00822 //pass to base class?  ignore?  currently ignoring.
00823       break;
00824     }
00825   }
00826 }
00827 
00828 void bitmap_tree::OnMouseMove(UINT nFlags, CPoint point)
00829 {
00830   if (m_dragList) {
00831     bool target_set= false, has_drag_images= (m_ilDrag.m_hImageList != NULL);
00832     HTREEITEM target;
00833     CPoint screen= point;
00834 
00835     MapWindowPoints(NULL, &screen, 1);
00836 
00837     // which item are we over?
00838     if ((target = GetItemUnderMouse()) != NULL)
00839     {
00840       int img, simg;
00841 
00842       if (has_drag_images)
00843       {
00844         if (m_multiSelected)
00845           m_dragList->SetDragCursorImage(m_multiDrag, CPoint(0,0));
00846         else
00847           m_dragList->SetDragCursorImage(m_docDrag, CPoint(0,0));
00848       }
00849 
00850       while (target)
00851       {
00852         GetItemImage(target, img, simg);
00853         if (IsDropTarget(target, img))
00854         {
00855           m_dragList->DragLeave(NULL);
00856           SelectDropTarget(target);
00857           m_dragList->DragEnter(NULL, screen);
00858           target_set= true;
00859           break;
00860         }
00861         target= GetParentItem(target);
00862       }
00863     }
00864     else
00865     {
00866       // not over a valid area
00867       if (has_drag_images)
00868         m_dragList->SetDragCursorImage(m_xDrag, CPoint(0,0));
00869     }
00870 
00871     if (!(target_set))
00872     {
00873       m_dragList->DragLeave(NULL);
00874       SelectDropTarget(NULL);
00875       m_dragList->DragEnter(NULL, screen);
00876     }
00877 
00878   }
00879 
00880   CTreeCtrl::OnMouseMove(nFlags, point);
00881 }
00882 
00883 
00884 #endif //BITMAP_TREE_IMPLEMENTATION_FILE
00885 

Generated on Wed Nov 19 04:28:39 2008 for HOOPLE Libraries by  doxygen 1.5.1