Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
lvicon.c
Package: shell.rar [view]
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 70k
Category:
Windows Kernel
Development Platform:
Visual C++
- // large icon view stuff
- #include "ctlspriv.h"
- #include "listview.h"
- #ifdef FE_IME
- #include <imm.h>
- static char const szIMECompPos[]="IMECompPos";
- #endif
- #define ICONCXLABEL(pl, pi) ((pl->style & LVS_NOLABELWRAP) ? pi->cxSingleLabel : pi->cxMultiLabel)
- void NEAR PASCAL ListView_IDrawItem(LV* plv, int i, HDC hdc, LPPOINT lpptOrg, RECT FAR* prcClip, UINT fDraw)
- {
- RECT rcIcon;
- RECT rcLabel;
- RECT rcBounds;
- RECT rcT;
- ListView_GetRects(plv, i, &rcIcon, &rcLabel, &rcBounds, NULL);
- if (!prcClip || IntersectRect(&rcT, prcClip, &rcBounds))
- {
- LV_ITEM item;
- char ach[CCHLABELMAX];
- UINT fText;
- if (lpptOrg)
- {
- OffsetRect(&rcIcon, lpptOrg->x - rcBounds.left,
- lpptOrg->y - rcBounds.top);
- OffsetRect(&rcLabel, lpptOrg->x - rcBounds.left,
- lpptOrg->y - rcBounds.top);
- }
- item.iItem = i;
- item.iSubItem = 0;
- item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
- item.stateMask = LVIS_ALL;
- item.pszText = ach;
- item.cchTextMax = sizeof(ach);
- ListView_OnGetItem(plv, &item);
- fText = ListView_DrawImage(plv, &item, hdc,
- rcIcon.left + g_cxIconMargin, rcIcon.top + g_cyIconMargin, fDraw);
- // Don't draw label if it's being edited...
- //
- if (plv->iEdit != i)
- {
- if (rcLabel.bottom - rcLabel.top > plv->cyLabelChar)
- fText |= SHDT_DRAWTEXT;
- else
- fText |= SHDT_ELLIPSES;
- if (fDraw & LVDI_TRANSTEXT)
- fText |= SHDT_TRANSPARENT;
- if (item.pszText)
- {
- // yow! this eats stack. 256 from this proc and 256 from shell_drawtext
- SHDrawText(hdc, item.pszText, &rcLabel, LVCFMT_LEFT, fText,
- plv->cyLabelChar, plv->cxEllipses, plv->clrText,
- (plv->style & WS_DISABLED ? plv->clrBk : plv->clrTextBk));
- }
- if ((fDraw & LVDI_FOCUS) && (item.state & LVIS_FOCUSED))
- DrawFocusRect(hdc, &rcLabel);
- }
- }
- }
- int NEAR ListView_IItemHitTest(LV* plv, int x, int y, UINT FAR* pflags)
- {
- int iHit;
- UINT flags;
- POINT pt;
- // Map window-relative coordinates to view-relative coords...
- //
- pt.x = x + plv->ptOrigin.x;
- pt.y = y + plv->ptOrigin.y;
- // If there are any uncomputed items, recompute them now.
- //
- if (plv->rcView.left == RECOMPUTE)
- ListView_Recompute(plv);
- flags = 0;
- for (iHit = 0; iHit < ListView_Count(plv); iHit++)
- {
- LISTITEM FAR* pitem = ListView_FastGetZItemPtr(plv, iHit);
- POINT ptItem;
- RECT rcLabel;
- RECT rcIcon;
- ptItem.x = pitem->pt.x;
- ptItem.y = pitem->pt.y;
- rcIcon.top = ptItem.y - g_cyIconMargin;
- rcLabel.top = ptItem.y + plv->cyIcon + g_cyLabelSpace;
- rcLabel.bottom = rcLabel.top + pitem->cyMultiLabel;
- // Quick, easy rejection test...
- //
- if (pt.y < rcIcon.top || pt.y >= rcLabel.bottom)
- continue;
- rcIcon.left = ptItem.x - g_cxIconMargin;
- rcIcon.right = ptItem.x + plv->cxIcon + g_cxIconMargin;
- // We need to make sure there is no gap between the icon and label
- rcIcon.bottom = rcLabel.top;
- rcLabel.left = ptItem.x + (plv->cxIcon / 2) - (ICONCXLABEL(plv, pitem) / 2);
- rcLabel.right = rcLabel.left + ICONCXLABEL(plv, pitem);
- if (PtInRect(&rcIcon, pt))
- {
- flags = LVHT_ONITEMICON;
- break;
- }
- if (PtInRect(&rcLabel, pt))
- {
- flags = LVHT_ONITEMLABEL;
- break;
- }
- }
- if (flags == 0)
- {
- flags = LVHT_NOWHERE;
- iHit = -1;
- }
- else
- {
- iHit = DPA_GetPtrIndex(plv->hdpa, ListView_FastGetZItemPtr(plv, iHit));
- }
- *pflags = flags;
- return iHit;
- }
- // out:
- // prcIcon icon bounds including icon margin area
- void NEAR ListView_IGetRects(LV* plv, LISTITEM FAR* pitem, RECT FAR* prcIcon, RECT FAR* prcLabel, LPRECT prcBounds)
- {
- prcIcon->left = pitem->pt.x - g_cxIconMargin - plv->ptOrigin.x;
- prcIcon->right = prcIcon->left + plv->cxIcon + 2 * g_cxIconMargin;
- prcIcon->top = pitem->pt.y - g_cyIconMargin - plv->ptOrigin.y;
- prcIcon->bottom = prcIcon->top + plv->cyIcon + 2 * g_cyIconMargin;
- prcLabel->left = pitem->pt.x + (plv->cxIcon / 2) - (ICONCXLABEL(plv, pitem) / 2) - plv->ptOrigin.x;
- prcLabel->right = prcLabel->left + ICONCXLABEL(plv, pitem);
- prcLabel->top = pitem->pt.y + plv->cyIcon + g_cyLabelSpace - plv->ptOrigin.y;
- prcLabel->bottom = prcLabel->top + pitem->cyMultiLabel;
- }
- int NEAR ListView_GetSlotCount(LV* plv, BOOL fWithoutScrollbars)
- {
- int cxScreen;
- int cyScreen;
- int dxItem;
- int dyItem;
- int iSlots = 1;
- BOOL fCheckWithScroll = FALSE;
- DWORD style;
- // Always use the current client window size to determine
- //
- // REVIEW: Should we exclude any vertical scroll bar that may
- // exist when computing this? progman.exe does not.
- //
- cxScreen = plv->sizeClient.cx;
- cyScreen = plv->sizeClient.cy;
- if (fWithoutScrollbars) {
- style = GetWindowStyle(plv->hwnd);
- if (style & WS_VSCROLL)
- cxScreen += g_cxScrollbar;
- if (style & WS_HSCROLL)
- cyScreen += g_cyScrollbar;
- }
- if (ListView_IsSmallView(plv))
- dxItem = plv->cxItem;
- else
- dxItem = lv_cxIconSpacing;
- if (ListView_IsSmallView(plv))
- dyItem = plv->cyItem;
- else
- dyItem = lv_cyIconSpacing;
- // Lets see which direction the view states
- switch (plv->style & LVS_ALIGNMASK)
- {
- case LVS_ALIGNBOTTOM:
- case LVS_ALIGNTOP:
- iSlots = max(1, (cxScreen) / dxItem);
- fCheckWithScroll = (BOOL)(style & WS_VSCROLL);
- break;
- case LVS_ALIGNRIGHT:
- case LVS_ALIGNLEFT:
- iSlots = max(1, (cyScreen) / dyItem);
- fCheckWithScroll = (BOOL)(style & WS_HSCROLL);
- break;
- default:
- Assert(0);
- return 1;
- }
- // if we don't have enough slots total on the screen, we're going to have
- // a scrollbar, so recompute with the scrollbars on
- if (fWithoutScrollbars && fCheckWithScroll) {
- int iTotalSlots = (dxItem * dyItem);
- if (iTotalSlots < ListView_Count(plv)) {
- iSlots = ListView_GetSlotCount(plv, FALSE);
- }
- }
- return iSlots;
- }
- // Go through and recompute any icon positions and optionally
- // icon label dimensions.
- //
- // This function also recomputes the view bounds rectangle.
- //
- // The algorithm is to simply search the list for any items needing
- // recomputation. For icon positions, we scan possible icon slots
- // and check to see if any already-positioned icon intersects the slot.
- // If not, the slot is free. As an optimization, we start scanning
- // icon slots from the previous slot we found.
- //
- void NEAR ListView_Recompute(LV* plv)
- {
- int i;
- int cSlots;
- BOOL fUpdateSB;
- BOOL fAppendAtEnd = FALSE;
- BOOL fLargeIconView;
- int iFree;
- HDC hdc;
- if (!(ListView_IsIconView(plv) || ListView_IsSmallView(plv)))
- return;
- if (plv->flags & LVF_INRECOMPUTE)
- {
- return;
- }
- plv->flags |= LVF_INRECOMPUTE;
- fLargeIconView = ListView_IsIconView(plv);
- hdc = NULL;
- cSlots = ListView_GetSlotCount(plv, FALSE);
- // Scan all items for RECOMPUTE, and recompute slot if needed.
- //
- fUpdateSB = (plv->rcView.left == RECOMPUTE);
- iFree = -1;
- for (i = 0; i < ListView_Count(plv); i++)
- {
- LISTITEM FAR* pitem = ListView_FastGetItemPtr(plv, i);
- BOOL fRedraw = FALSE;
- if (pitem->cyMultiLabel == SRECOMPUTE)
- {
- hdc = ListView_RecomputeLabelSize(plv, pitem, i, hdc);
- fRedraw = TRUE;
- }
- if (pitem->pt.y == RECOMPUTE)
- {
- iFree = ListView_FindFreeSlot(plv, i, iFree + 1, cSlots,
- &fUpdateSB, &fAppendAtEnd, &hdc);
- Assert(iFree != -1);
- ListView_SetIconPos(plv, pitem, iFree, cSlots);
- fRedraw = TRUE;
- }
- if (fRedraw)
- {
- ListView_InvalidateItem(plv, i, FALSE, RDW_INVALIDATE | RDW_ERASE);
- fUpdateSB = TRUE;
- }
- }
- if (hdc)
- ReleaseDC(HWND_DESKTOP, hdc);
- // If we changed something, recompute the view rectangle
- // and then update the scroll bars.
- //
- if (fUpdateSB)
- {
- // NOTE: No infinite recursion results because we're setting
- // plv->rcView.left != RECOMPUTE
- //
- SetRectEmpty(&plv->rcView);
- for (i = 0; i < ListView_Count(plv); i++)
- {
- RECT rcItem;
- ListView_GetRects(plv, i, NULL, NULL, &rcItem, NULL);
- UnionRect(&plv->rcView, &plv->rcView, &rcItem);
- }
- // add a little space at the edges so that we don't bump text
- // completely to the end of the window
- plv->rcView.bottom += g_cyEdge;
- plv->rcView.right += g_cxEdge;
- OffsetRect(&plv->rcView, plv->ptOrigin.x, plv->ptOrigin.y);
- //DebugMsg(DM_TRACE, "RECOMPUTE: rcView %x %x %x %x", plv->rcView.left, plv->rcView.top, plv->rcView.right, plv->rcView.bottom);
- //DebugMsg(DM_TRACE, "Origin %x %x", plv->ptOrigin.x, plv->ptOrigin.y);
- ListView_UpdateScrollBars(plv);
- }
- // Now state we are out of the recompute...
- plv->flags &= ~LVF_INRECOMPUTE;
- }
- void NEAR PASCAL NearestSlot(int FAR *x, int FAR *y, int cxItem, int cyItem)
- {
- *x += cxItem/2;
- *y += cyItem/2;
- *x = *x - (*x % cxItem);
- *y = *y - (*y % cyItem);
- }
- void NEAR PASCAL NextSlot(LV* plv, LPRECT lprc)
- {
- int cxItem;
- if (ListView_IsSmallView(plv))
- {
- cxItem = plv->cxItem;
- }
- else
- {
- cxItem = lv_cxIconSpacing;
- }
- lprc->left += cxItem;
- lprc->right += cxItem;
- }
- BOOL NEAR _CalcSlotRect(LV* plv, int iSlot, int cSlot, BOOL fBias, LPRECT lprc)
- {
- int cxItem, cyItem;
- BOOL fSmallIcon;
- Assert(plv);
- if (cSlot < 1)
- cSlot = 1;
- if (fSmallIcon = ListView_IsSmallView(plv))
- {
- cxItem = plv->cxItem;
- cyItem = plv->cyItem;
- }
- else
- {
- cxItem = lv_cxIconSpacing;
- cyItem = lv_cyIconSpacing;
- }
- // Lets see which direction the view states
- switch (plv->style & LVS_ALIGNMASK)
- {
- case LVS_ALIGNBOTTOM:
- // Assert False (Change default in shell2d.. to ALIGN_TOP)
- case LVS_ALIGNTOP:
- lprc->left = (iSlot % cSlot) * cxItem;
- lprc->top = (iSlot / cSlot) * cyItem;
- break;
- case LVS_ALIGNLEFT:
- lprc->top = (iSlot % cSlot) * cyItem;
- lprc->left = (iSlot / cSlot) * cxItem;
- break;
- case LVS_ALIGNRIGHT:
- Assert(FALSE); // Not implemented yet...
- break;
- }
- if (fBias)
- {
- lprc->left -= plv->ptOrigin.x;
- lprc->top -= plv->ptOrigin.y;
- }
- lprc->bottom = lprc->top + cyItem;
- lprc->right = lprc->left + cxItem;
- return(fSmallIcon);
- }
- // Find an icon slot that doesn't intersect an icon.
- // Start search for free slot from slot i.
- //
- int NEAR ListView_FindFreeSlot(LV* plv, int iItem, int i, int cSlot, BOOL FAR* pfUpdate,
- BOOL FAR *pfAppend, HDC FAR* phdc)
- {
- int j;
- HDC hdc;
- RECT rcSlot;
- RECT rcItem;
- RECT rc;
- int xMax = -1;
- int yMax = -1;
- int cItems;
- // Horrible N-squared algorithm:
- // enumerate each slot and see if any items intersect it.
- //
- // REVIEW: This is really slow with long lists (e.g., 1000)
- //
- hdc = NULL;
- cItems = ListView_Count(plv);
- //
- // If the Append at end is set, we should be able to simply get the
- // rectangle of the i-1 element and check against it instead of
- // looking at every other item...
- //
- if (*pfAppend)
- {
- Assert(iItem > 0);
- // Be carefull about going of the end of the list. (i is a slot
- // number not an item index).
- ListView_GetRects(plv, iItem-1, NULL, NULL, &rcItem, NULL);
- }
- for ( ; ; i++)
- {
- // Compute view-relative slot rectangle...
- //
- _CalcSlotRect(plv, i, cSlot, TRUE, &rcSlot);
- if (*pfAppend)
- {
- if (!IntersectRect(&rc, &rcItem, &rcSlot))
- return i; // Found a free slot...
- }
- else
- {
- for (j = cItems; j-- > 0; )
- {
- LISTITEM FAR* pitem = ListView_FastGetItemPtr(plv, j);
- if (pitem->pt.y != RECOMPUTE)
- {
- // If the dimensions aren't computed, then do it now.
- //
- if (pitem->cyMultiLabel == SRECOMPUTE)
- {
- *phdc = ListView_RecomputeLabelSize(plv, pitem, i, *phdc);
- // Ensure that the item gets redrawn...
- //
- ListView_InvalidateItem(plv, i, FALSE, RDW_INVALIDATE | RDW_ERASE);
- // Set flag indicating that scroll bars need to be
- // adjusted.
- //
- *pfUpdate = TRUE;
- }
- ListView_GetRects(plv, j, NULL, NULL, &rc, NULL);
- if (IntersectRect(&rc, &rc, &rcSlot))
- break;
- }
- }
- if (j < 0)
- break;
- }
- }
- if ( (rcSlot.bottom > yMax) ||
- ((rcSlot.bottom == yMax) && (rcSlot.right > xMax)))
- *pfAppend = TRUE;
- return i;
- }
- // Recompute an item's label size (cxLabel/cyLabel). For speed, this function
- // is passed a DC to use for text measurement.
- //
- // If hdc is NULL, then this function will get a DC and return it. Otherwise,
- // the returned hdc is the same as the one passed in. It's the caller's
- // responsibility to eventually release the DC.
- //
- HDC NEAR ListView_RecomputeLabelSize(LV* plv, LISTITEM FAR* pitem, int i, HDC hdc)
- {
- char szLabel[CCHLABELMAX + 4];
- int cchLabel;
- RECT rcSingle, rcMulti;
- LV_ITEM item;
- Assert(plv);
- Assert(pitem);
- // Get the DC and select the font only once for entire loop.
- //
- if (!hdc)
- {
- // we return this DC and have the calller release it
- hdc = GetDC(HWND_DESKTOP);
- SelectFont(hdc, plv->hfontLabel);
- }
- item.mask = LVIF_TEXT;
- item.iItem = i;
- item.iSubItem = 0;
- item.pszText = szLabel;
- item.cchTextMax = sizeof(szLabel);
- item.stateMask = 0;
- ListView_OnGetItem(plv, &item);
- if (!item.pszText)
- {
- SetRectEmpty(&rcSingle);
- rcMulti = rcSingle;
- goto Exit;
- }
- if (item.pszText != szLabel)
- lstrcpy(szLabel, item.pszText);
- cchLabel = lstrlen(szLabel);
- rcMulti.left = rcMulti.top = rcMulti.bottom = 0;
- rcMulti.right = lv_cxIconSpacing - g_cxLabelMargin * 2;
- rcSingle = rcMulti;
- if (cchLabel > 0)
- {
- // Strip off spaces so they're not included in format
- // REVIEW: Is this is a DrawText bug?
- //
- while (cchLabel > 1 && szLabel[cchLabel - 1] == ' ')
- szLabel[--cchLabel] = 0;
- DrawText(hdc, szLabel, cchLabel, &rcSingle, (DT_LV | DT_CALCRECT));
- #ifdef WIN32
- DrawText(hdc, szLabel, cchLabel, &rcMulti, (DT_LVWRAP | DT_WORD_ELLIPSIS | DT_CALCRECT));
- #else
- DrawText(hdc, szLabel, cchLabel, &rcMulti, (DT_LVWRAP | DT_CALCRECT));
- #endif
- }
- else
- {
- rcMulti.bottom = rcMulti.top + plv->cyLabelChar;
- }
- Exit:
- pitem->cxSingleLabel = (rcSingle.right - rcSingle.left) + 2 * g_cxLabelMargin;
- pitem->cxMultiLabel = (rcMulti.right - rcMulti.left) + 2 * g_cxLabelMargin;
- pitem->cyMultiLabel = (short)(rcMulti.bottom - rcMulti.top);
- return hdc;
- }
- // Set up an icon slot position. Returns FALSE if position didn't change.
- //
- BOOL NEAR ListView_SetIconPos(LV* plv, LISTITEM FAR* pitem, int iSlot, int cSlot)
- {
- RECT rc;
- Assert(plv);
- //
- // Sort of a hack, this internal function return TRUE if small icon.
- if (!_CalcSlotRect(plv, iSlot, cSlot, FALSE, &rc))
- {
- rc.left += g_cxIconOffset;
- rc.top += g_cyIconOffset;
- }
- if (rc.left != pitem->pt.x || rc.top != pitem->pt.y)
- {
- pitem->pt.x = rc.left;
- pitem->pt.y = rc.top;
- // REVIEW: Performance idea:
- //
- // Invalidate rcView only if this icon's old or new position
- // touches or is outside of the current rcView.
- // If we do this, then we must change the various tests
- // of rcView.left == RECOMPUTE to more specific tests of pitem->...
- //
- plv->rcView.left = RECOMPUTE;
- return TRUE;
- }
- return FALSE;
- }
- void NEAR ListView_GetViewRect2(LV* plv, RECT FAR* prcView, int cx, int cy)
- {
- if (plv->rcView.left == RECOMPUTE)
- ListView_Recompute(plv);
- *prcView = plv->rcView;
- OffsetRect(prcView, -plv->ptOrigin.x, -plv->ptOrigin.y);
- if (ListView_IsIconView(plv) || ListView_IsSmallView(plv)) {
- // don't do that funky half-re-origining thing.
- RECT rc;
- rc.left = 0;
- rc.top = 0;
- rc.bottom = rc.top + 1;
- rc.right = rc.left + 1;
- UnionRect(prcView, prcView, &rc);
- rc.right = cx;
- rc.bottom = cy;
- rc.left = rc.right - 1;
- rc.top = rc.bottom - 1;
- UnionRect(prcView, prcView, &rc);
- #if 0
- // if we're scrolled way in the positive area (plv->ptOrigin > 0), make sure we
- // include our true origin
- if ((prcView->left > -plv->ptOrigin.x))
- prcView->left = -plv->ptOrigin.x;
- if ((prcView->top > -plv->ptOrigin.y))
- prcView->top = -plv->ptOrigin.y;
- // if we're scrolled way in the positive area (plv->ptOrigin > 0),
- // make sure our scrollbars include our current position
- if ((prcView->right < (plv->sizeClient.cx)))
- prcView->right = plv->sizeClient.cx;
- if ((prcView->bottom < (plv->sizeClient.cy)))
- prcView->bottom = plv->sizeClient.cy;
- #endif
- }
- }
- // prcViewRect used only if fSubScroll is TRUE
- DWORD NEAR ListView_GetClientRect(LV* plv, RECT FAR* prcClient, BOOL fSubScroll, RECT FAR *prcViewRect)
- {
- RECT rcClient;
- RECT rcView;
- DWORD style;
- #if 1
- // do this instead of the #else below because
- // in new versus old apps, you may need to add in g_c?Border because of
- // the one pixel overlap...
- GetWindowRect(plv->hwnd, &rcClient);
- if (GetWindowLong(plv->hwnd, GWL_EXSTYLE) & (WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE)) {
- rcClient.right -= 2 * g_cxEdge;
- rcClient.bottom -= 2 * g_cyEdge;
- }
- rcClient.right -= rcClient.left;
- rcClient.bottom -= rcClient.top;
- if (rcClient.right < 0)
- rcClient.right = 0;
- if (rcClient.bottom < 0)
- rcClient.bottom = 0;
- rcClient.top = rcClient.left = 0;
- #else
- style = GetWindowStyle(plv->hwnd);
- GetClientRect(plv->hwnd, &rcClient);
- if (style & WS_VSCROLL)
- rcClient.right += g_cxScrollbar;
- if (style & WS_HSCROLL)
- rcClient.bottom += g_cyScrollbar;
- #endif
- style = 0L;
- if (fSubScroll)
- {
- ListView_GetViewRect2(plv, &rcView,
- rcClient.right - g_cxScrollbar,
- rcClient.bottom - g_cyScrollbar);
- if ((rcClient.left < rcClient.right) && (rcClient.top < rcClient.bottom))
- {
- do
- {
- if (rcView.left < rcClient.left || rcView.right > rcClient.right)
- {
- style |= WS_HSCROLL;
- rcClient.bottom -= g_cyScrollbar;
- }
- if (rcView.top < rcClient.top || rcView.bottom > rcClient.bottom)
- {
- style |= WS_VSCROLL;
- rcClient.right -= g_cxScrollbar;
- }
- }
- while (!(style & WS_HSCROLL) && rcView.right > rcClient.right);
- }
- if (prcViewRect)
- *prcViewRect = rcView;
- }
- *prcClient = rcClient;
- return style;
- }
- int CALLBACK ArrangeIconCompare(LISTITEM FAR* pitem1, LISTITEM FAR* pitem2, LPARAM lParam)
- {
- int v1, v2;
- if (HIWORD(lParam))
- {
- // Vertical arrange
- v1 = pitem1->pt.x / (int)LOWORD(lParam);
- v2 = pitem2->pt.x / (int)LOWORD(lParam);
- if (v1 > v2)
- return 1;
- else if (v1 < v2)
- return -1;
- else
- {
- int y1 = pitem1->pt.y;
- int y2 = pitem2->pt.y;
- if (y1 > y2)
- return 1;
- else if (y1 < y2)
- return -1;
- }
- }
- else
- {
- v1 = pitem1->pt.y / (int)lParam;
- v2 = pitem2->pt.y / (int)lParam;
- if (v1 > v2)
- return 1;
- else if (v1 < v2)
- return -1;
- else
- {
- int x1 = pitem1->pt.x;
- int x2 = pitem2->pt.x;
- if (x1 > x2)
- return 1;
- else if (x1 < x2)
- return -1;
- }
- }
- return 0;
- }
- void NEAR PASCAL _ListView_GetRectsFromItem(LV* plv, BOOL bSmallIconView,
- LISTITEM FAR *pitem,
- LPRECT prcIcon, LPRECT prcLabel, LPRECT prcBounds, LPRECT prcSelectBounds)
- {
- RECT rcIcon;
- RECT rcLabel;
- if (!prcIcon)
- prcIcon = &rcIcon;
- if (!prcLabel)
- prcLabel = &rcLabel;
- // Test for NULL item passed in
- if (pitem)
- {
- // This routine is called during ListView_Recompute(), while
- // plv->rcView.left may still be == RECOMPUTE. So, we can't
- // test that to see if recomputation is needed.
- //
- if (pitem->pt.y == RECOMPUTE || pitem->cyMultiLabel == SRECOMPUTE)
- ListView_Recompute(plv);
- if (bSmallIconView)
- ListView_SGetRects(plv, pitem, prcIcon, prcLabel, prcBounds);
- else
- ListView_IGetRects(plv, pitem, prcIcon, prcLabel, prcBounds);
- if (prcBounds) {
- UnionRect(prcBounds, prcIcon, prcLabel);
- if (plv->himlState && (LV_StateImageValue(pitem))) {
- prcBounds->left -= plv->cxState;
- }
- }
- } else {
- SetRectEmpty(prcIcon);
- *prcLabel = *prcIcon;
- if (prcBounds)
- *prcBounds = *prcIcon;
- }
- if (prcSelectBounds)
- UnionRect(prcSelectBounds, prcIcon, prcLabel);
- }
- void NEAR _ListView_InvalidateItemPtr(LV* plv, BOOL bSmallIcon, LISTITEM FAR *pitem, UINT fRedraw)
- {
- RECT rcBounds;
- _ListView_GetRectsFromItem(plv, bSmallIcon, pitem, NULL, NULL, &rcBounds, NULL);
- RedrawWindow(plv->hwnd, &rcBounds, NULL, fRedraw);
- }
- // return TRUE if things still overlap
- // this only happens if we tried to unstack things, and there was NOSCROLL set and
- // items tried to go off the deep end
- BOOL NEAR PASCAL ListView_IUnstackOverlaps(LV* plv, HDPA hdpaSort, int iDirection)
- {
- BOOL fRet = FALSE;
- int i;
- int iCount;
- BOOL bSmallIconView;
- RECT rcItem, rcItem2, rcTemp;
- int cxItem, cyItem;
- LISTITEM FAR* pitem;
- LISTITEM FAR* pitem2;
- if (bSmallIconView = ListView_IsSmallView(plv))
- {
- cxItem = plv->cxItem;
- cyItem = plv->cyItem;
- }
- else
- {
- cxItem = lv_cxIconSpacing;
- cyItem = lv_cyIconSpacing;
- }
- iCount = ListView_Count(plv);
- // finally, unstack any overlaps
- for (i = 0 ; i < iCount ; i++) {
- int j;
- pitem = DPA_GetPtr(hdpaSort, i);
- if (bSmallIconView) {
- _ListView_GetRectsFromItem(plv, bSmallIconView, pitem, NULL, NULL, &rcItem, NULL);
- }
- // move all the items that overlap with us
- for (j = i+1 ; j < iCount; j++) {
- POINT ptOldPos;
- pitem2 = DPA_GetPtr(hdpaSort, j);
- ptOldPos = pitem2->pt;
- if (bSmallIconView) {
- // for small icons, we need to do an intersect rect
- _ListView_GetRectsFromItem(plv, bSmallIconView, pitem2, NULL, NULL, &rcItem2, NULL);
- if (IntersectRect(&rcTemp, &rcItem, &rcItem2)) {
- // yes, it intersects. move it out
- _ListView_InvalidateItemPtr(plv, bSmallIconView, pitem2, RDW_INVALIDATE| RDW_ERASE);
- do {
- pitem2->pt.x += (cxItem * iDirection);
- } while (PtInRect(&rcItem, pitem2->pt));
- } else {
- // no more intersect!
- break;
- }
- } else {
- // for large icons, just find the ones that share the x,y;
- if (pitem2->pt.x == pitem->pt.x && pitem2->pt.y == pitem->pt.y) {
- _ListView_InvalidateItemPtr(plv, bSmallIconView, pitem2, RDW_INVALIDATE| RDW_ERASE);
- pitem2->pt.x += (cxItem * iDirection);
- } else {
- // no more intersect!
- break;
- }
- }
- if (plv->style & LVS_NOSCROLL) {
- if (pitem2->pt.x < 0 || pitem2->pt.y < 0 ||
- pitem2->pt.x > (plv->sizeClient.cx - (cxItem/2))||
- pitem2->pt.y > (plv->sizeClient.cy - (cyItem/2))) {
- pitem2->pt = ptOldPos;
- fRet = TRUE;
- }
- }
- // invalidate the new position as well
- _ListView_InvalidateItemPtr(plv, bSmallIconView, pitem2, RDW_INVALIDATE| RDW_ERASE);
- }
- }
- return fRet;
- }
- BOOL NEAR PASCAL ListView_SnapToGrid(LV* plv, HDPA hdpaSort)
- {
- // this algorithm can't fit in the structure of the other
- // arrange loop without becoming n^2 or worse.
- // this algorithm is order n.
- // iterate through and snap to the nearest grid.
- // iterate through and push aside overlaps.
- int i;
- int iCount;
- LPARAM xySpacing;
- int x,y;
- LISTITEM FAR* pitem;
- BOOL bSmallIconView;
- int cxItem, cyItem;
- if (bSmallIconView = ListView_IsSmallView(plv))
- {
- cxItem = plv->cxItem;
- cyItem = plv->cyItem;
- }
- else
- {
- cxItem = lv_cxIconSpacing;
- cyItem = lv_cyIconSpacing;
- }
- iCount = ListView_Count(plv);
- // first snap to nearest grid
- for (i = 0; i < iCount; i++) {
- pitem = DPA_GetPtr(hdpaSort, i);
- x = pitem->pt.x;
- y = pitem->pt.y;
- if (!bSmallIconView) {
- x -= g_cxIconOffset;
- y -= g_cyIconOffset;
- }
- NearestSlot(&x,&y, cxItem, cyItem);
- if (!bSmallIconView) {
- x += g_cxIconOffset;
- y += g_cyIconOffset;
- }
- if (x != pitem->pt.x || y != pitem->pt.y) {
- _ListView_InvalidateItemPtr(plv, bSmallIconView, pitem, RDW_INVALIDATE| RDW_ERASE);
- if (plv->style & LVS_NOSCROLL) {
- // if it's marked noscroll, make sure it's still on the client region
- while (x >= (plv->sizeClient.cx - (cxItem/2)))
- x -= cxItem;
- while (x < 0)
- x += cxItem;
- while (y >= (plv->sizeClient.cy - (cyItem/2)))
- y -= cyItem;
- while (y < 0)
- y += cyItem;
- }
- pitem->pt.x = x;
- pitem->pt.y = y;
- _ListView_InvalidateItemPtr(plv, bSmallIconView, pitem, RDW_INVALIDATE| RDW_ERASE);
- }
- }
- // now resort the dpa
- switch (plv->style & LVS_ALIGNMASK)
- {
- case LVS_ALIGNLEFT:
- case LVS_ALIGNRIGHT:
- xySpacing = MAKELONG(bSmallIconView ? plv->cxItem : lv_cxIconSpacing, TRUE);
- break;
- default:
- xySpacing = MAKELONG(bSmallIconView ? plv->cyItem : lv_cyIconSpacing, FALSE);
- }
- if (!DPA_Sort(hdpaSort, ArrangeIconCompare, xySpacing))
- return FALSE;
- // go in one direction, if there are still overlaps, go in the other
- // direction as well
- if (ListView_IUnstackOverlaps(plv, hdpaSort, 1))
- ListView_IUnstackOverlaps(plv, hdpaSort, -1);
- return FALSE;
- }
- BOOL NEAR ListView_OnArrange(LV* plv, UINT style)
- {
- BOOL bSmallIconView;
- LPARAM xySpacing;
- HDPA hdpaSort;
- bSmallIconView = ListView_IsSmallView(plv);
- if (!bSmallIconView && !ListView_IsIconView(plv)) {
- return FALSE;
- }
- // Make sure our items have positions and their text rectangles
- // caluculated
- if (plv->rcView.left == RECOMPUTE)
- ListView_Recompute(plv);
- // we clone plv->hdpa so we don't blow away indices that
- // apps have saved away.
- // we sort here to make the nested for loop below more bearable.
- hdpaSort = DPA_Clone(plv->hdpa, NULL);
- if (!hdpaSort)
- return FALSE;
- switch (plv->style & LVS_ALIGNMASK)
- {
- case LVS_ALIGNLEFT:
- case LVS_ALIGNRIGHT:
- xySpacing = MAKELONG(bSmallIconView ? plv->cxItem : lv_cxIconSpacing, TRUE);
- break;
- default:
- xySpacing = MAKELONG(bSmallIconView ? plv->cyItem : lv_cyIconSpacing, FALSE);
- }
- if (!DPA_Sort(hdpaSort, ArrangeIconCompare, xySpacing))
- return FALSE;
- ListView_CommonArrange(plv, style, hdpaSort);
- DPA_Destroy(hdpaSort);
- }
- // this arranges the icon given a sorted hdpa.
- BOOL NEAR ListView_CommonArrange(LV* plv, UINT style, HDPA hdpaSort)
- {
- int iSlot;
- int iItem;
- int cSlots;
- BOOL fItemMoved;
- RECT rcLastItem;
- RECT rcSlot;
- RECT rcT;
- BOOL bSmallIconView;
- int xMin = 0;
- bSmallIconView = ListView_IsSmallView(plv);
- // REVIEW, this causes a repaint if we are scrollled
- // we can probably avoid this some how
- fItemMoved = (plv->ptOrigin.x != 0) || (plv->ptOrigin.y != 0);
- plv->ptOrigin.x = 0;
- plv->ptOrigin.y = 0;
- if (style == LVA_SNAPTOGRID) {
- fItemMoved |= ListView_SnapToGrid(plv, hdpaSort);
- } else {
- cSlots = ListView_GetSlotCount(plv, TRUE);
- SetRectEmpty(&rcLastItem);
- // manipulate only the sorted version of the item list below!
- iSlot = 0;
- for (iItem = 0; iItem < ListView_Count(plv); iItem++)
- {
- LISTITEM FAR* pitem = DPA_GetPtr(hdpaSort, iItem);
- if (bSmallIconView)
- {
- // BUGBUG:: Only check for Small view... See if this gets the
- // results people expect?
- for ( ; ; )
- {
- _CalcSlotRect(plv, iSlot, cSlots, FALSE, &rcSlot);
- if (!IntersectRect(&rcT, &rcSlot, &rcLastItem))
- break;
- iSlot++;
- }
- }
- fItemMoved |= ListView_SetIconPos(plv, pitem, iSlot++, cSlots);
- // do this instead of ListView_GetRects() because we need
- // to use the pitem from the sorted hdpa, not the ones in *plv
- _ListView_GetRectsFromItem(plv, bSmallIconView, pitem, NULL, NULL, &rcLastItem, NULL);
- //
- // Keep track of the minimum x as we don't want negative values
- // when we finish.
- if (rcLastItem.left < xMin)
- xMin = rcLastItem.left;
- }
- //
- // See if we need to scroll the items over to make sure that all of the
- // no items are hanging off the left hand side.
- //
- if (xMin < 0)
- {
- for (iItem = 0; iItem < ListView_Count(plv); iItem++)
- {
- LISTITEM FAR* pitem = ListView_FastGetItemPtr(plv, iItem);
- pitem->pt.x -= xMin; // scroll them over
- }
- plv->rcView.left = RECOMPUTE; // need to recompute.
- fItemMoved = TRUE;
- }
- }
- //
- // We might as well invalidate the entire window to make sure...
- if (fItemMoved) {
- if (ListView_RedrawEnabled(plv))
- RedrawWindow(plv->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
- else {
- ListView_DeleteHrgnInval(plv);
- plv->hrgnInval = (HRGN)ENTIRE_REGION;
- plv->flags |= LVF_ERASE;
- }
- // ensure important items are visible
- iItem = (plv->iFocus >= 0) ? plv->iFocus : ListView_OnGetNextItem(plv, -1, LVNI_SELECTED);
- if (iItem >= 0)
- ListView_OnEnsureVisible(plv, iItem, FALSE);
- if (ListView_RedrawEnabled(plv))
- ListView_UpdateScrollBars(plv);
- }
- return TRUE;
- }
- void NEAR ListView_IUpdateScrollBars(LV* plv)
- {
- RECT rcClient;
- RECT rcView;
- DWORD style;
- DWORD styleOld;
- SCROLLINFO si;
- styleOld = GetWindowStyle(plv->hwnd);
- style = ListView_GetClientRect(plv, &rcClient, TRUE, &rcView);
- //DebugMsg(DM_TRACE, "ListView_GetClientRect %x %x %x %x", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
- //DebugMsg(DM_TRACE, "ListView_GetViewRect2 %x %x %x %x", rcView.left, rcView.top, rcView.right, rcView.bottom);
- //DebugMsg(DM_TRACE, "rcView %x %x %x %x", plv->rcView.left, plv->rcView.top, plv->rcView.right, plv->rcView.bottom);
- //DebugMsg(DM_TRACE, "Origin %x %x", plv->ptOrigin.x, plv->ptOrigin.y);
- si.cbSize = sizeof(SCROLLINFO);
- if (style & WS_HSCROLL)
- {
- si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
- si.nMin = 0;
- si.nMax = rcView.right - rcView.left - 1;
- //DebugMsg(DM_TRACE, "si.nMax rcView.right - rcView.left - 1 %x", si.nMax);
- si.nPage = min(rcClient.right, rcView.right) - rcClient.left;
- //DebugMsg(DM_TRACE, "si.nPage %x", si.nPage);
- si.nPos = 0;
- if (rcView.left < rcClient.left)
- si.nPos = rcClient.left - rcView.left;
- //DebugMsg(DM_TRACE, "si.nPos %x", si.nPos);
- #ifdef IEWIN31_25
- plv->cxScrollPage = (int)si.nPage;
- SetScrollRange( plv->hwnd, SB_HORZ, (int) si.nMin,
- max( (int)(si.nMax-si.nPage+1), 0 ), FALSE );
- SetScrollPos( plv->hwnd, SB_HORZ, (int) si.nPos, TRUE );
- #else
- SetScrollInfo(plv->hwnd, SB_HORZ, &si, TRUE);
- #endif //IEWIN31_25
- }
- else if (styleOld & WS_HSCROLL)
- {
- SetScrollRange(plv->hwnd, SB_HORZ, 0, 0, TRUE);
- }
- if (style & WS_VSCROLL)
- {
- si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
- si.nMin = 0;
- si.nMax = rcView.bottom - rcView.top - 1;
- si.nPage = min(rcClient.bottom, rcView.bottom) - rcClient.top;
- si.nPos = 0;
- if (rcView.top < rcClient.top)
- si.nPos = rcClient.top - rcView.top;
- #ifdef IEWIN31_25
- plv->cyScrollPage = (int)si.nPage;
- SetScrollRange( plv->hwnd, SB_VERT, (int) si.nMin,
- max( (int)(si.nMax-si.nPage+1), 0 ), FALSE );
- SetScrollPos( plv->hwnd, SB_VERT, (int) si.nPos, TRUE );
- #else
- SetScrollInfo(plv->hwnd, SB_VERT, &si, TRUE);
- #endif //IEWIN31_25
- }
- else if (styleOld & WS_VSCROLL)
- {
- SetScrollRange(plv->hwnd, SB_VERT, 0, 0, TRUE);
- }
- }
- void FAR PASCAL ListView_ComOnScroll(LV* plv, UINT code, int posNew, int sb,
- int cLine, int cPage,
- SCROLLPROC lpfnScroll2)
- {
- int pos;
- SCROLLINFO si;
- BOOL fVert = (sb == SB_VERT);
- #ifdef IEWIN31_25
- {
- int n1, n2;
- GetScrollRange( plv->hwnd, sb, &n1, &n2 );
- si.nMin = n1;
- si.nMax = n2;
- si.nPos = GetScrollPos( plv->hwnd, sb );
- si.nPage = fVert ? plv->cyScrollPage : plv->cxScrollPage;
- }
- #else
- si.cbSize = sizeof(SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
- if (!GetScrollInfo(plv->hwnd, sb, &si)) {
- return;
- }
- #endif //IEWIN31_25
- if (cPage != -1)
- si.nPage = cPage;
- si.nMax -= (si.nPage - 1);
- if (si.nMax < si.nMin)
- si.nMax = si.nMin;
- pos = (int)si.nPos; // current position
- switch (code)
- {
- case SB_LEFT:
- si.nPos = si.nMin;
- break;
- case SB_RIGHT:
- si.nPos = si.nMax;
- break;
- case SB_PAGELEFT:
- si.nPos -= si.nPage;
- break;
- case SB_LINELEFT:
- si.nPos -= cLine;
- break;
- case SB_PAGERIGHT:
- si.nPos += si.nPage;
- break;
- case SB_LINERIGHT:
- si.nPos += cLine;
- break;
- case SB_THUMBTRACK:
- si.nPos = posNew;
- break;
- case SB_ENDSCROLL:
- // When scroll bar tracking is over, ensure scroll bars
- // are properly updated...
- //
- ListView_UpdateScrollBars(plv);
- return;
- default:
- return;
- }
- si.fMask = SIF_POS;
- #ifdef IEWIN31_25
- SetScrollPos( plv->hwnd, sb, (int) si.nPos, TRUE );
- si.nPos = GetScrollPos( plv->hwnd, sb );
- #else
- si.nPos = SetScrollInfo(plv->hwnd, sb, &si, TRUE);
- #endif
- if (pos != si.nPos)
- {
- int delta = (int)si.nPos - pos;
- int dx = 0, dy = 0;
- if (fVert)
- dy = delta;
- else
- dx = delta;
- lpfnScroll2(plv, dx, dy);
- UpdateWindow(plv->hwnd);
- }
- }
- void FAR PASCAL ListView_IScroll2(LV* plv, int dx, int dy)
- {
- if (dx | dy)
- {
- plv->ptOrigin.x += dx;
- plv->ptOrigin.y += dy;
- ScrollWindowEx(plv->hwnd, -dx, -dy, NULL, NULL, NULL, NULL,
- SW_INVALIDATE | SW_ERASE);
- }
- }
- void NEAR ListView_IOnScroll(LV* plv, UINT code, int posNew, int sb)
- {
- int cLine;
- if (sb == SB_VERT)
- {
- cLine = lv_cyIconSpacing / 2;
- }
- else
- {
- cLine = lv_cxIconSpacing / 2;
- }
- ListView_ComOnScroll(plv, code, posNew, sb,
- cLine, -1,
- ListView_IScroll2);
- }
- // NOTE: there is very similar code in the treeview
- //
- // Totally disgusting hack in order to catch VK_RETURN
- // before edit control gets it.
- //
- LRESULT CALLBACK ListView_EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- LV* plv = ListView_GetPtr(GetParent(hwnd));
- Assert(plv);
- #ifdef FE_IME
- if ( LOWORD(GetKeyboardLayout(0L)) == 0x0411 )
- {
- // The following code adds IME awareness to the
- // listview's label editing. Currently just for Japanese.
- //
- DWORD dwGcs;
- if (msg==WM_SIZE)
- {
- // If it's given the size, tell it to an IME.
- ListView_SizeIME(hwnd);
- }
- else if (msg == EM_SETLIMITTEXT )
- {
- if (wParam < 13)
- plv->flags |= LVF_DONTDRAWCOMP;
- else
- plv->flags &= ~LVF_DONTDRAWCOMP;
- }
- // Give up to draw IME composition by ourselves in case
- // we're working on SFN. Win95d-5709
- else if (!(plv->flags & LVF_DONTDRAWCOMP ))
- {
- switch (msg)
- {
- case WM_IME_STARTCOMPOSITION:
- case WM_IME_ENDCOMPOSITION:
- return 0L;
- case WM_IME_COMPOSITION:
- // If lParam has no data available bit, it implies
- // canceling composition.
- // ListView_InsertComposition() tries to get composition
- // string w/ GCS_COMPSTR then remove it from edit control if
- // nothing is available.
- //
- if ( !lParam )
- dwGcs = GCS_COMPSTR;
- else
- dwGcs = lParam;
- ListView_InsertComposition(hwnd, wParam, dwGcs, plv);
- ListView_PaintComposition(hwnd,plv);
- return 0L;
- case WM_IME_SETCONTEXT:
- // We draw composition string.
- //
- lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
- break;
- default:
- // the other messages should simply be processed
- // in this subclass procedure.
- break;
- }
- }
- }
- #endif
- switch (msg)
- {
- case WM_SETTEXT:
- SetWindowID(hwnd, 1);
- break;
- case WM_KEYDOWN:
- switch (wParam)
- {
- case VK_RETURN:
- ListView_DismissEdit(plv, FALSE);
- return 0L;
- case VK_ESCAPE:
- ListView_DismissEdit(plv, TRUE);
- return 0L;
- }
- break;
- case WM_CHAR:
- switch (wParam)
- {
- case VK_RETURN:
- // Eat the character, so edit control wont beep!
- return 0L;
- }
- break;
- case WM_GETDLGCODE:
- return DLGC_WANTALLKEYS; /* editing name, no dialog handling right now */
- }
- return CallWindowProc(plv->pfnEditWndProc, hwnd, msg, wParam, lParam);
- }
- // BUGBUG: very similar routine in treeview
- void NEAR ListView_SetEditSize(LV* plv)
- {
- RECT rcLabel;
- LISTITEM FAR* pitem;
- pitem = ListView_GetItemPtr(plv, plv->iEdit);
- if (!pitem)
- {
- ListView_DismissEdit(plv, TRUE); // cancel edits
- return;
- }
- ListView_GetRects(plv, plv->iEdit, NULL, &rcLabel, NULL, NULL);
- // OffsetRect(&rc, rcLabel.left + g_cxLabelMargin + g_cxBorder,
- // (rcLabel.bottom + rcLabel.top - rc.bottom) / 2 + g_cyBorder);
- // OffsetRect(&rc, rcLabel.left + g_cxLabelMargin , rcLabel.top);
- // get the text bounding rect
- if (ListView_IsIconView(plv))
- {
- // We should not adjust y-positoin in case of the icon view.
- InflateRect(&rcLabel, -g_cxLabelMargin, -g_cyBorder);
- }
- else
- {
- // Special case for single-line & centered
- InflateRect(&rcLabel, -g_cxLabelMargin - g_cxBorder, (-(rcLabel.bottom - rcLabel.top - plv->cyLabelChar) / 2) - g_cyBorder);
- }
- SetEditInPlaceSize(plv->hwndEdit, &rcLabel, plv->hfontLabel, ListView_IsIconView(plv) && !(plv->style & LVS_NOLABELWRAP));
- }
- // to avoid eating too much stack
- void NEAR ListView_DoOnEditLabel(LV *plv, int i, LPSTR pszInitial)
- {
- char szLabel[CCHLABELMAX];
- LV_ITEM item;
- item.mask = LVIF_TEXT;
- item.iItem = i;
- item.iSubItem = 0;
- item.pszText = szLabel;
- item.cchTextMax = sizeof(szLabel);
- ListView_OnGetItem(plv, &item);
- if (!item.pszText)
- return;
- // Make sure the edited item has the focus.
- if (plv->iFocus != i)
- ListView_SetFocusSel(plv, i, TRUE, TRUE, FALSE);
- // Make sure the item is fully visible
- ListView_OnEnsureVisible(plv, i, FALSE); // fPartialOK == FALSE
- plv->hwndEdit = CreateEditInPlaceWindow(plv->hwnd,
- pszInitial? pszInitial : item.pszText, sizeof(szLabel),
- ListView_IsIconView(plv) ?
- (WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD | ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL) :
- (WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD | ES_LEFT | ES_AUTOHSCROLL), plv->hfontLabel);
- if (plv->hwndEdit)
- {
- LISTITEM FAR* pitem;
- LV_DISPINFO nm;
- // We create the edit window but have not shown it. Ask the owner
- // if they are interested or not.
- // If we passed in initial text set the ID to be dirty...
- if (pszInitial)
- SetWindowID(plv->hwndEdit, 1);
- if (!(pitem = ListView_GetItemPtr(plv, i)))
- {
- DestroyWindow(plv->hwndEdit);
- plv->hwndEdit = NULL;
- return;
- }
- nm.item.iItem = i;
- nm.item.iSubItem = 0;
- nm.item.lParam = pitem->lParam;
- // if they have LVS_EDITLABELS but return non-FALSE here, stop!
- if ((BOOL)SendNotify(plv->hwndParent, plv->hwnd, LVN_BEGINLABELEDIT, &nm.hdr))
- {
- DestroyWindow(plv->hwndEdit);
- plv->hwndEdit = NULL;
- }
- else
- {
- // Ok To continue - so Show the window and set focus to it.
- SetFocus(plv->hwndEdit);
- ShowWindow(plv->hwndEdit, SW_SHOW);
- }
- }
- }
- void FAR PASCAL RescrollEditWindow(HWND hwndEdit)
- {
- Edit_SetSel(hwndEdit, 32000, 32000); // move to the end
- Edit_SetSel(hwndEdit, 0, 32000); // select all text
- }
- // BUGBUG: very similar code in treeview.c
- HWND NEAR ListView_OnEditLabel(LV* plv, int i, LPSTR pszInitialText)
- {
- // this eats stack
- ListView_DismissEdit(plv, FALSE);
- if (!(plv->style & LVS_EDITLABELS) || (GetFocus() != plv->hwnd) ||
- (i == -1))
- return(NULL); // Does not support this.
- ListView_DoOnEditLabel(plv, i, pszInitialText);
- if (plv->hwndEdit) {
- plv->iEdit = i;
- plv->pfnEditWndProc = SubclassWindow(plv->hwndEdit, ListView_EditWndProc);
- #ifdef FE_IME
- if (SendMessage(plv->hwndEdit, EM_GETLIMITTEXT, (WPARAM)0, (LPARAM)0)<13)
- {
- plv->flags |= LVF_DONTDRAWCOMP;
- }
- #endif
- ListView_SetEditSize(plv);
- RescrollEditWindow(plv->hwndEdit);
- }
- return plv->hwndEdit;
- }
- // BUGBUG: very similar code in treeview.c
- BOOL NEAR ListView_DismissEdit(LV* plv, BOOL fCancel)
- {
- LISTITEM FAR* pitem;
- BOOL fOkToContinue = TRUE;
- HWND hwndEdit = plv->hwndEdit;
- HWND hwnd = plv->hwnd;
- int iEdit;
- #ifdef FE_IME
- HIMC himc;
- #endif
- if (plv->fNoDismissEdit)
- return FALSE;
- if (!hwndEdit) {
- // Also make sure there are no pending edits...
- ListView_CancelPendingEdit(plv);
- return TRUE; // It is OK to process as normal...
- }
- // If the window is not visible, we are probably in the process
- // of being destroyed, so assume that we are being destroyed
- if (!IsWindowVisible(plv->hwnd))
- fCancel = TRUE;
- //
- // We are using the Window ID of the control as a BOOL to
- // state if it is dirty or not.
- switch (GetWindowID(hwndEdit)) {
- case 0:
- // The edit control is not dirty so act like cancel.
- fCancel = TRUE;
- // Fall through to set window so we will not recurse!
- case 1:
- // The edit control is dirty so continue.
- SetWindowID(hwndEdit, 2); // Don't recurse
- break;
- case 2:
- // We are in the process of processing an update now, bail out
- return TRUE;
- }
- // BUGBUG: this will fail if the program deleted the items out
- // from underneath us (while we are waiting for the edit timer).
- // make delete item invalidate our edit item
- // We uncouple the edit control and hwnd out from under this as
- // to allow code that process the LVN_ENDLABELEDIT to reenter
- // editing mode if an error happens.
- iEdit = plv->iEdit;
- pitem = ListView_GetItemPtr(plv, iEdit);
- Assert(pitem);
- if (pitem != NULL)
- {
- LV_DISPINFO nm;
- char szLabel[CCHLABELMAX];
- nm.item.iItem = iEdit;
- nm.item.lParam = pitem->lParam;
- nm.item.iSubItem = 0;
- nm.item.cchTextMax = 0;
- nm.item.mask = 0;
- if (fCancel)
- nm.item.pszText = NULL;
- else {
- Edit_GetText(hwndEdit, szLabel, sizeof(szLabel));
- nm.item.pszText = szLabel;
- }
- //
- // Notify the parent that we the label editing has completed.
- // We will use the LV_DISPINFO structure to return the new
- // label in. The parent still has the old text available by
- // calling the GetItemText function.
- //
- fOkToContinue = (BOOL)SendNotify(plv->hwndParent, plv->hwnd, LVN_ENDLABELEDIT, &nm.hdr);
- if (!IsWindow(hwnd)) {
- return FALSE;
- }
- if (fOkToContinue && !fCancel)
- {
- //
- // If the item has the text set as CALLBACK, we will let the
- // ower know that they are supposed to set the item text in
- // their own data structures. Else we will simply update the
- // text in the actual view.
- //
- if (pitem->pszText != LPSTR_TEXTCALLBACK)
- {
- // Set the item text (everything's set up in nm.item)
- //
- nm.item.mask = LVIF_TEXT;
- ListView_OnSetItem(plv, &nm.item);
- }
- else
- {
- SendNotify(plv->hwndParent, plv->hwnd, LVN_SETDISPINFO, &nm.hdr);
- // Also we will assume that our cached size is invalid...
- plv->rcView.left = RECOMPUTE;
- pitem->cyMultiLabel = pitem->cxSingleLabel = pitem->cxMultiLabel = SRECOMPUTE;
- }
- }
- #ifdef FE_IME
- if (LOWORD(GetKeyboardLayout(0L)) == 0x0411 && (himc = ImmGetContext(hwndEdit)))
- {
- ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0L);
- ImmReleaseContext(hwndEdit, himc);
- }
- #endif
- // redraw
- ListView_InvalidateItem(plv, iEdit, FALSE, RDW_INVALIDATE | RDW_ERASE);
- }
- // If the hwnedit is still us clear out the variables
- if (hwndEdit == plv->hwndEdit)
- {
- plv->iEdit = -1;
- plv->hwndEdit = NULL; // avoid being reentered
- }
- DestroyWindow(hwndEdit);
- return fOkToContinue;
- }
- //
- // This function will scall the icon positions that are stored in the
- // item structures between large and small icon view.
- //
- void NEAR ListView_ScaleIconPositions(LV* plv, BOOL fSmallIconView)
- {
- int cxItem, cyItem;
- HWND hwnd;
- int i;
- cxItem = plv->cxItem;
- cyItem = plv->cyItem;
- hwnd = plv->hwnd;
- if (fSmallIconView)
- {
- if (plv->flags & LVF_ICONPOSSML)
- return; // Already done
- }
- else
- {
- if ((plv->flags & LVF_ICONPOSSML) == 0)
- return; // dito
- }
- // Last but not least update our bit!
- plv->flags ^= LVF_ICONPOSSML;
- // We will now loop through all of the items and update their coordinats
- // We will update th position directly into the view instead of calling
- // SetItemPosition as to not do 5000 invalidates and messages...
- for (i = 0; i < ListView_Count(plv); i++)
- {
- LISTITEM FAR* pitem = ListView_FastGetItemPtr(plv, i);
- if (fSmallIconView)
- {
- if (pitem->pt.y != RECOMPUTE) {
- pitem->pt.x = MulDiv(pitem->pt.x - g_cxIconOffset, cxItem, lv_cxIconSpacing);
- pitem->pt.y = MulDiv(pitem->pt.y - g_cyIconOffset, cyItem, lv_cyIconSpacing);
- }
- }
- else
- {
- pitem->pt.x = MulDiv(pitem->pt.x, lv_cxIconSpacing, cxItem) + g_cxIconOffset;
- pitem->pt.y = MulDiv(pitem->pt.y, lv_cyIconSpacing, cyItem) + g_cyIconOffset;
- }
- }
- if (plv->style & LVS_AUTOARRANGE)
- {
- // If autoarrange is turned on, the arrange function will do
- // everything that is needed.
- ListView_OnArrange(plv, LVA_DEFAULT);
- return;
- }
- plv->rcView.left = RECOMPUTE;
- //
- // Also scale the origin
- //
- if (fSmallIconView)
- {
- plv->ptOrigin.x = MulDiv(plv->ptOrigin.x, cxItem, lv_cxIconSpacing);
- plv->ptOrigin.y = MulDiv(plv->ptOrigin.y, cyItem, lv_cyIconSpacing);
- }
- else
- {
- plv->ptOrigin.x = MulDiv(plv->ptOrigin.x, lv_cxIconSpacing, cxItem);
- plv->ptOrigin.y = MulDiv(plv->ptOrigin.y, lv_cyIconSpacing, cyItem);
- }
- // Make sure it fully redraws correctly
- RedrawWindow(plv->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
- }
- HWND FAR PASCAL CreateEditInPlaceWindow(HWND hwnd, LPCSTR lpText, int cbText, LONG style, HFONT hFont)
- {
- HWND hwndEdit;
- hwndEdit = CreateWindowEx(0 /* WS_EX_CLIENTEDGE */, "EDIT", lpText, style,
- 0, 0, 0, 0, hwnd, NULL, HINST_THISDLL, NULL);
- if (hwndEdit) {
- Edit_LimitText(hwndEdit, cbText);
- Edit_SetSel(hwndEdit, 0, 0); // move to the beginning
- FORWARD_WM_SETFONT(hwndEdit, hFont, FALSE, SendMessage);
- }
- return hwndEdit;
- }
- // BUGBUG: very similar routine in treeview
- // in:
- // hwndEdit edit control to position in client coords of parent window
- // prc bonding rect of the text, used to position everthing
- // hFont font being used
- // fWrap if this is a wrapped type edit
- //
- // Notes:
- // The top-left corner of the bouding rectangle must be the position
- // the client uses to draw text. We adjust the edit field rectangle
- // appropriately.
- //
- void FAR PASCAL SetEditInPlaceSize(HWND hwndEdit, RECT FAR *prc, HFONT hFont, BOOL fWrap)
- {
- RECT rc, rcClient, rcFormat;
- char szLabel[CCHLABELMAX + 1];
- int cchLabel, cxIconTextWidth;
- HDC hdc;
- HWND hwndParent = GetParent(hwndEdit);
- #ifdef DBCS
- short wRightMgn;
- #endif
- cchLabel = Edit_GetText(hwndEdit, szLabel, sizeof(szLabel));
- if (szLabel[0] == 0)
- {
- lstrcpy(szLabel, c_szSpace);
- cchLabel = 1;
- }
- hdc = GetDC(hwndParent);
- #ifdef DEBUG
- //DrawFocusRect(hdc, prc); // this is the rect they are passing in
- #endif
- SelectFont(hdc, hFont);
- cxIconTextWidth = g_cxIconSpacing - g_cxLabelMargin * 2;
- rc.left = rc.top = rc.bottom = 0;
- rc.right = cxIconTextWidth; // for DT_LVWRAP
- // REVIEW: we might want to include DT_EDITCONTROL in our DT_LVWRAP
- // If the string is NULL display a rectangle that is visible.
- DrawText(hdc, szLabel, cchLabel, &rc, fWrap ? (DT_LVWRAP | DT_CALCRECT) : (DT_LV | DT_CALCRECT));
- // Minimum text box size is 1/4 icon spacing size
- if (rc.right < g_cxIconSpacing / 4)
- rc.right = g_cxIconSpacing / 4;
- // position the text rect based on the text rect passed in
- // if wrapping, center the edit control around the text mid point
- OffsetRect(&rc,
- fWrap ? prc->left + ((prc->right - prc->left) - (rc.right - rc.left)) / 2 : prc->left,
- fWrap ? prc->top : prc->top + ((prc->bottom - prc->top) - (rc.bottom - rc.top)) / 2 );
- // give a little space to ease the editing of this thing
- if (!fWrap)
- rc.right += g_cxLabelMargin * 4;
- #ifdef DEBUG
- //DrawFocusRect(hdc, &rc);
- #endif
- ReleaseDC(hwndParent, hdc);
- //
- // #5688: We need to make it sure that the whole edit window is
- // always visible. We should not extend it to the outside of
- // the parent window.
- //
- {
- BOOL fSuccess;
- GetClientRect(hwndParent, &rcClient);
- fSuccess = IntersectRect(&rc, &rc, &rcClient);
- Assert(fSuccess || IsRectEmpty(&rcClient));
- }
- //
- // Inflate it after the clipping, because it's ok to hide border.
- //
- SendMessage(hwndEdit, EM_GETRECT, 0, (LPARAM)(LPRECT)&rcFormat);
- // account for the border style, REVIEW: there might be a better way!
- #ifdef DBCS
- // some FE fonts have suprisingly big negative C width
- #ifndef IEWIN31_25
- wRightMgn=HIWORD(SendMessage(hwndEdit, EM_GETMARGINS, 0, 0));
- #else
- wRightMgn=0;
- #endif
- InflateRect(&rc, rcFormat.left + wRightMgn + g_cxEdge, rcFormat.top + g_cyEdge);
- #else
- InflateRect(&rc, rcFormat.left + g_cxEdge, rcFormat.top + g_cyEdge);
- #endif
- rc.right += g_cyEdge; // try to leave a little more for dual blanks
- HideCaret(hwndEdit);
- SetWindowPos(hwndEdit, NULL, rc.left, rc.top,
- rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOACTIVATE);
- ShowCaret(hwndEdit);
- }
- UINT NEAR PASCAL ListView_DrawImage(LV* plv, LV_ITEM FAR* pitem, HDC hdc, int x, int y, UINT fDraw)
- {
- UINT fText = SHDT_DESELECTED;
- UINT fImage = ILD_NORMAL;
- COLORREF clr;
- HIMAGELIST himl;
- fImage = (pitem->state & LVIS_OVERLAYMASK);
- fText = SHDT_DESELECTED;
- himl = ListView_IsIconView(plv) ? plv->himl : plv->himlSmall;
- // the item can have one of 4 states, for 3 looks:
- // normal simple drawing
- // selected, no focus light image highlight, no text hi
- // selected w/ focus highlight image & text
- // drop highlighting highlight image & text
- if ((pitem->state & LVIS_DROPHILITED) ||
- ((fDraw & LVDI_SELECTED) && (pitem->state & LVIS_SELECTED)))
- {
- fText = SHDT_SELECTED;
- fImage |= ILD_BLEND50;
- clr = CLR_HILIGHT;
- }
- if (pitem->state & LVIS_CUT)
- {
- fImage |= ILD_BLEND50;
- clr = plv->clrBk;
- }
- #if 0 // dont do a selected but dont have the focus vis.
- else if (item.state & LVIS_SELECTED)
- {
- fImage |= ILD_BLEND25;
- clr = CLR_HILIGHT;
- }
- #endif
- if (!(fDraw & LVDI_NOIMAGE))
- {
- if (himl) {
- ImageList_DrawEx(himl, pitem->iImage, hdc, x, y, 0, 0, plv->clrBk, clr, fImage);
- }
- if (plv->himlState) {
- if (LV_StateImageValue(pitem)) {
- int iState = LV_StateImageIndex(pitem);
- int dyImage =
- (himl) ?
- ( (ListView_IsIconView(plv) ? plv->cyIcon : plv->cySmIcon) - plv->cyState)
- : 0;
- ImageList_Draw(plv->himlState, iState, hdc, x-plv->cxState,
- y + dyImage,
- ILD_NORMAL);
- }
- }
- }
- return fText;
- }
- #ifdef FE_IME
- void NEAR PASCAL ListView_SizeIME(HWND hwnd)
- {
- HIMC himc;
- #ifdef _WIN32
- CANDIDATEFORM candf;
- #else
- CANDIDATEFORM16 candf;
- #endif
- RECT rc;
- // If this subclass procedure is being called with WM_SIZE,
- // This routine sets the rectangle to an IME.
- GetClientRect(hwnd, &rc);
- // Candidate stuff
- candf.dwIndex = 0; // Bogus assumption for Japanese IME.
- candf.dwStyle = CFS_EXCLUDE;
- candf.ptCurrentPos.x = rc.left;
- candf.ptCurrentPos.y = rc.bottom;
- candf.rcArea = rc;
- if (himc=ImmGetContext(hwnd))
- {
- ImmSetCandidateWindow(himc, &candf);
- ImmReleaseContext(hwnd, himc);
- }
- }
- LPSTR NEAR PASCAL DoDBCSBoundary(LPSTR lpsz, int FAR *lpcchMax)
- {
- int i = 0;
- while (i < *lpcchMax && *lpsz)
- {
- i++;
- if (IsDBCSLeadByte(*lpsz))
- {
- if (i >= *lpcchMax)
- {
- --i; // Wrap up without the last leadbyte.
- break;
- }
- i++;
- lpsz+= 2;
- }
- else
- lpsz++;
- }
- *lpcchMax = i;
- return lpsz;
- }
- void NEAR PASCAL DrawCompositionLine(HWND hwnd, HDC hdc, HFONT hfont, LPCSTR lpszComp, LPCSTR lpszAttr, int ichCompStart, int ichCompEnd, int ichStart)
- {
- PSTR pszCompStr;
- int ichSt,ichEnd;
- DWORD dwPos;
- BYTE bAttr;
- HFONT hfontOld;
- COLORREF crFore = GetSysColor(COLOR_WINDOWTEXT);
- COLORREF crBack = GetSysColor(COLOR_WINDOW);
- COLORREF crForeH = GetSysColor(COLOR_HIGHLIGHTTEXT);
- COLORREF crBackH = GetSysColor(COLOR_HIGHLIGHT);
- int fnPen;
- HPEN hPen;
- COLORREF crDrawText;
- COLORREF crDrawBack;
- COLORREF crOldText;
- COLORREF crOldBk;
- while (ichCompStart < ichCompEnd)
- {
- // Get the fragment to draw
- //
- // ichCompStart,ichCompEnd -- index at Edit Control
- // ichSt,ichEnd -- index at lpszComp
- ichEnd = ichSt = ichCompStart - ichStart;
- bAttr = lpszAttr[ichSt];
- while (ichEnd < ichCompEnd - ichStart)
- {
- if (bAttr == lpszAttr[ichEnd])
- ichEnd++;
- else
- break;
- }
- pszCompStr = (PSTR)LocalAlloc(LPTR, ichEnd - ichSt + 1 + 1 ); // 1 for NULL.
- if (pszCompStr)
- {
- lstrcpyn(pszCompStr, &lpszComp[ichSt], ichEnd-ichSt+1);
- pszCompStr[ichEnd-ichSt] = '';
- }
- // Attribute stuff
- switch (bAttr)
- {
- case ATTR_INPUT:
- fnPen = PS_DOT;
- crDrawText = crFore;
- crDrawBack = crBack;
- break;
- case ATTR_TARGET_CONVERTED:
- case ATTR_TARGET_NOTCONVERTED:
- fnPen = PS_DOT;
- crDrawText = crForeH;
- crDrawBack = crBackH;
- break;
- case ATTR_CONVERTED:
- fnPen = PS_SOLID;
- crDrawText = crFore;
- crDrawBack = crBack;
- break;
- }
- crOldText = SetTextColor(hdc, crDrawText);
- crOldBk = SetBkColor(hdc, crDrawBack);
- hfontOld= SelectObject(hdc, hfont);
- // Get the start position of composition
- //
- dwPos = SendMessage(hwnd, EM_POSFROMCHAR, ichCompStart, 0);
- // Draw it.
- TextOut(hdc, LOWORD(dwPos), HIWORD(dwPos), pszCompStr, ichEnd-ichSt);
- // Underline
- hPen = CreatePen(fnPen, 1, crDrawText);
- if( hPen ) {
- HPEN hpenOld = SelectObject( hdc, hPen );
- int iOldBk = SetBkMode( hdc, TRANSPARENT );
- SIZE size;
- GetTextExtentPoint(hdc, pszCompStr, ichEnd-ichSt, &size);
- MoveToEx( hdc, LOWORD(dwPos), size.cy + HIWORD(dwPos)-1, NULL);
- LineTo( hdc, size.cx + LOWORD(dwPos), size.cy + HIWORD(dwPos)-1 );
- SetBkMode( hdc, iOldBk );
- if( hpenOld ) SelectObject( hdc, hpenOld );
- DeleteObject( hPen );
- }
- if (hfontOld)
- SelectObject(hdc, hfontOld);
- SetTextColor(hdc, crOldText);
- SetBkColor(hdc, crOldBk);
- LocalFree((HLOCAL)pszCompStr);
- //Next fragment
- //
- ichCompStart += ichEnd-ichSt;
- }
- }
- void NEAR PASCAL ListView_InsertComposition(HWND hwnd, WPARAM wParam, LPARAM lParam, LV *plv)
- {
- char *pszCompStr;
- int cchComp = 0;
- int cchCompNew;
- int cchMax;
- int cchText;
- DWORD dwSel;
- HIMC himc = (HIMC)0;
- // To prevent recursion..
- if (plv->flags & LVF_INSERTINGCOMP)
- {
- return;
- }
- plv->flags |= LVF_INSERTINGCOMP;
- // Don't want to redraw edit during inserting.
- //
- SendMessage(hwnd, WM_SETREDRAW, (WPARAM)FALSE, 0);
- // If we have RESULT STR, put it to EC first.
- if (himc = ImmGetContext(hwnd))
- {
- #ifdef WIN32
- if (!(dwSel = (DWORD)GetProp(hwnd, szIMECompPos)))
- dwSel = Edit_GetSel(hwnd);
- // Becaues we don't setsel after inserting composition
- // in win32 case.
- Edit_SetSel(hwnd, LOWORD(dwSel), HIWORD(dwSel));
- #endif
- if (lParam&GCS_RESULTSTR)
- {
- pszCompStr = (PSTR)LocalAlloc(LPTR, 1 );
- if(cchComp = (int)ImmGetCompositionString(himc, GCS_RESULTSTR, NULL, 0))
- {
- if(pszCompStr = (PSTR)LocalReAlloc(pszCompStr, cchComp+1,LMEM_MOVEABLE ))
- {
- ImmGetCompositionString(himc, GCS_RESULTSTR, pszCompStr, cchComp+1);
- }
- }
- pszCompStr[cchComp] = '';
- Edit_ReplaceSel(hwnd, pszCompStr);
- LocalFree((HLOCAL)pszCompStr);
- #ifdef WIN32
- // There's no longer selection
- //
- RemoveProp(hwnd, szIMECompPos);
- // Get current cursor pos so that the subsequent composition
- // handling will do the right thing.
- //
- dwSel = Edit_GetSel(hwnd);
- #endif
- }
- if (lParam & GCS_COMPSTR)
- {
- pszCompStr = (PSTR)LocalAlloc(LPTR, 1 );
- if(cchComp = (int)ImmGetCompositionString(himc, GCS_COMPSTR, NULL, 0))
- {
- pszCompStr = (PSTR)LocalReAlloc(pszCompStr, cchComp+1,LMEM_MOVEABLE );
- if (!pszCompStr)
- goto ReleaseContext;
- ImmGetCompositionString(himc, GCS_COMPSTR, pszCompStr, cchComp+1);
- // Get position of the current selection
- //
- #ifndef WIN32
- dwSel = Edit_GetSel(hwnd);
- #endif
- cchMax = (int)SendMessage(hwnd, EM_GETLIMITTEXT, 0, 0);
- cchText = Edit_GetTextLength(hwnd);
- // Cut the composition string if it exceeds limit.
- //
- cchCompNew = min(cchComp,
- cchMax-(cchText-(HIWORD(dwSel)-LOWORD(dwSel))));
- // wrap up the DBCS at the end of string
- //
- if (cchCompNew < cchComp)
- {
- DoDBCSBoundary((LPSTR)pszCompStr, (int FAR *)&cchCompNew);
- pszCompStr[cchCompNew] = '';
- // Reset composition string if we cut it.
- ImmSetCompositionString(himc, SCS_SETSTR, pszCompStr, cchCompNew, NULL, 0);
- cchComp = cchCompNew;
- }
- }
- pszCompStr[cchComp] = '';
- // Replace the current selection with composition string.
- //
- Edit_ReplaceSel(hwnd, pszCompStr);
- LocalFree((HLOCAL)pszCompStr);
- // Mark the composition string so that we can replace it again
- // for the next time.
- //
- #ifdef WIN32
- // Don't setsel to avoid flicking
- if (cchComp)
- {
- dwSel = MAKELONG(LOWORD(dwSel),LOWORD(dwSel)+cchComp);
- SetProp(hwnd, szIMECompPos, (HANDLE)dwSel);
- }
- else
- RemoveProp(hwnd, szIMECompPos);
- #else
- // Still use SETSEL for 16bit.
- if (cchComp)
- Edit_SetSel(hwnd, LOWORD(dwSel), LOWORD(dwSel)+cchComp);
- #endif
- }
- ReleaseContext:
- ImmReleaseContext(hwnd, himc);
- }
- SendMessage(hwnd, WM_SETREDRAW, (WPARAM)TRUE, 0);
- //
- // We want to update the size of label edit just once at
- // each WM_IME_COMPOSITION processing. ReplaceSel causes several EN_UPDATE
- // and it causes ugly flicking too.
- //
- SetWindowID(plv->hwndEdit, 1);
- ListView_SetEditSize(plv);
- RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT|RDW_INVALIDATE);
- UpdateWindow(hwnd);
- plv->flags &= ~LVF_INSERTINGCOMP;
- }
- void NEAR PASCAL ListView_PaintComposition(HWND hwnd, LV * plv)
- {
- char szCompStr[CCHLABELMAX + 1];
- char szCompAttr[CCHLABELMAX + 1];
- int cchLine, ichLineStart;
- int cchComp = 0;
- int nLine;
- int ichCompStart, ichCompEnd;
- DWORD dwSel;
- int cchMax, cchText;
- HIMC himc = (HIMC)0;
- HDC hdc;
- if (plv->flags & LVF_INSERTINGCOMP)
- {
- // This is the case that ImmSetCompositionString() generates
- // WM_IME_COMPOSITION. We're not ready to paint composition here.
- return;
- }
- if (himc = ImmGetContext(hwnd))
- {
- cchComp=(UINT)ImmGetCompositionString(himc, GCS_COMPSTR, szCompStr, sizeof(szCompStr));
- ImmGetCompositionString(himc, GCS_COMPATTR, szCompAttr, sizeof(szCompStr));
- ImmReleaseContext(hwnd, himc);
- }
- if (cchComp)
- {
- // Get the position of current selection
- //
- #ifdef WIN32
- if (!(dwSel = (DWORD)GetProp(hwnd, szIMECompPos)))
- dwSel = 0L;
- #else
- dwSel = Edit_GetSel(hwnd);
- #endif
- cchMax = (int)SendMessage(hwnd, EM_GETLIMITTEXT, 0, 0);
- cchText = Edit_GetTextLength(hwnd);
- cchComp = min(cchComp, cchMax-(cchText-(HIWORD(dwSel)-LOWORD(dwSel))));
- DoDBCSBoundary((LPSTR)szCompStr, (int FAR *)&cchComp);
- szCompStr[cchComp] = '';
- /////////////////////////////////////////////////
- // //
- // Draw composition string over the sel string.//
- // //
- /////////////////////////////////////////////////
- hdc = GetDC(hwnd);
- ichCompStart = LOWORD(dwSel);
- while (ichCompStart < (int)LOWORD(dwSel) + cchComp)
- {
- // Get line from each start pos.
- //
- nLine = Edit_LineFromChar(hwnd, ichCompStart);
- ichLineStart = Edit_LineIndex(hwnd, nLine);
- cchLine= Edit_LineLength(hwnd, ichLineStart);
- // See if composition string is longer than this line.
- //
- if(ichLineStart+cchLine > (int)LOWORD(dwSel)+cchComp)
- ichCompEnd = LOWORD(dwSel)+cchComp;
- else
- {
- // Yes, the composition string is longer.
- // Take the begining of the next line as next start.
- //
- if (ichLineStart+cchLine > ichCompStart)
- ichCompEnd = ichLineStart+cchLine;
- else
- {
- // If the starting position is not proceeding,
- // let's get out of here.
- break;
- }
- }
- // Draw the line
- //
- DrawCompositionLine(hwnd, hdc, plv->hfontLabel, szCompStr, szCompAttr, ichCompStart, ichCompEnd, LOWORD(dwSel));
- ichCompStart = ichCompEnd;
- }
- ReleaseDC(hwnd, hdc);
- }
- // We don't want to repaint the window.
- ValidateRect(hwnd, NULL);
- }
- #endif