home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 08 / dflat5 / listbox.c < prev    next >
Text File  |  1991-06-27  |  11KB  |  429 lines

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