home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1992 / 06 / dflt12 / listbox.c < prev    next >
Text File  |  1992-01-17  |  14KB  |  470 lines

  1. /* ------------- listbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. #ifdef INCLUDE_EXTENDEDSELECTIONS
  6. static int ExtendSelections(WINDOW, int, int);
  7. static void TestExtended(WINDOW, PARAM);
  8. static void ClearAllSelections(WINDOW);
  9. static void SetSelection(WINDOW, int);
  10. static void FlipSelection(WINDOW, int);
  11. static void ClearSelection(WINDOW, int);
  12. #else
  13. #define TestExtended(w,p) /**/
  14. #endif
  15. static void near ChangeSelection(WINDOW, int, int);
  16. static void near WriteSelection(WINDOW, int, int, RECT *);
  17. static BOOL SelectionInWindow(WINDOW, int);
  18.  
  19. static int py = -1;    /* the previous y mouse coordinate */
  20.  
  21. #ifdef INCLUDE_EXTENDEDSELECTIONS
  22. /* --------- SHIFT_F8 Key ------------ */
  23. static void AddModeKey(WINDOW wnd)
  24. {
  25.     if (isMultiLine(wnd))    {
  26.         wnd->AddMode ^= TRUE;
  27.         SendMessage(GetParent(wnd), ADDSTATUS,
  28.             wnd->AddMode ? ((PARAM) "Add Mode") : 0, 0);
  29.     }
  30. }
  31. #endif
  32.  
  33. /* --------- UP (Up Arrow) Key ------------ */
  34. static void UpKey(WINDOW wnd, PARAM p2)
  35. {
  36.     if (wnd->selection > 0)    {
  37.         if (wnd->selection == wnd->wtop)    {
  38.             BaseWndProc(LISTBOX, wnd, KEYBOARD, UP, p2);
  39.             PostMessage(wnd, LB_SELECTION, wnd->selection-1,
  40.                 isMultiLine(wnd) ? p2 : FALSE);
  41.         }
  42.         else    {
  43.             int newsel = wnd->selection-1;
  44.             if (wnd->wlines == ClientHeight(wnd))
  45.                 while (*TextLine(wnd, newsel) == LINE)
  46.                     --newsel;
  47.             PostMessage(wnd, LB_SELECTION, newsel,
  48. #ifdef INCLUDE_EXTENDEDSELECTIONS
  49.                 isMultiLine(wnd) ? p2 :
  50. #endif
  51.                 FALSE);
  52.         }
  53.     }
  54. }
  55.  
  56. /* --------- DN (Down Arrow) Key ------------ */
  57. static void DnKey(WINDOW wnd, PARAM p2)
  58. {
  59.     if (wnd->selection < wnd->wlines-1)    {
  60.         if (wnd->selection == wnd->wtop+ClientHeight(wnd)-1)  {
  61.             BaseWndProc(LISTBOX, wnd, KEYBOARD, DN, p2);
  62.             PostMessage(wnd, LB_SELECTION, wnd->selection+1,
  63.                 isMultiLine(wnd) ? p2 : FALSE);
  64.         }
  65.         else    {
  66.             int newsel = wnd->selection+1;
  67.             if (wnd->wlines == ClientHeight(wnd))
  68.                 while (*TextLine(wnd, newsel) == LINE)
  69.                     newsel++;
  70.             PostMessage(wnd, LB_SELECTION, newsel,
  71. #ifdef INCLUDE_EXTENDEDSELECTIONS
  72.                 isMultiLine(wnd) ? p2 :
  73. #endif
  74.                 FALSE);
  75.         }
  76.     }
  77. }
  78.  
  79. /* --------- HOME and PGUP Keys ------------ */
  80. static void HomePgUpKey(WINDOW wnd, PARAM p1, PARAM p2)
  81. {
  82.     BaseWndProc(LISTBOX, wnd, KEYBOARD, p1, p2);
  83.     PostMessage(wnd, LB_SELECTION, wnd->wtop,
  84. #ifdef INCLUDE_EXTENDEDSELECTIONS
  85.         isMultiLine(wnd) ? p2 :
  86. #endif
  87.         FALSE);
  88. }
  89.  
  90. /* --------- END and PGDN Keys ------------ */
  91. static void EndPgDnKey(WINDOW wnd, PARAM p1, PARAM p2)
  92. {
  93.     int bot;
  94.     BaseWndProc(LISTBOX, wnd, KEYBOARD, p1, p2);
  95.     bot = wnd->wtop+ClientHeight(wnd)-1;
  96.     if (bot > wnd->wlines-1)
  97.         bot = wnd->wlines-1;
  98.     PostMessage(wnd, LB_SELECTION, bot,
  99. #ifdef INCLUDE_EXTENDEDSELECTIONS
  100.         isMultiLine(wnd) ? p2 :
  101. #endif
  102.         FALSE);
  103. }
  104.  
  105. #ifdef INCLUDE_EXTENDEDSELECTIONS
  106. /* --------- Space Bar Key ------------ */
  107. static void SpacebarKey(WINDOW wnd, PARAM p2)
  108. {
  109.     if (isMultiLine(wnd))    {
  110.         int sel = SendMessage(wnd, LB_CURRENTSELECTION, 0, 0);
  111.         if (sel != -1)    {
  112.             if (wnd->AddMode)
  113.                 FlipSelection(wnd, sel);
  114.             if (ItemSelected(wnd, sel))    {
  115.                 if (!((int) p2 & (LEFTSHIFT | RIGHTSHIFT)))
  116.                     wnd->AnchorPoint = sel;
  117.                 ExtendSelections(wnd, sel, (int) p2);
  118.             }
  119.             else
  120.                 wnd->AnchorPoint = -1;
  121.             SendMessage(wnd, PAINT, 0, 0);
  122.         }
  123.     }
  124. }
  125. #endif
  126.  
  127. /* --------- Enter ('\r') Key ------------ */
  128. static void EnterKey(WINDOW wnd)
  129. {
  130.     if (wnd->selection != -1)    {
  131.         SendMessage(wnd, LB_SELECTION, wnd->selection, TRUE);
  132.         SendMessage(wnd, LB_CHOOSE, wnd->selection, 0);
  133.     }
  134. }
  135.  
  136. /* --------- All Other Key Presses ------------ */
  137. static void KeyPress(WINDOW wnd, PARAM p1, PARAM p2)
  138. {
  139.     int sel = wnd->selection+1;
  140.     while (sel < wnd->wlines)    {
  141.         char *cp = TextLine(wnd, sel);
  142.         if (cp == NULL)
  143.             break;
  144. #ifdef INCLUDE_EXTENDEDSELECTIONS
  145.         if (isMultiLine(wnd))
  146.             cp++;
  147. #endif
  148.         /* --- special for directory list box --- */
  149.         if (*cp == '[')
  150.             cp++;
  151.         if (tolower(*cp) == (int)p1)    {
  152.             SendMessage(wnd, LB_SELECTION, sel,
  153.                 isMultiLine(wnd) ? p2 : FALSE);
  154.             if (!SelectionInWindow(wnd, sel))    {
  155.                 wnd->wtop = sel-ClientHeight(wnd)+1;
  156.                 SendMessage(wnd, PAINT, 0, 0);
  157.             }
  158.             break;
  159.         }
  160.         sel++;
  161.     }
  162. }
  163.  
  164. /* --------- KEYBOARD Message ------------ */
  165. static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  166. {
  167.     switch ((int) p1)    {
  168. #ifdef INCLUDE_EXTENDEDSELECTIONS
  169.         case SHIFT_F8:
  170.             AddModeKey(wnd);
  171.             return TRUE;
  172. #endif
  173.         case UP:
  174.             TestExtended(wnd, p2);
  175.             UpKey(wnd, p2);
  176.             return TRUE;
  177.         case DN:
  178.             TestExtended(wnd, p2);
  179.             DnKey(wnd, p2);
  180.             return TRUE;
  181.         case PGUP:
  182.         case HOME:
  183.             TestExtended(wnd, p2);
  184.             HomePgUpKey(wnd, p1, p2);
  185.             return TRUE;
  186.         case PGDN:
  187.         case END:
  188.             TestExtended(wnd, p2);
  189.             EndPgDnKey(wnd, p1, p2);
  190.             return TRUE;
  191. #ifdef INCLUDE_EXTENDEDSELECTIONS
  192.         case ' ':
  193.             SpacebarKey(wnd, p2);
  194.             break;
  195. #endif
  196.         case '\r':
  197.             EnterKey(wnd);
  198.             return TRUE;
  199.         default:
  200.             KeyPress(wnd, p1, p2);
  201.             break;
  202.     }
  203.     return FALSE;
  204. }
  205.  
  206. /* ------- LEFT_BUTTON Message -------- */
  207. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  208. {
  209.     int my = (int) p2 - GetTop(wnd);
  210.     if (my >= wnd->wlines-wnd->wtop)
  211.         my = wnd->wlines - wnd->wtop;
  212.  
  213.     if (!InsideRect(p1, p2, ClientRect(wnd)))
  214.         return FALSE;
  215.     if (wnd->wlines && my != py)    {
  216.         int sel = wnd->wtop+my-1;
  217. #ifdef INCLUDE_EXTENDEDSELECTIONS
  218.         int sh = getshift();
  219.         if (!(sh & (LEFTSHIFT | RIGHTSHIFT)))    {
  220.             if (!(sh & CTRLKEY))
  221.                 ClearAllSelections(wnd);
  222.             wnd->AnchorPoint = sel;
  223.             SendMessage(wnd, PAINT, 0, 0);
  224.         }
  225. #endif
  226.         SendMessage(wnd, LB_SELECTION, sel, TRUE);
  227.         py = my;
  228.     }
  229.     return TRUE;
  230. }
  231.  
  232. /* ------------- DOUBLE_CLICK Message ------------ */
  233. static int DoubleClickMsg(WINDOW wnd, PARAM p1, PARAM p2)
  234. {
  235.     if (WindowMoving || WindowSizing)
  236.         return FALSE;
  237.     if (wnd->wlines)    {
  238.         RECT rc = ClientRect(wnd);
  239.         BaseWndProc(LISTBOX, wnd, DOUBLE_CLICK, p1, p2);
  240.         if (InsideRect(p1, p2, rc))
  241.             SendMessage(wnd, LB_CHOOSE, wnd->selection, 0);
  242.     }
  243.     return TRUE;
  244. }
  245.  
  246. /* ------------ ADDTEXT Message -------------- */
  247. static int AddTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  248. {
  249.     int rtn = BaseWndProc(LISTBOX, wnd, ADDTEXT, p1, p2);
  250.     if (wnd->selection == -1)
  251.         SendMessage(wnd, LB_SETSELECTION, 0, 0);
  252. #ifdef INCLUDE_EXTENDEDSELECTIONS
  253.     if (*(char *)p1 == LISTSELECTOR)
  254.         wnd->SelectCount++;
  255. #endif
  256.     return rtn;
  257. }
  258.  
  259. /* --------- GETTEXT Message ------------ */
  260. static void GetTextMsg(WINDOW wnd, PARAM p1, PARAM p2)
  261. {
  262.     if ((int)p2 != -1)    {
  263.         char *cp1 = (char *)p1;
  264.         char *cp2 = TextLine(wnd, (int)p2);
  265.         while (cp2 && *cp2 && *cp2 != '\n')
  266.             *cp1++ = *cp2++;
  267.         *cp1 = '\0';
  268.     }
  269. }
  270.  
  271. /* --------- LISTBOX Window Processing Module ------------ */
  272. int ListBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  273. {
  274.     switch (msg)    {
  275.         case CREATE_WINDOW:
  276.             BaseWndProc(LISTBOX, wnd, msg, p1, p2);
  277.             wnd->selection = -1;
  278. #ifdef INCLUDE_EXTENDEDSELECTIONS
  279.             wnd->AnchorPoint = -1;
  280. #endif
  281.             return TRUE;
  282.         case KEYBOARD:
  283.             if (WindowMoving || WindowSizing)
  284.                 break;
  285.             if (KeyboardMsg(wnd, p1, p2))
  286.                 return TRUE;
  287.             break;
  288.         case LEFT_BUTTON:
  289.             if (LeftButtonMsg(wnd, p1, p2) == TRUE)
  290.                 return TRUE;
  291.             break;
  292.         case DOUBLE_CLICK:
  293.             if (DoubleClickMsg(wnd, p1, p2))
  294.                 return TRUE;
  295.             break;
  296.         case BUTTON_RELEASED:
  297.             if (WindowMoving || WindowSizing || VSliding)
  298.                 break;
  299.             py = -1;
  300.             return TRUE;
  301.         case ADDTEXT:
  302.             return AddTextMsg(wnd, p1, p2);
  303.         case LB_GETTEXT:
  304.             GetTextMsg(wnd, p1, p2);
  305.             return TRUE;
  306.         case CLEARTEXT:
  307.             wnd->selection = -1;
  308. #ifdef INCLUDE_EXTENDEDSELECTIONS
  309.             wnd->AnchorPoint = -1;
  310. #endif
  311.             wnd->SelectCount = 0;
  312.             break;
  313.         case PAINT:
  314.             BaseWndProc(LISTBOX, wnd, msg, p1, p2);
  315.             WriteSelection(wnd, wnd->selection, TRUE, (RECT *)p1);
  316.             return TRUE;
  317.         case SCROLL:
  318.         case HORIZSCROLL:
  319.         case SCROLLPAGE:
  320.         case HORIZPAGE:
  321.         case SCROLLDOC:
  322.             BaseWndProc(LISTBOX, wnd, msg, p1, p2);
  323.             WriteSelection(wnd,wnd->selection,TRUE,NULL);
  324.             return TRUE;
  325.         case LB_CHOOSE:
  326.             SendMessage(GetParent(wnd), LB_CHOOSE, p1, p2);
  327.             return TRUE;
  328.         case LB_SELECTION:
  329.             ChangeSelection(wnd, (int) p1, (int) p2);
  330.             SendMessage(GetParent(wnd), LB_SELECTION,
  331.                 wnd->selection, 0);
  332.             return TRUE;
  333.         case LB_CURRENTSELECTION:
  334.             return wnd->selection;
  335.         case LB_SETSELECTION:
  336.             ChangeSelection(wnd, (int) p1, 0);
  337.             return TRUE;
  338. #ifdef INCLUDE_EXTENDEDSELECTIONS
  339.         case CLOSE_WINDOW:
  340.             if (isMultiLine(wnd) && wnd->AddMode)    {
  341.                 wnd->AddMode = FALSE;
  342.                 SendMessage(GetParent(wnd), ADDSTATUS, 0, 0);
  343.             }
  344.             break;
  345. #endif
  346.         default:
  347.             break;
  348.     }
  349.     return BaseWndProc(LISTBOX, wnd, msg, p1, p2);
  350. }
  351.  
  352. static BOOL SelectionInWindow(WINDOW wnd, int sel)
  353. {
  354.     return (wnd->wlines && sel >= wnd->wtop &&
  355.             sel < wnd->wtop+ClientHeight(wnd));
  356. }
  357.  
  358. static void near WriteSelection(WINDOW wnd, int sel,
  359.                                     int reverse, RECT *rc)
  360. {
  361.     if (isVisible(wnd))
  362.         if (SelectionInWindow(wnd, sel))
  363.             WriteTextLine(wnd, rc, sel, reverse);
  364. }
  365.  
  366. #ifdef INCLUDE_EXTENDEDSELECTIONS
  367. /* ----- Test for extended selections in the listbox ----- */
  368. static void TestExtended(WINDOW wnd, PARAM p2)
  369. {
  370.     if (isMultiLine(wnd) && !wnd->AddMode &&
  371.             !((int) p2 & (LEFTSHIFT | RIGHTSHIFT)))    {
  372.         if (wnd->SelectCount > 1)    {
  373.             ClearAllSelections(wnd);
  374.             SendMessage(wnd, PAINT, 0, 0);
  375.         }
  376.     }
  377. }
  378.  
  379. /* ----- Clear selections in the listbox ----- */
  380. static void ClearAllSelections(WINDOW wnd)
  381. {
  382.     if (isMultiLine(wnd) && wnd->SelectCount > 0)    {
  383.         int sel;
  384.         for (sel = 0; sel < wnd->wlines; sel++)
  385.             ClearSelection(wnd, sel);
  386.     }
  387. }
  388.  
  389. /* ----- Invert a selection in the listbox ----- */
  390. static void FlipSelection(WINDOW wnd, int sel)
  391. {
  392.     if (isMultiLine(wnd))    {
  393.         if (ItemSelected(wnd, sel))
  394.             ClearSelection(wnd, sel);
  395.         else
  396.             SetSelection(wnd, sel);
  397.     }
  398. }
  399.  
  400. static int ExtendSelections(WINDOW wnd, int sel, int shift)
  401. {    
  402.     if (shift & (LEFTSHIFT | RIGHTSHIFT) &&
  403.                         wnd->AnchorPoint != -1)    {
  404.         int i = sel;
  405.         int j = wnd->AnchorPoint;
  406.         int rtn;
  407.         if (j > i)
  408.             swap(i,j);
  409.         rtn = i - j;
  410.         while (j <= i)
  411.             SetSelection(wnd, j++);
  412.         return rtn;
  413.     }
  414.     return 0;
  415. }
  416.  
  417. static void SetSelection(WINDOW wnd, int sel)
  418. {
  419.     if (isMultiLine(wnd) && !ItemSelected(wnd, sel))    {
  420.         char *lp = TextLine(wnd, sel);
  421.         *lp = LISTSELECTOR;
  422.         wnd->SelectCount++;
  423.     }
  424. }
  425.  
  426. static void ClearSelection(WINDOW wnd, int sel)
  427. {
  428.     if (isMultiLine(wnd) && ItemSelected(wnd, sel))    {
  429.         char *lp = TextLine(wnd, sel);
  430.         *lp = ' ';
  431.         --wnd->SelectCount;
  432.     }
  433. }
  434.  
  435. BOOL ItemSelected(WINDOW wnd, int sel)
  436. {
  437.     if (isMultiLine(wnd) && sel < wnd->wlines)    {
  438.         char *cp = TextLine(wnd, sel);
  439.         return (int)((*cp) & 255) == LISTSELECTOR;
  440.     }
  441.     return FALSE;
  442. }
  443. #endif
  444.  
  445. static void near ChangeSelection(WINDOW wnd,int sel,int shift)
  446. {
  447.     if (sel != wnd->selection)    {
  448. #ifdef INCLUDE_EXTENDEDSELECTIONS
  449.         if (isMultiLine(wnd))        {
  450.             int sels;
  451.             if (!wnd->AddMode)
  452.                 ClearAllSelections(wnd);
  453.             sels = ExtendSelections(wnd, sel, shift);
  454.             if (sels > 1)
  455.                 SendMessage(wnd, PAINT, 0, 0);
  456.             if (sels == 0 && !wnd->AddMode)    {
  457.                 ClearSelection(wnd, wnd->selection);
  458.                 SetSelection(wnd, sel);
  459.                 wnd->AnchorPoint = sel;
  460.             }
  461.         }
  462. #endif
  463.         WriteSelection(wnd, wnd->selection, FALSE, NULL);
  464.         wnd->selection = sel;
  465.         WriteSelection(wnd, sel, TRUE, NULL);
  466.      }
  467. }
  468.  
  469.  
  470.